]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branches 'devel', 'devel-stable' and 'fixes' into for-linus
authorRussell King <rmk+kernel@arm.linux.org.uk>
Fri, 27 May 2011 21:59:57 +0000 (22:59 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Fri, 27 May 2011 21:59:57 +0000 (22:59 +0100)
948 files changed:
.mailmap
CREDITS
Documentation/ABI/testing/sysfs-block
Documentation/ABI/testing/sysfs-ptp [new file with mode: 0644]
Documentation/IRQ-affinity.txt
Documentation/blockdev/cciss.txt
Documentation/cachetlb.txt
Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
Documentation/filesystems/9p.txt
Documentation/filesystems/proc.txt
Documentation/hwmon/emc6w201 [new file with mode: 0644]
Documentation/hwmon/f71882fg
Documentation/hwmon/fam15h_power [new file with mode: 0644]
Documentation/hwmon/k10temp
Documentation/hwmon/max6650
Documentation/ioctl/ioctl-number.txt
Documentation/kbuild/kconfig-language.txt
Documentation/kbuild/kconfig.txt
Documentation/kernel-parameters.txt
Documentation/lockstat.txt
Documentation/mmc/00-INDEX
Documentation/mmc/mmc-dev-attrs.txt
Documentation/mmc/mmc-dev-parts.txt [new file with mode: 0644]
Documentation/networking/bonding.txt
Documentation/ptp/ptp.txt [new file with mode: 0644]
Documentation/ptp/testptp.c [new file with mode: 0644]
Documentation/ptp/testptp.mk [new file with mode: 0644]
Documentation/virtual/uml/UserModeLinux-HOWTO.txt
Documentation/vm/locking
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/include/asm/gpio.h [new file with mode: 0644]
arch/alpha/include/asm/smp.h
arch/alpha/kernel/process.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/smp.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_titan.c
arch/alpha/mm/init.c
arch/alpha/mm/numa.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/include/asm/fiq.h
arch/arm/include/asm/page.h
arch/arm/include/asm/smp.h
arch/arm/include/asm/tlb.h
arch/arm/include/asm/unistd.h
arch/arm/kernel/Makefile
arch/arm/kernel/calls.S
arch/arm/kernel/fiq.c
arch/arm/kernel/fiqasm.S [new file with mode: 0644]
arch/arm/kernel/head.S
arch/arm/kernel/smp.c
arch/arm/lib/lib1funcs.S
arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h [new file with mode: 0644]
arch/arm/mach-netx/fb.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rx51-video.c
arch/arm/mach-omap2/board-zoom-display.c
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/include/mach/board-zoom.h
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/board-ag5evm.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-g4evm.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/clock-sh73a0.c
arch/arm/mach-shmobile/cpuidle.c [new file with mode: 0644]
arch/arm/mach-shmobile/headsmp.S
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/head-ap4evb.txt
arch/arm/mach-shmobile/include/mach/head-mackerel.txt
arch/arm/mach-shmobile/include/mach/sh7372.h
arch/arm/mach-shmobile/include/mach/sh73a0.h
arch/arm/mach-shmobile/intc-sh7372.c
arch/arm/mach-shmobile/pm-sh7372.c [new file with mode: 0644]
arch/arm/mach-shmobile/setup-sh7367.c
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-shmobile/setup-sh7377.c
arch/arm/mach-shmobile/setup-sh73a0.c
arch/arm/mach-shmobile/sleep-sh7372.S [new file with mode: 0644]
arch/arm/mach-shmobile/smp-sh73a0.c
arch/arm/mach-shmobile/suspend.c [new file with mode: 0644]
arch/arm/mach-tegra/include/mach/sdhci.h
arch/arm/mach-ux500/Kconfig
arch/arm/mach-ux500/Makefile
arch/arm/mach-ux500/board-mop500-sdi.c
arch/arm/mach-ux500/cpu-db5500.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/cpu.c
arch/arm/mach-ux500/cpufreq.c [deleted file]
arch/arm/mach-ux500/devices-common.h
arch/arm/mach-ux500/devices-db5500.h
arch/arm/mach-ux500/devices-db8500.h
arch/arm/mach-ux500/include/mach/db5500-regs.h
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/include/mach/hardware.h
arch/arm/mach-ux500/include/mach/id.h
arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
arch/arm/mach-ux500/include/mach/irqs-board-u5500.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/irqs-db5500.h
arch/arm/mach-ux500/include/mach/irqs-db8500.h
arch/arm/mach-ux500/include/mach/irqs.h
arch/arm/mach-ux500/include/mach/prcmu-defs.h [deleted file]
arch/arm/mach-ux500/include/mach/prcmu.h [deleted file]
arch/arm/mach-ux500/prcmu.c [deleted file]
arch/arm/mm/cache-v6.S
arch/arm/mm/cache-v7.S
arch/arm/mm/context.c
arch/arm/mm/init.c
arch/arm/mm/mm.h
arch/arm/mm/mmu.c
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S
arch/avr32/mm/init.c
arch/blackfin/Kconfig
arch/blackfin/Kconfig.debug
arch/blackfin/configs/BF527-EZKIT-V2_defconfig
arch/blackfin/configs/BF527-EZKIT_defconfig
arch/blackfin/configs/BF533-STAMP_defconfig
arch/blackfin/configs/BF537-STAMP_defconfig
arch/blackfin/include/asm/bfin-global.h
arch/blackfin/include/asm/bfin_pfmon.h [new file with mode: 0644]
arch/blackfin/include/asm/bfin_sport.h
arch/blackfin/include/asm/cacheflush.h
arch/blackfin/include/asm/cpu.h
arch/blackfin/include/asm/def_LPBlackfin.h
arch/blackfin/include/asm/irq_handler.h
arch/blackfin/include/asm/kgdb.h
arch/blackfin/include/asm/perf_event.h [new file with mode: 0644]
arch/blackfin/include/asm/ptrace.h
arch/blackfin/include/mach-common/irq.h [new file with mode: 0644]
arch/blackfin/kernel/Makefile
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/bfin_ksyms.c
arch/blackfin/kernel/debug-mmrs.c [new file with mode: 0644]
arch/blackfin/kernel/ipipe.c
arch/blackfin/kernel/irqchip.c
arch/blackfin/kernel/nmi.c
arch/blackfin/kernel/perf_event.c [new file with mode: 0644]
arch/blackfin/kernel/process.c
arch/blackfin/kernel/reboot.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/vmlinux.lds.S
arch/blackfin/mach-bf518/include/mach/anomaly.h
arch/blackfin/mach-bf518/include/mach/cdefBF512.h
arch/blackfin/mach-bf518/include/mach/defBF512.h
arch/blackfin/mach-bf518/include/mach/irq.h
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf527/include/mach/anomaly.h
arch/blackfin/mach-bf527/include/mach/cdefBF522.h
arch/blackfin/mach-bf527/include/mach/defBF522.h
arch/blackfin/mach-bf527/include/mach/irq.h
arch/blackfin/mach-bf533/include/mach/anomaly.h
arch/blackfin/mach-bf533/include/mach/irq.h
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/include/mach/anomaly.h
arch/blackfin/mach-bf537/include/mach/irq.h
arch/blackfin/mach-bf537/ints-priority.c
arch/blackfin/mach-bf538/include/mach/anomaly.h
arch/blackfin/mach-bf538/include/mach/irq.h
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf548/include/mach/anomaly.h
arch/blackfin/mach-bf548/include/mach/irq.h
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-bf561/include/mach/anomaly.h
arch/blackfin/mach-bf561/include/mach/irq.h
arch/blackfin/mach-bf561/smp.c
arch/blackfin/mach-common/dpmc.c
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mach-common/smp.c
arch/blackfin/mm/sram-alloc.c
arch/cris/arch-v32/kernel/irq.c
arch/cris/arch-v32/kernel/smp.c
arch/cris/mm/init.c
arch/frv/mm/init.c
arch/ia64/include/asm/tlb.h
arch/ia64/mm/contig.c
arch/ia64/mm/discontig.c
arch/ia64/mm/init.c
arch/m32r/Kconfig.debug
arch/m32r/include/asm/smp.h
arch/m32r/mm/discontig.c
arch/m32r/mm/init.c
arch/m68k/mm/init_mm.c
arch/microblaze/mm/init.c
arch/mips/Kconfig.debug
arch/mips/mm/init.c
arch/mn10300/kernel/irq.c
arch/mn10300/kernel/smp.c
arch/mn10300/mm/cache-smp.c
arch/mn10300/mm/init.c
arch/mn10300/mm/tlb-smp.c
arch/parisc/include/asm/smp.h
arch/parisc/mm/init.c
arch/powerpc/Kconfig
arch/powerpc/Kconfig.debug
arch/powerpc/boot/dts/mpc8313erdb.dts
arch/powerpc/boot/dts/mpc8572ds.dts
arch/powerpc/boot/dts/p2020ds.dts
arch/powerpc/boot/dts/p2020rdb.dts
arch/powerpc/include/asm/pgalloc.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/kernel/process.c
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/tlb_hash32.c
arch/powerpc/mm/tlb_hash64.c
arch/powerpc/mm/tlb_nohash.c
arch/s390/include/asm/tlb.h
arch/s390/mm/pgtable.c
arch/score/Kconfig.debug
arch/score/mm/init.c
arch/sh/Kconfig.debug
arch/sh/include/asm/tlb.h
arch/sh/mm/init.c
arch/sparc/Kconfig.debug
arch/sparc/include/asm/pgalloc_64.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/tlb_64.h
arch/sparc/include/asm/tlbflush_64.h
arch/sparc/kernel/setup_32.c
arch/sparc/mm/init_32.c
arch/sparc/mm/tlb.c
arch/sparc/mm/tsb.c
arch/tile/Kconfig
arch/tile/Kconfig.debug
arch/tile/configs/tile_defconfig [deleted file]
arch/tile/configs/tilegx_defconfig [new file with mode: 0644]
arch/tile/configs/tilepro_defconfig [new file with mode: 0644]
arch/tile/include/arch/chip_tilegx.h [new file with mode: 0644]
arch/tile/include/arch/icache.h
arch/tile/include/arch/interrupts_64.h [new file with mode: 0644]
arch/tile/include/arch/spr_def.h
arch/tile/include/arch/spr_def_64.h [new file with mode: 0644]
arch/tile/include/asm/atomic.h
arch/tile/include/asm/atomic_32.h
arch/tile/include/asm/atomic_64.h [new file with mode: 0644]
arch/tile/include/asm/backtrace.h
arch/tile/include/asm/bitops.h
arch/tile/include/asm/bitops_32.h
arch/tile/include/asm/bitops_64.h [new file with mode: 0644]
arch/tile/include/asm/cacheflush.h
arch/tile/include/asm/compat.h
arch/tile/include/asm/dma-mapping.h
arch/tile/include/asm/fb.h [new file with mode: 0644]
arch/tile/include/asm/io.h
arch/tile/include/asm/irq.h
arch/tile/include/asm/mmu_context.h
arch/tile/include/asm/opcode-tile_32.h
arch/tile/include/asm/opcode-tile_64.h
arch/tile/include/asm/opcode_constants_64.h
arch/tile/include/asm/page.h
arch/tile/include/asm/parport.h [new file with mode: 0644]
arch/tile/include/asm/pci.h
arch/tile/include/asm/pgtable_64.h [new file with mode: 0644]
arch/tile/include/asm/processor.h
arch/tile/include/asm/serial.h [new file with mode: 0644]
arch/tile/include/asm/signal.h
arch/tile/include/asm/spinlock_64.h [new file with mode: 0644]
arch/tile/include/asm/stat.h
arch/tile/include/asm/swab.h
arch/tile/include/asm/thread_info.h
arch/tile/include/asm/topology.h
arch/tile/include/asm/traps.h
arch/tile/include/asm/unistd.h
arch/tile/include/asm/vga.h [moved from arch/tile/include/hv/pagesize.h with 52% similarity]
arch/tile/include/hv/hypervisor.h
arch/tile/kernel/backtrace.c
arch/tile/kernel/compat.c
arch/tile/kernel/compat_signal.c
arch/tile/kernel/futex_64.S [new file with mode: 0644]
arch/tile/kernel/hardwall.c
arch/tile/kernel/head_64.S [new file with mode: 0644]
arch/tile/kernel/intvec_32.S
arch/tile/kernel/intvec_64.S [new file with mode: 0644]
arch/tile/kernel/module.c
arch/tile/kernel/pci-dma.c
arch/tile/kernel/pci.c
arch/tile/kernel/process.c
arch/tile/kernel/regs_64.S [new file with mode: 0644]
arch/tile/kernel/setup.c
arch/tile/kernel/signal.c
arch/tile/kernel/single_step.c
arch/tile/kernel/stack.c
arch/tile/kernel/sys.c
arch/tile/kernel/tile-desc_32.c
arch/tile/kernel/tile-desc_64.c [new file with mode: 0644]
arch/tile/kernel/time.c
arch/tile/kernel/tlb.c
arch/tile/kernel/traps.c
arch/tile/lib/atomic_asm_32.S
arch/tile/lib/cacheflush.c
arch/tile/lib/memchr_64.c [new file with mode: 0644]
arch/tile/lib/memcpy_64.c [new file with mode: 0644]
arch/tile/lib/memcpy_user_64.c [new file with mode: 0644]
arch/tile/lib/memset_64.c [new file with mode: 0644]
arch/tile/lib/spinlock_64.c [new file with mode: 0644]
arch/tile/lib/strchr_64.c [new file with mode: 0644]
arch/tile/lib/strlen_64.c [new file with mode: 0644]
arch/tile/lib/usercopy_64.S [new file with mode: 0644]
arch/tile/mm/fault.c
arch/tile/mm/init.c
arch/tile/mm/migrate_64.S [new file with mode: 0644]
arch/um/Kconfig.debug
arch/um/drivers/Makefile
arch/um/drivers/mcast.h [deleted file]
arch/um/drivers/mcast_kern.c [deleted file]
arch/um/drivers/mcast_user.c [deleted file]
arch/um/drivers/umcast.h [new file with mode: 0644]
arch/um/drivers/umcast_kern.c [new file with mode: 0644]
arch/um/drivers/umcast_user.c [new file with mode: 0644]
arch/um/drivers/xterm.c
arch/um/include/asm/processor-generic.h
arch/um/include/asm/smp.h
arch/um/include/asm/tlb.h
arch/um/include/shared/os.h
arch/um/kernel/Makefile
arch/um/kernel/early_printk.c [new file with mode: 0644]
arch/um/kernel/smp.c
arch/um/kernel/trap.c
arch/um/os-Linux/main.c
arch/um/os-Linux/process.c
arch/um/os-Linux/util.c
arch/unicore32/Kconfig.debug
arch/unicore32/mm/init.c
arch/unicore32/mm/mmu.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/include/asm/io.h
arch/x86/kernel/setup.c
arch/x86/kernel/tboot.c
arch/x86/kvm/mmu.c
arch/x86/mm/fault.c
arch/x86/mm/hugetlbpage.c
arch/x86/mm/init.c
arch/xtensa/include/asm/page.h
arch/xtensa/mm/mmu.c
arch/xtensa/mm/pgtable.c [deleted file]
block/blk-cgroup.c
block/blk-cgroup.h
block/blk-core.c
block/blk-exec.c
block/blk-flush.c
block/blk-ioc.c
block/blk-lib.c
block/blk-settings.c
block/blk-sysfs.c
block/blk-throttle.c
block/blk.h
block/cfq-iosched.c
block/elevator.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/apei/einj.c
drivers/acpi/atomicio.c
drivers/amba/bus.c
drivers/ata/libata-scsi.c
drivers/base/node.c
drivers/bcma/host_pci.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/cciss.c
drivers/block/cciss.h
drivers/block/cciss_cmd.h
drivers/block/cciss_scsi.c
drivers/block/cciss_scsi.h
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_bitmap.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_req.h
drivers/block/drbd/drbd_worker.c
drivers/block/loop.c
drivers/block/paride/pcd.c
drivers/block/rbd.c
drivers/block/xen-blkback/Makefile [new file with mode: 0644]
drivers/block/xen-blkback/blkback.c [new file with mode: 0644]
drivers/block/xen-blkback/common.h [new file with mode: 0644]
drivers/block/xen-blkback/xenbus.c [new file with mode: 0644]
drivers/block/xen-blkfront.c
drivers/cdrom/viocd.c
drivers/char/i8k.c
drivers/cpufreq/Makefile
drivers/cpufreq/db8500-cpufreq.c [new file with mode: 0644]
drivers/dma/shdma.c
drivers/dma/shdma.h
drivers/edac/i3200_edac.c
drivers/gpio/ml_ioh_gpio.c
drivers/gpio/vx855_gpio.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/ttm/ttm_page_alloc.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c
drivers/hwmon/abituguru3.c
drivers/hwmon/acpi_power_meter.c [moved from drivers/acpi/power_meter.c with 100% similarity]
drivers/hwmon/adcxx.c
drivers/hwmon/emc6w201.c [new file with mode: 0644]
drivers/hwmon/f71882fg.c
drivers/hwmon/fam15h_power.c [new file with mode: 0644]
drivers/hwmon/ibmaem.c
drivers/hwmon/it87.c
drivers/hwmon/jc42.c
drivers/hwmon/k10temp.c
drivers/hwmon/k8temp.c
drivers/hwmon/lm70.c
drivers/hwmon/max6650.c
drivers/hwmon/sch5627.c
drivers/hwmon/ultra45_env.c
drivers/ide/ide-cd.c
drivers/input/input-compat.h
drivers/isdn/hardware/mISDN/netjet.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/leds-gpio-register.c [new file with mode: 0644]
drivers/leds/leds-h1940.c [deleted file]
drivers/leds/leds-lm3530.c
drivers/leds/leds-pca9532.c
drivers/leds/leds.h
drivers/leds/ledtrig-timer.c
drivers/media/video/omap/omap_vout.c
drivers/media/video/omap/omap_voutdef.h
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/ab8500-i2c.c
drivers/mfd/db5500-prcmu-regs.h [moved from arch/arm/mach-ux500/include/mach/prcmu-regs.h with 80% similarity]
drivers/mfd/db5500-prcmu.c [new file with mode: 0644]
drivers/mfd/db8500-prcmu-regs.h [new file with mode: 0644]
drivers/mfd/db8500-prcmu.c [new file with mode: 0644]
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/mmc_ops.h
drivers/mmc/core/quirks.c
drivers/mmc/core/sd.c
drivers/mmc/core/sd.h
drivers/mmc/core/sd_ops.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_irq.c
drivers/mmc/core/sdio_ops.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/mmci.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pxa.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_dma.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/vub300.c [new file with mode: 0644]
drivers/net/Makefile
drivers/net/arm/ixp4xx_eth.c
drivers/net/benet/be_cmds.c
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/ehea/ehea_main.c
drivers/net/gianfar_ptp.c [new file with mode: 0644]
drivers/net/ioc3-eth.c
drivers/net/irda/bfin_sir.c
drivers/net/irda/bfin_sir.h
drivers/net/phy/Makefile
drivers/net/phy/dp83640.c [new file with mode: 0644]
drivers/net/phy/dp83640_reg.h [new file with mode: 0644]
drivers/net/tg3.c
drivers/net/tile/tilepro.c
drivers/net/usb/cdc_ncm.c
drivers/net/via-velocity.h
drivers/net/wireless/airo.c
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/ar5008_initvals.h
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9001_initvals.h
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_initvals.h
drivers/net/wireless/ath/ath9k/ar9002_mac.c
drivers/net/wireless/ath/ath9k/ar9002_phy.c
drivers/net/wireless/ath/ath9k/ar9002_phy.h
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_mac.h
drivers/net/wireless/ath/ath9k/ar9003_paprd.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9485_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/btcoex.h
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom.c
drivers/net/wireless/ath/ath9k/eeprom.h
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/hif_usb.h
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/htc_hst.c
drivers/net/wireless/ath/ath9k/htc_hst.h
drivers/net/wireless/ath/ath9k/hw-ops.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/phy.h
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/wmi.c
drivers/net/wireless/ath/ath9k/wmi.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/carl9170.h
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/hw.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/leds.c
drivers/net/wireless/b43/lo.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_a.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_g.c
drivers/net/wireless/b43/phy_lp.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/pio.c
drivers/net/wireless/b43/rfkill.c
drivers/net/wireless/b43/sdio.c
drivers/net/wireless/b43/sysfs.c
drivers/net/wireless/b43/tables_lpphy.c
drivers/net/wireless/b43/wa.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-sta.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sv-open.c
drivers/net/wireless/iwlwifi/iwl-testmode.h
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
drivers/net/xen-netfront.c
drivers/platform/x86/ibm_rtl.c
drivers/platform/x86/intel_ips.c
drivers/ptp/Kconfig [new file with mode: 0644]
drivers/ptp/Makefile [new file with mode: 0644]
drivers/ptp/ptp_chardev.c [new file with mode: 0644]
drivers/ptp/ptp_clock.c [new file with mode: 0644]
drivers/ptp/ptp_ixp46x.c [new file with mode: 0644]
drivers/ptp/ptp_private.h [new file with mode: 0644]
drivers/ptp/ptp_sysfs.c [new file with mode: 0644]
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/db8500-prcmu.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-tile.c [new file with mode: 0644]
drivers/scsi/qla4xxx/ql4_nx.c
drivers/scsi/sr.c
drivers/staging/ath6kl/os/linux/cfg80211.c
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
drivers/staging/wlan-ng/cfg80211.c
drivers/staging/zcache/zcache.c
drivers/tty/serial/68328serial.c
drivers/tty/serial/pch_uart.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/amifb.c
drivers/video/backlight/adp5520_bl.c
drivers/video/da8xx-fb.c
drivers/video/efifb.c
drivers/video/mb862xx/Makefile
drivers/video/mb862xx/mb862xx-i2c.c [new file with mode: 0644]
drivers/video/mb862xx/mb862xx_reg.h
drivers/video/mb862xx/mb862xxfb.h
drivers/video/mb862xx/mb862xxfbdrv.c [moved from drivers/video/mb862xx/mb862xxfb.c with 86% similarity]
drivers/video/omap/dispc.c
drivers/video/omap/omapfb_main.c
drivers/video/omap/rfbi.c
drivers/video/omap2/Makefile
drivers/video/omap2/displays/Kconfig
drivers/video/omap2/displays/panel-acx565akm.c
drivers/video/omap2/displays/panel-generic-dpi.c
drivers/video/omap2/displays/panel-lgphilips-lb035q02.c
drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c
drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
drivers/video/omap2/displays/panel-taal.c
drivers/video/omap2/displays/panel-tpo-td043mtea1.c
drivers/video/omap2/dss/Kconfig
drivers/video/omap2/dss/core.c
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dispc.h [new file with mode: 0644]
drivers/video/omap2/dss/display.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/dss_features.c
drivers/video/omap2/dss/dss_features.h
drivers/video/omap2/dss/hdmi.c
drivers/video/omap2/dss/hdmi.h
drivers/video/omap2/dss/hdmi_omap4_panel.c
drivers/video/omap2/dss/manager.c
drivers/video/omap2/dss/overlay.c
drivers/video/omap2/dss/rfbi.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/omapfb-ioctl.c
drivers/video/omap2/omapfb/omapfb-main.c
drivers/video/omap2/omapfb/omapfb-sysfs.c
drivers/video/omap2/omapfb/omapfb.h
drivers/video/s3c-fb.c
drivers/video/s3c2410fb.c
drivers/video/s3fb.c
drivers/video/savage/savagefb-i2c.c
drivers/video/savage/savagefb.h
drivers/video/savage/savagefb_driver.c
drivers/video/sh7760fb.c
drivers/video/sh_mobile_hdmi.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/sh_mobile_lcdcfb.h
drivers/video/sh_mobile_meram.c [new file with mode: 0644]
drivers/video/sh_mobile_meram.h [new file with mode: 0644]
drivers/video/sm501fb.c
drivers/video/udlfb.c
fs/9p/Kconfig
fs/9p/vfs_inode_dotl.c
fs/Kconfig
fs/block_dev.c
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/dcache.c
fs/drop_caches.c
fs/exec.c
fs/fscache/operation.c
fs/fscache/page.c
fs/gfs2/glock.c
fs/gfs2/quota.c
fs/gfs2/quota.h
fs/hugetlbfs/inode.c
fs/inode.c
fs/mbcache.c
fs/ncpfs/inode.c
fs/nfs/dir.c
fs/nfs/internal.h
fs/partitions/check.c
fs/proc/Makefile
fs/proc/base.c
fs/proc/generic.c
fs/proc/inode.c
fs/proc/internal.h
fs/proc/namespaces.c [new file with mode: 0644]
fs/proc/task_mmu.c
fs/quota/dquot.c
fs/splice.c
fs/xfs/linux-2.6/xfs_buf.c
fs/xfs/linux-2.6/xfs_sync.c
fs/xfs/quota/xfs_qm.c
include/asm-generic/audit_change_attr.h
include/asm-generic/audit_dir_write.h
include/asm-generic/audit_read.h
include/asm-generic/audit_write.h
include/asm-generic/bug.h
include/asm-generic/cacheflush.h
include/asm-generic/resource.h
include/asm-generic/tlb.h
include/asm-generic/unistd.h
include/linux/Kbuild
include/linux/bitmap.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/bootmem.h
include/linux/c2port.h
include/linux/ceph/ceph_fs.h
include/linux/compat.h
include/linux/compiler-gcc.h
include/linux/compiler-gcc4.h
include/linux/cpumask.h
include/linux/drbd.h
include/linux/drbd_tag_magic.h
include/linux/fs.h
include/linux/fscache-cache.h
include/linux/genalloc.h
include/linux/genhd.h
include/linux/gfp.h
include/linux/huge_mm.h
include/linux/i2c.h
include/linux/if_link.h
include/linux/if_vlan.h
include/linux/kernel.h
include/linux/leds-pca9532.h
include/linux/leds.h
include/linux/lockdep.h
include/linux/lru_cache.h
include/linux/memblock.h
include/linux/mempolicy.h
include/linux/mfd/db5500-prcmu.h [new file with mode: 0644]
include/linux/mfd/db8500-prcmu.h [new file with mode: 0644]
include/linux/mfd/tmio.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/Kbuild [new file with mode: 0644]
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/ioctl.h [new file with mode: 0644]
include/linux/mmc/mmc.h
include/linux/mmc/sd.h
include/linux/mmc/sdhci.h
include/linux/mmc/sh_mobile_sdhi.h
include/linux/mmu_notifier.h
include/linux/mmzone.h
include/linux/mutex.h
include/linux/oom.h
include/linux/pagemap.h
include/linux/percpu_counter.h
include/linux/posix-timers.h
include/linux/printk.h
include/linux/proc_fs.h
include/linux/ptp_classify.h
include/linux/ptp_clock.h [new file with mode: 0644]
include/linux/ptp_clock_kernel.h [new file with mode: 0644]
include/linux/regulator/db8500-prcmu.h [new file with mode: 0644]
include/linux/rfkill-gpio.h [new file with mode: 0644]
include/linux/rmap.h
include/linux/sched.h
include/linux/shmem_fs.h
include/linux/syscalls.h
include/linux/vmstat.h
include/linux/xattr.h
include/net/9p/9p.h
include/net/9p/client.h
include/net/9p/transport.h
include/net/cfg80211.h
include/net/dst.h
include/net/net_namespace.h
include/video/omap-panel-generic-dpi.h [moved from arch/arm/plat-omap/include/plat/panel-generic-dpi.h with 86% similarity]
include/video/omap-panel-nokia-dsi.h [moved from arch/arm/plat-omap/include/plat/nokia-dsi-panel.h with 65% similarity]
include/video/omapdss.h [moved from arch/arm/plat-omap/include/plat/display.h with 85% similarity]
include/video/sh_mobile_lcdc.h
include/video/sh_mobile_meram.h [new file with mode: 0644]
include/xen/interface/io/blkif.h
init/calibrate.c
init/main.c
ipc/namespace.c
kernel/compat.c
kernel/fork.c
kernel/hrtimer.c
kernel/irq/proc.c
kernel/mutex.c
kernel/nsproxy.c
kernel/posix-timers.c
kernel/printk.c
kernel/ptrace.c
kernel/signal.c
kernel/sysctl.c
kernel/utsname.c
lib/Kconfig.debug
lib/audit.c
lib/bitmap.c
lib/genalloc.c
lib/kstrtox.c
lib/lru_cache.c
lib/show_mem.c
lib/vsprintf.c
mm/backing-dev.c
mm/filemap.c
mm/filemap_xip.c
mm/fremap.c
mm/huge_memory.c
mm/hugetlb.c
mm/init-mm.c
mm/internal.h
mm/ksm.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/migrate.c
mm/mmap.c
mm/mremap.c
mm/nobootmem.c
mm/nommu.c
mm/oom_kill.c
mm/page_alloc.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slub.c
mm/swap.c
mm/swapfile.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
net/802/psnap.c
net/8021q/vlan.h
net/9p/Kconfig
net/9p/client.c
net/9p/mod.c
net/9p/trans_fd.c
net/9p/util.c
net/atm/proc.c
net/bridge/br_netfilter.c
net/can/bcm.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/core/dev.c
net/core/dst.c
net/core/fib_rules.c
net/core/filter.c
net/core/net_namespace.c
net/core/rtnetlink.c
net/ipv4/igmp.c
net/ipv4/ping.c
net/ipv4/raw.c
net/ipv4/tcp_ipv4.c
net/ipv4/udp.c
net/ipv6/raw.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_tunnel.c
net/key/af_key.c
net/mac80211/iface.c
net/mac80211/main.c
net/mac80211/mesh.h
net/mac80211/mesh_pathtbl.c
net/mac80211/scan.c
net/netlink/af_netlink.c
net/packet/af_packet.c
net/phonet/socket.c
net/rfkill/Kconfig
net/rfkill/Makefile
net/rfkill/rfkill-gpio.c [new file with mode: 0644]
net/sched/sch_sfq.c
net/sctp/associola.c
net/sctp/proc.c
net/sunrpc/auth.c
net/unix/af_unix.c
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/sme.c
net/wireless/util.c
scripts/checkpatch.pl
scripts/checkversion.pl
scripts/export_report.pl
scripts/kconfig/Makefile
scripts/kconfig/confdata.c
scripts/kconfig/expr.h
scripts/kconfig/gconf.c
scripts/kconfig/lex.zconf.c_shipped
scripts/kconfig/nconf.c
scripts/kconfig/qconf.cc
scripts/kconfig/zconf.l
scripts/package/Makefile
scripts/package/mkspec
scripts/patch-kernel

index 5a6dd592eedc888090d43bb8299b1ddc2143ce08..353ad5607156f0f2d4b5138f1b5d9db529933aa8 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -32,6 +32,7 @@ Brian Avery <b.avery@hp.com>
 Brian King <brking@us.ibm.com>
 Christoph Hellwig <hch@lst.de>
 Corey Minyard <minyard@acm.org>
+Damian Hobson-Garcia <dhobsong@igel.co.jp>
 David Brownell <david-b@pacbell.net>
 David Woodhouse <dwmw2@shinybook.infradead.org>
 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
diff --git a/CREDITS b/CREDITS
index 95c469c610bc8a059b3bebac13fba37b98b544c1..a7ea8e343836fb47fd82ef624d77c630ba199df2 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2943,6 +2943,10 @@ S: Kasarmikatu 11 A4
 S: 70110 Kuopio
 S: Finland
 
+N: Tobias Ringström
+E: tori@unhappy.mine.nu
+D: Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver
+
 N: Luca Risolia
 E: luca.risolia@studio.unibo.it
 P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4
@@ -3913,6 +3917,10 @@ S: Flandernstrasse 101
 S: D-73732 Esslingen
 S: Germany
 
+N: Roman Zippel
+E: zippel@linux-m68k.org
+D: AFFS and HFS filesystems, m68k maintainer, new kernel configuration in 2.5
+
 N: Leonard N. Zubkoff
 W: http://www.dandelion.com/Linux/
 D: BusLogic SCSI driver
index 4873c759d535a7549d5eecf62a7125b29d6c2dea..c1eb41cb9876083d3df79a6a995b692762acd21b 100644 (file)
@@ -142,3 +142,67 @@ Description:
                with the previous I/O request are enabled. When set to 2,
                all merge tries are disabled. The default value is 0 -
                which enables all types of merge tries.
+
+What:          /sys/block/<disk>/discard_alignment
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may
+               internally allocate space in units that are bigger than
+               the exported logical block size. The discard_alignment
+               parameter indicates how many bytes the beginning of the
+               device is offset from the internal allocation unit's
+               natural alignment.
+
+What:          /sys/block/<disk>/<partition>/discard_alignment
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may
+               internally allocate space in units that are bigger than
+               the exported logical block size. The discard_alignment
+               parameter indicates how many bytes the beginning of the
+               partition is offset from the internal allocation unit's
+               natural alignment.
+
+What:          /sys/block/<disk>/queue/discard_granularity
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may
+               internally allocate space using units that are bigger
+               than the logical block size. The discard_granularity
+               parameter indicates the size of the internal allocation
+               unit in bytes if reported by the device. Otherwise the
+               discard_granularity will be set to match the device's
+               physical block size. A discard_granularity of 0 means
+               that the device does not support discard functionality.
+
+What:          /sys/block/<disk>/queue/discard_max_bytes
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may have
+               internal limits on the number of bytes that can be
+               trimmed or unmapped in a single operation. Some storage
+               protocols also have inherent limits on the number of
+               blocks that can be described in a single command. The
+               discard_max_bytes parameter is set by the device driver
+               to the maximum number of bytes that can be discarded in
+               a single operation. Discard requests issued to the
+               device must not exceed this limit. A discard_max_bytes
+               value of 0 means that the device does not support
+               discard functionality.
+
+What:          /sys/block/<disk>/queue/discard_zeroes_data
+Date:          May 2011
+Contact:       Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+               Devices that support discard functionality may return
+               stale or random data when a previously discarded block
+               is read back. This can cause problems if the filesystem
+               expects discarded blocks to be explicitly cleared. If a
+               device reports that it deterministically returns zeroes
+               when a discarded area is read the discard_zeroes_data
+               parameter will be set to one. Otherwise it will be 0 and
+               the result of reading a discarded area is undefined.
diff --git a/Documentation/ABI/testing/sysfs-ptp b/Documentation/ABI/testing/sysfs-ptp
new file mode 100644 (file)
index 0000000..d40d2b5
--- /dev/null
@@ -0,0 +1,98 @@
+What:          /sys/class/ptp/
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This directory contains files and directories
+               providing a standardized interface to the ancillary
+               features of PTP hardware clocks.
+
+What:          /sys/class/ptp/ptpN/
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This directory contains the attributes of the Nth PTP
+               hardware clock registered into the PTP class driver
+               subsystem.
+
+What:          /sys/class/ptp/ptpN/clock_name
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the name of the PTP hardware clock
+               as a human readable string.
+
+What:          /sys/class/ptp/ptpN/max_adjustment
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the PTP hardware clock's maximum
+               frequency adjustment value (a positive integer) in
+               parts per billion.
+
+What:          /sys/class/ptp/ptpN/n_alarms
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the number of periodic or one shot
+               alarms offer by the PTP hardware clock.
+
+What:          /sys/class/ptp/ptpN/n_external_timestamps
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the number of external timestamp
+               channels offered by the PTP hardware clock.
+
+What:          /sys/class/ptp/ptpN/n_periodic_outputs
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the number of programmable periodic
+               output channels offered by the PTP hardware clock.
+
+What:          /sys/class/ptp/ptpN/pps_avaiable
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file indicates whether the PTP hardware clock
+               supports a Pulse Per Second to the host CPU. Reading
+               "1" means that the PPS is supported, while "0" means
+               not supported.
+
+What:          /sys/class/ptp/ptpN/extts_enable
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This write-only file enables or disables external
+               timestamps. To enable external timestamps, write the
+               channel index followed by a "1" into the file.
+               To disable external timestamps, write the channel
+               index followed by a "0" into the file.
+
+What:          /sys/class/ptp/ptpN/fifo
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file provides timestamps on external events, in
+               the form of three integers: channel index, seconds,
+               and nanoseconds.
+
+What:          /sys/class/ptp/ptpN/period
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This write-only file enables or disables periodic
+               outputs. To enable a periodic output, write five
+               integers into the file: channel index, start time
+               seconds, start time nanoseconds, period seconds, and
+               period nanoseconds. To disable a periodic output, set
+               all the seconds and nanoseconds values to zero.
+
+What:          /sys/class/ptp/ptpN/pps_enable
+Date:          September 2010
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This write-only file enables or disables delivery of
+               PPS events to the Linux PPS subsystem. To enable PPS
+               events, write a "1" into the file. To disable events,
+               write a "0" into the file.
index b4a615b78403a48f02252b90a41fabb1392fefe4..7890fae18529e3473700528a10f65d6ffd6f0533 100644 (file)
@@ -4,10 +4,11 @@ ChangeLog:
 
 SMP IRQ affinity
 
-/proc/irq/IRQ#/smp_affinity specifies which target CPUs are permitted
-for a given IRQ source. It's a bitmask of allowed CPUs. It's not allowed
-to turn off all CPUs, and if an IRQ controller does not support IRQ
-affinity then the value will not change from the default 0xffffffff.
+/proc/irq/IRQ#/smp_affinity and /proc/irq/IRQ#/smp_affinity_list specify
+which target CPUs are permitted for a given IRQ source.  It's a bitmask
+(smp_affinity) or cpu list (smp_affinity_list) of allowed CPUs.  It's not
+allowed to turn off all CPUs, and if an IRQ controller does not support
+IRQ affinity then the value will not change from the default of all cpus.
 
 /proc/irq/default_smp_affinity specifies default affinity mask that applies
 to all non-active IRQs. Once IRQ is allocated/activated its affinity bitmask
@@ -54,3 +55,11 @@ round-trip min/avg/max = 0.1/0.5/585.4 ms
 This time around IRQ44 was delivered only to the last four processors.
 i.e counters for the CPU0-3 did not change.
 
+Here is an example of limiting that same irq (44) to cpus 1024 to 1031:
+
+[root@moon 44]# echo 1024-1031 > smp_affinity
+[root@moon 44]# cat smp_affinity
+1024-1031
+
+Note that to do this with a bitmask would require 32 bitmasks of zero
+to follow the pertinent one.
index 89698e8df7d46deb7e2b5332dd8199606073b15c..c00c6a5ab21f6b0d253bf465eb6e1274d5994d18 100644 (file)
@@ -169,3 +169,18 @@ is issued which positions the tape to a known position.  Typically you
 must rewind the tape (by issuing "mt -f /dev/st0 rewind" for example)
 before i/o can proceed again to a tape drive which was reset.
 
+There is a cciss_tape_cmds module parameter which can be used to make cciss
+allocate more commands for use by tape drives.  Ordinarily only a few commands
+(6) are allocated for tape drives because tape drives are slow and
+infrequently used and the primary purpose of Smart Array controllers is to
+act as a RAID controller for disk drives, so the vast majority of commands
+are allocated for disk devices.  However, if you have more than a few tape
+drives attached to a smart array, the default number of commands may not be
+enought (for example, if you have 8 tape drives, you could only rewind 6
+at one time with the default number of commands.)  The cciss_tape_cmds module
+parameter allows more commands (up to 16 more) to be allocated for use by
+tape drives.  For example:
+
+        insmod cciss.ko cciss_tape_cmds=16
+
+Or, as a kernel boot parameter passed in via grub:  cciss.cciss_tape_cmds=8
index 9164ae3b83bcc6b466ffe25cf97093b72684a944..9b728dc17535f6f8c1630fe2e8f3a96e997feac9 100644 (file)
@@ -16,7 +16,7 @@ on all processors in the system.  Don't let this scare you into
 thinking SMP cache/tlb flushing must be so inefficient, this is in
 fact an area where many optimizations are possible.  For example,
 if it can be proven that a user address space has never executed
-on a cpu (see vma->cpu_vm_mask), one need not perform a flush
+on a cpu (see mm_cpumask()), one need not perform a flush
 for this address space on that cpu.
 
 First, the TLB flushing interfaces, since they are the simplest.  The
index edb7ae19e868a2166c8c93e977a0d4064e95dfc2..2c6be0377f55d0963970972c4d2b494e73f4507f 100644 (file)
@@ -74,3 +74,57 @@ Example:
                interrupt-parent = <&mpic>;
                phy-handle = <&phy0>
        };
+
+* Gianfar PTP clock nodes
+
+General Properties:
+
+  - compatible   Should be "fsl,etsec-ptp"
+  - reg          Offset and length of the register set for the device
+  - interrupts   There should be at least two interrupts. Some devices
+                 have as many as four PTP related interrupts.
+
+Clock Properties:
+
+  - fsl,tclk-period  Timer reference clock period in nanoseconds.
+  - fsl,tmr-prsc     Prescaler, divides the output clock.
+  - fsl,tmr-add      Frequency compensation value.
+  - fsl,tmr-fiper1   Fixed interval period pulse generator.
+  - fsl,tmr-fiper2   Fixed interval period pulse generator.
+  - fsl,max-adj      Maximum frequency adjustment in parts per billion.
+
+  These properties set the operational parameters for the PTP
+  clock. You must choose these carefully for the clock to work right.
+  Here is how to figure good values:
+
+  TimerOsc     = system clock               MHz
+  tclk_period  = desired clock period       nanoseconds
+  NominalFreq  = 1000 / tclk_period         MHz
+  FreqDivRatio = TimerOsc / NominalFreq     (must be greater that 1.0)
+  tmr_add      = ceil(2^32 / FreqDivRatio)
+  OutputClock  = NominalFreq / tmr_prsc     MHz
+  PulseWidth   = 1 / OutputClock            microseconds
+  FiperFreq1   = desired frequency in Hz
+  FiperDiv1    = 1000000 * OutputClock / FiperFreq1
+  tmr_fiper1   = tmr_prsc * tclk_period * FiperDiv1 - tclk_period
+  max_adj      = 1000000000 * (FreqDivRatio - 1.0) - 1
+
+  The calculation for tmr_fiper2 is the same as for tmr_fiper1. The
+  driver expects that tmr_fiper1 will be correctly set to produce a 1
+  Pulse Per Second (PPS) signal, since this will be offered to the PPS
+  subsystem to synchronize the Linux clock.
+
+Example:
+
+       ptp_clock@24E00 {
+               compatible = "fsl,etsec-ptp";
+               reg = <0x24E00 0xB0>;
+               interrupts = <12 0x8 13 0x8>;
+               interrupt-parent = < &ipic >;
+               fsl,tclk-period = <10>;
+               fsl,tmr-prsc    = <100>;
+               fsl,tmr-add     = <0x999999A4>;
+               fsl,tmr-fiper1  = <0x3B9AC9F6>;
+               fsl,tmr-fiper2  = <0x00018696>;
+               fsl,max-adj     = <659999998>;
+       };
index b22abba78fede6049ab07b8167bce2dedc99fe90..13de64c7f0ab0bf7f347156573e187a0a72ac4a0 100644 (file)
@@ -25,6 +25,8 @@ Other applications are described in the following papers:
                http://xcpu.org/papers/cellfs-talk.pdf
        * PROSE I/O: Using 9p to enable Application Partitions
                http://plan9.escet.urjc.es/iwp9/cready/PROSE_iwp9_2006.pdf
+       * VirtFS: A Virtualization Aware File System pass-through
+               http://goo.gl/3WPDg
 
 USAGE
 =====
@@ -130,31 +132,20 @@ OPTIONS
 RESOURCES
 =========
 
-Our current recommendation is to use Inferno (http://www.vitanuova.com/nferno/index.html)
-as the 9p server.  You can start a 9p server under Inferno by issuing the
-following command:
-   ; styxlisten -A tcp!*!564 export '#U*'
+Protocol specifications are maintained on github:
+http://ericvh.github.com/9p-rfc/
 
-The -A specifies an unauthenticated export.  The 564 is the port # (you may
-have to choose a higher port number if running as a normal user).  The '#U*'
-specifies exporting the root of the Linux name space.  You may specify a
-subset of the namespace by extending the path: '#U*'/tmp would just export
-/tmp.  For more information, see the Inferno manual pages covering styxlisten
-and export.
+9p client and server implementations are listed on
+http://9p.cat-v.org/implementations
 
-A Linux version of the 9p server is now maintained under the npfs project
-on sourceforge (http://sourceforge.net/projects/npfs).  The currently
-maintained version is the single-threaded version of the server (named spfs)
-available from the same SVN repository.
+A 9p2000.L server is being developed by LLNL and can be found
+at http://code.google.com/p/diod/
 
 There are user and developer mailing lists available through the v9fs project
 on sourceforge (http://sourceforge.net/projects/v9fs).
 
-A stand-alone version of the module (which should build for any 2.6 kernel)
-is available via (http://github.com/ericvh/9p-sac/tree/master)
-
-News and other information is maintained on SWiK (http://swik.net/v9fs)
-and the Wiki (http://sf.net/apps/mediawiki/v9fs/index.php).
+News and other information is maintained on a Wiki.
+(http://sf.net/apps/mediawiki/v9fs/index.php).
 
 Bug reports may be issued through the kernel.org bugzilla 
 (http://bugzilla.kernel.org)
index 60740e8ecb3779e7bb314dcde47d88f54183788b..f48178024067fd48fc3454806bdaa366c64dd966 100644 (file)
@@ -574,6 +574,12 @@ The contents of each smp_affinity file is the same by default:
   > cat /proc/irq/0/smp_affinity
   ffffffff
 
+There is an alternate interface, smp_affinity_list which allows specifying
+a cpu range instead of a bitmask:
+
+  > cat /proc/irq/0/smp_affinity_list
+  1024-1031
+
 The default_smp_affinity mask applies to all non-active IRQs, which are the
 IRQs which have not yet been allocated/activated, and hence which lack a
 /proc/irq/[0-9]* directory.
@@ -583,12 +589,13 @@ reports itself as being attached. This hardware locality information does not
 include information about any possible driver locality preference.
 
 prof_cpu_mask specifies which CPUs are to be profiled by the system wide
-profiler. Default value is ffffffff (all cpus).
+profiler. Default value is ffffffff (all cpus if there are only 32 of them).
 
 The way IRQs are routed is handled by the IO-APIC, and it's Round Robin
 between all the CPUs which are allowed to handle it. As usual the kernel has
 more info than you and does a better job than you, so the defaults are the
-best choice for almost everyone.
+best choice for almost everyone.  [Note this applies only to those IO-APIC's
+that support "Round Robin" interrupt distribution.]
 
 There are  three  more  important subdirectories in /proc: net, scsi, and sys.
 The general  rule  is  that  the  contents,  or  even  the  existence of these
diff --git a/Documentation/hwmon/emc6w201 b/Documentation/hwmon/emc6w201
new file mode 100644 (file)
index 0000000..32f355a
--- /dev/null
@@ -0,0 +1,42 @@
+Kernel driver emc6w201
+======================
+
+Supported chips:
+  * SMSC EMC6W201
+    Prefix: 'emc6w201'
+    Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+    Datasheet: Not public
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+
+Description
+-----------
+
+From the datasheet:
+
+"The EMC6W201 is an environmental monitoring device with automatic fan
+control capability and enhanced system acoustics for noise suppression.
+This ACPI compliant device provides hardware monitoring for up to six
+voltages (including its own VCC) and five external thermal sensors,
+measures the speed of up to five fans, and controls the speed of
+multiple DC fans using three Pulse Width Modulator (PWM) outputs. Note
+that it is possible to control more than three fans by connecting two
+fans to one PWM output. The EMC6W201 will be available in a 36-pin
+QFN package."
+
+The device is functionally close to the EMC6D100 series, but is
+register-incompatible.
+
+The driver currently only supports the monitoring of the voltages,
+temperatures and fan speeds. Limits can be changed. Alarms are not
+supported, and neither is fan speed control.
+
+
+Known Systems With EMC6W201
+---------------------------
+
+The EMC6W201 is a rare device, only found on a few systems, made in
+2005 and 2006. Known systems with this device:
+* Dell Precision 670 workstation
+* Gigabyte 2CEWH mainboard
index df02245d1419d76a1962f3a879f5480c9cf02a5f..84d2623810f31ade6b45315297ee755c6985209d 100644 (file)
@@ -6,6 +6,10 @@ Supported chips:
     Prefix: 'f71808e'
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Not public
+  * Fintek F71808A
+    Prefix: 'f71808a'
+    Addresses scanned: none, address read from Super I/O config space
+    Datasheet: Not public
   * Fintek F71858FG
     Prefix: 'f71858fg'
     Addresses scanned: none, address read from Super I/O config space
diff --git a/Documentation/hwmon/fam15h_power b/Documentation/hwmon/fam15h_power
new file mode 100644 (file)
index 0000000..a92918e
--- /dev/null
@@ -0,0 +1,37 @@
+Kernel driver fam15h_power
+==========================
+
+Supported chips:
+* AMD Family 15h Processors
+
+  Prefix: 'fam15h_power'
+  Addresses scanned: PCI space
+  Datasheets:
+  BIOS and Kernel Developer's Guide (BKDG) For AMD Family 15h Processors
+    (not yet published)
+
+Author: Andreas Herrmann <andreas.herrmann3@amd.com>
+
+Description
+-----------
+
+This driver permits reading of registers providing power information
+of AMD Family 15h processors.
+
+For AMD Family 15h processors the following power values can be
+calculated using different processor northbridge function registers:
+
+* BasePwrWatts: Specifies in watts the maximum amount of power
+  consumed by the processor for NB and logic external to the core.
+* ProcessorPwrWatts: Specifies in watts the maximum amount of power
+  the processor can support.
+* CurrPwrWatts: Specifies in watts the current amount of power being
+  consumed by the processor.
+
+This driver provides ProcessorPwrWatts and CurrPwrWatts:
+* power1_crit (ProcessorPwrWatts)
+* power1_input (CurrPwrWatts)
+
+On multi-node processors the calculated value is for the entire
+package and not for a single node. Thus the driver creates sysfs
+attributes only for internal node0 of a multi-node processor.
index d2b56a4fd1f5a44566968e7b5faebe62b879ccaa..0393c89277c021b3e64921a7cda1007cb4f4d602 100644 (file)
@@ -11,6 +11,7 @@ Supported chips:
   Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
 * AMD Family 12h processors: "Llano"
 * AMD Family 14h processors: "Brazos" (C/E/G-Series)
+* AMD Family 15h processors: "Bulldozer"
 
   Prefix: 'k10temp'
   Addresses scanned: PCI space
@@ -40,7 +41,7 @@ Description
 -----------
 
 This driver permits reading of the internal temperature sensor of AMD
-Family 10h/11h/12h/14h processors.
+Family 10h/11h/12h/14h/15h processors.
 
 All these processors have a sensor, but on those for Socket F or AM2+,
 the sensor may return inconsistent values (erratum 319).  The driver
index c565650fcfc6f6949c8a24ae1bd2002ae9da86fa..58d9644a2bde87eb5931f92b0e1bfc936d9ed682 100644 (file)
@@ -2,9 +2,13 @@ Kernel driver max6650
 =====================
 
 Supported chips:
-  * Maxim 6650 / 6651
+  * Maxim MAX6650
     Prefix: 'max6650'
-    Addresses scanned: I2C 0x1b, 0x1f, 0x48, 0x4b
+    Addresses scanned: none
+    Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
+  * Maxim MAX6651
+    Prefix: 'max6651'
+    Addresses scanned: none
     Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
 
 Authors:
@@ -15,10 +19,10 @@ Authors:
 Description
 -----------
 
-This driver implements support for the Maxim 6650/6651
+This driver implements support for the Maxim MAX6650 and MAX6651.
 
-The 2 devices are very similar, but the Maxim 6550 has a reduced feature
-set, e.g. only one fan-input, instead of 4 for the 6651.
+The 2 devices are very similar, but the MAX6550 has a reduced feature
+set, e.g. only one fan-input, instead of 4 for the MAX6651.
 
 The driver is not able to distinguish between the 2 devices.
 
@@ -36,6 +40,13 @@ fan1_div     rw      sets the speed range the inputs can handle. Legal
                        values are 1, 2, 4, and 8. Use lower values for
                        faster fans.
 
+Usage notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
 Module parameters
 -----------------
 
index 2d1ad12e2b3ec783c186a81b3763ea4d3f8ce3cb..3a46e360496dd6798fbcf9f1e59e4eec9728e5d5 100644 (file)
@@ -304,6 +304,7 @@ Code  Seq#(hex)     Include File            Comments
 0xB0   all     RATIO devices           in development:
                                        <mailto:vgo@ratio.de>
 0xB1   00-1F   PPPoX                   <mailto:mostrows@styx.uwaterloo.ca>
+0xB3   00      linux/mmc/ioctl.h
 0xC0   00-0F   linux/usb/iowarrior.h
 0xCB   00-1F   CBM serial IEC bus      in development:
                                        <mailto:michael.klein@puffin.lb.shuttle.de>
index b507d61fd41cd6a20157dca27f38a28b98f4fa1d..44e2649fbb295db936245c4c0de09109738bfc5e 100644 (file)
@@ -113,6 +113,13 @@ applicable everywhere (see syntax).
        That will limit the usefulness but on the other hand avoid
        the illegal configurations all over.
 
+- limiting menu display: "visible if" <expr>
+  This attribute is only applicable to menu blocks, if the condition is
+  false, the menu block is not displayed to the user (the symbols
+  contained there can still be selected by other symbols, though). It is
+  similar to a conditional "prompt" attribude for individual menu
+  entries. Default value of "visible" is true.
+
 - numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
   This allows to limit the range of possible input values for int
   and hex symbols. The user can only input a value which is larger than
@@ -303,7 +310,8 @@ menu:
        "endmenu"
 
 This defines a menu block, see "Menu structure" above for more
-information. The only possible options are dependencies.
+information. The only possible options are dependencies and "visible"
+attributes.
 
 if:
 
@@ -381,3 +389,25 @@ config FOO
 
 limits FOO to module (=m) or disabled (=n).
 
+Kconfig symbol existence
+~~~~~~~~~~~~~~~~~~~~~~~~
+The following two methods produce the same kconfig symbol dependencies
+but differ greatly in kconfig symbol existence (production) in the
+generated config file.
+
+case 1:
+
+config FOO
+       tristate "about foo"
+       depends on BAR
+
+vs. case 2:
+
+if BAR
+config FOO
+       tristate "about foo"
+endif
+
+In case 1, the symbol FOO will always exist in the config file (given
+no other dependencies).  In case 2, the symbol FOO will only exist in
+the config file if BAR is enabled.
index cca46b1a0f6c2a33f4a39ea87f49a4ae91585c2c..c313d71324b4a83db6934114e86af7eed0f30be6 100644 (file)
@@ -48,11 +48,6 @@ KCONFIG_OVERWRITECONFIG
 If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
 break symlinks when .config is a symlink to somewhere else.
 
-KCONFIG_NOTIMESTAMP
---------------------------------------------------
-If this environment variable exists and is non-null, the timestamp line
-in generated .config files is omitted.
-
 ______________________________________________________________________
 Environment variables for '{allyes/allmod/allno/rand}config'
 
index 7c6624e7a5cb50f80bcc1d92e010d8896ec92956..5438a2d7907f564b05644a93931f081de19844d3 100644 (file)
@@ -1777,9 +1777,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        nosoftlockup    [KNL] Disable the soft-lockup detector.
 
-       noswapaccount   [KNL] Disable accounting of swap in memory resource
-                       controller. (See Documentation/cgroups/memory.txt)
-
        nosync          [HW,M68K] Disables sync negotiation for all devices.
 
        notsc           [BUGS=X86-32] Disable Time Stamp Counter
index 65f4c795015dead0cfde0f60381b7efcec67da9b..9c0a80d17a23b9bdf1bb9ab9672e5360be7e14b5 100644 (file)
@@ -136,7 +136,7 @@ View the top contending locks:
                              dcache_lock:          1037           1161           0.38          45.32         774.51           6611         243371           0.15         306.48       77387.24
                          &inode->i_mutex:           161            286 18446744073709       62882.54     1244614.55           3653          20598 18446744073709       62318.60     1693822.74
                          &zone->lru_lock:            94             94           0.53           7.33          92.10           4366          32690           0.29          59.81       16350.06
-              &inode->i_data.i_mmap_lock:            79             79           0.40           3.77          53.03          11779          87755           0.28         116.93       29898.44
+              &inode->i_data.i_mmap_mutex:            79             79           0.40           3.77          53.03          11779          87755           0.28         116.93       29898.44
                         &q->__queue_lock:            48             50           0.52          31.62          86.31            774          13131           0.17         113.08       12277.52
                         &rq->rq_lock_key:            43             47           0.74          68.50         170.63           3706          33929           0.22         107.99       17460.62
                       &rq->rq_lock_key#2:            39             46           0.75           6.68          49.03           2979          32292           0.17         125.17       17137.63
index fca586f5b8539cb8dac5c22bfbbe0fa5f4987bb4..93dd7a714075bee668b0b425b81e9c133b8a8292 100644 (file)
@@ -2,3 +2,5 @@
         - this file
 mmc-dev-attrs.txt
         - info on SD and MMC device attributes
+mmc-dev-parts.txt
+        - info on SD and MMC device partitions
index ff2bd685bced95526ab79e66859cd2697b0f5d1f..8898a95b41e5ee1b277cd64697870726b11bc2fa 100644 (file)
@@ -1,3 +1,13 @@
+SD and MMC Block Device Attributes
+==================================
+
+These attributes are defined for the block devices associated with the
+SD or MMC device.
+
+The following attributes are read/write.
+
+       force_ro                Enforce read-only access even if write protect switch is off.
+
 SD and MMC Device Attributes
 ============================
 
diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt
new file mode 100644 (file)
index 0000000..2db28b8
--- /dev/null
@@ -0,0 +1,27 @@
+SD and MMC Device Partitions
+============================
+
+Device partitions are additional logical block devices present on the
+SD/MMC device.
+
+As of this writing, MMC boot partitions as supported and exposed as
+/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
+parent /dev/mmcblkX.
+
+MMC Boot Partitions
+===================
+
+Read and write access is provided to the two MMC boot partitions. Due to
+the sensitive nature of the boot partition contents, which often store
+a bootloader or bootloader configuration tables crucial to booting the
+platform, write access is disabled by default to reduce the chance of
+accidental bricking.
+
+To enable write access to /dev/mmcblkXbootY, disable the forced read-only
+access with:
+
+echo 0 > /sys/block/mmcblkXbootY/force_ro
+
+To re-enable read-only access:
+
+echo 1 > /sys/block/mmcblkXbootY/force_ro
index 1f45bd887d65615621ac5443875dc81097166f10..675612ff41ae2b902d89ad93e6404515f2bdef19 100644 (file)
@@ -770,8 +770,17 @@ resend_igmp
        a failover event. One membership report is issued immediately after
        the failover, subsequent packets are sent in each 200ms interval.
 
-       The valid range is 0 - 255; the default value is 1. This option
-       was added for bonding version 3.7.0.
+       The valid range is 0 - 255; the default value is 1. A value of 0
+       prevents the IGMP membership report from being issued in response
+       to the failover event.
+
+       This option is useful for bonding modes balance-rr (0), active-backup
+       (1), balance-tlb (5) and balance-alb (6), in which a failover can
+       switch the IGMP traffic from one slave to another.  Therefore a fresh
+       IGMP report must be issued to cause the switch to forward the incoming
+       IGMP traffic over the newly selected slave.
+
+       This option was added for bonding version 3.7.0.
 
 3. Configuring Bonding Devices
 ==============================
diff --git a/Documentation/ptp/ptp.txt b/Documentation/ptp/ptp.txt
new file mode 100644 (file)
index 0000000..ae8fef8
--- /dev/null
@@ -0,0 +1,89 @@
+
+* PTP hardware clock infrastructure for Linux
+
+  This patch set introduces support for IEEE 1588 PTP clocks in
+  Linux. Together with the SO_TIMESTAMPING socket options, this
+  presents a standardized method for developing PTP user space
+  programs, synchronizing Linux with external clocks, and using the
+  ancillary features of PTP hardware clocks.
+
+  A new class driver exports a kernel interface for specific clock
+  drivers and a user space interface. The infrastructure supports a
+  complete set of PTP hardware clock functionality.
+
+  + Basic clock operations
+    - Set time
+    - Get time
+    - Shift the clock by a given offset atomically
+    - Adjust clock frequency
+
+  + Ancillary clock features
+    - One short or periodic alarms, with signal delivery to user program
+    - Time stamp external events
+    - Period output signals configurable from user space
+    - Synchronization of the Linux system time via the PPS subsystem
+
+** PTP hardware clock kernel API
+
+   A PTP clock driver registers itself with the class driver. The
+   class driver handles all of the dealings with user space. The
+   author of a clock driver need only implement the details of
+   programming the clock hardware. The clock driver notifies the class
+   driver of asynchronous events (alarms and external time stamps) via
+   a simple message passing interface.
+
+   The class driver supports multiple PTP clock drivers. In normal use
+   cases, only one PTP clock is needed. However, for testing and
+   development, it can be useful to have more than one clock in a
+   single system, in order to allow performance comparisons.
+
+** PTP hardware clock user space API
+
+   The class driver also creates a character device for each
+   registered clock. User space can use an open file descriptor from
+   the character device as a POSIX clock id and may call
+   clock_gettime, clock_settime, and clock_adjtime.  These calls
+   implement the basic clock operations.
+
+   User space programs may control the clock using standardized
+   ioctls. A program may query, enable, configure, and disable the
+   ancillary clock features. User space can receive time stamped
+   events via blocking read() and poll(). One shot and periodic
+   signals may be configured via the POSIX timer_settime() system
+   call.
+
+** Writing clock drivers
+
+   Clock drivers include include/linux/ptp_clock_kernel.h and register
+   themselves by presenting a 'struct ptp_clock_info' to the
+   registration method. Clock drivers must implement all of the
+   functions in the interface. If a clock does not offer a particular
+   ancillary feature, then the driver should just return -EOPNOTSUPP
+   from those functions.
+
+   Drivers must ensure that all of the methods in interface are
+   reentrant. Since most hardware implementations treat the time value
+   as a 64 bit integer accessed as two 32 bit registers, drivers
+   should use spin_lock_irqsave/spin_unlock_irqrestore to protect
+   against concurrent access. This locking cannot be accomplished in
+   class driver, since the lock may also be needed by the clock
+   driver's interrupt service routine.
+
+** Supported hardware
+
+   + Freescale eTSEC gianfar
+     - 2 Time stamp external triggers, programmable polarity (opt. interrupt)
+     - 2 Alarm registers (optional interrupt)
+     - 3 Periodic signals (optional interrupt)
+
+   + National DP83640
+     - 6 GPIOs programmable as inputs or outputs
+     - 6 GPIOs with dedicated functions (LED/JTAG/clock) can also be
+       used as general inputs or outputs
+     - GPIO inputs can time stamp external triggers
+     - GPIO outputs can produce periodic signals
+     - 1 interrupt pin
+
+   + Intel IXP465
+     - Auxiliary Slave/Master Mode Snapshot (optional interrupt)
+     - Target Time (optional interrupt)
diff --git a/Documentation/ptp/testptp.c b/Documentation/ptp/testptp.c
new file mode 100644 (file)
index 0000000..f59ded0
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * PTP 1588 clock support - User space test program
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/ptp_clock.h>
+
+#define DEVICE "/dev/ptp0"
+
+#ifndef ADJ_SETOFFSET
+#define ADJ_SETOFFSET 0x0100
+#endif
+
+#ifndef CLOCK_INVALID
+#define CLOCK_INVALID -1
+#endif
+
+/* When glibc offers the syscall, this will go away. */
+#include <sys/syscall.h>
+static int clock_adjtime(clockid_t id, struct timex *tx)
+{
+       return syscall(__NR_clock_adjtime, id, tx);
+}
+
+static clockid_t get_clockid(int fd)
+{
+#define CLOCKFD 3
+#define FD_TO_CLOCKID(fd)      ((~(clockid_t) (fd) << 3) | CLOCKFD)
+
+       return FD_TO_CLOCKID(fd);
+}
+
+static void handle_alarm(int s)
+{
+       printf("received signal %d\n", s);
+}
+
+static int install_handler(int signum, void (*handler)(int))
+{
+       struct sigaction action;
+       sigset_t mask;
+
+       /* Unblock the signal. */
+       sigemptyset(&mask);
+       sigaddset(&mask, signum);
+       sigprocmask(SIG_UNBLOCK, &mask, NULL);
+
+       /* Install the signal handler. */
+       action.sa_handler = handler;
+       action.sa_flags = 0;
+       sigemptyset(&action.sa_mask);
+       sigaction(signum, &action, NULL);
+
+       return 0;
+}
+
+static long ppb_to_scaled_ppm(int ppb)
+{
+       /*
+        * The 'freq' field in the 'struct timex' is in parts per
+        * million, but with a 16 bit binary fractional field.
+        * Instead of calculating either one of
+        *
+        *    scaled_ppm = (ppb / 1000) << 16  [1]
+        *    scaled_ppm = (ppb << 16) / 1000  [2]
+        *
+        * we simply use double precision math, in order to avoid the
+        * truncation in [1] and the possible overflow in [2].
+        */
+       return (long) (ppb * 65.536);
+}
+
+static void usage(char *progname)
+{
+       fprintf(stderr,
+               "usage: %s [options]\n"
+               " -a val     request a one-shot alarm after 'val' seconds\n"
+               " -A val     request a periodic alarm every 'val' seconds\n"
+               " -c         query the ptp clock's capabilities\n"
+               " -d name    device to open\n"
+               " -e val     read 'val' external time stamp events\n"
+               " -f val     adjust the ptp clock frequency by 'val' ppb\n"
+               " -g         get the ptp clock time\n"
+               " -h         prints this message\n"
+               " -p val     enable output with a period of 'val' nanoseconds\n"
+               " -P val     enable or disable (val=1|0) the system clock PPS\n"
+               " -s         set the ptp clock time from the system time\n"
+               " -S         set the system time from the ptp clock time\n"
+               " -t val     shift the ptp clock time by 'val' seconds\n",
+               progname);
+}
+
+int main(int argc, char *argv[])
+{
+       struct ptp_clock_caps caps;
+       struct ptp_extts_event event;
+       struct ptp_extts_request extts_request;
+       struct ptp_perout_request perout_request;
+       struct timespec ts;
+       struct timex tx;
+
+       static timer_t timerid;
+       struct itimerspec timeout;
+       struct sigevent sigevent;
+
+       char *progname;
+       int c, cnt, fd;
+
+       char *device = DEVICE;
+       clockid_t clkid;
+       int adjfreq = 0x7fffffff;
+       int adjtime = 0;
+       int capabilities = 0;
+       int extts = 0;
+       int gettime = 0;
+       int oneshot = 0;
+       int periodic = 0;
+       int perout = -1;
+       int pps = -1;
+       int settime = 0;
+
+       progname = strrchr(argv[0], '/');
+       progname = progname ? 1+progname : argv[0];
+       while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghp:P:sSt:v"))) {
+               switch (c) {
+               case 'a':
+                       oneshot = atoi(optarg);
+                       break;
+               case 'A':
+                       periodic = atoi(optarg);
+                       break;
+               case 'c':
+                       capabilities = 1;
+                       break;
+               case 'd':
+                       device = optarg;
+                       break;
+               case 'e':
+                       extts = atoi(optarg);
+                       break;
+               case 'f':
+                       adjfreq = atoi(optarg);
+                       break;
+               case 'g':
+                       gettime = 1;
+                       break;
+               case 'p':
+                       perout = atoi(optarg);
+                       break;
+               case 'P':
+                       pps = atoi(optarg);
+                       break;
+               case 's':
+                       settime = 1;
+                       break;
+               case 'S':
+                       settime = 2;
+                       break;
+               case 't':
+                       adjtime = atoi(optarg);
+                       break;
+               case 'h':
+                       usage(progname);
+                       return 0;
+               case '?':
+               default:
+                       usage(progname);
+                       return -1;
+               }
+       }
+
+       fd = open(device, O_RDWR);
+       if (fd < 0) {
+               fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
+               return -1;
+       }
+
+       clkid = get_clockid(fd);
+       if (CLOCK_INVALID == clkid) {
+               fprintf(stderr, "failed to read clock id\n");
+               return -1;
+       }
+
+       if (capabilities) {
+               if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
+                       perror("PTP_CLOCK_GETCAPS");
+               } else {
+                       printf("capabilities:\n"
+                              "  %d maximum frequency adjustment (ppb)\n"
+                              "  %d programmable alarms\n"
+                              "  %d external time stamp channels\n"
+                              "  %d programmable periodic signals\n"
+                              "  %d pulse per second\n",
+                              caps.max_adj,
+                              caps.n_alarm,
+                              caps.n_ext_ts,
+                              caps.n_per_out,
+                              caps.pps);
+               }
+       }
+
+       if (0x7fffffff != adjfreq) {
+               memset(&tx, 0, sizeof(tx));
+               tx.modes = ADJ_FREQUENCY;
+               tx.freq = ppb_to_scaled_ppm(adjfreq);
+               if (clock_adjtime(clkid, &tx)) {
+                       perror("clock_adjtime");
+               } else {
+                       puts("frequency adjustment okay");
+               }
+       }
+
+       if (adjtime) {
+               memset(&tx, 0, sizeof(tx));
+               tx.modes = ADJ_SETOFFSET;
+               tx.time.tv_sec = adjtime;
+               tx.time.tv_usec = 0;
+               if (clock_adjtime(clkid, &tx) < 0) {
+                       perror("clock_adjtime");
+               } else {
+                       puts("time shift okay");
+               }
+       }
+
+       if (gettime) {
+               if (clock_gettime(clkid, &ts)) {
+                       perror("clock_gettime");
+               } else {
+                       printf("clock time: %ld.%09ld or %s",
+                              ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
+               }
+       }
+
+       if (settime == 1) {
+               clock_gettime(CLOCK_REALTIME, &ts);
+               if (clock_settime(clkid, &ts)) {
+                       perror("clock_settime");
+               } else {
+                       puts("set time okay");
+               }
+       }
+
+       if (settime == 2) {
+               clock_gettime(clkid, &ts);
+               if (clock_settime(CLOCK_REALTIME, &ts)) {
+                       perror("clock_settime");
+               } else {
+                       puts("set time okay");
+               }
+       }
+
+       if (extts) {
+               memset(&extts_request, 0, sizeof(extts_request));
+               extts_request.index = 0;
+               extts_request.flags = PTP_ENABLE_FEATURE;
+               if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
+                       perror("PTP_EXTTS_REQUEST");
+                       extts = 0;
+               } else {
+                       puts("external time stamp request okay");
+               }
+               for (; extts; extts--) {
+                       cnt = read(fd, &event, sizeof(event));
+                       if (cnt != sizeof(event)) {
+                               perror("read");
+                               break;
+                       }
+                       printf("event index %u at %lld.%09u\n", event.index,
+                              event.t.sec, event.t.nsec);
+                       fflush(stdout);
+               }
+               /* Disable the feature again. */
+               extts_request.flags = 0;
+               if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
+                       perror("PTP_EXTTS_REQUEST");
+               }
+       }
+
+       if (oneshot) {
+               install_handler(SIGALRM, handle_alarm);
+               /* Create a timer. */
+               sigevent.sigev_notify = SIGEV_SIGNAL;
+               sigevent.sigev_signo = SIGALRM;
+               if (timer_create(clkid, &sigevent, &timerid)) {
+                       perror("timer_create");
+                       return -1;
+               }
+               /* Start the timer. */
+               memset(&timeout, 0, sizeof(timeout));
+               timeout.it_value.tv_sec = oneshot;
+               if (timer_settime(timerid, 0, &timeout, NULL)) {
+                       perror("timer_settime");
+                       return -1;
+               }
+               pause();
+               timer_delete(timerid);
+       }
+
+       if (periodic) {
+               install_handler(SIGALRM, handle_alarm);
+               /* Create a timer. */
+               sigevent.sigev_notify = SIGEV_SIGNAL;
+               sigevent.sigev_signo = SIGALRM;
+               if (timer_create(clkid, &sigevent, &timerid)) {
+                       perror("timer_create");
+                       return -1;
+               }
+               /* Start the timer. */
+               memset(&timeout, 0, sizeof(timeout));
+               timeout.it_interval.tv_sec = periodic;
+               timeout.it_value.tv_sec = periodic;
+               if (timer_settime(timerid, 0, &timeout, NULL)) {
+                       perror("timer_settime");
+                       return -1;
+               }
+               while (1) {
+                       pause();
+               }
+               timer_delete(timerid);
+       }
+
+       if (perout >= 0) {
+               if (clock_gettime(clkid, &ts)) {
+                       perror("clock_gettime");
+                       return -1;
+               }
+               memset(&perout_request, 0, sizeof(perout_request));
+               perout_request.index = 0;
+               perout_request.start.sec = ts.tv_sec + 2;
+               perout_request.start.nsec = 0;
+               perout_request.period.sec = 0;
+               perout_request.period.nsec = perout;
+               if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
+                       perror("PTP_PEROUT_REQUEST");
+               } else {
+                       puts("periodic output request okay");
+               }
+       }
+
+       if (pps != -1) {
+               int enable = pps ? 1 : 0;
+               if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
+                       perror("PTP_ENABLE_PPS");
+               } else {
+                       puts("pps for system time request okay");
+               }
+       }
+
+       close(fd);
+       return 0;
+}
diff --git a/Documentation/ptp/testptp.mk b/Documentation/ptp/testptp.mk
new file mode 100644 (file)
index 0000000..4ef2d97
--- /dev/null
@@ -0,0 +1,33 @@
+# PTP 1588 clock support - User space test program
+#
+# Copyright (C) 2010 OMICRON electronics GmbH
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+CC        = $(CROSS_COMPILE)gcc
+INC       = -I$(KBUILD_OUTPUT)/usr/include
+CFLAGS    = -Wall $(INC)
+LDLIBS    = -lrt
+PROGS     = testptp
+
+all: $(PROGS)
+
+testptp: testptp.o
+
+clean:
+       rm -f testptp.o
+
+distclean: clean
+       rm -f $(PROGS)
index 9b7e1904db1c96230336f2799f0cb2501ab7588f..5d0fc8bfcdb9b608bccf03855c33a4d01386d270 100644 (file)
   forge.net/>  and explains these in detail, as well as
   some other issues.
 
+  There is also a related point-to-point only "ucast" transport.
+  This is useful when your network does not support multicast, and
+  all network connections are simple point to point links.
+
+  The full set of command line options for this transport are
+
+
+       ethn=ucast,ethernet address,remote address,listen port,remote port
+
+
 
 
   6\b6.\b.6\b6.\b.  T\bTU\bUN\bN/\b/T\bTA\bAP\bP w\bwi\bit\bth\bh t\bth\bhe\be u\bum\bml\bl_\b_n\bne\bet\bt h\bhe\bel\blp\bpe\ber\br
index 25fadb448760008dc6408ed0cca2a72c66b2efd0..f61228bd639577195b4e5142d1388e33136b7ace 100644 (file)
@@ -66,7 +66,7 @@ in some cases it is not really needed. Eg, vm_start is modified by
 expand_stack(), it is hard to come up with a destructive scenario without 
 having the vmlist protection in this case.
 
-The page_table_lock nests with the inode i_mmap_lock and the kmem cache
+The page_table_lock nests with the inode i_mmap_mutex and the kmem cache
 c_spinlock spinlocks.  This is okay, since the kmem code asks for pages after
 dropping c_spinlock.  The page_table_lock also nests with pagecache_lock and
 pagemap_lru_lock spinlocks, and no code asks for memory with these locks
index 98c324b07a164913d171d4ef6d07592940b8facf..1ab17de642e572298ef32b38b5a69198739b7cf8 100644 (file)
@@ -287,35 +287,35 @@ F:        sound/pci/ad1889.*
 
 AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD5254
 S:     Supported
 F:     drivers/misc/ad525x_dpot.c
 
 AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD5398
 S:     Supported
 F:     drivers/regulator/ad5398.c
 
 AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD7142
 S:     Supported
 F:     drivers/input/misc/ad714x.c
 
 AD7877 TOUCHSCREEN DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD7877
 S:     Supported
 F:     drivers/input/touchscreen/ad7877.c
 
 AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD7879
 S:     Supported
 F:     drivers/input/touchscreen/ad7879.c
@@ -341,7 +341,7 @@ F:  drivers/net/wireless/adm8211.*
 
 ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP5520
 S:     Supported
 F:     drivers/mfd/adp5520.c
@@ -352,7 +352,7 @@ F:  drivers/input/keyboard/adp5520-keys.c
 
 ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP5588
 S:     Supported
 F:     drivers/input/keyboard/adp5588-keys.c
@@ -360,7 +360,7 @@ F:  drivers/gpio/adp5588-gpio.c
 
 ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP8860
 S:     Supported
 F:     drivers/video/backlight/adp8860_bl.c
@@ -387,7 +387,7 @@ F:  drivers/hwmon/adt7475.c
 
 ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADXL345
 S:     Supported
 F:     drivers/input/misc/adxl34x.c
@@ -483,6 +483,13 @@ F: drivers/tty/serial/altera_jtaguart.c
 F:     include/linux/altera_uart.h
 F:     include/linux/altera_jtaguart.h
 
+AMD FAM15H PROCESSOR POWER MONITORING DRIVER
+M:     Andreas Herrmann <andreas.herrmann3@amd.com>
+L:     lm-sensors@lm-sensors.org
+S:     Maintained
+F:     Documentation/hwmon/fam15h_power
+F:     drivers/hwmon/fam15h_power.c
+
 AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
 M:     Thomas Dahlmann <dahlmann.thomas@arcor.de>
 L:     linux-geode@lists.infradead.org (moderated for non-subscribers)
@@ -526,7 +533,7 @@ S:  Maintained
 F:     drivers/infiniband/hw/amso1100/
 
 ANALOG DEVICES INC ASOC CODEC DRIVERS
-L:     device-driver-devel@blackfin.uclinux.org
+L:     device-drivers-devel@blackfin.uclinux.org
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://wiki.analog.com/
 S:     Supported
@@ -2034,9 +2041,8 @@ F:        net/ax25/ax25_timer.c
 F:     net/ax25/sysctl_net_ax25.c
 
 DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
-M:     Tobias Ringstrom <tori@unhappy.mine.nu>
 L:     netdev@vger.kernel.org
-S:     Maintained
+S:     Orphan
 F:     Documentation/networking/dmfe.txt
 F:     drivers/net/tulip/dmfe.c
 
@@ -3591,10 +3597,9 @@ F:       Documentation/hwmon/k8temp
 F:     drivers/hwmon/k8temp.c
 
 KCONFIG
-M:     Roman Zippel <zippel@linux-m68k.org>
+M:     Michal Marek <mmarek@suse.cz>
 L:     linux-kbuild@vger.kernel.org
-Q:     http://patchwork.kernel.org/project/linux-kbuild/list/
-S:     Maintained
+S:     Odd Fixes
 F:     Documentation/kbuild/kconfig-language.txt
 F:     scripts/kconfig/
 
@@ -3898,7 +3903,6 @@ F:        drivers/*/*/*pasemi*
 LINUX SECURITY MODULE (LSM) FRAMEWORK
 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
 
 LIS3LV02D ACCELEROMETER DRIVER
@@ -6796,6 +6800,13 @@ L:       lm-sensors@lm-sensors.org
 S:     Maintained
 F:     drivers/hwmon/vt8231.c
 
+VUB300 USB to SDIO/SD/MMC bridge chip
+M:     Tony Olech <tony.olech@elandigitalsystems.com>
+L:     linux-mmc@vger.kernel.org
+L:     linux-usb@vger.kernel.org
+S:     Supported
+F:     drivers/mmc/host/vub300.c
+
 W1 DALLAS'S 1-WIRE BUS
 M:     Evgeniy Polyakov <johnpol@2ka.mipt.ru>
 S:     Maintained
index 6b73d1eed1ea0c9aea3af6270fb504d2c836cceb..529d93fa2430282bda65da27258dfff8091b1be9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -220,6 +220,14 @@ ifeq ($(ARCH),sh64)
        SRCARCH := sh
 endif
 
+# Additional ARCH settings for tile
+ifeq ($(ARCH),tilepro)
+       SRCARCH := tile
+endif
+ifeq ($(ARCH),tilegx)
+       SRCARCH := tile
+endif
+
 # Where to locate arch specific headers
 hdr-arch  := $(SRCARCH)
 
@@ -1009,7 +1017,8 @@ include/generated/utsrelease.h: include/config/kernel.release FORCE
 
 PHONY += headerdep
 headerdep:
-       $(Q)find include/ -name '*.h' | xargs --max-args 1 scripts/headerdep.pl
+       $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \
+       $(srctree)/scripts/headerdep.pl -I$(srctree)/include
 
 # ---------------------------------------------------------------------------
 
@@ -1417,13 +1426,15 @@ tags TAGS cscope gtags: FORCE
 # Scripts to check various things for consistency
 # ---------------------------------------------------------------------------
 
+PHONY += includecheck versioncheck coccicheck namespacecheck export_report
+
 includecheck:
-       find * $(RCS_FIND_IGNORE) \
+       find $(srctree)/* $(RCS_FIND_IGNORE) \
                -name '*.[hcS]' -type f -print | sort \
                | xargs $(PERL) -w $(srctree)/scripts/checkincludes.pl
 
 versioncheck:
-       find * $(RCS_FIND_IGNORE) \
+       find $(srctree)/* $(RCS_FIND_IGNORE) \
                -name '*.[hcS]' -type f -print | sort \
                | xargs $(PERL) -w $(srctree)/scripts/checkversion.pl
 
index 8d24bacaa61ea5746e326133d32f019f9511b602..26b0e2397a5724140bc8683fedd6bbae67706fe5 100644 (file)
@@ -175,4 +175,7 @@ config HAVE_ARCH_JUMP_LABEL
 config HAVE_ARCH_MUTEX_CPU_RELAX
        bool
 
+config HAVE_RCU_TABLE_FREE
+       bool
+
 source "kernel/gcov/Kconfig"
index 9808998cc07321dd5f45f6f782b4eedf222446ec..e3a82775f9da7fc17215b07b57f972bb2b417c0d 100644 (file)
@@ -12,6 +12,7 @@ config ALPHA
        select GENERIC_IRQ_PROBE
        select AUTO_IRQ_AFFINITY if SMP
        select GENERIC_IRQ_SHOW
+       select ARCH_WANT_OPTIONAL_GPIOLIB
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
@@ -51,6 +52,9 @@ config GENERIC_CALIBRATE_DELAY
 config GENERIC_CMOS_UPDATE
         def_bool y
 
+config GENERIC_GPIO
+       def_bool y
+
 config ZONE_DMA
        bool
        default y
diff --git a/arch/alpha/include/asm/gpio.h b/arch/alpha/include/asm/gpio.h
new file mode 100644 (file)
index 0000000..7dc6a63
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Generic GPIO API implementation for Alpha.
+ *
+ * A stright copy of that for PowerPC which was:
+ *
+ * Copyright (c) 2007-2008  MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _ASM_ALPHA_GPIO_H
+#define _ASM_ALPHA_GPIO_H
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+/*
+ * We don't (yet) implement inlined/rapid versions for on-chip gpios.
+ * Just call gpiolib.
+ */
+static inline int gpio_get_value(unsigned int gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+       return __gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* _ASM_ALPHA_GPIO_H */
index 3f390e8cc0b33fdee5070297d99d30e102f90557..c46e714aa3e024ccd04ec7cf11207ba0a1243b13 100644 (file)
@@ -39,8 +39,6 @@ struct cpuinfo_alpha {
 
 extern struct cpuinfo_alpha cpu_data[NR_CPUS];
 
-#define PROC_CHANGE_PENALTY     20
-
 #define hard_smp_processor_id()        __hard_smp_processor_id()
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
index 3ec35066f1dc51c09367c32bea106453a109953d..838eac128409e235b33080ca893847ebaa69b827 100644 (file)
@@ -121,7 +121,7 @@ common_shutdown_1(void *generic_ptr)
        /* Wait for the secondaries to halt. */
        set_cpu_present(boot_cpuid, false);
        set_cpu_possible(boot_cpuid, false);
-       while (cpus_weight(cpu_present_map))
+       while (cpumask_weight(cpu_present_mask))
                barrier();
 #endif
 
index edbddcbd5bc654692fbfc98572ed8277303d49db..cc0fd862cf26a9565580c9f137e0d67ac3119bab 100644 (file)
@@ -1257,7 +1257,7 @@ show_cpuinfo(struct seq_file *f, void *slot)
 #ifdef CONFIG_SMP
        seq_printf(f, "cpus active\t\t: %u\n"
                      "cpu active mask\t\t: %016lx\n",
-                      num_online_cpus(), cpus_addr(cpu_possible_map)[0]);
+                      num_online_cpus(), cpumask_bits(cpu_possible_mask)[0]);
 #endif
 
        show_cache_size (f, "L1 Icache", alpha_l1i_cacheshape);
index 5a621c6d22ab4e217b489376c82da5f3d5f94894..d739703608fcc6c29c0adaa2b2e065ee22b77a85 100644 (file)
@@ -451,7 +451,7 @@ setup_smp(void)
        }
 
        printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_map = %lx\n",
-              smp_num_probed, cpu_present_map.bits[0]);
+              smp_num_probed, cpumask_bits(cpu_present_mask)[0]);
 }
 
 /*
@@ -629,8 +629,9 @@ smp_send_reschedule(int cpu)
 void
 smp_send_stop(void)
 {
-       cpumask_t to_whom = cpu_possible_map;
-       cpu_clear(smp_processor_id(), to_whom);
+       cpumask_t to_whom;
+       cpumask_copy(&to_whom, cpu_possible_mask);
+       cpumask_clear_cpu(smp_processor_id(), &to_whom);
 #ifdef DEBUG_IPI_MSG
        if (hard_smp_processor_id() != boot_cpu_id)
                printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
index 5ac00fd4cd0cbd12ca4fe97208dbbe4809b99d7d..f8856829c22a96bdff7ce25eab5a4c012c07cae9 100644 (file)
@@ -140,7 +140,7 @@ cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
 
        for (cpu = 0; cpu < 4; cpu++) {
                unsigned long aff = cpu_irq_affinity[cpu];
-               if (cpu_isset(cpu, affinity))
+               if (cpumask_test_cpu(cpu, &affinity))
                        aff |= 1UL << irq;
                else
                        aff &= ~(1UL << irq);
index fea0e4620994455fd4a3d52471c5b89371571087..6994407e242aec27f243f08860c247b1162ddf70 100644 (file)
@@ -65,10 +65,11 @@ titan_update_irq_hw(unsigned long mask)
        register int bcpu = boot_cpuid;
 
 #ifdef CONFIG_SMP
-       cpumask_t cpm = cpu_present_map;
+       cpumask_t cpm;
        volatile unsigned long *dim0, *dim1, *dim2, *dim3;
        unsigned long mask0, mask1, mask2, mask3, dummy;
 
+       cpumask_copy(&cpm, cpu_present_mask);
        mask &= ~isa_enable;
        mask0 = mask & titan_cpu_irq_affinity[0];
        mask1 = mask & titan_cpu_irq_affinity[1];
@@ -84,10 +85,10 @@ titan_update_irq_hw(unsigned long mask)
        dim1 = &cchip->dim1.csr;
        dim2 = &cchip->dim2.csr;
        dim3 = &cchip->dim3.csr;
-       if (!cpu_isset(0, cpm)) dim0 = &dummy;
-       if (!cpu_isset(1, cpm)) dim1 = &dummy;
-       if (!cpu_isset(2, cpm)) dim2 = &dummy;
-       if (!cpu_isset(3, cpm)) dim3 = &dummy;
+       if (!cpumask_test_cpu(0, &cpm)) dim0 = &dummy;
+       if (!cpumask_test_cpu(1, &cpm)) dim1 = &dummy;
+       if (!cpumask_test_cpu(2, &cpm)) dim2 = &dummy;
+       if (!cpumask_test_cpu(3, &cpm)) dim3 = &dummy;
 
        *dim0 = mask0;
        *dim1 = mask1;
@@ -137,7 +138,7 @@ titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
        int cpu;
 
        for (cpu = 0; cpu < 4; cpu++) {
-               if (cpu_isset(cpu, affinity))
+               if (cpumask_test_cpu(cpu, &affinity))
                        titan_cpu_irq_affinity[cpu] |= 1UL << irq;
                else
                        titan_cpu_irq_affinity[cpu] &= ~(1UL << irq);
index 86425ab53bf5d1afa9bd0d4dddcb2e8543b621e4..69d0c5761e2f206d5de46da70703ca22e940ed08 100644 (file)
@@ -32,8 +32,6 @@
 #include <asm/console.h>
 #include <asm/tlb.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 extern void die_if_kernel(char *,struct pt_regs *,long);
 
 static struct pcb_struct original_pcb;
index 7b2c56d8f930b89fc6747ccdca550456f35f83b6..3973ae3957720dd68143cc0a21ecca2a76e8d48d 100644 (file)
@@ -313,6 +313,7 @@ void __init paging_init(void)
                        zones_size[ZONE_DMA] = dma_local_pfn;
                        zones_size[ZONE_NORMAL] = (end_pfn - start_pfn) - dma_local_pfn;
                }
+               node_set_state(nid, N_NORMAL_MEMORY);
                free_area_init_node(nid, zones_size, start_pfn, NULL);
        }
 
index f59758dd86cfc8684d431128c3e21da147792bc5..9adc278a22abb36df1bdfdacd1db1fe240f8d0fb 100644 (file)
@@ -1389,7 +1389,6 @@ config NR_CPUS
 config HOTPLUG_CPU
        bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
        depends on SMP && HOTPLUG && EXPERIMENTAL
-       depends on !ARCH_MSM
        help
          Say Y here to experiment with turning CPUs off and on.  CPUs
          can be controlled through /sys/devices/system/cpu.
@@ -1506,6 +1505,9 @@ config ARCH_SPARSEMEM_DEFAULT
 config ARCH_SELECT_MEMORY_MODEL
        def_bool ARCH_SPARSEMEM_ENABLE
 
+config HAVE_ARCH_PFN_VALID
+       def_bool ARCH_HAS_HOLES_MEMORYMODEL || !SPARSEMEM
+
 config HIGHMEM
        bool "High Memory Support"
        depends on MMU
index 03d01d783e3bf95c72f28259aad1550b97c5cc68..81cbe40c159c63c20968d224f960d3d353509946 100644 (file)
@@ -63,13 +63,6 @@ config DEBUG_USER
              8 - SIGSEGV faults
             16 - SIGBUS faults
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T output.
-
 # These options are only for real kernel hackers who want to get their hands dirty.
 config DEBUG_LL
        bool "Kernel low-level debugging functions"
index 2242ce22ec6c866285391f94696149e3977dece3..d493d0b742a1383e716ab1b3c8f3286756e27689 100644 (file)
@@ -4,6 +4,13 @@
  * Support for FIQ on ARM architectures.
  * Written by Philip Blundell <philb@gnu.org>, 1998
  * Re-written by Russell King
+ *
+ * NOTE: The FIQ mode registers are not magically preserved across
+ * suspend/resume.
+ *
+ * Drivers which require these registers to be preserved across power
+ * management operations must implement appropriate suspend/resume handlers to
+ * save and restore them.
  */
 
 #ifndef __ASM_FIQ_H
@@ -29,9 +36,21 @@ struct fiq_handler {
 extern int claim_fiq(struct fiq_handler *f);
 extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
-extern void set_fiq_regs(struct pt_regs *regs);
-extern void get_fiq_regs(struct pt_regs *regs);
 extern void enable_fiq(int fiq);
 extern void disable_fiq(int fiq);
 
+/* helpers defined in fiqasm.S: */
+extern void __set_fiq_regs(unsigned long const *regs);
+extern void __get_fiq_regs(unsigned long *regs);
+
+static inline void set_fiq_regs(struct pt_regs const *regs)
+{
+       __set_fiq_regs(&regs->ARM_r8);
+}
+
+static inline void get_fiq_regs(struct pt_regs *regs)
+{
+       __get_fiq_regs(&regs->ARM_r8);
+}
+
 #endif
index f51a69595f6ed53bc2d46d07a146f8b08ac6b83d..ac75d08488892f22dace530691de9a001d884f48 100644 (file)
@@ -197,7 +197,7 @@ typedef unsigned long pgprot_t;
 
 typedef struct page *pgtable_t;
 
-#ifndef CONFIG_SPARSEMEM
+#ifdef CONFIG_HAVE_ARCH_PFN_VALID
 extern int pfn_valid(unsigned long);
 #endif
 
index a87664f54f93480b702afe8c52d838052217bc58..e42d96a45d3e9267566cfa662a71235423c1e2f0 100644 (file)
 
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
-/*
- * at the moment, there's not a big penalty for changing CPUs
- * (the >big< penalty is running SMP in the first place)
- */
-#define PROC_CHANGE_PENALTY            15
-
 struct seq_file;
 
 /*
@@ -76,6 +70,7 @@ extern void platform_smp_prepare_cpus(unsigned int);
  */
 struct secondary_data {
        unsigned long pgdir;
+       unsigned long swapper_pg_dir;
        void *stack;
 };
 extern struct secondary_data secondary_data;
index 82dfe5d0c41e764b077acd0fca5b36c525586fc5..265f908c4a6e79b98e07d43b7614c5164e86da53 100644 (file)
  */
 #if defined(CONFIG_SMP) || defined(CONFIG_CPU_32v7)
 #define tlb_fast_mode(tlb)     0
-#define FREE_PTE_NR            500
 #else
 #define tlb_fast_mode(tlb)     1
-#define FREE_PTE_NR            0
 #endif
 
+#define MMU_GATHER_BUNDLE      8
+
 /*
  * TLB handling.  This allows us to remove pages from the page
  * tables, and efficiently handle the TLB issues.
@@ -58,7 +58,9 @@ struct mmu_gather {
        unsigned long           range_start;
        unsigned long           range_end;
        unsigned int            nr;
-       struct page             *pages[FREE_PTE_NR];
+       unsigned int            max;
+       struct page             **pages;
+       struct page             *local[MMU_GATHER_BUNDLE];
 };
 
 DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -97,26 +99,37 @@ static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
        }
 }
 
+static inline void __tlb_alloc_page(struct mmu_gather *tlb)
+{
+       unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
+
+       if (addr) {
+               tlb->pages = (void *)addr;
+               tlb->max = PAGE_SIZE / sizeof(struct page *);
+       }
+}
+
 static inline void tlb_flush_mmu(struct mmu_gather *tlb)
 {
        tlb_flush(tlb);
        if (!tlb_fast_mode(tlb)) {
                free_pages_and_swap_cache(tlb->pages, tlb->nr);
                tlb->nr = 0;
+               if (tlb->pages == tlb->local)
+                       __tlb_alloc_page(tlb);
        }
 }
 
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int fullmm)
 {
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
        tlb->mm = mm;
-       tlb->fullmm = full_mm_flush;
+       tlb->fullmm = fullmm;
        tlb->vma = NULL;
+       tlb->max = ARRAY_SIZE(tlb->local);
+       tlb->pages = tlb->local;
        tlb->nr = 0;
-
-       return tlb;
+       __tlb_alloc_page(tlb);
 }
 
 static inline void
@@ -127,7 +140,8 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
        /* keep the page table cache within bounds */
        check_pgt_cache();
 
-       put_cpu_var(mmu_gathers);
+       if (tlb->pages != tlb->local)
+               free_pages((unsigned long)tlb->pages, 0);
 }
 
 /*
@@ -162,15 +176,22 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
                tlb_flush(tlb);
 }
 
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        if (tlb_fast_mode(tlb)) {
                free_page_and_swap_cache(page);
-       } else {
-               tlb->pages[tlb->nr++] = page;
-               if (tlb->nr >= FREE_PTE_NR)
-                       tlb_flush_mmu(tlb);
+               return 1; /* avoid calling tlb_flush_mmu */
        }
+
+       tlb->pages[tlb->nr++] = page;
+       VM_BUG_ON(tlb->nr > tlb->max);
+       return tlb->max - tlb->nr;
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       if (!__tlb_remove_page(tlb, page))
+               tlb_flush_mmu(tlb);
 }
 
 static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
index 87dbe3e21970c224391e4f2e29e08c34157821f7..3de689aa6f6840227ecfd2ccc3e79b73cd787ff0 100644 (file)
 #define __NR_open_by_handle_at         (__NR_SYSCALL_BASE+371)
 #define __NR_clock_adjtime             (__NR_SYSCALL_BASE+372)
 #define __NR_syncfs                    (__NR_SYSCALL_BASE+373)
+#define __NR_sendmmsg                  (__NR_SYSCALL_BASE+374)
 
 /*
  * The following SWIs are ARM private.
index 908c78cb1d1c4a80c0c3c6a9eb7d640b730c6828..a5b31af5c2b81717bc98a6851a8daf2ec2b04d7a 100644 (file)
@@ -24,7 +24,7 @@ obj-$(CONFIG_OC_ETM)          += etm.o
 
 obj-$(CONFIG_ISA_DMA_API)      += dma.o
 obj-$(CONFIG_ARCH_ACORN)       += ecard.o 
-obj-$(CONFIG_FIQ)              += fiq.o
+obj-$(CONFIG_FIQ)              += fiq.o fiqasm.o
 obj-$(CONFIG_MODULES)          += armksyms.o module.o
 obj-$(CONFIG_ARTHUR)           += arthur.o
 obj-$(CONFIG_ISA_DMA)          += dma-isa.o
index 7fbf28c35bb2b438469894bb6bc80797fd8a3cf6..24cdac3ce2e3e6f8db9c98e480df48b876515b45 100644 (file)
                CALL(sys_open_by_handle_at)
                CALL(sys_clock_adjtime)
                CALL(sys_syncfs)
+               CALL(sys_sendmmsg)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
index e72dc34eea1cfbd0f3202067c1a937c4a20821d2..4c164ece5891cfba0bd5e346a4fc51565f92d94b 100644 (file)
@@ -89,47 +89,6 @@ void set_fiq_handler(void *start, unsigned int length)
                flush_icache_range(0x1c, 0x1c + length);
 }
 
-/*
- * Taking an interrupt in FIQ mode is death, so both these functions
- * disable irqs for the duration.  Note - these functions are almost
- * entirely coded in assembly.
- */
-void __naked set_fiq_regs(struct pt_regs *regs)
-{
-       register unsigned long tmp;
-       asm volatile (
-       "mov    ip, sp\n\
-       stmfd   sp!, {fp, ip, lr, pc}\n\
-       sub     fp, ip, #4\n\
-       mrs     %0, cpsr\n\
-       msr     cpsr_c, %2      @ select FIQ mode\n\
-       mov     r0, r0\n\
-       ldmia   %1, {r8 - r14}\n\
-       msr     cpsr_c, %0      @ return to SVC mode\n\
-       mov     r0, r0\n\
-       ldmfd   sp, {fp, sp, pc}"
-       : "=&r" (tmp)
-       : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
-}
-
-void __naked get_fiq_regs(struct pt_regs *regs)
-{
-       register unsigned long tmp;
-       asm volatile (
-       "mov    ip, sp\n\
-       stmfd   sp!, {fp, ip, lr, pc}\n\
-       sub     fp, ip, #4\n\
-       mrs     %0, cpsr\n\
-       msr     cpsr_c, %2      @ select FIQ mode\n\
-       mov     r0, r0\n\
-       stmia   %1, {r8 - r14}\n\
-       msr     cpsr_c, %0      @ return to SVC mode\n\
-       mov     r0, r0\n\
-       ldmfd   sp, {fp, sp, pc}"
-       : "=&r" (tmp)
-       : "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | FIQ_MODE));
-}
-
 int claim_fiq(struct fiq_handler *f)
 {
        int ret = 0;
@@ -174,8 +133,8 @@ void disable_fiq(int fiq)
 }
 
 EXPORT_SYMBOL(set_fiq_handler);
-EXPORT_SYMBOL(set_fiq_regs);
-EXPORT_SYMBOL(get_fiq_regs);
+EXPORT_SYMBOL(__set_fiq_regs); /* defined in fiqasm.S */
+EXPORT_SYMBOL(__get_fiq_regs); /* defined in fiqasm.S */
 EXPORT_SYMBOL(claim_fiq);
 EXPORT_SYMBOL(release_fiq);
 EXPORT_SYMBOL(enable_fiq);
diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S
new file mode 100644 (file)
index 0000000..207f9d6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  linux/arch/arm/kernel/fiqasm.S
+ *
+ *  Derived from code originally in linux/arch/arm/kernel/fiq.c:
+ *
+ *  Copyright (C) 1998 Russell King
+ *  Copyright (C) 1998, 1999 Phil Blundell
+ *  Copyright (C) 2011, Linaro Limited
+ *
+ *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
+ *
+ *  FIQ support re-written by Russell King to be more generic
+ *
+ *  v7/Thumb-2 compatibility modifications by Linaro Limited, 2011.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Taking an interrupt in FIQ mode is death, so both these functions
+ * disable irqs for the duration.
+ */
+
+ENTRY(__set_fiq_regs)
+       mov     r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
+       mrs     r1, cpsr
+       msr     cpsr_c, r2      @ select FIQ mode
+       mov     r0, r0          @ avoid hazard prior to ARMv4
+       ldmia   r0!, {r8 - r12}
+       ldr     sp, [r0], #4
+       ldr     lr, [r0]
+       msr     cpsr_c, r1      @ return to SVC mode
+       mov     r0, r0          @ avoid hazard prior to ARMv4
+       mov     pc, lr
+ENDPROC(__set_fiq_regs)
+
+ENTRY(__get_fiq_regs)
+       mov     r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
+       mrs     r1, cpsr
+       msr     cpsr_c, r2      @ select FIQ mode
+       mov     r0, r0          @ avoid hazard prior to ARMv4
+       stmia   r0!, {r8 - r12}
+       str     sp, [r0], #4
+       str     lr, [r0]
+       msr     cpsr_c, r1      @ return to SVC mode
+       mov     r0, r0          @ avoid hazard prior to ARMv4
+       mov     pc, lr
+ENDPROC(__get_fiq_regs)
index a5e5c5b9b48e5b68e1ef83582dca5e8861754fd3..278c1b0ebb2ee340fcb0e4f4b010c80e535c9308 100644 (file)
@@ -113,6 +113,7 @@ ENTRY(stext)
        ldr     r13, =__mmap_switched           @ address to jump to after
                                                @ mmu has been enabled
        adr     lr, BSYM(1f)                    @ return (PIC) address
+       mov     r8, r4                          @ set TTBR1 to swapper_pg_dir
  ARM(  add     pc, r10, #PROCINFO_INITFUNC     )
  THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
  THUMB(        mov     pc, r12                         )
@@ -302,8 +303,10 @@ ENTRY(secondary_startup)
         */
        adr     r4, __secondary_data
        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
+       sub     lr, r4, r5                      @ mmu has been enabled
+       ldr     r4, [r7, lr]                    @ get secondary_data.pgdir
+       add     r7, r7, #4
+       ldr     r8, [r7, lr]                    @ get secondary_data.swapper_pg_dir
        adr     lr, BSYM(__enable_mmu)          @ return address
        mov     r13, r12                        @ __secondary_switched address
  ARM(  add     pc, r10, #PROCINFO_INITFUNC     ) @ initialise processor
index d439a8f4c078fcef079a0adcb3844e69bf8d3cee..344e52b16c8cd4234b523547d07a8b6ff9106bd6 100644 (file)
@@ -105,6 +105,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
         */
        secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
        secondary_data.pgdir = virt_to_phys(pgd);
+       secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir);
        __cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data));
        outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1));
 
index 6dc06487f3c3e95359b2559163f24d8a8ca635cf..c562f649734cea40f813c3d6c50b9cffcd619ae9 100644 (file)
@@ -35,7 +35,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-
+#include <asm/unwind.h>
 
 .macro ARM_DIV_BODY dividend, divisor, result, curbit
 
@@ -207,6 +207,7 @@ Boston, MA 02111-1307, USA.  */
 
 ENTRY(__udivsi3)
 ENTRY(__aeabi_uidiv)
+UNWIND(.fnstart)
 
        subs    r2, r1, #1
        moveq   pc, lr
@@ -230,10 +231,12 @@ ENTRY(__aeabi_uidiv)
        mov     r0, r0, lsr r2
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__udivsi3)
 ENDPROC(__aeabi_uidiv)
 
 ENTRY(__umodsi3)
+UNWIND(.fnstart)
 
        subs    r2, r1, #1                      @ compare divisor with 1
        bcc     Ldiv0
@@ -247,10 +250,12 @@ ENTRY(__umodsi3)
 
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__umodsi3)
 
 ENTRY(__divsi3)
 ENTRY(__aeabi_idiv)
+UNWIND(.fnstart)
 
        cmp     r1, #0
        eor     ip, r0, r1                      @ save the sign of the result.
@@ -287,10 +292,12 @@ ENTRY(__aeabi_idiv)
        rsbmi   r0, r0, #0
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__divsi3)
 ENDPROC(__aeabi_idiv)
 
 ENTRY(__modsi3)
+UNWIND(.fnstart)
 
        cmp     r1, #0
        beq     Ldiv0
@@ -310,11 +317,14 @@ ENTRY(__modsi3)
        rsbmi   r0, r0, #0
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__modsi3)
 
 #ifdef CONFIG_AEABI
 
 ENTRY(__aeabi_uidivmod)
+UNWIND(.fnstart)
+UNWIND(.save {r0, r1, ip, lr}  )
 
        stmfd   sp!, {r0, r1, ip, lr}
        bl      __aeabi_uidiv
@@ -323,10 +333,12 @@ ENTRY(__aeabi_uidivmod)
        sub     r1, r1, r3
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__aeabi_uidivmod)
 
 ENTRY(__aeabi_idivmod)
-
+UNWIND(.fnstart)
+UNWIND(.save {r0, r1, ip, lr}  )
        stmfd   sp!, {r0, r1, ip, lr}
        bl      __aeabi_idiv
        ldmfd   sp!, {r1, r2, ip, lr}
@@ -334,15 +346,18 @@ ENTRY(__aeabi_idivmod)
        sub     r1, r1, r3
        mov     pc, lr
 
+UNWIND(.fnend)
 ENDPROC(__aeabi_idivmod)
 
 #endif
 
 Ldiv0:
-
+UNWIND(.fnstart)
+UNWIND(.pad #4)
+UNWIND(.save {lr})
        str     lr, [sp, #-8]!
        bl      __div0
        mov     r0, #0                  @ About as wrong as it could be.
        ldr     pc, [sp], #8
-
-
+UNWIND(.fnend)
+ENDPROC(Ldiv0)
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h b/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h
new file mode 100644 (file)
index 0000000..292d55e
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * PTP 1588 clock using the IXP46X
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _IXP46X_TS_H_
+#define _IXP46X_TS_H_
+
+#define DEFAULT_ADDEND 0xF0000029
+#define TICKS_NS_SHIFT 4
+
+struct ixp46x_channel_ctl {
+       u32 ch_control;  /* 0x40 Time Synchronization Channel Control */
+       u32 ch_event;    /* 0x44 Time Synchronization Channel Event */
+       u32 tx_snap_lo;  /* 0x48 Transmit Snapshot Low Register */
+       u32 tx_snap_hi;  /* 0x4C Transmit Snapshot High Register */
+       u32 rx_snap_lo;  /* 0x50 Receive Snapshot Low Register */
+       u32 rx_snap_hi;  /* 0x54 Receive Snapshot High Register */
+       u32 src_uuid_lo; /* 0x58 Source UUID0 Low Register */
+       u32 src_uuid_hi; /* 0x5C Sequence Identifier/Source UUID0 High */
+};
+
+struct ixp46x_ts_regs {
+       u32 control;     /* 0x00 Time Sync Control Register */
+       u32 event;       /* 0x04 Time Sync Event Register */
+       u32 addend;      /* 0x08 Time Sync Addend Register */
+       u32 accum;       /* 0x0C Time Sync Accumulator Register */
+       u32 test;        /* 0x10 Time Sync Test Register */
+       u32 unused;      /* 0x14 */
+       u32 rsystime_lo; /* 0x18 RawSystemTime_Low Register */
+       u32 rsystime_hi; /* 0x1C RawSystemTime_High Register */
+       u32 systime_lo;  /* 0x20 SystemTime_Low Register */
+       u32 systime_hi;  /* 0x24 SystemTime_High Register */
+       u32 trgt_lo;     /* 0x28 TargetTime_Low Register */
+       u32 trgt_hi;     /* 0x2C TargetTime_High Register */
+       u32 asms_lo;     /* 0x30 Auxiliary Slave Mode Snapshot Low  */
+       u32 asms_hi;     /* 0x34 Auxiliary Slave Mode Snapshot High */
+       u32 amms_lo;     /* 0x38 Auxiliary Master Mode Snapshot Low */
+       u32 amms_hi;     /* 0x3C Auxiliary Master Mode Snapshot High */
+
+       struct ixp46x_channel_ctl channel[3];
+};
+
+/* 0x00 Time Sync Control Register Bits */
+#define TSCR_AMM (1<<3)
+#define TSCR_ASM (1<<2)
+#define TSCR_TTM (1<<1)
+#define TSCR_RST (1<<0)
+
+/* 0x04 Time Sync Event Register Bits */
+#define TSER_SNM (1<<3)
+#define TSER_SNS (1<<2)
+#define TTIPEND  (1<<1)
+
+/* 0x40 Time Synchronization Channel Control Register Bits */
+#define MASTER_MODE   (1<<0)
+#define TIMESTAMP_ALL (1<<1)
+
+/* 0x44 Time Synchronization Channel Event Register Bits */
+#define TX_SNAPSHOT_LOCKED (1<<0)
+#define RX_SNAPSHOT_LOCKED (1<<1)
+
+#endif
index 5b84bcd30271321a17a38c7e0d2a2f51d4f286c2..b9913234bbf66458e93740aa1fd1e9c2004d42a1 100644 (file)
@@ -103,7 +103,6 @@ static struct amba_device fb_device = {
                .flags  = IORESOURCE_MEM,
        },
        .irq            = { NETX_IRQ_LCD, NO_IRQ },
-       .periphid       = 0x10112400,
 };
 
 int netx_fb_init(struct clcd_board *board, struct clcd_panel *panel)
index 9afd087cc29c9b1346cde3b161236e6d01b37524..23244cd0a5b6fed83adb041056558e8e58f6b13a 100644 (file)
@@ -37,8 +37,8 @@
 #include <plat/common.h>
 #include <plat/dma.h>
 #include <plat/gpmc.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include <plat/gpmc-smc91x.h>
 
index 56702c5e577fe3365cab09b56c32d5b4913020a0..93edd7fcf4512bbeebd40a9801b6982d317b5d77 100644 (file)
@@ -36,7 +36,7 @@
 #include <plat/usb.h>
 #include <plat/mmc.h>
 #include <plat/omap4-keypad.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "mux.h"
 #include "hsmmc.h"
@@ -680,6 +680,15 @@ static struct omap_dss_device sdp4430_hdmi_device = {
        .name = "hdmi",
        .driver_name = "hdmi_panel",
        .type = OMAP_DISPLAY_TYPE_HDMI,
+       .clocks = {
+               .dispc  = {
+                       .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK,
+               },
+               .hdmi   = {
+                       .regn   = 15,
+                       .regm2  = 1,
+               },
+       },
        .platform_enable = sdp4430_panel_enable_hdmi,
        .platform_disable = sdp4430_panel_disable_hdmi,
        .channel = OMAP_DSS_CHANNEL_DIGIT,
index ce7d5e6e41508c3708a64b9680566dce6933b9dc..ff8c59be36e5ff121fd6dcb0cda4efebfdf68da5 100644 (file)
@@ -34,8 +34,8 @@
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include "mux.h"
 #include "control.h"
index 02a12b41c0ff0b178e3493706e24c54d68a2bf70..9340f6a06f4a0a218bc56beb91508e9d22cdd0b6 100644 (file)
@@ -45,8 +45,8 @@
 #include <plat/nand.h>
 #include <plat/gpmc.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/mcspi.h>
 
 #include <mach/hardware.h>
index 65f9fde2c567253a5f2e5cf8f73f32c624dc721d..1d1b56a29fb1cf89b2f506ede3304e953cdf64dc 100644 (file)
@@ -45,8 +45,8 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
index 34cf982b96798edf3e24fd3816d0248b034c75e4..3da64d361651a9077e84a990bcccbb4e1a297b3d 100644 (file)
@@ -31,8 +31,8 @@
 #include <plat/common.h>
 #include <plat/gpmc.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/onenand.h>
 
 #include "mux.h"
index 33007fd4a0835fd298129c9fda30b844707cc08b..97750d483a701e7a9cbdf0a78fe69f16aa9510c1 100644 (file)
@@ -41,8 +41,8 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
index 5a1a916e5cc8a1989959d807731d94719eb39513..7f94cccdb07685a9826fc9467eaedba0c438998d 100644 (file)
@@ -44,8 +44,8 @@
 #include <plat/usb.h>
 #include <plat/common.h>
 #include <plat/mcspi.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include "mux.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
index 07dba888f4502b4a4beb18389c56034439633e0f..1db15492d82bca96dce8279da960736032309925 100644 (file)
@@ -46,7 +46,7 @@
 #include <mach/hardware.h>
 #include <plat/mcspi.h>
 #include <plat/usb.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/nand.h>
 
 #include "mux.h"
index a6e0b9161c99ceac2b98122f7a5f78955bbf4c53..a72c90a08c8a940c8f0ffa6d4b628f6507b54e01 100644 (file)
@@ -39,8 +39,8 @@
 #include <plat/gpmc.h>
 #include <plat/nand.h>
 #include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 
 #include <plat/mcspi.h>
 #include <linux/input/matrix_keypad.h>
index f3a7b1011914c7958e5fdd5ce51b2790c74702ea..e4973ac77cbc8d3d18a27cb94bffab0204194588 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include <plat/board.h>
 #include <plat/common.h>
 #include <plat/usb.h>
 #include <plat/mmc.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omap-panel-generic-dpi.h>
 #include "timer-gp.h"
 
 #include "hsmmc.h"
index 59ca33326b8c630ff789bf3f003c1b6e4ecadd68..9d192ff3b9ac113307c4de5e42f98abd2b60cefa 100644 (file)
@@ -43,8 +43,8 @@
 
 #include <plat/board.h>
 #include <plat/common.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
 #include <mach/gpio.h>
 #include <plat/gpmc.h>
 #include <mach/hardware.h>
index 89a66db8b77d513c76abe85a522c6c70394021f5..2df10b6a5940ae74786112d61a2bd7e2edb3a7ff 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/spi/spi.h>
 #include <linux/mm.h>
 #include <asm/mach-types.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vram.h>
 #include <plat/mcspi.h>
 
index 37b84c2b850fd813b0e40ceccec6e2b19152de40..60e8645db59da15c6342d5537e50000140095514 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/i2c/twl.h>
 #include <linux/spi/spi.h>
 #include <plat/mcspi.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define LCD_PANEL_RESET_GPIO_PROD      96
 #define LCD_PANEL_RESET_GPIO_PILOT     55
index 256d23fb79abad7a3c40f15ea7905972e780ea7b..543fcb8b518cb227d967f32a03a0ed8d68b63400 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
 
@@ -56,37 +56,58 @@ static bool opt_clock_available(const char *clk_role)
        return false;
 }
 
+struct omap_dss_hwmod_data {
+       const char *oh_name;
+       const char *dev_name;
+       const int id;
+};
+
+static const struct omap_dss_hwmod_data omap2_dss_hwmod_data[] __initdata = {
+       { "dss_core", "omapdss_dss", -1 },
+       { "dss_dispc", "omapdss_dispc", -1 },
+       { "dss_rfbi", "omapdss_rfbi", -1 },
+       { "dss_venc", "omapdss_venc", -1 },
+};
+
+static const struct omap_dss_hwmod_data omap3_dss_hwmod_data[] __initdata = {
+       { "dss_core", "omapdss_dss", -1 },
+       { "dss_dispc", "omapdss_dispc", -1 },
+       { "dss_rfbi", "omapdss_rfbi", -1 },
+       { "dss_venc", "omapdss_venc", -1 },
+       { "dss_dsi1", "omapdss_dsi1", -1 },
+};
+
+static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = {
+       { "dss_core", "omapdss_dss", -1 },
+       { "dss_dispc", "omapdss_dispc", -1 },
+       { "dss_rfbi", "omapdss_rfbi", -1 },
+       { "dss_venc", "omapdss_venc", -1 },
+       { "dss_dsi1", "omapdss_dsi1", -1 },
+       { "dss_dsi2", "omapdss_dsi2", -1 },
+       { "dss_hdmi", "omapdss_hdmi", -1 },
+};
+
 int __init omap_display_init(struct omap_dss_board_info *board_data)
 {
        int r = 0;
        struct omap_hwmod *oh;
        struct omap_device *od;
-       int i;
+       int i, oh_count;
        struct omap_display_platform_data pdata;
-
-       /*
-        * omap: valid DSS hwmod names
-        * omap2,3,4: dss_core, dss_dispc, dss_rfbi, dss_venc
-        * omap3,4: dss_dsi1
-        * omap4: dss_dsi2, dss_hdmi
-        */
-       char *oh_name[] = { "dss_core", "dss_dispc", "dss_rfbi", "dss_venc",
-               "dss_dsi1", "dss_dsi2", "dss_hdmi" };
-       char *dev_name[] = { "omapdss_dss", "omapdss_dispc", "omapdss_rfbi",
-               "omapdss_venc", "omapdss_dsi1", "omapdss_dsi2",
-               "omapdss_hdmi" };
-       int oh_count;
+       const struct omap_dss_hwmod_data *curr_dss_hwmod;
 
        memset(&pdata, 0, sizeof(pdata));
 
-       if (cpu_is_omap24xx())
-               oh_count = ARRAY_SIZE(oh_name) - 3;
-               /* last 3 hwmod dev in oh_name are not available for omap2 */
-       else if (cpu_is_omap44xx())
-               oh_count = ARRAY_SIZE(oh_name);
-       else
-               oh_count = ARRAY_SIZE(oh_name) - 2;
-               /* last 2 hwmod dev in oh_name are not available for omap3 */
+       if (cpu_is_omap24xx()) {
+               curr_dss_hwmod = omap2_dss_hwmod_data;
+               oh_count = ARRAY_SIZE(omap2_dss_hwmod_data);
+       } else if (cpu_is_omap34xx()) {
+               curr_dss_hwmod = omap3_dss_hwmod_data;
+               oh_count = ARRAY_SIZE(omap3_dss_hwmod_data);
+       } else {
+               curr_dss_hwmod = omap4_dss_hwmod_data;
+               oh_count = ARRAY_SIZE(omap4_dss_hwmod_data);
+       }
 
        /* opt_clks are always associated with dss hwmod */
        oh_core = omap_hwmod_lookup("dss_core");
@@ -100,19 +121,21 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
        pdata.opt_clock_available = opt_clock_available;
 
        for (i = 0; i < oh_count; i++) {
-               oh = omap_hwmod_lookup(oh_name[i]);
+               oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
                if (!oh) {
-                       pr_err("Could not look up %s\n", oh_name[i]);
+                       pr_err("Could not look up %s\n",
+                               curr_dss_hwmod[i].oh_name);
                        return -ENODEV;
                }
 
-               od = omap_device_build(dev_name[i], -1, oh, &pdata,
+               od = omap_device_build(curr_dss_hwmod[i].dev_name,
+                               curr_dss_hwmod[i].id, oh, &pdata,
                                sizeof(struct omap_display_platform_data),
                                omap_dss_latency,
                                ARRAY_SIZE(omap_dss_latency), 0);
 
                if (WARN((IS_ERR(od)), "Could not build omap_device for %s\n",
-                               oh_name[i]))
+                               curr_dss_hwmod[i].oh_name))
                        return -ENODEV;
        }
        omap_display_device.dev.platform_data = board_data;
index d20bd9c1a1061cfde9b547073b354fb23e8d0321..775fdc3b000b686d20e09ab21d4a5c756c8c9542 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Defines for zoom boards
  */
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define ZOOM_NAND_CS    0
 
index e2507f66f9d5b8f68c9beab25c738e3891c43f3c..612b27000c3e3863cd50e5aa3b4b15fc1bfc2586 100644 (file)
@@ -30,6 +30,11 @@ obj-$(CONFIG_ARCH_SH7377)    += entry-intc.o
 obj-$(CONFIG_ARCH_SH7372)      += entry-intc.o
 obj-$(CONFIG_ARCH_SH73A0)      += entry-gic.o
 
+# PM objects
+obj-$(CONFIG_SUSPEND)          += suspend.o
+obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
+obj-$(CONFIG_ARCH_SH7372)      += pm-sh7372.o sleep-sh7372.o
+
 # Board objects
 obj-$(CONFIG_MACH_G3EVM)       += board-g3evm.o
 obj-$(CONFIG_MACH_G4EVM)       += board-g4evm.o
index 3e6f0aab460bd2382552a5723c738a739fbc4610..c95258c274c11c0c3eea565ef0709531440c3cab 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/input/sh_keysc.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
+#include <linux/mfd/tmio.h>
 #include <linux/sh_clk.h>
 #include <video/sh_mobile_lcdc.h>
 #include <video/sh_mipi_dsi.h>
@@ -156,10 +158,19 @@ static struct resource sh_mmcif_resources[] = {
        },
 };
 
+static struct sh_mmcif_dma sh_mmcif_dma = {
+       .chan_priv_rx   = {
+               .slave_id       = SHDMA_SLAVE_MMCIF_RX,
+       },
+       .chan_priv_tx   = {
+               .slave_id       = SHDMA_SLAVE_MMCIF_TX,
+       },
+};
 static struct sh_mmcif_plat_data sh_mmcif_platdata = {
        .sup_pclk       = 0,
        .ocr            = MMC_VDD_165_195,
        .caps           = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+       .dma            = &sh_mmcif_dma,
 };
 
 static struct platform_device mmc_device = {
@@ -296,11 +307,13 @@ static struct platform_device lcdc0_device = {
 /* MIPI-DSI */
 static struct resource mipidsi0_resources[] = {
        [0] = {
+               .name   = "DSI0",
                .start  = 0xfeab0000,
                .end    = 0xfeab3fff,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
+               .name   = "DSI0",
                .start  = 0xfeab4000,
                .end    = 0xfeab7fff,
                .flags  = IORESOURCE_MEM,
@@ -325,6 +338,89 @@ static struct platform_device mipidsi0_device = {
        },
 };
 
+static struct sh_mobile_sdhi_info sdhi0_info = {
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
+       .tmio_caps      = MMC_CAP_SD_HIGHSPEED,
+       .tmio_ocr_mask  = MMC_VDD_27_28 | MMC_VDD_28_29,
+};
+
+static struct resource sdhi0_resources[] = {
+       [0] = {
+               .name   = "SDHI0",
+               .start  = 0xee100000,
+               .end    = 0xee1000ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(83),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = gic_spi(84),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = gic_spi(85),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device sdhi0_device = {
+       .name           = "sh_mobile_sdhi",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(sdhi0_resources),
+       .resource       = sdhi0_resources,
+       .dev    = {
+               .platform_data  = &sdhi0_info,
+       },
+};
+
+void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
+{
+       gpio_set_value(GPIO_PORT114, state);
+}
+
+static struct sh_mobile_sdhi_info sh_sdhi1_platdata = {
+       .dma_slave_tx   = SHDMA_SLAVE_SDHI1_TX,
+       .dma_slave_rx   = SHDMA_SLAVE_SDHI1_RX,
+       .tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE,
+       .tmio_caps      = MMC_CAP_NONREMOVABLE,
+       .tmio_ocr_mask  = MMC_VDD_32_33 | MMC_VDD_33_34,
+       .set_pwr        = ag5evm_sdhi1_set_pwr,
+};
+
+static struct resource sdhi1_resources[] = {
+       [0] = {
+               .name   = "SDHI1",
+               .start  = 0xee120000,
+               .end    = 0xee1200ff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = gic_spi(87),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = gic_spi(88),
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = gic_spi(89),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device sdhi1_device = {
+       .name           = "sh_mobile_sdhi",
+       .id             = 1,
+       .dev            = {
+               .platform_data  = &sh_sdhi1_platdata,
+       },
+       .num_resources  = ARRAY_SIZE(sdhi1_resources),
+       .resource       = sdhi1_resources,
+};
+
 static struct platform_device *ag5evm_devices[] __initdata = {
        &eth_device,
        &keysc_device,
@@ -333,6 +429,8 @@ static struct platform_device *ag5evm_devices[] __initdata = {
        &irda_device,
        &lcdc0_device,
        &mipidsi0_device,
+       &sdhi0_device,
+       &sdhi1_device,
 };
 
 static struct map_desc ag5evm_io_desc[] __initdata = {
@@ -454,6 +552,26 @@ static void __init ag5evm_init(void)
        /* MIPI-DSI clock setup */
        __raw_writel(0x2a809010, DSI0PHYCR);
 
+       /* enable SDHI0 on CN15 [SD I/F] */
+       gpio_request(GPIO_FN_SDHICD0, NULL);
+       gpio_request(GPIO_FN_SDHIWP0, NULL);
+       gpio_request(GPIO_FN_SDHICMD0, NULL);
+       gpio_request(GPIO_FN_SDHICLK0, NULL);
+       gpio_request(GPIO_FN_SDHID0_3, NULL);
+       gpio_request(GPIO_FN_SDHID0_2, NULL);
+       gpio_request(GPIO_FN_SDHID0_1, NULL);
+       gpio_request(GPIO_FN_SDHID0_0, NULL);
+
+       /* enable SDHI1 on CN4 [WLAN I/F] */
+       gpio_request(GPIO_FN_SDHICLK1, NULL);
+       gpio_request(GPIO_FN_SDHICMD1_PU, NULL);
+       gpio_request(GPIO_FN_SDHID1_3_PU, NULL);
+       gpio_request(GPIO_FN_SDHID1_2_PU, NULL);
+       gpio_request(GPIO_FN_SDHID1_1_PU, NULL);
+       gpio_request(GPIO_FN_SDHID1_0_PU, NULL);
+       gpio_request(GPIO_PORT114, "sdhi1_power");
+       gpio_direction_output(GPIO_PORT114, 0);
+
 #ifdef CONFIG_CACHE_L2X0
        /* Shared attribute override enable, 64K*8way */
        l2x0_init(__io(0xf0100000), 0x00460000, 0xc2000fff);
index 1e35fa976d6450064e6a6b616d95864a7e73103b..08acb6ec81390c5a4eb6204dfda57b5a5e28d862 100644 (file)
@@ -316,8 +316,16 @@ static struct resource sdhi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x0e00) /* SDHI0 */,
-               .flags  = IORESOURCE_IRQ,
+               .start  = evt2irq(0x0e00) /* SDHI0_SDHI0I0 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x0e20) /* SDHI0_SDHI0I1 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x0e40) /* SDHI0_SDHI0I2 */,
+               .flags  = IORESOURCE_IRQ,
        },
 };
 
@@ -349,8 +357,16 @@ static struct resource sdhi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x0e80),
-               .flags  = IORESOURCE_IRQ,
+               .start  = evt2irq(0x0e80), /* SDHI1_SDHI1I0 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */
+               .flags  = IORESOURCE_IRQ,
        },
 };
 
@@ -980,11 +996,6 @@ static void __init hdmi_init_pm_clock(void)
                goto out;
        }
 
-       ret = clk_enable(&sh7372_pllc2_clk);
-       if (ret < 0) {
-               pr_err("Cannot enable pllc2 clock\n");
-               goto out;
-       }
        pr_debug("PLLC2 set frequency %lu\n", rate);
 
        ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
@@ -1343,6 +1354,7 @@ static void __init ap4evb_init(void)
 
        hdmi_init_pm_clock();
        fsi_init_pm_clock();
+       sh7372_pm_init();
 }
 
 static void __init ap4evb_timer_init(void)
index c87a7b7c583278f2f43bbf964c74c02f8b7f84d0..8e3c5559f27f937c68f059c1c89a525945a498b4 100644 (file)
@@ -205,7 +205,7 @@ static struct resource sdhi0_resources[] = {
        [0] = {
                .name   = "SDHI0",
                .start  = 0xe6d50000,
-               .end    = 0xe6d50nff,
+               .end    = 0xe6d500ff,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
index 7da2ca24229dc296f41795cd788c5f989451abb1..448ddbe4333504d517a0ba5c70099c198fb2e9a9 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/sh_intc.h>
 #include <linux/tca6416_keypad.h>
 #include <linux/usb/r8a66597.h>
+#include <linux/usb/renesas_usbhs.h>
 
 #include <video/sh_mobile_hdmi.h>
 #include <video/sh_mobile_lcdc.h>
  * open      | external VBUS | Function
  *
  * *1
- * CN31 is used as Host in Linux.
+ * CN31 is used as
+ * CONFIG_USB_R8A66597_HCD     Host
+ * CONFIG_USB_RENESAS_USBHS    Function
+ *
+ * CAUTION
+ *
+ * renesas_usbhs driver can use external interrupt mode
+ * (which come from USB-PHY) or autonomy mode (it use own interrupt)
+ * for detecting connection/disconnection when Function.
+ * USB will be power OFF while it has been disconnecting
+ * if external interrupt mode, and it is always power ON if autonomy mode,
+ *
+ * mackerel can not use external interrupt (IRQ7-PORT167) mode on "USB0",
+ * because Touchscreen is using IRQ7-PORT40.
+ * It is impossible to use IRQ7 demux on this board.
+ *
+ * We can use external interrupt mode USB-Function on "USB1".
+ * USB1 can become Host by r8a66597, and become Function by renesas_usbhs.
+ * But don't select both drivers in same time.
+ * These uses same IRQ number for request_irq(), and aren't supporting
+ * IRQF_SHARD / IORESOURCE_IRQ_SHAREABLE.
+ *
+ * Actually these are old/new version of USB driver.
+ * This mean its register will be broken if it supports SHARD IRQ,
  */
 
 /*
  * FIXME !!
  *
  * gpio_no_direction
+ * gpio_pull_down
  * are quick_hack.
  *
  * current gpio frame work doesn't have
@@ -196,6 +221,16 @@ static void __init gpio_no_direction(u32 addr)
        __raw_writeb(0x00, addr);
 }
 
+static void __init gpio_pull_down(u32 addr)
+{
+       u8 data = __raw_readb(addr);
+
+       data &= 0x0F;
+       data |= 0xA0;
+
+       __raw_writeb(data, addr);
+}
+
 /* MTD */
 static struct mtd_partition nor_flash_partitions[] = {
        {
@@ -458,12 +493,6 @@ static void __init hdmi_init_pm_clock(void)
                goto out;
        }
 
-       ret = clk_enable(&sh7372_pllc2_clk);
-       if (ret < 0) {
-               pr_err("Cannot enable pllc2 clock\n");
-               goto out;
-       }
-
        pr_debug("PLLC2 set frequency %lu\n", rate);
 
        ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
@@ -515,6 +544,157 @@ static struct platform_device usb1_host_device = {
        .resource       = usb1_host_resources,
 };
 
+/* USB1 (Function) */
+#define USB_PHY_MODE           (1 << 4)
+#define USB_PHY_INT_EN         ((1 << 3) | (1 << 2))
+#define USB_PHY_ON             (1 << 1)
+#define USB_PHY_OFF            (1 << 0)
+#define USB_PHY_INT_CLR                (USB_PHY_ON | USB_PHY_OFF)
+
+struct usbhs_private {
+       unsigned int irq;
+       unsigned int usbphyaddr;
+       unsigned int usbcrcaddr;
+       struct renesas_usbhs_platform_info info;
+};
+
+#define usbhs_get_priv(pdev)                           \
+       container_of(renesas_usbhs_get_info(pdev),      \
+                    struct usbhs_private, info)
+
+#define usbhs_is_connected(priv)                       \
+       (!((1 << 7) & __raw_readw(priv->usbcrcaddr)))
+
+static int usbhs1_get_id(struct platform_device *pdev)
+{
+       return USBHS_GADGET;
+}
+
+static int usbhs1_get_vbus(struct platform_device *pdev)
+{
+       return usbhs_is_connected(usbhs_get_priv(pdev));
+}
+
+static irqreturn_t usbhs1_interrupt(int irq, void *data)
+{
+       struct platform_device *pdev = data;
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       dev_dbg(&pdev->dev, "%s\n", __func__);
+
+       renesas_usbhs_call_notify_hotplug(pdev);
+
+       /* clear status */
+       __raw_writew(__raw_readw(priv->usbphyaddr) | USB_PHY_INT_CLR,
+                    priv->usbphyaddr);
+
+       return IRQ_HANDLED;
+}
+
+static int usbhs1_hardware_init(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+       int ret;
+
+       irq_set_irq_type(priv->irq, IRQ_TYPE_LEVEL_HIGH);
+
+       /* clear interrupt status */
+       __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
+
+       ret = request_irq(priv->irq, usbhs1_interrupt, 0,
+                         dev_name(&pdev->dev), pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "request_irq err\n");
+               return ret;
+       }
+
+       /* enable USB phy interrupt */
+       __raw_writew(USB_PHY_MODE | USB_PHY_INT_EN, priv->usbphyaddr);
+
+       return 0;
+}
+
+static void usbhs1_hardware_exit(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       /* clear interrupt status */
+       __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
+
+       free_irq(priv->irq, pdev);
+}
+
+static void usbhs1_phy_reset(struct platform_device *pdev)
+{
+       struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+       /* init phy */
+       __raw_writew(0x8a0a, priv->usbcrcaddr);
+}
+
+static u32 usbhs1_pipe_cfg[] = {
+       USB_ENDPOINT_XFER_CONTROL,
+       USB_ENDPOINT_XFER_ISOC,
+       USB_ENDPOINT_XFER_ISOC,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_INT,
+       USB_ENDPOINT_XFER_INT,
+       USB_ENDPOINT_XFER_INT,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+       USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usbhs_private usbhs1_private = {
+       .irq            = evt2irq(0x0300),      /* IRQ8 */
+       .usbphyaddr     = 0xE60581E2,           /* USBPHY1INTAP */
+       .usbcrcaddr     = 0xE6058130,           /* USBCR4 */
+       .info = {
+               .platform_callback = {
+                       .hardware_init  = usbhs1_hardware_init,
+                       .hardware_exit  = usbhs1_hardware_exit,
+                       .phy_reset      = usbhs1_phy_reset,
+                       .get_id         = usbhs1_get_id,
+                       .get_vbus       = usbhs1_get_vbus,
+               },
+               .driver_param = {
+                       .buswait_bwait  = 4,
+                       .pipe_type      = usbhs1_pipe_cfg,
+                       .pipe_size      = ARRAY_SIZE(usbhs1_pipe_cfg),
+               },
+       },
+};
+
+static struct resource usbhs1_resources[] = {
+       [0] = {
+               .name   = "USBHS",
+               .start  = 0xE68B0000,
+               .end    = 0xE68B00E6 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = evt2irq(0x1ce0) /* USB1_USB1I0 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device usbhs1_device = {
+       .name   = "renesas_usbhs",
+       .id     = 1,
+       .dev = {
+               .platform_data          = &usbhs1_private.info,
+       },
+       .num_resources  = ARRAY_SIZE(usbhs1_resources),
+       .resource       = usbhs1_resources,
+};
+
+
 /* LED */
 static struct gpio_led mackerel_leds[] = {
        {
@@ -690,7 +870,15 @@ static struct resource sdhi0_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x0e00) /* SDHI0 */,
+               .start  = evt2irq(0x0e00) /* SDHI0_SDHI0I0 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x0e20) /* SDHI0_SDHI0I1 */,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x0e40) /* SDHI0_SDHI0I2 */,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -705,7 +893,7 @@ static struct platform_device sdhi0_device = {
        },
 };
 
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
 /* SDHI1 */
 static struct sh_mobile_sdhi_info sdhi1_info = {
        .dma_slave_tx   = SHDMA_SLAVE_SDHI1_TX,
@@ -725,7 +913,15 @@ static struct resource sdhi1_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x0e80),
+               .start  = evt2irq(0x0e80), /* SDHI1_SDHI1I0 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -768,7 +964,15 @@ static struct resource sdhi2_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = evt2irq(0x1200),
+               .start  = evt2irq(0x1200), /* SDHI2_SDHI2I0 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = evt2irq(0x1220), /* SDHI2_SDHI2I1 */
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = evt2irq(0x1240), /* SDHI2_SDHI2I2 */
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -803,6 +1007,15 @@ static struct resource sh_mmcif_resources[] = {
        },
 };
 
+static struct sh_mmcif_dma sh_mmcif_dma = {
+       .chan_priv_rx   = {
+               .slave_id       = SHDMA_SLAVE_MMCIF_RX,
+       },
+       .chan_priv_tx   = {
+               .slave_id       = SHDMA_SLAVE_MMCIF_TX,
+       },
+};
+
 static struct sh_mmcif_plat_data sh_mmcif_plat = {
        .sup_pclk       = 0,
        .ocr            = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
@@ -810,6 +1023,7 @@ static struct sh_mmcif_plat_data sh_mmcif_plat = {
                          MMC_CAP_8_BIT_DATA |
                          MMC_CAP_NEEDS_POLL,
        .get_cd         = slot_cn7_get_cd,
+       .dma            = &sh_mmcif_dma,
 };
 
 static struct platform_device sh_mmcif_device = {
@@ -858,37 +1072,23 @@ static struct soc_camera_link camera_link = {
        .priv           = &camera_info,
 };
 
-static void dummy_release(struct device *dev)
+static struct platform_device *camera_device;
+
+static void mackerel_camera_release(struct device *dev)
 {
+       soc_camera_platform_release(&camera_device);
 }
 
-static struct platform_device camera_device = {
-       .name           = "soc_camera_platform",
-       .dev            = {
-               .platform_data  = &camera_info,
-               .release        = dummy_release,
-       },
-};
-
 static int mackerel_camera_add(struct soc_camera_link *icl,
                               struct device *dev)
 {
-       if (icl != &camera_link)
-               return -ENODEV;
-
-       camera_info.dev = dev;
-
-       return platform_device_register(&camera_device);
+       return soc_camera_platform_add(icl, dev, &camera_device, &camera_link,
+                                      mackerel_camera_release, 0);
 }
 
 static void mackerel_camera_del(struct soc_camera_link *icl)
 {
-       if (icl != &camera_link)
-               return;
-
-       platform_device_unregister(&camera_device);
-       memset(&camera_device.dev.kobj, 0,
-              sizeof(camera_device.dev.kobj));
+       soc_camera_platform_del(icl, camera_device, &camera_link);
 }
 
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
@@ -935,12 +1135,13 @@ static struct platform_device *mackerel_devices[] __initdata = {
        &smc911x_device,
        &lcdc_device,
        &usb1_host_device,
+       &usbhs1_device,
        &leds_device,
        &fsi_device,
        &fsi_ak4643_device,
        &fsi_hdmi_device,
        &sdhi0_device,
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
        &sdhi1_device,
 #endif
        &sdhi2_device,
@@ -1030,6 +1231,7 @@ static void __init mackerel_map_io(void)
 
 #define GPIO_PORT9CR   0xE6051009
 #define GPIO_PORT10CR  0xE605100A
+#define GPIO_PORT168CR 0xE60520A8
 #define SRCR4          0xe61580bc
 #define USCCR1         0xE6058144
 static void __init mackerel_init(void)
@@ -1088,6 +1290,7 @@ static void __init mackerel_init(void)
        gpio_request(GPIO_FN_OVCN_1_114, NULL);
        gpio_request(GPIO_FN_EXTLP_1,    NULL);
        gpio_request(GPIO_FN_OVCN2_1,    NULL);
+       gpio_pull_down(GPIO_PORT168CR);
 
        /* setup USB phy */
        __raw_writew(0x8a0a, 0xE6058130);       /* USBCR4 */
@@ -1140,7 +1343,7 @@ static void __init mackerel_init(void)
        gpio_request(GPIO_FN_SDHID0_1, NULL);
        gpio_request(GPIO_FN_SDHID0_0, NULL);
 
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
        /* enable SDHI1 */
        gpio_request(GPIO_FN_SDHICMD1, NULL);
        gpio_request(GPIO_FN_SDHICLK1, NULL);
@@ -1216,6 +1419,7 @@ static void __init mackerel_init(void)
        platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices));
 
        hdmi_init_pm_clock();
+       sh7372_pm_init();
 }
 
 static void __init mackerel_timer_init(void)
index e9731b5a73edacc54f2d0a9340ca455e84a063e5..d17eb66f4ac20980fb7ec441edf15e80b9f142b3 100644 (file)
 #define DSI1PCKCR      0xe6150098
 #define PLLC01CR       0xe6150028
 #define PLLC2CR                0xe615002c
+#define RMSTPCR0       0xe6150110
+#define RMSTPCR1       0xe6150114
+#define RMSTPCR2       0xe6150118
+#define RMSTPCR3       0xe615011c
+#define RMSTPCR4       0xe6150120
 #define SMSTPCR0       0xe6150130
 #define SMSTPCR1       0xe6150134
 #define SMSTPCR2       0xe6150138
@@ -421,9 +426,6 @@ static unsigned long fsidiv_recalc(struct clk *clk)
 
        value = __raw_readl(clk->mapping->base);
 
-       if ((value & 0x3) != 0x3)
-               return 0;
-
        value >>= 16;
        if (value < 2)
                return 0;
@@ -504,7 +506,7 @@ static struct clk *late_main_clks[] = {
 enum { MSTP001,
        MSTP131, MSTP130,
        MSTP129, MSTP128, MSTP127, MSTP126, MSTP125,
-       MSTP118, MSTP117, MSTP116,
+       MSTP118, MSTP117, MSTP116, MSTP113,
        MSTP106, MSTP101, MSTP100,
        MSTP223,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
@@ -527,6 +529,7 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */
        [MSTP117] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */
        [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
+       [MSTP113] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 13, 0), /* MERAM */
        [MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */
        [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */
        [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
@@ -617,6 +620,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX0 */
        CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */
        CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */
+       CLKDEV_DEV_ID("sh_mobile_meram.0", &mstp_clks[MSTP113]), /* MERAM */
        CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */
        CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */
        CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
@@ -634,6 +638,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
        CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
        CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */
+       CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP322]), /* USB0 */
        CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
        CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
        CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
@@ -644,6 +649,7 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
        CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
        CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
+       CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[MSTP406]), /* USB1 */
        CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
 
        CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]),
@@ -655,6 +661,13 @@ void __init sh7372_clock_init(void)
 {
        int k, ret = 0;
 
+       /* make sure MSTP bits on the RT/SH4AL-DSP side are off */
+       __raw_writel(0xe4ef8087, RMSTPCR0);
+       __raw_writel(0xffffffff, RMSTPCR1);
+       __raw_writel(0x37c7f7ff, RMSTPCR2);
+       __raw_writel(0xffffffff, RMSTPCR3);
+       __raw_writel(0xffe0fffd, RMSTPCR4);
+
        for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
                ret = clk_register(main_clks[k]);
 
index 7e58904c1c8c506aa63789d80cf52674b209afd8..bcacb1e8cf85148e79d75b423de47d0f8e61ccbc 100644 (file)
@@ -266,7 +266,8 @@ enum { MSTP001,
        MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP100,
        MSTP219,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
-       MSTP331, MSTP329, MSTP325, MSTP323, MSTP312,
+       MSTP331, MSTP329, MSTP325, MSTP323, MSTP318,
+       MSTP314, MSTP313, MSTP312, MSTP311,
        MSTP411, MSTP410, MSTP403,
        MSTP_NR };
 
@@ -295,7 +296,11 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
        [MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IrDA */
        [MSTP323] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 23, 0), /* IIC1 */
+       [MSTP318] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 18, 0), /* SY-DMAC */
+       [MSTP314] = MSTP(&div6_clks[DIV6_SDHI0], SMSTPCR3, 14, 0), /* SDHI0 */
+       [MSTP313] = MSTP(&div6_clks[DIV6_SDHI1], SMSTPCR3, 13, 0), /* SDHI1 */
        [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */
+       [MSTP311] = MSTP(&div6_clks[DIV6_SDHI2], SMSTPCR3, 11, 0), /* SDHI2 */
        [MSTP411] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 11, 0), /* IIC3 */
        [MSTP410] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 10, 0), /* IIC4 */
        [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
@@ -313,6 +318,9 @@ static struct clk_lookup lookups[] = {
        CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
        CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
        CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
+       CLKDEV_CON_ID("sdhi0_clk", &div6_clks[DIV6_SDHI0]),
+       CLKDEV_CON_ID("sdhi1_clk", &div6_clks[DIV6_SDHI1]),
+       CLKDEV_CON_ID("sdhi2_clk", &div6_clks[DIV6_SDHI2]),
        CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]),
        CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]),
        CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]),
@@ -341,7 +349,11 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
        CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */
        CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */
+       CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP318]), /* SY-DMAC */
+       CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
+       CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
        CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */
+       CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), /* SDHI2 */
        CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */
        CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */
        CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
@@ -351,6 +363,11 @@ void __init sh73a0_clock_init(void)
 {
        int k, ret = 0;
 
+       /* Set SDHI clocks to a known state */
+       __raw_writel(0x108, SD0CKCR);
+       __raw_writel(0x108, SD1CKCR);
+       __raw_writel(0x108, SD2CKCR);
+
        /* detect main clock parent */
        switch ((__raw_readl(CKSCR) >> 24) & 0x03) {
        case 0:
diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c
new file mode 100644 (file)
index 0000000..2e44f11
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * CPUIdle support code for SH-Mobile ARM
+ *
+ *  Copyright (C) 2011 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/pm.h>
+#include <linux/cpuidle.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+static void shmobile_enter_wfi(void)
+{
+       cpu_do_idle();
+}
+
+void (*shmobile_cpuidle_modes[CPUIDLE_STATE_MAX])(void) = {
+       shmobile_enter_wfi, /* regular sleep mode */
+};
+
+static int shmobile_cpuidle_enter(struct cpuidle_device *dev,
+                                 struct cpuidle_state *state)
+{
+       ktime_t before, after;
+       int requested_state = state - &dev->states[0];
+
+       dev->last_state = &dev->states[requested_state];
+       before = ktime_get();
+
+       local_irq_disable();
+       local_fiq_disable();
+
+       shmobile_cpuidle_modes[requested_state]();
+
+       local_irq_enable();
+       local_fiq_enable();
+
+       after = ktime_get();
+       return ktime_to_ns(ktime_sub(after, before)) >> 10;
+}
+
+static struct cpuidle_device shmobile_cpuidle_dev;
+static struct cpuidle_driver shmobile_cpuidle_driver = {
+       .name =         "shmobile_cpuidle",
+       .owner =        THIS_MODULE,
+};
+
+void (*shmobile_cpuidle_setup)(struct cpuidle_device *dev);
+
+static int shmobile_cpuidle_init(void)
+{
+       struct cpuidle_device *dev = &shmobile_cpuidle_dev;
+       struct cpuidle_state *state;
+       int i;
+
+       cpuidle_register_driver(&shmobile_cpuidle_driver);
+
+       for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
+               dev->states[i].name[0] = '\0';
+               dev->states[i].desc[0] = '\0';
+               dev->states[i].enter = shmobile_cpuidle_enter;
+       }
+
+       i = CPUIDLE_DRIVER_STATE_START;
+
+       state = &dev->states[i++];
+       snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
+       strncpy(state->desc, "WFI", CPUIDLE_DESC_LEN);
+       state->exit_latency = 1;
+       state->target_residency = 1 * 2;
+       state->power_usage = 3;
+       state->flags = 0;
+       state->flags |= CPUIDLE_FLAG_TIME_VALID;
+
+       dev->safe_state = state;
+       dev->state_count = i;
+
+       if (shmobile_cpuidle_setup)
+               shmobile_cpuidle_setup(dev);
+
+       cpuidle_register_device(dev);
+
+       return 0;
+}
+late_initcall(shmobile_cpuidle_init);
index d4cec6b4c7d93cab2a22385efcae773f411bc018..26079d933d913e1bf4f04e68d6a23e1eb3225e3d 100644 (file)
@@ -24,4 +24,4 @@
        .align  12
 ENTRY(shmobile_secondary_vector)
        ldr     pc, 1f
-1:     .long   secondary_startup - PAGE_OFFSET + PHYS_OFFSET
+1:     .long   secondary_startup - PAGE_OFFSET + PLAT_PHYS_OFFSET
index 013ac0ee8256acd4dfd8eda35f770860ef289cdc..06aecb31d9c7ececc9784ced7086ccc9ed83418f 100644 (file)
@@ -8,6 +8,10 @@ struct clk;
 extern int clk_init(void);
 extern void shmobile_handle_irq_intc(struct pt_regs *);
 extern void shmobile_handle_irq_gic(struct pt_regs *);
+extern struct platform_suspend_ops shmobile_suspend_ops;
+struct cpuidle_device;
+extern void (*shmobile_cpuidle_modes[])(void);
+extern void (*shmobile_cpuidle_setup)(struct cpuidle_device *dev);
 
 extern void sh7367_init_irq(void);
 extern void sh7367_add_early_devices(void);
@@ -30,6 +34,9 @@ extern void sh7372_add_early_devices(void);
 extern void sh7372_add_standard_devices(void);
 extern void sh7372_clock_init(void);
 extern void sh7372_pinmux_init(void);
+extern void sh7372_pm_init(void);
+extern void sh7372_cpu_suspend(void);
+extern void sh7372_cpu_resume(void);
 extern struct clk sh7372_extal1_clk;
 extern struct clk sh7372_extal2_clk;
 
index 3029aba38688e846ade96eefda7ecbceeb4f6732..9f134dfeffdcf6b5761914aa646ff6e878887223 100644 (file)
@@ -87,8 +87,7 @@ WAIT 1, 0xFE40009C
 ED 0xFE400354, 0x01AD8002
 
 LIST "SCIF0 - Serial port for earlyprintk"
-EB 0xE6053098, 0x11
 EB 0xE6053098, 0xe1
 EW 0xE6C40000, 0x0000
 EB 0xE6C40004, 0x19
-EW 0xE6C40008, 0x3000
+EW 0xE6C40008, 0x0030
index 3029aba38688e846ade96eefda7ecbceeb4f6732..9f134dfeffdcf6b5761914aa646ff6e878887223 100644 (file)
@@ -87,8 +87,7 @@ WAIT 1, 0xFE40009C
 ED 0xFE400354, 0x01AD8002
 
 LIST "SCIF0 - Serial port for earlyprintk"
-EB 0xE6053098, 0x11
 EB 0xE6053098, 0xe1
 EW 0xE6C40000, 0x0000
 EB 0xE6C40004, 0x19
-EW 0xE6C40008, 0x3000
+EW 0xE6C40008, 0x0030
index 5736efcca60c484d7762e346a16cee2d18ad7759..df20d7670172d402e156a54b5639d8d5ab840328 100644 (file)
@@ -435,6 +435,7 @@ enum {
 
 /* DMA slave IDs */
 enum {
+       SHDMA_SLAVE_INVALID,
        SHDMA_SLAVE_SCIF0_TX,
        SHDMA_SLAVE_SCIF0_RX,
        SHDMA_SLAVE_SCIF1_TX,
index ceb2cdc92bf9f38a51b0f1c193d0c8ed4b5a03c3..216c3d695ef177f36f131f47bbee51be3b9be877 100644 (file)
@@ -463,5 +463,35 @@ enum {
        GPIO_FN_FSIAIBT_PU,
        GPIO_FN_FSIAISLD_PU,
 };
+/* DMA slave IDs */
+enum {
+       SHDMA_SLAVE_INVALID,
+       SHDMA_SLAVE_SCIF0_TX,
+       SHDMA_SLAVE_SCIF0_RX,
+       SHDMA_SLAVE_SCIF1_TX,
+       SHDMA_SLAVE_SCIF1_RX,
+       SHDMA_SLAVE_SCIF2_TX,
+       SHDMA_SLAVE_SCIF2_RX,
+       SHDMA_SLAVE_SCIF3_TX,
+       SHDMA_SLAVE_SCIF3_RX,
+       SHDMA_SLAVE_SCIF4_TX,
+       SHDMA_SLAVE_SCIF4_RX,
+       SHDMA_SLAVE_SCIF5_TX,
+       SHDMA_SLAVE_SCIF5_RX,
+       SHDMA_SLAVE_SCIF6_TX,
+       SHDMA_SLAVE_SCIF6_RX,
+       SHDMA_SLAVE_SCIF7_TX,
+       SHDMA_SLAVE_SCIF7_RX,
+       SHDMA_SLAVE_SCIF8_TX,
+       SHDMA_SLAVE_SCIF8_RX,
+       SHDMA_SLAVE_SDHI0_TX,
+       SHDMA_SLAVE_SDHI0_RX,
+       SHDMA_SLAVE_SDHI1_TX,
+       SHDMA_SLAVE_SDHI1_RX,
+       SHDMA_SLAVE_SDHI2_TX,
+       SHDMA_SLAVE_SDHI2_RX,
+       SHDMA_SLAVE_MMCIF_TX,
+       SHDMA_SLAVE_MMCIF_RX,
+};
 
 #endif /* __ASM_SH73A0_H__ */
index 7a4960f9c1e3fcb313cf103fcacd3ccbfe3fab71..3b28743c77eb738f502737f434f0aee4c0f7cdf3 100644 (file)
@@ -27,8 +27,6 @@
 
 enum {
        UNUSED_INTCA = 0,
-       ENABLED,
-       DISABLED,
 
        /* interrupt sources INTCA */
        IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A,
@@ -49,14 +47,14 @@ enum {
        MSIOF2, MSIOF1,
        SCIFA4, SCIFA5, SCIFB,
        FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
-       SDHI0,
-       SDHI1,
+       SDHI0_SDHI0I0, SDHI0_SDHI0I1, SDHI0_SDHI0I2, SDHI0_SDHI0I3,
+       SDHI1_SDHI1I0, SDHI1_SDHI1I1, SDHI1_SDHI1I2,
        IRREM,
        IRDA,
        TPU0,
        TTI20,
        DDM,
-       SDHI2,
+       SDHI2_SDHI2I0, SDHI2_SDHI2I1, SDHI2_SDHI2I2, SDHI2_SDHI2I3,
        RWDT0,
        DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3,
        DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR,
@@ -84,7 +82,7 @@ enum {
 
        /* interrupt groups INTCA */
        DMAC1_1, DMAC1_2, DMAC2_1, DMAC2_2, DMAC3_1, DMAC3_2, SHWYSTAT,
-       AP_ARM1, AP_ARM2, SPU2, FLCTL, IIC1
+       AP_ARM1, AP_ARM2, SPU2, FLCTL, IIC1, SDHI0, SDHI1, SDHI2
 };
 
 static struct intc_vect intca_vectors[] __initdata = {
@@ -125,17 +123,17 @@ static struct intc_vect intca_vectors[] __initdata = {
        INTC_VECT(SCIFB, 0x0d60),
        INTC_VECT(FLCTL_FLSTEI, 0x0d80), INTC_VECT(FLCTL_FLTENDI, 0x0da0),
        INTC_VECT(FLCTL_FLTREQ0I, 0x0dc0), INTC_VECT(FLCTL_FLTREQ1I, 0x0de0),
-       INTC_VECT(SDHI0, 0x0e00), INTC_VECT(SDHI0, 0x0e20),
-       INTC_VECT(SDHI0, 0x0e40), INTC_VECT(SDHI0, 0x0e60),
-       INTC_VECT(SDHI1, 0x0e80), INTC_VECT(SDHI1, 0x0ea0),
-       INTC_VECT(SDHI1, 0x0ec0),
+       INTC_VECT(SDHI0_SDHI0I0, 0x0e00), INTC_VECT(SDHI0_SDHI0I1, 0x0e20),
+       INTC_VECT(SDHI0_SDHI0I2, 0x0e40), INTC_VECT(SDHI0_SDHI0I3, 0x0e60),
+       INTC_VECT(SDHI1_SDHI1I0, 0x0e80), INTC_VECT(SDHI1_SDHI1I1, 0x0ea0),
+       INTC_VECT(SDHI1_SDHI1I2, 0x0ec0),
        INTC_VECT(IRREM, 0x0f60),
        INTC_VECT(IRDA, 0x0480),
        INTC_VECT(TPU0, 0x04a0),
        INTC_VECT(TTI20, 0x1100),
        INTC_VECT(DDM, 0x1140),
-       INTC_VECT(SDHI2, 0x1200), INTC_VECT(SDHI2, 0x1220),
-       INTC_VECT(SDHI2, 0x1240), INTC_VECT(SDHI2, 0x1260),
+       INTC_VECT(SDHI2_SDHI2I0, 0x1200), INTC_VECT(SDHI2_SDHI2I1, 0x1220),
+       INTC_VECT(SDHI2_SDHI2I2, 0x1240), INTC_VECT(SDHI2_SDHI2I3, 0x1260),
        INTC_VECT(RWDT0, 0x1280),
        INTC_VECT(DMAC1_1_DEI0, 0x2000), INTC_VECT(DMAC1_1_DEI1, 0x2020),
        INTC_VECT(DMAC1_1_DEI2, 0x2040), INTC_VECT(DMAC1_1_DEI3, 0x2060),
@@ -195,6 +193,12 @@ static struct intc_group intca_groups[] __initdata = {
        INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLTENDI,
                   FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
        INTC_GROUP(IIC1, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1),
+       INTC_GROUP(SDHI0, SDHI0_SDHI0I0, SDHI0_SDHI0I1,
+                  SDHI0_SDHI0I2, SDHI0_SDHI0I3),
+       INTC_GROUP(SDHI1, SDHI1_SDHI1I0, SDHI1_SDHI1I1,
+                  SDHI1_SDHI1I2),
+       INTC_GROUP(SDHI2, SDHI2_SDHI2I0, SDHI2_SDHI2I1,
+                  SDHI2_SDHI2I2, SDHI2_SDHI2I3),
        INTC_GROUP(SHWYSTAT, SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM),
 };
 
@@ -230,10 +234,10 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
          { SCIFB, SCIFA5, SCIFA4, MSIOF1,
            0, 0, MSIOF2, 0 } },
        { 0xe694009c, 0xe69400dc, 8, /* IMR7A / IMCR7A */
-         { DISABLED, ENABLED, ENABLED, ENABLED,
+         { SDHI0_SDHI0I3, SDHI0_SDHI0I2, SDHI0_SDHI0I1, SDHI0_SDHI0I0,
            FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } },
        { 0xe69400a0, 0xe69400e0, 8, /* IMR8A / IMCR8A */
-         { 0, ENABLED, ENABLED, ENABLED,
+         { 0, SDHI1_SDHI1I2, SDHI1_SDHI1I1, SDHI1_SDHI1I0,
            TTI20, USBHSDMAC0_USHDMI, 0, 0 } },
        { 0xe69400a4, 0xe69400e4, 8, /* IMR9A / IMCR9A */
          { CMT1_CMT13, CMT1_CMT12, CMT1_CMT11, CMT1_CMT10,
@@ -248,7 +252,7 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
          { 0, 0, TPU0, 0,
            0, 0, 0, 0 } },
        { 0xe69400b4, 0xe69400f4, 8, /* IMR13A / IMCR13A */
-         { DISABLED, DISABLED, ENABLED, ENABLED,
+         { SDHI2_SDHI2I3, SDHI2_SDHI2I2, SDHI2_SDHI2I1, SDHI2_SDHI2I0,
            0, CMT3, 0, RWDT0 } },
        { 0xe6950080, 0xe69500c0, 8, /* IMR0A3 / IMCR0A3 */
          { SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM, 0,
@@ -354,14 +358,10 @@ static struct intc_mask_reg intca_ack_registers[] __initdata = {
          { IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } },
 };
 
-static struct intc_desc intca_desc __initdata = {
-       .name = "sh7372-intca",
-       .force_enable = ENABLED,
-       .force_disable = DISABLED,
-       .hw = INTC_HW_DESC(intca_vectors, intca_groups,
-                          intca_mask_registers, intca_prio_registers,
-                          intca_sense_registers, intca_ack_registers),
-};
+static DECLARE_INTC_DESC_ACK(intca_desc, "sh7372-intca",
+                            intca_vectors, intca_groups,
+                            intca_mask_registers, intca_prio_registers,
+                            intca_sense_registers, intca_ack_registers);
 
 enum {
        UNUSED_INTCS = 0,
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
new file mode 100644 (file)
index 0000000..8e4aadf
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * sh7372 Power management support
+ *
+ *  Copyright (C) 2011 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/pm.h>
+#include <linux/suspend.h>
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <mach/common.h>
+
+#define SMFRAM 0xe6a70000
+#define SYSTBCR 0xe6150024
+#define SBAR 0xe6180020
+#define APARMBAREA 0xe6f10020
+
+static void sh7372_enter_core_standby(void)
+{
+       void __iomem *smfram = (void __iomem *)SMFRAM;
+
+       __raw_writel(0, APARMBAREA); /* translate 4k */
+       __raw_writel(__pa(sh7372_cpu_resume), SBAR); /* set reset vector */
+       __raw_writel(0x10, SYSTBCR); /* enable core standby */
+
+       __raw_writel(0, smfram + 0x3c); /* clear page table address */
+
+       sh7372_cpu_suspend();
+       cpu_init();
+
+       /* if page table address is non-NULL then we have been powered down */
+       if (__raw_readl(smfram + 0x3c)) {
+               __raw_writel(__raw_readl(smfram + 0x40),
+                            __va(__raw_readl(smfram + 0x3c)));
+
+               flush_tlb_all();
+               set_cr(__raw_readl(smfram + 0x38));
+       }
+
+       __raw_writel(0, SYSTBCR); /* disable core standby */
+       __raw_writel(0, SBAR); /* disable reset vector translation */
+}
+
+#ifdef CONFIG_CPU_IDLE
+static void sh7372_cpuidle_setup(struct cpuidle_device *dev)
+{
+       struct cpuidle_state *state;
+       int i = dev->state_count;
+
+       state = &dev->states[i];
+       snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
+       strncpy(state->desc, "Core Standby Mode", CPUIDLE_DESC_LEN);
+       state->exit_latency = 10;
+       state->target_residency = 20 + 10;
+       state->power_usage = 1; /* perhaps not */
+       state->flags = 0;
+       state->flags |= CPUIDLE_FLAG_TIME_VALID;
+       shmobile_cpuidle_modes[i] = sh7372_enter_core_standby;
+
+       dev->state_count = i + 1;
+}
+
+static void sh7372_cpuidle_init(void)
+{
+       shmobile_cpuidle_setup = sh7372_cpuidle_setup;
+}
+#else
+static void sh7372_cpuidle_init(void) {}
+#endif
+
+#ifdef CONFIG_SUSPEND
+static int sh7372_enter_suspend(suspend_state_t suspend_state)
+{
+       sh7372_enter_core_standby();
+       return 0;
+}
+
+static void sh7372_suspend_init(void)
+{
+       shmobile_suspend_ops.enter = sh7372_enter_suspend;
+}
+#else
+static void sh7372_suspend_init(void) {}
+#endif
+
+#define DBGREG1 0xe6100020
+#define DBGREG9 0xe6100040
+
+void __init sh7372_pm_init(void)
+{
+       /* enable DBG hardware block to kick SYSC */
+       __raw_writel(0x0000a500, DBGREG9);
+       __raw_writel(0x0000a501, DBGREG9);
+       __raw_writel(0x00000000, DBGREG1);
+
+       sh7372_suspend_init();
+       sh7372_cpuidle_init();
+}
index ce28141662da72c9812ba12edad47537f3f371a9..2c10190dbb554eb7a9063de3f31408dfab1d5e93 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/uio_driver.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/io.h>
@@ -195,6 +196,214 @@ static struct platform_device cmt10_device = {
        .num_resources  = ARRAY_SIZE(cmt10_resources),
 };
 
+/* VPU */
+static struct uio_info vpu_platform_data = {
+       .name = "VPU5",
+       .version = "0",
+       .irq = intcs_evt2irq(0x980),
+};
+
+static struct resource vpu_resources[] = {
+       [0] = {
+               .name   = "VPU",
+               .start  = 0xfe900000,
+               .end    = 0xfe902807,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device vpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &vpu_platform_data,
+       },
+       .resource       = vpu_resources,
+       .num_resources  = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+       .name = "VEU0",
+       .version = "0",
+       .irq = intcs_evt2irq(0x700),
+};
+
+static struct resource veu0_resources[] = {
+       [0] = {
+               .name   = "VEU0",
+               .start  = 0xfe920000,
+               .end    = 0xfe9200b7,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &veu0_platform_data,
+       },
+       .resource       = veu0_resources,
+       .num_resources  = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+       .name = "VEU1",
+       .version = "0",
+       .irq = intcs_evt2irq(0x720),
+};
+
+static struct resource veu1_resources[] = {
+       [0] = {
+               .name   = "VEU1",
+               .start  = 0xfe924000,
+               .end    = 0xfe9240b7,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &veu1_platform_data,
+       },
+       .resource       = veu1_resources,
+       .num_resources  = ARRAY_SIZE(veu1_resources),
+};
+
+/* VEU2 */
+static struct uio_info veu2_platform_data = {
+       .name = "VEU2",
+       .version = "0",
+       .irq = intcs_evt2irq(0x740),
+};
+
+static struct resource veu2_resources[] = {
+       [0] = {
+               .name   = "VEU2",
+               .start  = 0xfe928000,
+               .end    = 0xfe9280b7,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu2_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &veu2_platform_data,
+       },
+       .resource       = veu2_resources,
+       .num_resources  = ARRAY_SIZE(veu2_resources),
+};
+
+/* VEU3 */
+static struct uio_info veu3_platform_data = {
+       .name = "VEU3",
+       .version = "0",
+       .irq = intcs_evt2irq(0x760),
+};
+
+static struct resource veu3_resources[] = {
+       [0] = {
+               .name   = "VEU3",
+               .start  = 0xfe92c000,
+               .end    = 0xfe92c0b7,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu3_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &veu3_platform_data,
+       },
+       .resource       = veu3_resources,
+       .num_resources  = ARRAY_SIZE(veu3_resources),
+};
+
+/* VEU2H */
+static struct uio_info veu2h_platform_data = {
+       .name = "VEU2H",
+       .version = "0",
+       .irq = intcs_evt2irq(0x520),
+};
+
+static struct resource veu2h_resources[] = {
+       [0] = {
+               .name   = "VEU2H",
+               .start  = 0xfe93c000,
+               .end    = 0xfe93c27b,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu2h_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &veu2h_platform_data,
+       },
+       .resource       = veu2h_resources,
+       .num_resources  = ARRAY_SIZE(veu2h_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+       .name = "JPU",
+       .version = "0",
+       .irq = intcs_evt2irq(0x560),
+};
+
+static struct resource jpu_resources[] = {
+       [0] = {
+               .name   = "JPU",
+               .start  = 0xfe980000,
+               .end    = 0xfe9902d3,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device jpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 6,
+       .dev = {
+               .platform_data  = &jpu_platform_data,
+       },
+       .resource       = jpu_resources,
+       .num_resources  = ARRAY_SIZE(jpu_resources),
+};
+
+/* SPU1 */
+static struct uio_info spu1_platform_data = {
+       .name = "SPU1",
+       .version = "0",
+       .irq = evt2irq(0xfc0),
+};
+
+static struct resource spu1_resources[] = {
+       [0] = {
+               .name   = "SPU1",
+               .start  = 0xfe300000,
+               .end    = 0xfe3fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 7,
+       .dev = {
+               .platform_data  = &spu1_platform_data,
+       },
+       .resource       = spu1_resources,
+       .num_resources  = ARRAY_SIZE(spu1_resources),
+};
+
 static struct platform_device *sh7367_early_devices[] __initdata = {
        &scif0_device,
        &scif1_device,
@@ -206,10 +415,24 @@ static struct platform_device *sh7367_early_devices[] __initdata = {
        &cmt10_device,
 };
 
+static struct platform_device *sh7367_devices[] __initdata = {
+       &vpu_device,
+       &veu0_device,
+       &veu1_device,
+       &veu2_device,
+       &veu3_device,
+       &veu2h_device,
+       &jpu_device,
+       &spu1_device,
+};
+
 void __init sh7367_add_standard_devices(void)
 {
        platform_add_devices(sh7367_early_devices,
                             ARRAY_SIZE(sh7367_early_devices));
+
+       platform_add_devices(sh7367_devices,
+                           ARRAY_SIZE(sh7367_devices));
 }
 
 #define SYMSTPCR2 0xe6158048
index ff0494f3d00cb5816a1c90041226823585482721..cd807eea69e2e720bf2554dfb6c7c233cab31958 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/uio_driver.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/io.h>
@@ -601,6 +602,214 @@ static struct platform_device dma2_device = {
        },
 };
 
+/* VPU */
+static struct uio_info vpu_platform_data = {
+       .name = "VPU5HG",
+       .version = "0",
+       .irq = intcs_evt2irq(0x980),
+};
+
+static struct resource vpu_resources[] = {
+       [0] = {
+               .name   = "VPU",
+               .start  = 0xfe900000,
+               .end    = 0xfe900157,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device vpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &vpu_platform_data,
+       },
+       .resource       = vpu_resources,
+       .num_resources  = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+       .name = "VEU0",
+       .version = "0",
+       .irq = intcs_evt2irq(0x700),
+};
+
+static struct resource veu0_resources[] = {
+       [0] = {
+               .name   = "VEU0",
+               .start  = 0xfe920000,
+               .end    = 0xfe9200cb,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &veu0_platform_data,
+       },
+       .resource       = veu0_resources,
+       .num_resources  = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+       .name = "VEU1",
+       .version = "0",
+       .irq = intcs_evt2irq(0x720),
+};
+
+static struct resource veu1_resources[] = {
+       [0] = {
+               .name   = "VEU1",
+               .start  = 0xfe924000,
+               .end    = 0xfe9240cb,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &veu1_platform_data,
+       },
+       .resource       = veu1_resources,
+       .num_resources  = ARRAY_SIZE(veu1_resources),
+};
+
+/* VEU2 */
+static struct uio_info veu2_platform_data = {
+       .name = "VEU2",
+       .version = "0",
+       .irq = intcs_evt2irq(0x740),
+};
+
+static struct resource veu2_resources[] = {
+       [0] = {
+               .name   = "VEU2",
+               .start  = 0xfe928000,
+               .end    = 0xfe928307,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu2_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &veu2_platform_data,
+       },
+       .resource       = veu2_resources,
+       .num_resources  = ARRAY_SIZE(veu2_resources),
+};
+
+/* VEU3 */
+static struct uio_info veu3_platform_data = {
+       .name = "VEU3",
+       .version = "0",
+       .irq = intcs_evt2irq(0x760),
+};
+
+static struct resource veu3_resources[] = {
+       [0] = {
+               .name   = "VEU3",
+               .start  = 0xfe92c000,
+               .end    = 0xfe92c307,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu3_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &veu3_platform_data,
+       },
+       .resource       = veu3_resources,
+       .num_resources  = ARRAY_SIZE(veu3_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+       .name = "JPU",
+       .version = "0",
+       .irq = intcs_evt2irq(0x560),
+};
+
+static struct resource jpu_resources[] = {
+       [0] = {
+               .name   = "JPU",
+               .start  = 0xfe980000,
+               .end    = 0xfe9902d3,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device jpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &jpu_platform_data,
+       },
+       .resource       = jpu_resources,
+       .num_resources  = ARRAY_SIZE(jpu_resources),
+};
+
+/* SPU2DSP0 */
+static struct uio_info spu0_platform_data = {
+       .name = "SPU2DSP0",
+       .version = "0",
+       .irq = evt2irq(0x1800),
+};
+
+static struct resource spu0_resources[] = {
+       [0] = {
+               .name   = "SPU2DSP0",
+               .start  = 0xfe200000,
+               .end    = 0xfe2fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 6,
+       .dev = {
+               .platform_data  = &spu0_platform_data,
+       },
+       .resource       = spu0_resources,
+       .num_resources  = ARRAY_SIZE(spu0_resources),
+};
+
+/* SPU2DSP1 */
+static struct uio_info spu1_platform_data = {
+       .name = "SPU2DSP1",
+       .version = "0",
+       .irq = evt2irq(0x1820),
+};
+
+static struct resource spu1_resources[] = {
+       [0] = {
+               .name   = "SPU2DSP1",
+               .start  = 0xfe300000,
+               .end    = 0xfe3fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 7,
+       .dev = {
+               .platform_data  = &spu1_platform_data,
+       },
+       .resource       = spu1_resources,
+       .num_resources  = ARRAY_SIZE(spu1_resources),
+};
+
 static struct platform_device *sh7372_early_devices[] __initdata = {
        &scif0_device,
        &scif1_device,
@@ -620,6 +829,14 @@ static struct platform_device *sh7372_late_devices[] __initdata = {
        &dma0_device,
        &dma1_device,
        &dma2_device,
+       &vpu_device,
+       &veu0_device,
+       &veu1_device,
+       &veu2_device,
+       &veu3_device,
+       &jpu_device,
+       &spu0_device,
+       &spu1_device,
 };
 
 void __init sh7372_add_standard_devices(void)
index 8099b0b8a9346dcb76a17c2902dec2a1dba01c8b..bb405b8e459be00c11ce956c0e67bf9e181557f2 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/platform_device.h>
+#include <linux/uio_driver.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/io.h>
@@ -38,7 +39,7 @@ static struct plat_sci_port scif0_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc00), evt2irq(0xc00),
                            evt2irq(0xc00), evt2irq(0xc00) },
 };
@@ -57,7 +58,7 @@ static struct plat_sci_port scif1_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc20), evt2irq(0xc20),
                            evt2irq(0xc20), evt2irq(0xc20) },
 };
@@ -76,7 +77,7 @@ static struct plat_sci_port scif2_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc40), evt2irq(0xc40),
                            evt2irq(0xc40), evt2irq(0xc40) },
 };
@@ -95,7 +96,7 @@ static struct plat_sci_port scif3_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xc60), evt2irq(0xc60),
                            evt2irq(0xc60), evt2irq(0xc60) },
 };
@@ -114,7 +115,7 @@ static struct plat_sci_port scif4_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xd20), evt2irq(0xd20),
                            evt2irq(0xd20), evt2irq(0xd20) },
 };
@@ -133,7 +134,7 @@ static struct plat_sci_port scif5_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { evt2irq(0xd40), evt2irq(0xd40),
                            evt2irq(0xd40), evt2irq(0xd40) },
 };
@@ -152,7 +153,7 @@ static struct plat_sci_port scif6_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFA,
        .irqs           = { intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80),
                            intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80) },
 };
@@ -171,7 +172,7 @@ static struct plat_sci_port scif7_platform_data = {
        .flags          = UPF_BOOT_AUTOCONF,
        .scscr          = SCSCR_RE | SCSCR_TE,
        .scbrr_algo_id  = SCBRR_ALGO_4,
-       .type           = PORT_SCIF,
+       .type           = PORT_SCIFB,
        .irqs           = { evt2irq(0xd60), evt2irq(0xd60),
                            evt2irq(0xd60), evt2irq(0xd60) },
 };
@@ -215,6 +216,214 @@ static struct platform_device cmt10_device = {
        .num_resources  = ARRAY_SIZE(cmt10_resources),
 };
 
+/* VPU */
+static struct uio_info vpu_platform_data = {
+       .name = "VPU5HG",
+       .version = "0",
+       .irq = intcs_evt2irq(0x980),
+};
+
+static struct resource vpu_resources[] = {
+       [0] = {
+               .name   = "VPU",
+               .start  = 0xfe900000,
+               .end    = 0xfe900157,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device vpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 0,
+       .dev = {
+               .platform_data  = &vpu_platform_data,
+       },
+       .resource       = vpu_resources,
+       .num_resources  = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+       .name = "VEU0",
+       .version = "0",
+       .irq = intcs_evt2irq(0x700),
+};
+
+static struct resource veu0_resources[] = {
+       [0] = {
+               .name   = "VEU0",
+               .start  = 0xfe920000,
+               .end    = 0xfe9200cb,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 1,
+       .dev = {
+               .platform_data  = &veu0_platform_data,
+       },
+       .resource       = veu0_resources,
+       .num_resources  = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+       .name = "VEU1",
+       .version = "0",
+       .irq = intcs_evt2irq(0x720),
+};
+
+static struct resource veu1_resources[] = {
+       [0] = {
+               .name   = "VEU1",
+               .start  = 0xfe924000,
+               .end    = 0xfe9240cb,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 2,
+       .dev = {
+               .platform_data  = &veu1_platform_data,
+       },
+       .resource       = veu1_resources,
+       .num_resources  = ARRAY_SIZE(veu1_resources),
+};
+
+/* VEU2 */
+static struct uio_info veu2_platform_data = {
+       .name = "VEU2",
+       .version = "0",
+       .irq = intcs_evt2irq(0x740),
+};
+
+static struct resource veu2_resources[] = {
+       [0] = {
+               .name   = "VEU2",
+               .start  = 0xfe928000,
+               .end    = 0xfe928307,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu2_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 3,
+       .dev = {
+               .platform_data  = &veu2_platform_data,
+       },
+       .resource       = veu2_resources,
+       .num_resources  = ARRAY_SIZE(veu2_resources),
+};
+
+/* VEU3 */
+static struct uio_info veu3_platform_data = {
+       .name = "VEU3",
+       .version = "0",
+       .irq = intcs_evt2irq(0x760),
+};
+
+static struct resource veu3_resources[] = {
+       [0] = {
+               .name   = "VEU3",
+               .start  = 0xfe92c000,
+               .end    = 0xfe92c307,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device veu3_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 4,
+       .dev = {
+               .platform_data  = &veu3_platform_data,
+       },
+       .resource       = veu3_resources,
+       .num_resources  = ARRAY_SIZE(veu3_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+       .name = "JPU",
+       .version = "0",
+       .irq = intcs_evt2irq(0x560),
+};
+
+static struct resource jpu_resources[] = {
+       [0] = {
+               .name   = "JPU",
+               .start  = 0xfe980000,
+               .end    = 0xfe9902d3,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device jpu_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 5,
+       .dev = {
+               .platform_data  = &jpu_platform_data,
+       },
+       .resource       = jpu_resources,
+       .num_resources  = ARRAY_SIZE(jpu_resources),
+};
+
+/* SPU2DSP0 */
+static struct uio_info spu0_platform_data = {
+       .name = "SPU2DSP0",
+       .version = "0",
+       .irq = evt2irq(0x1800),
+};
+
+static struct resource spu0_resources[] = {
+       [0] = {
+               .name   = "SPU2DSP0",
+               .start  = 0xfe200000,
+               .end    = 0xfe2fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu0_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 6,
+       .dev = {
+               .platform_data  = &spu0_platform_data,
+       },
+       .resource       = spu0_resources,
+       .num_resources  = ARRAY_SIZE(spu0_resources),
+};
+
+/* SPU2DSP1 */
+static struct uio_info spu1_platform_data = {
+       .name = "SPU2DSP1",
+       .version = "0",
+       .irq = evt2irq(0x1820),
+};
+
+static struct resource spu1_resources[] = {
+       [0] = {
+               .name   = "SPU2DSP1",
+               .start  = 0xfe300000,
+               .end    = 0xfe3fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device spu1_device = {
+       .name           = "uio_pdrv_genirq",
+       .id             = 7,
+       .dev = {
+               .platform_data  = &spu1_platform_data,
+       },
+       .resource       = spu1_resources,
+       .num_resources  = ARRAY_SIZE(spu1_resources),
+};
+
 static struct platform_device *sh7377_early_devices[] __initdata = {
        &scif0_device,
        &scif1_device,
@@ -227,10 +436,24 @@ static struct platform_device *sh7377_early_devices[] __initdata = {
        &cmt10_device,
 };
 
+static struct platform_device *sh7377_devices[] __initdata = {
+       &vpu_device,
+       &veu0_device,
+       &veu1_device,
+       &veu2_device,
+       &veu3_device,
+       &jpu_device,
+       &spu0_device,
+       &spu1_device,
+};
+
 void __init sh7377_add_standard_devices(void)
 {
        platform_add_devices(sh7377_early_devices,
                            ARRAY_SIZE(sh7377_early_devices));
+
+       platform_add_devices(sh7377_devices,
+                           ARRAY_SIZE(sh7377_devices));
 }
 
 #define SMSTPCR3 0xe615013c
index 685c40a2f5e65139e24a8a36d74e55ecc2b9e916..e46821c0a62ef6a08aa06d6a390a9db884276861 100644 (file)
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
+#include <linux/sh_dma.h>
 #include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <mach/hardware.h>
+#include <mach/sh73a0.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 
@@ -392,6 +394,242 @@ static struct platform_device i2c4_device = {
        .num_resources  = ARRAY_SIZE(i2c4_resources),
 };
 
+/* Transmit sizes and respective CHCR register values */
+enum {
+       XMIT_SZ_8BIT            = 0,
+       XMIT_SZ_16BIT           = 1,
+       XMIT_SZ_32BIT           = 2,
+       XMIT_SZ_64BIT           = 7,
+       XMIT_SZ_128BIT          = 3,
+       XMIT_SZ_256BIT          = 4,
+       XMIT_SZ_512BIT          = 5,
+};
+
+/* log2(size / 8) - used to calculate number of transfers */
+#define TS_SHIFT {                     \
+       [XMIT_SZ_8BIT]          = 0,    \
+       [XMIT_SZ_16BIT]         = 1,    \
+       [XMIT_SZ_32BIT]         = 2,    \
+       [XMIT_SZ_64BIT]         = 3,    \
+       [XMIT_SZ_128BIT]        = 4,    \
+       [XMIT_SZ_256BIT]        = 5,    \
+       [XMIT_SZ_512BIT]        = 6,    \
+}
+
+#define TS_INDEX2VAL(i) ((((i) & 3) << 3) | (((i) & 0xc) << (20 - 2)))
+#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz)))
+#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz)))
+
+static const struct sh_dmae_slave_config sh73a0_dmae_slaves[] = {
+       {
+               .slave_id       = SHDMA_SLAVE_SCIF0_TX,
+               .addr           = 0xe6c40020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x21,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF0_RX,
+               .addr           = 0xe6c40024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x22,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF1_TX,
+               .addr           = 0xe6c50020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x25,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF1_RX,
+               .addr           = 0xe6c50024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x26,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF2_TX,
+               .addr           = 0xe6c60020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x29,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF2_RX,
+               .addr           = 0xe6c60024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x2a,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF3_TX,
+               .addr           = 0xe6c70020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x2d,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF3_RX,
+               .addr           = 0xe6c70024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x2e,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF4_TX,
+               .addr           = 0xe6c80020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x39,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF4_RX,
+               .addr           = 0xe6c80024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x3a,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF5_TX,
+               .addr           = 0xe6cb0020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x35,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF5_RX,
+               .addr           = 0xe6cb0024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x36,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF6_TX,
+               .addr           = 0xe6cc0020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x1d,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF6_RX,
+               .addr           = 0xe6cc0024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x1e,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF7_TX,
+               .addr           = 0xe6cd0020,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x19,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF7_RX,
+               .addr           = 0xe6cd0024,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x1a,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF8_TX,
+               .addr           = 0xe6c30040,
+               .chcr           = CHCR_TX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x3d,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SCIF8_RX,
+               .addr           = 0xe6c30060,
+               .chcr           = CHCR_RX(XMIT_SZ_8BIT),
+               .mid_rid        = 0x3e,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_TX,
+               .addr           = 0xee100030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI0_RX,
+               .addr           = 0xee100030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc2,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_TX,
+               .addr           = 0xee120030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xc9,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI1_RX,
+               .addr           = 0xee120030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xca,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI2_TX,
+               .addr           = 0xee140030,
+               .chcr           = CHCR_TX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xcd,
+       }, {
+               .slave_id       = SHDMA_SLAVE_SDHI2_RX,
+               .addr           = 0xee140030,
+               .chcr           = CHCR_RX(XMIT_SZ_16BIT),
+               .mid_rid        = 0xce,
+       }, {
+               .slave_id       = SHDMA_SLAVE_MMCIF_TX,
+               .addr           = 0xe6bd0034,
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xd1,
+       }, {
+               .slave_id       = SHDMA_SLAVE_MMCIF_RX,
+               .addr           = 0xe6bd0034,
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xd2,
+       },
+};
+
+#define DMAE_CHANNEL(_offset)                                  \
+       {                                                       \
+               .offset         = _offset - 0x20,               \
+               .dmars          = _offset - 0x20 + 0x40,        \
+       }
+
+static const struct sh_dmae_channel sh73a0_dmae_channels[] = {
+       DMAE_CHANNEL(0x8000),
+       DMAE_CHANNEL(0x8080),
+       DMAE_CHANNEL(0x8100),
+       DMAE_CHANNEL(0x8180),
+       DMAE_CHANNEL(0x8200),
+       DMAE_CHANNEL(0x8280),
+       DMAE_CHANNEL(0x8300),
+       DMAE_CHANNEL(0x8380),
+       DMAE_CHANNEL(0x8400),
+       DMAE_CHANNEL(0x8480),
+       DMAE_CHANNEL(0x8500),
+       DMAE_CHANNEL(0x8580),
+       DMAE_CHANNEL(0x8600),
+       DMAE_CHANNEL(0x8680),
+       DMAE_CHANNEL(0x8700),
+       DMAE_CHANNEL(0x8780),
+       DMAE_CHANNEL(0x8800),
+       DMAE_CHANNEL(0x8880),
+       DMAE_CHANNEL(0x8900),
+       DMAE_CHANNEL(0x8980),
+};
+
+static const unsigned int ts_shift[] = TS_SHIFT;
+
+static struct sh_dmae_pdata sh73a0_dmae_platform_data = {
+       .slave          = sh73a0_dmae_slaves,
+       .slave_num      = ARRAY_SIZE(sh73a0_dmae_slaves),
+       .channel        = sh73a0_dmae_channels,
+       .channel_num    = ARRAY_SIZE(sh73a0_dmae_channels),
+       .ts_low_shift   = 3,
+       .ts_low_mask    = 0x18,
+       .ts_high_shift  = (20 - 2),     /* 2 bits for shifted low TS */
+       .ts_high_mask   = 0x00300000,
+       .ts_shift       = ts_shift,
+       .ts_shift_num   = ARRAY_SIZE(ts_shift),
+       .dmaor_init     = DMAOR_DME,
+};
+
+static struct resource sh73a0_dmae_resources[] = {
+       {
+               /* Registers including DMAOR and channels including DMARSx */
+               .start  = 0xfe000020,
+               .end    = 0xfe008a00 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               /* DMA error IRQ */
+               .start  = gic_spi(129),
+               .end    = gic_spi(129),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               /* IRQ for channels 0-19 */
+               .start  = gic_spi(109),
+               .end    = gic_spi(128),
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device dma0_device = {
+       .name           = "sh-dma-engine",
+       .id             = 0,
+       .resource       = sh73a0_dmae_resources,
+       .num_resources  = ARRAY_SIZE(sh73a0_dmae_resources),
+       .dev            = {
+               .platform_data  = &sh73a0_dmae_platform_data,
+       },
+};
+
 static struct platform_device *sh73a0_early_devices[] __initdata = {
        &scif0_device,
        &scif1_device,
@@ -413,10 +651,16 @@ static struct platform_device *sh73a0_late_devices[] __initdata = {
        &i2c2_device,
        &i2c3_device,
        &i2c4_device,
+       &dma0_device,
 };
 
+#define SRCR2          0xe61580b0
+
 void __init sh73a0_add_standard_devices(void)
 {
+       /* Clear software reset bit on SY-DMAC module */
+       __raw_writel(__raw_readl(SRCR2) & ~(1 << 18), SRCR2);
+
        platform_add_devices(sh73a0_early_devices,
                            ARRAY_SIZE(sh73a0_early_devices));
        platform_add_devices(sh73a0_late_devices,
diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S
new file mode 100644 (file)
index 0000000..d37d3ca
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * sh7372 lowlevel sleep code for "Core Standby Mode"
+ *
+ * Copyright (C) 2011 Magnus Damm
+ *
+ * In "Core Standby Mode" the ARM core is off, but L2 cache is still on
+ *
+ * Based on mach-omap2/sleep34xx.S
+ *
+ * (C) Copyright 2007 Texas Instruments
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * (C) Copyright 2004 Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+#define SMFRAM 0xe6a70000
+
+       .align
+kernel_flush:
+       .word   v7_flush_dcache_all
+
+       .align  3
+ENTRY(sh7372_cpu_suspend)
+       stmfd   sp!, {r0-r12, lr}       @ save registers on stack
+
+       ldr     r8, =SMFRAM
+
+       mov     r4, sp                  @ Store sp
+       mrs     r5, spsr                @ Store spsr
+       mov     r6, lr                  @ Store lr
+       stmia   r8!, {r4-r6}
+
+       mrc     p15, 0, r4, c1, c0, 2   @ Coprocessor access control register
+       mrc     p15, 0, r5, c2, c0, 0   @ TTBR0
+       mrc     p15, 0, r6, c2, c0, 1   @ TTBR1
+       mrc     p15, 0, r7, c2, c0, 2   @ TTBCR
+       stmia   r8!, {r4-r7}
+
+       mrc     p15, 0, r4, c3, c0, 0   @ Domain access Control Register
+       mrc     p15, 0, r5, c10, c2, 0  @ PRRR
+       mrc     p15, 0, r6, c10, c2, 1  @ NMRR
+       stmia   r8!,{r4-r6}
+
+       mrc     p15, 0, r4, c13, c0, 1  @ Context ID
+       mrc     p15, 0, r5, c13, c0, 2  @ User r/w thread and process ID
+       mrc     p15, 0, r6, c12, c0, 0  @ Secure or NS vector base address
+       mrs     r7, cpsr                @ Store current cpsr
+       stmia   r8!, {r4-r7}
+
+       mrc     p15, 0, r4, c1, c0, 0   @ save control register
+       stmia   r8!, {r4}
+
+       /*
+        * jump out to kernel flush routine
+        *  - reuse that code is better
+        *  - it executes in a cached space so is faster than refetch per-block
+        *  - should be faster and will change with kernel
+        *  - 'might' have to copy address, load and jump to it
+        * Flush all data from the L1 data cache before disabling
+        * SCTLR.C bit.
+        */
+       ldr     r1, kernel_flush
+       mov     lr, pc
+       bx      r1
+
+       /*
+        * Clear the SCTLR.C bit to prevent further data cache
+        * allocation. Clearing SCTLR.C would make all the data accesses
+        * strongly ordered and would not hit the cache.
+        */
+       mrc     p15, 0, r0, c1, c0, 0
+       bic     r0, r0, #(1 << 2)       @ Disable the C bit
+       mcr     p15, 0, r0, c1, c0, 0
+       isb
+
+       /*
+        * Invalidate L1 data cache. Even though only invalidate is
+        * necessary exported flush API is used here. Doing clean
+        * on already clean cache would be almost NOP.
+        */
+       ldr     r1, kernel_flush
+       blx     r1
+       /*
+        * The kernel doesn't interwork: v7_flush_dcache_all in particluar will
+        * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled.
+        * This sequence switches back to ARM.  Note that .align may insert a
+        * nop: bx pc needs to be word-aligned in order to work.
+        */
+ THUMB(        .thumb          )
+ THUMB(        .align          )
+ THUMB(        bx      pc      )
+ THUMB(        nop             )
+       .arm
+
+       /* Data memory barrier and Data sync barrier */
+       dsb
+       dmb
+
+/*
+ * ===================================
+ * == WFI instruction => Enter idle ==
+ * ===================================
+ */
+       wfi                             @ wait for interrupt
+
+/*
+ * ===================================
+ * == Resume path for non-OFF modes ==
+ * ===================================
+ */
+       mrc     p15, 0, r0, c1, c0, 0
+       tst     r0, #(1 << 2)           @ Check C bit enabled?
+       orreq   r0, r0, #(1 << 2)       @ Enable the C bit if cleared
+       mcreq   p15, 0, r0, c1, c0, 0
+       isb
+
+/*
+ * ===================================
+ * == Exit point from non-OFF modes ==
+ * ===================================
+ */
+       ldmfd   sp!, {r0-r12, pc}       @ restore regs and return
+
+       .pool
+
+       .align  12
+       .text
+       .global sh7372_cpu_resume
+sh7372_cpu_resume:
+
+       mov     r1, #0
+       /*
+        * Invalidate all instruction caches to PoU
+        * and flush branch target cache
+        */
+       mcr     p15, 0, r1, c7, c5, 0
+
+       ldr     r3, =SMFRAM
+
+       ldmia   r3!, {r4-r6}
+       mov     sp, r4                  @ Restore sp
+       msr     spsr_cxsf, r5           @ Restore spsr
+       mov     lr, r6                  @ Restore lr
+
+       ldmia   r3!, {r4-r7}
+       mcr     p15, 0, r4, c1, c0, 2   @ Coprocessor access Control Register
+       mcr     p15, 0, r5, c2, c0, 0   @ TTBR0
+       mcr     p15, 0, r6, c2, c0, 1   @ TTBR1
+       mcr     p15, 0, r7, c2, c0, 2   @ TTBCR
+
+       ldmia   r3!,{r4-r6}
+       mcr     p15, 0, r4, c3, c0, 0   @ Domain access Control Register
+       mcr     p15, 0, r5, c10, c2, 0  @ PRRR
+       mcr     p15, 0, r6, c10, c2, 1  @ NMRR
+
+       ldmia   r3!,{r4-r7}
+       mcr     p15, 0, r4, c13, c0, 1  @ Context ID
+       mcr     p15, 0, r5, c13, c0, 2  @ User r/w thread and process ID
+       mrc     p15, 0, r6, c12, c0, 0  @ Secure or NS vector base address
+       msr     cpsr, r7                @ store cpsr
+
+       /* Starting to enable MMU here */
+       mrc     p15, 0, r7, c2, c0, 2   @ Read TTBRControl
+       /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1 */
+       and     r7, #0x7
+       cmp     r7, #0x0
+       beq     usettbr0
+ttbr_error:
+       /*
+        * More work needs to be done to support N[0:2] value other than 0
+        * So looping here so that the error can be detected
+        */
+       b       ttbr_error
+
+       .align
+cache_pred_disable_mask:
+       .word   0xFFFFE7FB
+ttbrbit_mask:
+       .word   0xFFFFC000
+table_index_mask:
+       .word   0xFFF00000
+table_entry:
+       .word   0x00000C02
+usettbr0:
+
+       mrc     p15, 0, r2, c2, c0, 0
+       ldr     r5, ttbrbit_mask
+       and     r2, r5
+       mov     r4, pc
+       ldr     r5, table_index_mask
+       and     r4, r5                  @ r4 = 31 to 20 bits of pc
+       /* Extract the value to be written to table entry */
+       ldr     r6, table_entry
+       /* r6 has the value to be written to table entry */
+       add     r6, r6, r4
+       /* Getting the address of table entry to modify */
+       lsr     r4, #18
+       /* r2 has the location which needs to be modified */
+       add     r2, r4
+       ldr     r4, [r2]
+       str     r6, [r2] /* modify the table entry */
+
+       mov     r7, r6
+       mov     r5, r2
+       mov     r6, r4
+       /* r5 = original page table address */
+       /* r6 = original page table data */
+
+       mov     r0, #0
+       mcr     p15, 0, r0, c7, c5, 4   @ Flush prefetch buffer
+       mcr     p15, 0, r0, c7, c5, 6   @ Invalidate branch predictor array
+       mcr     p15, 0, r0, c8, c5, 0   @ Invalidate instruction TLB
+       mcr     p15, 0, r0, c8, c6, 0   @ Invalidate data TLB
+
+       /*
+        * Restore control register. This enables the MMU.
+        * The caches and prediction are not enabled here, they
+        * will be enabled after restoring the MMU table entry.
+        */
+       ldmia   r3!, {r4}
+       stmia   r3!, {r5} /* save original page table address */
+       stmia   r3!, {r6} /* save original page table data */
+       stmia   r3!, {r7} /* save modified page table data */
+
+       ldr     r2, cache_pred_disable_mask
+       and     r4, r2
+       mcr     p15, 0, r4, c1, c0, 0
+       dsb
+       isb
+
+       ldr     r0, =restoremmu_on
+       bx      r0
+
+/*
+ * ==============================
+ * == Exit point from OFF mode ==
+ * ==============================
+ */
+restoremmu_on:
+
+       ldmfd   sp!, {r0-r12, pc}       @ restore regs and return
index a156d2108df1a9cf582340155557a7a7caf3615e..3ffdbc92ba828ddd0755ecc73648edc48539021a 100644 (file)
@@ -59,6 +59,11 @@ unsigned int __init sh73a0_get_core_count(void)
 {
        void __iomem *scu_base = scu_base_addr();
 
+#ifdef CONFIG_HAVE_ARM_TWD
+       /* twd_base needs to be initialized before percpu_timer_setup() */
+       twd_base = (void __iomem *)0xf0000600;
+#endif
+
        return scu_get_core_count(scu_base);
 }
 
@@ -82,10 +87,6 @@ int __cpuinit sh73a0_boot_secondary(unsigned int cpu)
 
 void __init sh73a0_smp_prepare_cpus(void)
 {
-#ifdef CONFIG_HAVE_ARM_TWD
-       twd_base = (void __iomem *)0xf0000600;
-#endif
-
        scu_enable(scu_base_addr());
 
        /* Map the reset vector (in headsmp.S) */
diff --git a/arch/arm/mach-shmobile/suspend.c b/arch/arm/mach-shmobile/suspend.c
new file mode 100644 (file)
index 0000000..c1febe1
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Suspend-to-RAM support code for SH-Mobile ARM
+ *
+ *  Copyright (C) 2011 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/pm.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+static int shmobile_suspend_default_enter(suspend_state_t suspend_state)
+{
+       cpu_do_idle();
+       return 0;
+}
+
+static int shmobile_suspend_begin(suspend_state_t state)
+{
+       disable_hlt();
+       return 0;
+}
+
+static void shmobile_suspend_end(void)
+{
+       enable_hlt();
+}
+
+struct platform_suspend_ops shmobile_suspend_ops = {
+       .begin          = shmobile_suspend_begin,
+       .end            = shmobile_suspend_end,
+       .enter          = shmobile_suspend_default_enter,
+       .valid          = suspend_valid_only_mem,
+};
+
+static int __init shmobile_suspend_init(void)
+{
+       suspend_set_ops(&shmobile_suspend_ops);
+       return 0;
+}
+late_initcall(shmobile_suspend_init);
index 3ad086e859c38f91696e832e4a51358afb40bcd2..4231bc7b865206a7fa4f21a8ae02b227374a7ec9 100644 (file)
@@ -24,6 +24,7 @@ struct tegra_sdhci_platform_data {
        int wp_gpio;
        int power_gpio;
        int is_8bit;
+       int pm_flags;
 };
 
 #endif
index 58626013aa322874bd0ebd33eb5ce22f2bb3ab1f..54429d0159547d89399f252fca89a48abddff876 100644 (file)
@@ -12,9 +12,12 @@ menu "Ux500 SoC"
 
 config UX500_SOC_DB5500
        bool "DB5500"
+       select MFD_DB5500_PRCMU
 
 config UX500_SOC_DB8500
        bool "DB8500"
+       select MFD_DB8500_PRCMU
+       select REGULATOR_DB8500_PRCMU
 
 endmenu
 
index b549a8fb4231a6b8d30e4860e83f45460323bb1f..1694916e68229f543609a6a5c68dfa7c8216b790 100644 (file)
@@ -5,7 +5,7 @@
 obj-y                          := clock.o cpu.o devices.o devices-common.o \
                                   id.o usb.o
 obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
-obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
+obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
 obj-$(CONFIG_MACH_U8500)       += board-mop500.o board-mop500-sdi.o \
                                board-mop500-regulators.o \
                                board-mop500-uib.o board-mop500-stuib.o \
@@ -17,4 +17,4 @@ obj-$(CONFIG_HOTPLUG_CPU)     += hotplug.o
 obj-$(CONFIG_LOCAL_TIMERS)     += localtimer.o
 obj-$(CONFIG_U5500_MODEM_IRQ)  += modem-irq-db5500.o
 obj-$(CONFIG_U5500_MBOX)       += mbox-db5500.o
-obj-$(CONFIG_CPU_FREQ)         += cpufreq.o
+
index bf0b02414e5bfeed31f61c3db596714bab8aeb64..7c6cb4fa47a937211b16917cd63d5ac008bd574c 100644 (file)
@@ -99,8 +99,11 @@ static void sdi0_configure(void)
        gpio_direction_output(sdi0_vsel, 0);
        gpio_direction_output(sdi0_en, 1);
 
-       /* Add the device */
-       db8500_add_sdi0(&mop500_sdi0_data);
+       /* Add the device, force v2 to subrevision 1 */
+       if (cpu_is_u8500v2())
+               db8500_add_sdi0(&mop500_sdi0_data, 0x10480180);
+       else
+               db8500_add_sdi0(&mop500_sdi0_data, 0);
 }
 
 void mop500_sdi_tc35892_init(void)
@@ -188,13 +191,18 @@ static struct mmci_platform_data mop500_sdi4_data = {
 
 void __init mop500_sdi_init(void)
 {
+       u32 periphid = 0;
+
+       /* v2 has a new version of this block that need to be forced */
+       if (cpu_is_u8500v2())
+               periphid = 0x10480180;
        /* PoP:ed eMMC on top of DB8500 v1.0 has problems with high speed */
        if (!cpu_is_u8500v10())
                mop500_sdi2_data.capabilities |= MMC_CAP_MMC_HIGHSPEED;
-       db8500_add_sdi2(&mop500_sdi2_data);
+       db8500_add_sdi2(&mop500_sdi2_data, periphid);
 
        /* On-board eMMC */
-       db8500_add_sdi4(&mop500_sdi4_data);
+       db8500_add_sdi4(&mop500_sdi4_data, periphid);
 
        if (machine_is_hrefv60()) {
                mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO;
index c9dc2eff3cb2d5a8677c16ee7e43ec6d992c47b9..c01bc19e3c5eac6c51d3adf1cffb13333a29047b 100644 (file)
@@ -188,6 +188,8 @@ void __init u5500_map_io(void)
        ux500_map_io();
 
        iotable_init(u5500_io_desc, ARRAY_SIZE(u5500_io_desc));
+
+       _PRCMU_BASE = __io_address(U5500_PRCMU_BASE);
 }
 
 static int usb_db5500_rx_dma_cfg[] = {
index 516126cb357dfeb52d918e57d4af4598669773d1..c3c417656bd96ecd531b4b7ebe9ca0c26fac9de6 100644 (file)
@@ -87,6 +87,8 @@ void __init u8500_map_io(void)
                iotable_init(u8500_v1_io_desc, ARRAY_SIZE(u8500_v1_io_desc));
        else if (cpu_is_u8500v2())
                iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc));
+
+       _PRCMU_BASE = __io_address(U8500_PRCMU_BASE);
 }
 
 static struct resource db8500_pmu_resources[] = {
@@ -129,9 +131,14 @@ static struct platform_device db8500_pmu_device = {
        .dev.platform_data      = &db8500_pmu_platdata,
 };
 
+static struct platform_device db8500_prcmu_device = {
+       .name                   = "db8500-prcmu",
+};
+
 static struct platform_device *platform_devs[] __initdata = {
        &u8500_dma40_device,
        &db8500_pmu_device,
+       &db8500_prcmu_device,
 };
 
 static resource_size_t __initdata db8500_gpio_base[] = {
index 5a43107c62325fc8a3f533053777ca0385cdc436..1da23bb87c16bcec2047d9ac8e08e474d2f505ce 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <linux/mfd/db5500-prcmu.h>
 
 #include <asm/cacheflush.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <mach/hardware.h>
 #include <mach/setup.h>
 #include <mach/devices.h>
-#include <mach/prcmu.h>
 
 #include "clock.h"
 
+void __iomem *_PRCMU_BASE;
+
 #ifdef CONFIG_CACHE_L2X0
 static void __iomem *l2x0_base;
 #endif
@@ -47,6 +50,8 @@ void __init ux500_init_irq(void)
         * Init clocks here so that they are available for system timer
         * initialization.
         */
+       if (cpu_is_u5500())
+               db5500_prcmu_early_init();
        if (cpu_is_u8500())
                prcmu_early_init();
        clk_init();
diff --git a/arch/arm/mach-ux500/cpufreq.c b/arch/arm/mach-ux500/cpufreq.c
deleted file mode 100644 (file)
index 5c5b747..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * CPU frequency scaling for u8500
- * Inspired by linux/arch/arm/mach-davinci/cpufreq.c
- *
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- *
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Martin Persson <martin.persson@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/cpufreq.h>
-#include <linux/delay.h>
-
-#include <mach/hardware.h>
-#include <mach/prcmu.h>
-#include <mach/prcmu-defs.h>
-
-#define DRIVER_NAME "cpufreq-u8500"
-#define CPUFREQ_NAME "u8500"
-
-static struct device *dev;
-
-static struct cpufreq_frequency_table freq_table[] = {
-       [0] = {
-               .index = 0,
-               .frequency = 200000,
-       },
-       [1] = {
-               .index = 1,
-               .frequency = 300000,
-       },
-       [2] = {
-               .index = 2,
-               .frequency = 600000,
-       },
-       [3] = {
-               /* Used for CPU_OPP_MAX, if available */
-               .index = 3,
-               .frequency = CPUFREQ_TABLE_END,
-       },
-       [4] = {
-               .index = 4,
-               .frequency = CPUFREQ_TABLE_END,
-       },
-};
-
-static enum prcmu_cpu_opp index2opp[] = {
-       CPU_OPP_EXT_CLK,
-       CPU_OPP_50,
-       CPU_OPP_100,
-       CPU_OPP_MAX
-};
-
-static int u8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
-{
-       return cpufreq_frequency_table_verify(policy, freq_table);
-}
-
-static int u8500_cpufreq_target(struct cpufreq_policy *policy,
-                               unsigned int target_freq,
-                               unsigned int relation)
-{
-       struct cpufreq_freqs freqs;
-       unsigned int index;
-       int ret = 0;
-
-       /*
-        * Ensure desired rate is within allowed range.  Some govenors
-        * (ondemand) will just pass target_freq=0 to get the minimum.
-        */
-       if (target_freq < policy->cpuinfo.min_freq)
-               target_freq = policy->cpuinfo.min_freq;
-       if (target_freq > policy->cpuinfo.max_freq)
-               target_freq = policy->cpuinfo.max_freq;
-
-       ret = cpufreq_frequency_table_target(policy, freq_table,
-                                            target_freq, relation, &index);
-       if (ret < 0) {
-               dev_err(dev, "Could not look up next frequency\n");
-               return ret;
-       }
-
-       freqs.old = policy->cur;
-       freqs.new = freq_table[index].frequency;
-       freqs.cpu = policy->cpu;
-
-       if (freqs.old == freqs.new) {
-               dev_dbg(dev, "Current and target frequencies are equal\n");
-               return 0;
-       }
-
-       dev_dbg(dev, "transition: %u --> %u\n", freqs.old, freqs.new);
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
-       ret = prcmu_set_cpu_opp(index2opp[index]);
-       if (ret < 0) {
-               dev_err(dev, "Failed to set OPP level\n");
-               return ret;
-       }
-
-       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
-       return ret;
-}
-
-static unsigned int u8500_cpufreq_getspeed(unsigned int cpu)
-{
-       int i;
-
-       for (i = 0; prcmu_get_cpu_opp() != index2opp[i]; i++)
-               ;
-       return freq_table[i].frequency;
-}
-
-static int __cpuinit u8500_cpu_init(struct cpufreq_policy *policy)
-{
-       int res;
-
-       BUILD_BUG_ON(ARRAY_SIZE(index2opp) + 1 != ARRAY_SIZE(freq_table));
-
-       if (cpu_is_u8500v2()) {
-               freq_table[1].frequency = 400000;
-               freq_table[2].frequency = 800000;
-               if (prcmu_has_arm_maxopp())
-                       freq_table[3].frequency = 1000000;
-       }
-
-       /* get policy fields based on the table */
-       res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
-       if (!res)
-               cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
-       else {
-               dev_err(dev, "u8500-cpufreq : Failed to read policy table\n");
-               return res;
-       }
-
-       policy->min = policy->cpuinfo.min_freq;
-       policy->max = policy->cpuinfo.max_freq;
-       policy->cur = u8500_cpufreq_getspeed(policy->cpu);
-       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
-       /*
-        * FIXME : Need to take time measurement across the target()
-        *         function with no/some/all drivers in the notification
-        *         list.
-        */
-       policy->cpuinfo.transition_latency = 200 * 1000; /* in ns */
-
-       /* policy sharing between dual CPUs */
-       cpumask_copy(policy->cpus, &cpu_present_map);
-
-       policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
-
-       return res;
-}
-
-static struct freq_attr *u8500_cpufreq_attr[] = {
-       &cpufreq_freq_attr_scaling_available_freqs,
-       NULL,
-};
-static int u8500_cpu_exit(struct cpufreq_policy *policy)
-{
-       cpufreq_frequency_table_put_attr(policy->cpu);
-       return 0;
-}
-
-static struct cpufreq_driver u8500_driver = {
-       .owner = THIS_MODULE,
-       .flags = CPUFREQ_STICKY,
-       .verify = u8500_cpufreq_verify_speed,
-       .target = u8500_cpufreq_target,
-       .get = u8500_cpufreq_getspeed,
-       .init = u8500_cpu_init,
-       .exit = u8500_cpu_exit,
-       .name = CPUFREQ_NAME,
-       .attr = u8500_cpufreq_attr,
-};
-
-static int __init u8500_cpufreq_probe(struct platform_device *pdev)
-{
-       dev = &pdev->dev;
-       return cpufreq_register_driver(&u8500_driver);
-}
-
-static int __exit u8500_cpufreq_remove(struct platform_device *pdev)
-{
-       return cpufreq_unregister_driver(&u8500_driver);
-}
-
-static struct platform_driver u8500_cpufreq_driver = {
-       .driver = {
-               .name    = DRIVER_NAME,
-               .owner   = THIS_MODULE,
-       },
-       .remove = __exit_p(u8500_cpufreq_remove),
-};
-
-static int __init u8500_cpufreq_init(void)
-{
-       return platform_driver_probe(&u8500_cpufreq_driver,
-                                    &u8500_cpufreq_probe);
-}
-
-device_initcall(u8500_cpufreq_init);
index c719b5a1d9130ee47f36e97889686ee7c7038ad0..7825705033bfe6e18881e6e8fa15aaa2d8c4d82f 100644 (file)
@@ -28,18 +28,20 @@ dbx500_add_msp_spi(const char *name, resource_size_t base, int irq,
 
 static inline struct amba_device *
 dbx500_add_spi(const char *name, resource_size_t base, int irq,
-                                  struct spi_master_cntlr *pdata)
+              struct spi_master_cntlr *pdata,
+              u32 periphid)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(name, base, irq, pdata, periphid);
 }
 
 struct mmci_platform_data;
 
 static inline struct amba_device *
 dbx500_add_sdi(const char *name, resource_size_t base, int irq,
-              struct mmci_platform_data *pdata)
+              struct mmci_platform_data *pdata,
+              u32 periphid)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(name, base, irq, pdata, periphid);
 }
 
 struct amba_pl011_data;
index 94627f7783b033458b98eb401aae9ccdfd7eeb6a..0c4bccd02b90fe2836c4b8954235bf88d5eac270 100644 (file)
        ux500_add_usb(U5500_USBOTG_BASE, IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
 
 #define db5500_add_sdi0(pdata) \
-       dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata)
+       dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata, \
+                      0x10480180)
 #define db5500_add_sdi1(pdata) \
-       dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata)
+       dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata, \
+                      0x10480180)
 #define db5500_add_sdi2(pdata) \
-       dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata)
+       dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata \
+                      0x10480180)
 #define db5500_add_sdi3(pdata) \
-       dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata)
+       dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata \
+                      0x10480180)
 #define db5500_add_sdi4(pdata) \
-       dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata)
+       dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata \
+                      0x10480180)
 
+/* This one has a bad peripheral ID in the U5500 silicon */
 #define db5500_add_spi0(pdata) \
-       dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata)
+       dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata, \
+                      0x10080023)
 #define db5500_add_spi1(pdata) \
-       dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata)
+       dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata, \
+                      0x10080023)
 #define db5500_add_spi2(pdata) \
-       dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata)
+       dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata \
+                      0x10080023)
 #define db5500_add_spi3(pdata) \
-       dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata)
+       dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata \
+                      0x10080023)
 
 #define db5500_add_uart0(plat) \
        dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0, plat)
index 9cc6f8f5d3e621c9008c1006ef6c59bda65cd8b4..cbd4a9ae81093a14e7ca73c67cadc0869c6d579d 100644 (file)
@@ -25,7 +25,7 @@ static inline struct amba_device *
 db8500_add_ssp(const char *name, resource_size_t base, int irq,
               struct pl022_ssp_controller *pdata)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, SSP_PER_ID);
+       return dbx500_add_amba_device(name, base, irq, pdata, 0);
 }
 
 
@@ -64,18 +64,18 @@ db8500_add_ssp(const char *name, resource_size_t base, int irq,
 #define db8500_add_usb(rx_cfg, tx_cfg) \
        ux500_add_usb(U8500_USBOTG_BASE, IRQ_DB8500_USBOTG, rx_cfg, tx_cfg)
 
-#define db8500_add_sdi0(pdata) \
-       dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata)
-#define db8500_add_sdi1(pdata) \
-       dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata)
-#define db8500_add_sdi2(pdata) \
-       dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata)
-#define db8500_add_sdi3(pdata) \
-       dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata)
-#define db8500_add_sdi4(pdata) \
-       dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata)
-#define db8500_add_sdi5(pdata) \
-       dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata)
+#define db8500_add_sdi0(pdata, pid) \
+       dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata, pid)
+#define db8500_add_sdi1(pdata, pid) \
+       dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata, pid)
+#define db8500_add_sdi2(pdata, pid) \
+       dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata, pid)
+#define db8500_add_sdi3(pdata, pid) \
+       dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata, pid)
+#define db8500_add_sdi4(pdata, pid) \
+       dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata, pid)
+#define db8500_add_sdi5(pdata, pid) \
+       dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata, pid)
 
 #define db8500_add_ssp0(pdata) \
        db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata)
@@ -83,13 +83,13 @@ db8500_add_ssp(const char *name, resource_size_t base, int irq,
        db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata)
 
 #define db8500_add_spi0(pdata) \
-       dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata)
+       dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata, 0)
 #define db8500_add_spi1(pdata) \
-       dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata)
+       dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata, 0)
 #define db8500_add_spi2(pdata) \
-       dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata)
+       dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata, 0)
 #define db8500_add_spi3(pdata) \
-       dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata)
+       dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata, 0)
 
 #define db8500_add_uart0(pdata) \
        dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0, pdata)
index bd88c1e74060740158c95ab0c427d40265717694..6ad983294103f83c7eea6e96a9df0f6e3741cc47 100644 (file)
@@ -17,6 +17,8 @@
 #define U5500_GIC_DIST_BASE    0xA0411000
 #define U5500_GIC_CPU_BASE     0xA0410100
 #define U5500_DMA_BASE         0x90030000
+#define U5500_STM_BASE         0x90020000
+#define U5500_STM_REG_BASE     (U5500_STM_BASE + 0xF000)
 #define U5500_MCDE_BASE                0xA0400000
 #define U5500_MODEM_BASE       0xB0000000
 #define U5500_L2CC_BASE                0xA0412000
@@ -29,7 +31,9 @@
 #define U5500_NAND0_BASE       0x60000000
 #define U5500_NAND1_BASE       0x70000000
 #define U5500_TWD_BASE         0xa0410600
+#define U5500_ICN_BASE         0xA0040000
 #define U5500_B2R2_BASE                0xa0200000
+#define U5500_BOOT_ROM_BASE    0x90000000
 
 #define U5500_FSMC_BASE                (U5500_PER1_BASE + 0x0000)
 #define U5500_SDI0_BASE                (U5500_PER1_BASE + 0x1000)
@@ -60,6 +64,7 @@
 #define U5500_MSP1_BASE                (U5500_PER4_BASE + 0x9000)
 #define U5500_GPIO2_BASE       (U5500_PER4_BASE + 0xA000)
 #define U5500_CDETECT_BASE     (U5500_PER4_BASE + 0xF000)
+#define U5500_PRCMU_TCDM_BASE  (U5500_PER4_BASE + 0x18000)
 
 #define U5500_SPI0_BASE                (U5500_PER5_BASE + 0x0000)
 #define U5500_SPI1_BASE                (U5500_PER5_BASE + 0x1000)
@@ -83,7 +88,7 @@
 #define U5500_HASH0_BASE       (U5500_PER6_BASE + 0x1000)
 #define U5500_HASH1_BASE       (U5500_PER6_BASE + 0x2000)
 #define U5500_PKA_BASE         (U5500_PER6_BASE + 0x4000)
-#define U5500_PKAM_BASE                (U5500_PER6_BASE + 0x5000)
+#define U5500_PKAM_BASE                (U5500_PER6_BASE + 0x5100)
 #define U5500_MTU0_BASE                (U5500_PER6_BASE + 0x6000)
 #define U5500_MTU1_BASE                (U5500_PER6_BASE + 0x7000)
 #define U5500_CR_BASE          (U5500_PER6_BASE + 0x8000)
 #define U5500_MBOX2_LOCAL_START        (U5500_MBOX_BASE + 0x20)
 #define U5500_MBOX2_LOCAL_END  (U5500_MBOX_BASE + 0x3F)
 
-#define U5500_ESRAM_BASE               0x40000000
+#define U5500_ACCCON_BASE_SEC  (0xBFFF0000)
+#define U5500_ACCCON_BASE              (0xBFFF1000)
+#define U5500_ACCCON_CPUVEC_RESET_ADDR_OFFSET (0x00000020)
+#define U5500_ACCCON_ACC_CPU_CTRL_OFFSET (0x000000BC)
+
+#define U5500_ESRAM_BASE               0x40000000
 #define U5500_ESRAM_DMA_LCPA_OFFSET    0x10000
 #define U5500_DMA_LCPA_BASE    (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET)
 
+#define U5500_MCDE_SIZE                0x1000
+#define U5500_DSI_LINK_SIZE    0x1000
+#define U5500_DSI_LINK_COUNT   0x2
+#define U5500_DSI_LINK1_BASE   (U5500_MCDE_BASE + U5500_MCDE_SIZE)
+#define U5500_DSI_LINK2_BASE   (U5500_DSI_LINK1_BASE + U5500_DSI_LINK_SIZE)
+
 #endif
index 16647b2553786d11b17654e336dd5df6cefa54cb..049997109cf951d1d960bb2ac38fd1779fd1539b 100644 (file)
 #define U8500_ESRAM_BANK2      (U8500_ESRAM_BANK1 + U8500_ESRAM_BANK_SIZE)
 #define U8500_ESRAM_BANK3      (U8500_ESRAM_BANK2 + U8500_ESRAM_BANK_SIZE)
 #define U8500_ESRAM_BANK4      (U8500_ESRAM_BANK3 + U8500_ESRAM_BANK_SIZE)
-/* Use bank 4 for DMA LCPA */
-#define U8500_DMA_LCPA_BASE    U8500_ESRAM_BANK4
+/*
+ * on V1 DMA uses 4KB for logical parameters position is right after the 64KB
+ * reserved for security
+ */
+#define U8500_ESRAM_DMA_LCPA_OFFSET     0x10000
+
+#define U8500_DMA_LCPA_BASE    (U8500_ESRAM_BANK0 + U8500_ESRAM_DMA_LCPA_OFFSET)
 #define U8500_DMA_LCPA_BASE_ED (U8500_ESRAM_BANK4 + 0x4000)
 
 #define U8500_PER3_BASE                0x80000000
 #define U8500_B2R2_BASE                0x80130000
 #define U8500_HSEM_BASE                0x80140000
 #define U8500_PER4_BASE                0x80150000
+#define U8500_TPIU_BASE                0x80190000
 #define U8500_ICN_BASE         0x81000000
 
 #define U8500_BOOT_ROM_BASE    0x90000000
+/* ASIC ID is at 0xbf4 offset within this region */
+#define U8500_ASIC_ID_BASE     0x9001D000
 
 #define U8500_PER6_BASE                0xa03c0000
 #define U8500_PER5_BASE                0xa03e0000
 
 /* per6 base addresses */
 #define U8500_RNG_BASE         (U8500_PER6_BASE + 0x0000)
-#define U8500_PKA_BASE         (U8500_PER6_BASE + 0x1000)
-#define U8500_PKAM_BASE                (U8500_PER6_BASE + 0x2000)
+#define U8500_HASH0_BASE        (U8500_PER6_BASE + 0x1000)
+#define U8500_HASH1_BASE        (U8500_PER6_BASE + 0x2000)
+#define U8500_PKA_BASE         (U8500_PER6_BASE + 0x4000)
+#define U8500_PKAM_BASE                (U8500_PER6_BASE + 0x5100)
 #define U8500_MTU0_BASE                (U8500_PER6_BASE + 0x6000) /* v1 */
 #define U8500_MTU1_BASE                (U8500_PER6_BASE + 0x7000) /* v1 */
 #define U8500_CR_BASE          (U8500_PER6_BASE + 0x8000) /* v1 */
-#define U8500_CRYPTO0_BASE     (U8500_PER6_BASE + 0xa000)
-#define U8500_CRYPTO1_BASE     (U8500_PER6_BASE + 0xb000)
+#define U8500_CRYP0_BASE       (U8500_PER6_BASE + 0xa000)
+#define U8500_CRYP1_BASE       (U8500_PER6_BASE + 0xb000)
 #define U8500_CLKRST6_BASE     (U8500_PER6_BASE + 0xf000)
 
 /* per5 base addresses */
 #define U8500_DMC_BASE         (U8500_PER4_BASE + 0x06000)
 #define U8500_PRCMU_BASE       (U8500_PER4_BASE + 0x07000)
 #define U8500_PRCMU_TCDM_BASE_V1 (U8500_PER4_BASE + 0x0f000)
-#define U8500_PRCMU_TCDM_BASE   (U8500_PER4_BASE + 0x68000)
+#define U8500_PRCMU_TCDM_BASE  (U8500_PER4_BASE + 0x68000)
+#define U8500_PRCMU_TCPM_BASE   (U8500_PER4_BASE + 0x60000)
 
 /* per3 base addresses */
 #define U8500_FSMC_BASE                (U8500_PER3_BASE + 0x0000)
 #define U8500_I2C1_BASE                (U8500_PER1_BASE + 0x2000)
 #define U8500_MSP0_BASE                (U8500_PER1_BASE + 0x3000)
 #define U8500_MSP1_BASE                (U8500_PER1_BASE + 0x4000)
+#define U8500_MSP3_BASE                (U8500_PER1_BASE + 0x5000)
 #define U8500_SDI0_BASE                (U8500_PER1_BASE + 0x6000)
 #define U8500_I2C2_BASE                (U8500_PER1_BASE + 0x8000)
 #define U8500_SPI3_BASE                (U8500_PER1_BASE + 0x9000)
 #define U8500_GPIOBANK7_BASE   (U8500_GPIO2_BASE + 0x80)
 #define U8500_GPIOBANK8_BASE   U8500_GPIO3_BASE
 
+#define U8500_MCDE_SIZE                0x1000
+#define U8500_DSI_LINK_SIZE    0x1000
+#define U8500_DSI_LINK1_BASE   (U8500_MCDE_BASE + U8500_MCDE_SIZE)
+#define U8500_DSI_LINK2_BASE   (U8500_DSI_LINK1_BASE + U8500_DSI_LINK_SIZE)
+#define U8500_DSI_LINK3_BASE   (U8500_DSI_LINK2_BASE + U8500_DSI_LINK_SIZE)
+#define U8500_DSI_LINK_COUNT   0x3
+
+/* Modem and APE physical addresses */
+#define U8500_MODEM_BASE       0xe000000
+#define U8500_APE_BASE         0x6000000
+
 #endif
index bf63f2631ba0519234ef6f1d0c94d0af92d2b548..470ac52663d61e7021586c29de997a78205fdba9 100644 (file)
 #include <mach/db8500-regs.h>
 #include <mach/db5500-regs.h>
 
-/* ST-Ericsson modified pl022 id */
-#define SSP_PER_ID             0x01080022
-
 #ifndef __ASSEMBLY__
 
 #include <mach/id.h>
+extern void __iomem *_PRCMU_BASE;
 
 #define ARRAY_AND_SIZE(x)      (x), ARRAY_SIZE(x)
 
index f1288d10b6ab7eb537040e950d65a16828747b4b..02b541a37ee5ebca1f28dac8a03e6d248f42a41b 100644 (file)
@@ -75,6 +75,26 @@ static inline bool __attribute_const__ cpu_is_u8500v2(void)
        return cpu_is_u8500() && ((dbx500_revision() & 0xf0) == 0xB0);
 }
 
+static inline bool cpu_is_u8500v20(void)
+{
+       return cpu_is_u8500() && (dbx500_revision() == 0xB0);
+}
+
+static inline bool cpu_is_u8500v21(void)
+{
+       return cpu_is_u8500() && (dbx500_revision() == 0xB1);
+}
+
+static inline bool cpu_is_u8500v20_or_later(void)
+{
+       return cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11();
+}
+
+static inline bool ux500_is_svp(void)
+{
+       return false;
+}
+
 #define ux500_unknown_soc()    BUG()
 
 #endif
index 97ef55f8493496486723c8fb4fa4ada65717e785..47969909836c9bb1441b7143dc5c4e156915267f 100644 (file)
 
 #define MOP500_IRQ_END         MOP500_NR_IRQS
 
+/*
+ * We may have several boards, but only one will run at a
+ * time, so the one with most IRQs will bump this ahead,
+ * but the IRQ_BOARD_START remains the same for either board.
+ */
 #if MOP500_IRQ_END > IRQ_BOARD_END
 #undef IRQ_BOARD_END
 #define IRQ_BOARD_END  MOP500_IRQ_END
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
new file mode 100644 (file)
index 0000000..29d972c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_BOARD_U5500_H
+#define __MACH_IRQS_BOARD_U5500_H
+
+#define AB5500_NR_IRQS         5
+#define IRQ_AB5500_BASE                IRQ_BOARD_START
+#define IRQ_AB5500_END         (IRQ_AB5500_BASE + AB5500_NR_IRQS)
+
+#define U5500_IRQ_END          IRQ_AB5500_END
+
+#if IRQ_BOARD_END < U5500_IRQ_END
+#undef IRQ_BOARD_END
+#define IRQ_BOARD_END          U5500_IRQ_END
+#endif
+
+#endif
index bfa123dbec3b15d993d76f24509773c7e9777141..77239776a6f2358d9b8eb53b2d5e7c25331cef87 100644 (file)
 #define IRQ_DB5500_GPIO6               (IRQ_SHPI_START + 125)
 #define IRQ_DB5500_GPIO7               (IRQ_SHPI_START + 126)
 
+#ifdef CONFIG_UX500_SOC_DB5500
+
+/*
+ * After the GPIO ones we reserve a range of IRQ:s in which virtual
+ * IRQ:s representing modem IRQ:s can be allocated
+ */
+#define IRQ_MODEM_EVENTS_BASE  IRQ_SOC_START
+#define IRQ_MODEM_EVENTS_NBR   72
+#define IRQ_MODEM_EVENTS_END   (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
+
+/* List of virtual IRQ:s that are allocated from the range above */
+#define MBOX_PAIR0_VIRT_IRQ    (IRQ_MODEM_EVENTS_BASE + 43)
+#define MBOX_PAIR1_VIRT_IRQ    (IRQ_MODEM_EVENTS_BASE + 45)
+#define MBOX_PAIR2_VIRT_IRQ    (IRQ_MODEM_EVENTS_BASE + 41)
+
+/*
+ * We may have several SoCs, but only one will run at a
+ * time, so the one with most IRQs will bump this ahead,
+ * but the IRQ_SOC_START remains the same for either SoC.
+ */
+#if IRQ_SOC_END < IRQ_MODEM_EVENTS_END
+#undef IRQ_SOC_END
+#define IRQ_SOC_END            IRQ_MODEM_EVENTS_END
+#endif
+
+#endif /* CONFIG_UX500_SOC_DB5500 */
+
 #endif
index 8b5d9f0a1633a4cb0edc501a915b9144a98734d9..68bc149746080863b67bbfdcdd81a43ab9206bd8 100644 (file)
 #define IRQ_DB8500_GPIO7               (IRQ_SHPI_START + 126)
 #define IRQ_DB8500_GPIO8               (IRQ_SHPI_START + 127)
 
+#define IRQ_CA_WAKE_REQ_ED                     (IRQ_SHPI_START + 71)
+#define IRQ_AC_READ_NOTIFICATION_0_ED          (IRQ_SHPI_START + 66)
+#define IRQ_AC_READ_NOTIFICATION_1_ED          (IRQ_SHPI_START + 64)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_0_ED      (IRQ_SHPI_START + 67)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_1_ED      (IRQ_SHPI_START + 65)
+
+#define IRQ_CA_WAKE_REQ_V1                     (IRQ_SHPI_START + 83)
+#define IRQ_AC_READ_NOTIFICATION_0_V1          (IRQ_SHPI_START + 78)
+#define IRQ_AC_READ_NOTIFICATION_1_V1          (IRQ_SHPI_START + 76)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_0_V1      (IRQ_SHPI_START + 79)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_1_V1      (IRQ_SHPI_START + 77)
+
+#ifdef CONFIG_UX500_SOC_DB8500
+
+/* Virtual interrupts corresponding to the PRCMU wakeups.  */
+#define IRQ_PRCMU_BASE IRQ_SOC_START
+#define NUM_PRCMU_WAKEUPS (IRQ_PRCMU_END - IRQ_PRCMU_BASE)
+
+#define IRQ_PRCMU_RTC (IRQ_PRCMU_BASE)
+#define IRQ_PRCMU_RTT0 (IRQ_PRCMU_BASE + 1)
+#define IRQ_PRCMU_RTT1 (IRQ_PRCMU_BASE + 2)
+#define IRQ_PRCMU_HSI0 (IRQ_PRCMU_BASE + 3)
+#define IRQ_PRCMU_HSI1 (IRQ_PRCMU_BASE + 4)
+#define IRQ_PRCMU_CA_WAKE (IRQ_PRCMU_BASE + 5)
+#define IRQ_PRCMU_USB (IRQ_PRCMU_BASE + 6)
+#define IRQ_PRCMU_ABB (IRQ_PRCMU_BASE + 7)
+#define IRQ_PRCMU_ABB_FIFO (IRQ_PRCMU_BASE + 8)
+#define IRQ_PRCMU_ARM (IRQ_PRCMU_BASE + 9)
+#define IRQ_PRCMU_MODEM_SW_RESET_REQ (IRQ_PRCMU_BASE + 10)
+#define IRQ_PRCMU_GPIO0 (IRQ_PRCMU_BASE + 11)
+#define IRQ_PRCMU_GPIO1 (IRQ_PRCMU_BASE + 12)
+#define IRQ_PRCMU_GPIO2 (IRQ_PRCMU_BASE + 13)
+#define IRQ_PRCMU_GPIO3 (IRQ_PRCMU_BASE + 14)
+#define IRQ_PRCMU_GPIO4 (IRQ_PRCMU_BASE + 15)
+#define IRQ_PRCMU_GPIO5 (IRQ_PRCMU_BASE + 16)
+#define IRQ_PRCMU_GPIO6 (IRQ_PRCMU_BASE + 17)
+#define IRQ_PRCMU_GPIO7 (IRQ_PRCMU_BASE + 18)
+#define IRQ_PRCMU_GPIO8 (IRQ_PRCMU_BASE + 19)
+#define IRQ_PRCMU_CA_SLEEP (IRQ_PRCMU_BASE + 20)
+#define IRQ_PRCMU_HOTMON_LOW (IRQ_PRCMU_BASE + 21)
+#define IRQ_PRCMU_HOTMON_HIGH (IRQ_PRCMU_BASE + 22)
+#define IRQ_PRCMU_END (IRQ_PRCMU_BASE + 23)
+
+/*
+ * We may have several SoCs, but only one will run at a
+ * time, so the one with most IRQs will bump this ahead,
+ * but the IRQ_SOC_START remains the same for either SoC.
+ */
+#if IRQ_SOC_END < IRQ_PRCMU_END
+#undef IRQ_SOC_END
+#define IRQ_SOC_END IRQ_PRCMU_END
+#endif
+
+#endif /* CONFIG_UX500_SOC_DB8500 */
 #endif
index ba1294c13c4dc56939ff7d02ce108980c12d41fd..9db68d264c5f727c1fffc15f5a563d4b2a9d9a65 100644 (file)
 #ifndef ASM_ARCH_IRQS_H
 #define ASM_ARCH_IRQS_H
 
-#include <mach/irqs-db5500.h>
-#include <mach/irqs-db8500.h>
+#include <mach/hardware.h>
 
-#define IRQ_LOCALTIMER                  29
-#define IRQ_LOCALWDOG                   30
+#define IRQ_LOCALTIMER                 29
+#define IRQ_LOCALWDOG                  30
 
 /* Shared Peripheral Interrupt (SHPI) */
 #define IRQ_SHPI_START                 32
 
-/* Interrupt numbers generic for shared peripheral */
+/*
+ * MTU0 preserved for now until plat-nomadik is taught not to use it.  Don't
+ * add any other IRQs here, use the irqs-dbx500.h files.
+ */
 #define IRQ_MTU0               (IRQ_SHPI_START + 4)
 
-/* There are 128 shared peripheral interrupts assigned to
- * INTID[160:32]. The first 32 interrupts are reserved.
- */
-#define DBX500_NR_INTERNAL_IRQS                161
+#define DBX500_NR_INTERNAL_IRQS                160
 
 /* After chip-specific IRQ numbers we have the GPIO ones */
 #define NOMADIK_NR_GPIO                        288
 #define NOMADIK_GPIO_TO_IRQ(gpio)      ((gpio) + DBX500_NR_INTERNAL_IRQS)
 #define NOMADIK_IRQ_TO_GPIO(irq)       ((irq) - DBX500_NR_INTERNAL_IRQS)
-#define IRQ_BOARD_START                        NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
+#define IRQ_GPIO_END                   NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
+
+#define IRQ_SOC_START          IRQ_GPIO_END
+/* This will be overridden by SoC-specific irq headers */
+#define IRQ_SOC_END            IRQ_SOC_START
 
+#include <mach/irqs-db5500.h>
+#include <mach/irqs-db8500.h>
+
+#define IRQ_BOARD_START                IRQ_SOC_END
 /* This will be overridden by board-specific irq headers */
-#define IRQ_BOARD_END                  IRQ_BOARD_START
+#define IRQ_BOARD_END          IRQ_BOARD_START
 
 #ifdef CONFIG_MACH_U8500
 #include <mach/irqs-board-mop500.h>
 #endif
 
-/*
- * After the board specific IRQ:s we reserve a range of IRQ:s in which virtual
- * IRQ:s representing modem IRQ:s can be allocated
- */
-#define IRQ_MODEM_EVENTS_BASE (IRQ_BOARD_END + 1)
-#define IRQ_MODEM_EVENTS_NBR 72
-#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
-
-/* List of virtual IRQ:s that are allocated from the range above */
-#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
-#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
-#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
+#ifdef CONFIG_MACH_U5500
+#include <mach/irqs-board-u5500.h>
+#endif
 
-#define NR_IRQS                                IRQ_MODEM_EVENTS_END
+#define NR_IRQS                        IRQ_BOARD_END
 
 #endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-defs.h b/arch/arm/mach-ux500/include/mach/prcmu-defs.h
deleted file mode 100644 (file)
index 848ba64..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Martin Persson <martin.persson@stericsson.com>
- *
- * License Terms: GNU General Public License v2
- *
- * PRCM Unit definitions
- */
-
-#ifndef __MACH_PRCMU_DEFS_H
-#define __MACH_PRCMU_DEFS_H
-
-enum prcmu_cpu_opp {
-       CPU_OPP_INIT      = 0x00,
-       CPU_OPP_NO_CHANGE = 0x01,
-       CPU_OPP_100       = 0x02,
-       CPU_OPP_50        = 0x03,
-       CPU_OPP_MAX       = 0x04,
-       CPU_OPP_EXT_CLK   = 0x07
-};
-enum prcmu_ape_opp {
-       APE_OPP_NO_CHANGE = 0x00,
-       APE_OPP_100       = 0x02,
-       APE_OPP_50        = 0x03,
-};
-
-#endif /* __MACH_PRCMU_DEFS_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h
deleted file mode 100644 (file)
index c49e456..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- *
- * License Terms: GNU General Public License v2
- *
- * PRCM Unit f/w API
- */
-#ifndef __MACH_PRCMU_H
-#define __MACH_PRCMU_H
-#include <mach/prcmu-defs.h>
-
-void __init prcmu_early_init(void);
-int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
-int prcmu_set_ape_opp(enum prcmu_ape_opp opp);
-int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp);
-int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
-                          enum prcmu_cpu_opp cpu_opp);
-int prcmu_get_ape_opp(void);
-int prcmu_get_cpu_opp(void);
-bool prcmu_has_arm_maxopp(void);
-
-#endif /* __MACH_PRCMU_H */
diff --git a/arch/arm/mach-ux500/prcmu.c b/arch/arm/mach-ux500/prcmu.c
deleted file mode 100644 (file)
index c522d26..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- *
- * U8500 PRCM Unit interface driver
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/completion.h>
-#include <linux/jiffies.h>
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-
-#include <mach/hardware.h>
-#include <mach/prcmu-regs.h>
-#include <mach/prcmu-defs.h>
-
-/* Global var to runtime determine TCDM base for v2 or v1 */
-static __iomem void *tcdm_base;
-
-#define _MBOX_HEADER           (tcdm_base + 0xFE8)
-#define MBOX_HEADER_REQ_MB0    (_MBOX_HEADER + 0x0)
-
-#define REQ_MB1 (tcdm_base + 0xFD0)
-#define REQ_MB5 (tcdm_base + 0xE44)
-
-#define REQ_MB1_ARMOPP         (REQ_MB1 + 0x0)
-#define REQ_MB1_APEOPP         (REQ_MB1 + 0x1)
-#define REQ_MB1_BOOSTOPP       (REQ_MB1 + 0x2)
-
-#define ACK_MB1 (tcdm_base + 0xE04)
-#define ACK_MB5 (tcdm_base + 0xDF4)
-
-#define ACK_MB1_CURR_ARMOPP            (ACK_MB1 + 0x0)
-#define ACK_MB1_CURR_APEOPP            (ACK_MB1 + 0x1)
-
-#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
-#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
-#define REQ_MB5_I2C_REG (REQ_MB5 + 2)
-#define REQ_MB5_I2C_VAL (REQ_MB5 + 3)
-
-#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
-#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
-
-#define PRCM_AVS_VARM_MAX_OPP          (tcdm_base + 0x2E4)
-#define PRCM_AVS_ISMODEENABLE          7
-#define PRCM_AVS_ISMODEENABLE_MASK     (1 << PRCM_AVS_ISMODEENABLE)
-
-#define I2C_WRITE(slave) \
-       (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
-#define I2C_READ(slave) \
-       (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0))
-#define I2C_STOP_EN BIT(3)
-
-enum mb1_h {
-       MB1H_ARM_OPP = 1,
-       MB1H_APE_OPP,
-       MB1H_ARM_APE_OPP,
-};
-
-static struct {
-       struct mutex lock;
-       struct completion work;
-       struct {
-               u8 arm_opp;
-               u8 ape_opp;
-               u8 arm_status;
-               u8 ape_status;
-       } ack;
-} mb1_transfer;
-
-enum ack_mb5_status {
-       I2C_WR_OK = 0x01,
-       I2C_RD_OK = 0x02,
-};
-
-#define MBOX_BIT BIT
-#define NUM_MBOX 8
-
-static struct {
-       struct mutex lock;
-       struct completion work;
-       bool failed;
-       struct {
-               u8 status;
-               u8 value;
-       } ack;
-} mb5_transfer;
-
-/**
- * prcmu_abb_read() - Read register value(s) from the ABB.
- * @slave:     The I2C slave address.
- * @reg:       The (start) register address.
- * @value:     The read out value(s).
- * @size:      The number of registers to read.
- *
- * Reads register value(s) from the ABB.
- * @size has to be 1 for the current firmware version.
- */
-int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
-{
-       int r;
-
-       if (size != 1)
-               return -EINVAL;
-
-       r = mutex_lock_interruptible(&mb5_transfer.lock);
-       if (r)
-               return r;
-
-       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
-               cpu_relax();
-
-       writeb(I2C_READ(slave), REQ_MB5_I2C_SLAVE_OP);
-       writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
-       writeb(reg, REQ_MB5_I2C_REG);
-
-       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
-       if (!wait_for_completion_timeout(&mb5_transfer.work,
-                       msecs_to_jiffies(500))) {
-               pr_err("prcmu: prcmu_abb_read timed out.\n");
-               r = -EIO;
-               goto unlock_and_return;
-       }
-       r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
-       if (!r)
-               *value = mb5_transfer.ack.value;
-
-unlock_and_return:
-       mutex_unlock(&mb5_transfer.lock);
-       return r;
-}
-EXPORT_SYMBOL(prcmu_abb_read);
-
-/**
- * prcmu_abb_write() - Write register value(s) to the ABB.
- * @slave:     The I2C slave address.
- * @reg:       The (start) register address.
- * @value:     The value(s) to write.
- * @size:      The number of registers to write.
- *
- * Reads register value(s) from the ABB.
- * @size has to be 1 for the current firmware version.
- */
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
-{
-       int r;
-
-       if (size != 1)
-               return -EINVAL;
-
-       r = mutex_lock_interruptible(&mb5_transfer.lock);
-       if (r)
-               return r;
-
-
-       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
-               cpu_relax();
-
-       writeb(I2C_WRITE(slave), REQ_MB5_I2C_SLAVE_OP);
-       writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
-       writeb(reg, REQ_MB5_I2C_REG);
-       writeb(*value, REQ_MB5_I2C_VAL);
-
-       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
-       if (!wait_for_completion_timeout(&mb5_transfer.work,
-                       msecs_to_jiffies(500))) {
-               pr_err("prcmu: prcmu_abb_write timed out.\n");
-               r = -EIO;
-               goto unlock_and_return;
-       }
-       r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
-
-unlock_and_return:
-       mutex_unlock(&mb5_transfer.lock);
-       return r;
-}
-EXPORT_SYMBOL(prcmu_abb_write);
-
-static int set_ape_cpu_opps(u8 header, enum prcmu_ape_opp ape_opp,
-                           enum prcmu_cpu_opp cpu_opp)
-{
-       bool do_ape;
-       bool do_arm;
-       int err = 0;
-
-       do_ape = ((header == MB1H_APE_OPP) || (header == MB1H_ARM_APE_OPP));
-       do_arm = ((header == MB1H_ARM_OPP) || (header == MB1H_ARM_APE_OPP));
-
-       mutex_lock(&mb1_transfer.lock);
-
-       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
-               cpu_relax();
-
-       writeb(0, MBOX_HEADER_REQ_MB0);
-       writeb(cpu_opp, REQ_MB1_ARMOPP);
-       writeb(ape_opp, REQ_MB1_APEOPP);
-       writeb(0, REQ_MB1_BOOSTOPP);
-       writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
-       wait_for_completion(&mb1_transfer.work);
-       if ((do_ape) && (mb1_transfer.ack.ape_status != 0))
-               err = -EIO;
-       if ((do_arm) && (mb1_transfer.ack.arm_status != 0))
-               err = -EIO;
-
-       mutex_unlock(&mb1_transfer.lock);
-
-       return err;
-}
-
-/**
- * prcmu_set_ape_opp() - Set the OPP of the APE.
- * @opp:       The OPP to set.
- *
- * This function sets the OPP of the APE.
- */
-int prcmu_set_ape_opp(enum prcmu_ape_opp opp)
-{
-       return set_ape_cpu_opps(MB1H_APE_OPP, opp, APE_OPP_NO_CHANGE);
-}
-EXPORT_SYMBOL(prcmu_set_ape_opp);
-
-/**
- * prcmu_set_cpu_opp() - Set the OPP of the CPU.
- * @opp:       The OPP to set.
- *
- * This function sets the OPP of the CPU.
- */
-int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp)
-{
-       return set_ape_cpu_opps(MB1H_ARM_OPP, CPU_OPP_NO_CHANGE, opp);
-}
-EXPORT_SYMBOL(prcmu_set_cpu_opp);
-
-/**
- * prcmu_set_ape_cpu_opps() - Set the OPPs of the APE and the CPU.
- * @ape_opp:   The APE OPP to set.
- * @cpu_opp:   The CPU OPP to set.
- *
- * This function sets the OPPs of the APE and the CPU.
- */
-int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
-                          enum prcmu_cpu_opp cpu_opp)
-{
-       return set_ape_cpu_opps(MB1H_ARM_APE_OPP, ape_opp, cpu_opp);
-}
-EXPORT_SYMBOL(prcmu_set_ape_cpu_opps);
-
-/**
- * prcmu_get_ape_opp() - Get the OPP of the APE.
- *
- * This function gets the OPP of the APE.
- */
-enum prcmu_ape_opp prcmu_get_ape_opp(void)
-{
-       return readb(ACK_MB1_CURR_APEOPP);
-}
-EXPORT_SYMBOL(prcmu_get_ape_opp);
-
-/**
- * prcmu_get_cpu_opp() - Get the OPP of the CPU.
- *
- * This function gets the OPP of the CPU. The OPP is specified in %%.
- * PRCMU_OPP_EXT is a special OPP value, not specified in %%.
- */
-int prcmu_get_cpu_opp(void)
-{
-       return readb(ACK_MB1_CURR_ARMOPP);
-}
-EXPORT_SYMBOL(prcmu_get_cpu_opp);
-
-bool prcmu_has_arm_maxopp(void)
-{
-       return (readb(PRCM_AVS_VARM_MAX_OPP) & PRCM_AVS_ISMODEENABLE_MASK)
-               == PRCM_AVS_ISMODEENABLE_MASK;
-}
-
-static void read_mailbox_0(void)
-{
-       writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_1(void)
-{
-       mb1_transfer.ack.arm_opp = readb(ACK_MB1_CURR_ARMOPP);
-       mb1_transfer.ack.ape_opp = readb(ACK_MB1_CURR_APEOPP);
-       complete(&mb1_transfer.work);
-       writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_2(void)
-{
-       writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_3(void)
-{
-       writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_4(void)
-{
-       writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_5(void)
-{
-       mb5_transfer.ack.status = readb(ACK_MB5_I2C_STATUS);
-       mb5_transfer.ack.value = readb(ACK_MB5_I2C_VAL);
-       complete(&mb5_transfer.work);
-       writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_6(void)
-{
-       writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_7(void)
-{
-       writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
-}
-
-static void (* const read_mailbox[NUM_MBOX])(void) = {
-       read_mailbox_0,
-       read_mailbox_1,
-       read_mailbox_2,
-       read_mailbox_3,
-       read_mailbox_4,
-       read_mailbox_5,
-       read_mailbox_6,
-       read_mailbox_7
-};
-
-static irqreturn_t prcmu_irq_handler(int irq, void *data)
-{
-       u32 bits;
-       u8 n;
-
-       bits = (readl(PRCM_ARM_IT1_VAL) & (MBOX_BIT(NUM_MBOX) - 1));
-       if (unlikely(!bits))
-               return IRQ_NONE;
-
-       for (n = 0; bits; n++) {
-               if (bits & MBOX_BIT(n)) {
-                       bits -= MBOX_BIT(n);
-                       read_mailbox[n]();
-               }
-       }
-       return IRQ_HANDLED;
-}
-
-void __init prcmu_early_init(void)
-{
-       if (cpu_is_u8500v11() || cpu_is_u8500ed()) {
-               tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
-       } else if (cpu_is_u8500v2()) {
-               tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
-       } else {
-               pr_err("prcmu: Unsupported chip version\n");
-               BUG();
-       }
-}
-
-static int __init prcmu_init(void)
-{
-       if (cpu_is_u8500ed()) {
-               pr_err("prcmu: Unsupported chip version\n");
-               return 0;
-       }
-
-       mutex_init(&mb1_transfer.lock);
-       init_completion(&mb1_transfer.work);
-       mutex_init(&mb5_transfer.lock);
-       init_completion(&mb5_transfer.work);
-
-       /* Clean up the mailbox interrupts after pre-kernel code. */
-       writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR);
-
-       return request_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, 0,
-                          "prcmu", NULL);
-}
-
-arch_initcall(prcmu_init);
index c96fa1b3f49f5d78b670289a1d8fc8ccf3b38b30..73b4a8b66a575cabbbac35cf3611b2991777e640 100644 (file)
@@ -176,6 +176,7 @@ ENDPROC(v6_coherent_kern_range)
  */
 ENTRY(v6_flush_kern_dcache_area)
        add     r1, r0, r1
+       bic     r0, r0, #D_CACHE_LINE_SIZE - 1
 1:
 #ifdef HARVARD_CACHE
        mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line
index dc18d81ef8ce5d94e8f7e9c62515bf8624cd79c8..d32f02b618663d985b90b61d9a91996997c85433 100644 (file)
@@ -221,6 +221,8 @@ ENDPROC(v7_coherent_user_range)
 ENTRY(v7_flush_kern_dcache_area)
        dcache_line_size r2, r3
        add     r1, r0, r1
+       sub     r3, r2, #1
+       bic     r0, r0, r3
 1:
        mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line / unified line
        add     r0, r0, r2
index b0ee9ba3cfab41a52853eca727466abff88ddf27..8bfae964b133987e061c430a0426f951b07172fa 100644 (file)
@@ -24,9 +24,7 @@ DEFINE_PER_CPU(struct mm_struct *, current_mm);
 
 /*
  * We fork()ed a process, and we need a new context for the child
- * to run in.  We reserve version 0 for initial tasks so we will
- * always allocate an ASID. The ASID 0 is reserved for the TTBR
- * register changing sequence.
+ * to run in.
  */
 void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
@@ -36,8 +34,11 @@ void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 
 static void flush_context(void)
 {
-       /* set the reserved ASID before flushing the TLB */
-       asm("mcr        p15, 0, %0, c13, c0, 1\n" : : "r" (0));
+       u32 ttb;
+       /* Copy TTBR1 into TTBR0 */
+       asm volatile("mrc       p15, 0, %0, c2, c0, 1\n"
+                    "mcr       p15, 0, %0, c2, c0, 0"
+                    : "=r" (ttb));
        isb();
        local_flush_tlb_all();
        if (icache_is_vivt_asid_tagged()) {
@@ -93,7 +94,7 @@ static void reset_context(void *info)
                return;
 
        smp_rmb();
-       asid = cpu_last_asid + cpu + 1;
+       asid = cpu_last_asid + cpu;
 
        flush_context();
        set_mm_context(mm, asid);
@@ -143,13 +144,13 @@ void __new_context(struct mm_struct *mm)
         * to start a new version and flush the TLB.
         */
        if (unlikely((asid & ~ASID_MASK) == 0)) {
-               asid = cpu_last_asid + smp_processor_id() + 1;
+               asid = cpu_last_asid + smp_processor_id();
                flush_context();
 #ifdef CONFIG_SMP
                smp_wmb();
                smp_call_function(reset_context, NULL, 1);
 #endif
-               cpu_last_asid += NR_CPUS;
+               cpu_last_asid += NR_CPUS - 1;
        }
 
        set_mm_context(mm, asid);
index 751767279b3e36843882fb15126f00d5996dfd74..2c2cce9cd8c8399e02cf841298649daf72d06330 100644 (file)
@@ -95,7 +95,7 @@ void show_mem(unsigned int filter)
        struct meminfo * mi = &meminfo;
 
        printk("Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
 
        for_each_bank (i, mi) {
                struct membank *bank = &mi->bank[i];
@@ -283,13 +283,15 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
        free_area_init_node(0, zone_size, min, zhole_size);
 }
 
-#ifndef CONFIG_SPARSEMEM
+#ifdef CONFIG_HAVE_ARCH_PFN_VALID
 int pfn_valid(unsigned long pfn)
 {
        return memblock_is_memory(pfn << PAGE_SHIFT);
 }
 EXPORT_SYMBOL(pfn_valid);
+#endif
 
+#ifndef CONFIG_SPARSEMEM
 static void arm_memory_present(void)
 {
 }
index d2384106af9cbb32f96a61d54570ef39d391c5b7..5b3d7d543659154b36d3a568be429ebc096819e0 100644 (file)
@@ -5,14 +5,9 @@ extern pmd_t *top_pmd;
 
 #define TOP_PTE(x)     pte_offset_kernel(top_pmd, x)
 
-static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
-{
-       return pmd_offset(pud_offset(pgd, virt), virt);
-}
-
 static inline pmd_t *pmd_off_k(unsigned long virt)
 {
-       return pmd_off(pgd_offset_k(virt), virt);
+       return pmd_offset(pud_offset(pgd_offset_k(virt), virt), virt);
 }
 
 struct mem_type {
index 6cf76b3b68d1f374fcbc6be0c38224161f7db477..9d9e736c2b4f4afe2a90190d8b583c8e1f0c656a 100644 (file)
@@ -31,8 +31,6 @@
 
 #include "mm.h"
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * empty_zero_page is a special page that is used for
  * zero-initialized data and COW.
@@ -765,15 +763,12 @@ static void __init sanity_check_meminfo(void)
 {
        int i, j, highmem = 0;
 
-       lowmem_limit = __pa(vmalloc_min - 1) + 1;
-       memblock_set_current_limit(lowmem_limit);
-
        for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
                struct membank *bank = &meminfo.bank[j];
                *bank = meminfo.bank[i];
 
 #ifdef CONFIG_HIGHMEM
-               if (__va(bank->start) > vmalloc_min ||
+               if (__va(bank->start) >= vmalloc_min ||
                    __va(bank->start) < (void *)PAGE_OFFSET)
                        highmem = 1;
 
@@ -831,6 +826,9 @@ static void __init sanity_check_meminfo(void)
                        bank->size = newsize;
                }
 #endif
+               if (!bank->highmem && bank->start + bank->size > lowmem_limit)
+                       lowmem_limit = bank->start + bank->size;
+
                j++;
        }
 #ifdef CONFIG_HIGHMEM
@@ -854,6 +852,7 @@ static void __init sanity_check_meminfo(void)
        }
 #endif
        meminfo.nr_banks = j;
+       memblock_set_current_limit(lowmem_limit);
 }
 
 static inline void prepare_page_table(void)
index ab17cc0d3fa7cd5f2d0a97b7c5539789b2f20c09..1d2b8451bf25c24f9e66ac10f83faf54ebcdc401 100644 (file)
@@ -213,7 +213,9 @@ __v6_setup:
        mcr     p15, 0, r0, c2, c0, 2           @ TTB control register
        ALT_SMP(orr     r4, r4, #TTB_FLAGS_SMP)
        ALT_UP(orr      r4, r4, #TTB_FLAGS_UP)
-       mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
+       ALT_SMP(orr     r8, r8, #TTB_FLAGS_SMP)
+       ALT_UP(orr      r8, r8, #TTB_FLAGS_UP)
+       mcr     p15, 0, r8, c2, c0, 1           @ load TTB1
 #endif /* CONFIG_MMU */
        adr     r5, v6_crval
        ldmia   r5, {r5, r6}
index babfba09c89ff390deb7ddfd0496e813f442e047..b3b566ec83d397c1074c1dcbee0d5e33542e7d9c 100644 (file)
@@ -108,18 +108,16 @@ ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_ARM_ERRATA_430973
        mcr     p15, 0, r2, c7, c5, 6           @ flush BTAC/BTB
 #endif
-#ifdef CONFIG_ARM_ERRATA_754322
-       dsb
-#endif
-       mcr     p15, 0, r2, c13, c0, 1          @ set reserved context ID
-       isb
-1:     mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
+       mrc     p15, 0, r2, c2, c0, 1           @ load TTB 1
+       mcr     p15, 0, r2, c2, c0, 0           @ into TTB 0
        isb
 #ifdef CONFIG_ARM_ERRATA_754322
        dsb
 #endif
        mcr     p15, 0, r1, c13, c0, 1          @ set context ID
        isb
+       mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
+       isb
 #endif
        mov     pc, lr
 ENDPROC(cpu_v7_switch_mm)
@@ -368,7 +366,9 @@ __v7_setup:
        mcr     p15, 0, r10, c2, c0, 2          @ TTB control register
        ALT_SMP(orr     r4, r4, #TTB_FLAGS_SMP)
        ALT_UP(orr      r4, r4, #TTB_FLAGS_UP)
-       mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
+       ALT_SMP(orr     r8, r8, #TTB_FLAGS_SMP)
+       ALT_UP(orr      r8, r8, #TTB_FLAGS_UP)
+       mcr     p15, 0, r8, c2, c0, 1           @ load TTB1
        ldr     r5, =PRRR                       @ PRRR
        ldr     r6, =NMRR                       @ NMRR
        mcr     p15, 0, r5, c10, c2, 0          @ write PRRR
index a7314d44b17ba5a2afd1bd83b3edaf8cea222c33..2798c2d4a1cf9c79e43df9df28378394d0cdd60a 100644 (file)
@@ -25,8 +25,6 @@
 #include <asm/setup.h>
 #include <asm/sections.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_data;
 
 struct page *empty_zero_page;
index 8addb1220b4f290c5ec23eefa1f6f245b5753267..a18180f2d007aa3d5e70a5b9fa6da7a01ad7b60c 100644 (file)
@@ -24,11 +24,13 @@ config BLACKFIN
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_IDE
+       select HAVE_IRQ_WORK
        select HAVE_KERNEL_GZIP if RAMKERNEL
        select HAVE_KERNEL_BZIP2 if RAMKERNEL
        select HAVE_KERNEL_LZMA if RAMKERNEL
        select HAVE_KERNEL_LZO if RAMKERNEL
        select HAVE_OPROFILE
+       select HAVE_PERF_EVENTS
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_ATOMIC64
index 2641731f24cd12835e92da4dec18d0f61dee9f68..e2a3d4c8ab9aca33059de9475941007a595a9113 100644 (file)
@@ -9,15 +9,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T output.
-
-         This option will slow down process creation somewhat.
-
 config DEBUG_VERBOSE
        bool "Verbose fault messages"
        default y
@@ -32,7 +23,7 @@ config DEBUG_VERBOSE
          Most people should say N here.
 
 config DEBUG_MMRS
-       bool "Generate Blackfin MMR tree"
+       tristate "Generate Blackfin MMR tree"
        select DEBUG_FS
        help
          Create a tree of Blackfin MMRs via the debugfs tree.  If
index 95cf2ba9de17ba2e95337efc8de0d14f3a21e754..8465b3e6b8628a23b5961471c46de0adf617d1db 100644 (file)
@@ -121,13 +121,11 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 # CONFIG_LOGO_BLACKFIN_VGA16 is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SOC=m
-CONFIG_SND_BF5XX_I2S=m
-CONFIG_SND_BF5XX_SOC_SSM2602=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_BF5XX_I2S=y
+CONFIG_SND_BF5XX_SOC_SSM2602=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
index 8be8e33fac526c7eb6526f39ce9f44c7a1521ab9..5e7321b26040665fb4a6a3b74db5c82208af2107 100644 (file)
@@ -96,7 +96,7 @@ CONFIG_SERIAL_BFIN_UART1=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_BLACKFIN_TWI=m
+CONFIG_I2C_BLACKFIN_TWI=y
 CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
 CONFIG_SPI=y
 CONFIG_SPI_BFIN=y
@@ -115,13 +115,11 @@ CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 # CONFIG_LOGO_BLACKFIN_VGA16 is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SOC=m
-CONFIG_SND_BF5XX_I2S=m
-CONFIG_SND_BF5XX_SOC_SSM2602=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_BF5XX_I2S=y
+CONFIG_SND_BF5XX_SOC_SSM2602=y
 CONFIG_HID_A4TECH=y
 CONFIG_HID_APPLE=y
 CONFIG_HID_BELKIN=y
index 0aafde6c8c2d00fd079c62999fb60cf7023dcc87..b90d3792ed5209a46b2cd4342398d18e28bf531f 100644 (file)
@@ -99,8 +99,6 @@ CONFIG_SND_PCM_OSS=m
 CONFIG_SND_SOC=m
 CONFIG_SND_BF5XX_I2S=m
 CONFIG_SND_BF5XX_SOC_AD73311=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
 # CONFIG_USB_SUPPORT is not set
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_BFIN=y
index c9077fb581354bc621fe5e1ee152e9ae1933a56a..005362537a7b4c3f4d70dc46f864bd78feafcbf3 100644 (file)
@@ -110,8 +110,6 @@ CONFIG_SND_PCM_OSS=m
 CONFIG_SND_SOC=m
 CONFIG_SND_BF5XX_I2S=m
 CONFIG_SND_BF5XX_SOC_AD73311=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
 # CONFIG_USB_SUPPORT is not set
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_BFIN=y
index 121cc04d877d891c1e4594a9ade1795abf5991e4..17bcbf60bcae15641097aed9234ceae16a92e061 100644 (file)
@@ -49,16 +49,6 @@ extern void dump_bfin_trace_buffer(void);
 #define dump_bfin_trace_buffer()
 #endif
 
-/* init functions only */
-extern int init_arch_irq(void);
-extern void init_exception_vectors(void);
-extern void program_IAR(void);
-
-extern asmlinkage void lower_to_irq14(void);
-extern asmlinkage void bfin_return_from_exception(void);
-extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
-extern int bfin_internal_set_wake(unsigned int irq, unsigned int state);
-
 extern void *l1_data_A_sram_alloc(size_t);
 extern void *l1_data_B_sram_alloc(size_t);
 extern void *l1_inst_sram_alloc(size_t);
diff --git a/arch/blackfin/include/asm/bfin_pfmon.h b/arch/blackfin/include/asm/bfin_pfmon.h
new file mode 100644 (file)
index 0000000..accd47e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Blackfin Performance Monitor definitions
+ *
+ * Copyright 2005-2011 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or GPL-2 (or later).
+ */
+
+#ifndef __ASM_BFIN_PFMON_H__
+#define __ASM_BFIN_PFMON_H__
+
+/* PFCTL Masks */
+#define PFMON_MASK     0xff
+#define PFCEN_MASK     0x3
+#define PFCEN_DISABLE  0x0
+#define PFCEN_ENABLE_USER      0x1
+#define PFCEN_ENABLE_SUPV      0x2
+#define PFCEN_ENABLE_ALL       (PFCEN_ENABLE_USER | PFCEN_ENABLE_SUPV)
+
+#define PFPWR_P        0
+#define PEMUSW0_P      2
+#define PFCEN0_P       3
+#define PFMON0_P       5
+#define PEMUSW1_P      13
+#define PFCEN1_P       14
+#define PFMON1_P       16
+#define PFCNT0_P       24
+#define PFCNT1_P       25
+
+#define PFPWR  (1 << PFPWR_P)
+#define PEMUSW(n, x)   ((x) << ((n) ? PEMUSW1_P : PEMUSW0_P))
+#define PEMUSW0        PEMUSW(0, 1)
+#define PEMUSW1        PEMUSW(1, 1)
+#define PFCEN(n, x)    ((x) << ((n) ? PFCEN1_P : PFCEN0_P))
+#define PFCEN0 PFCEN(0, PFCEN_MASK)
+#define PFCEN1 PFCEN(1, PFCEN_MASK)
+#define PFCNT(n, x)    ((x) << ((n) ? PFCNT1_P : PFCNT0_P))
+#define PFCNT0 PFCNT(0, 1)
+#define PFCNT1 PFCNT(1, 1)
+#define PFMON(n, x)    ((x) << ((n) ? PFMON1_P : PFMON0_P))
+#define PFMON0 PFMON(0, PFMON_MASK)
+#define PFMON1 PFMON(1, PFMON_MASK)
+
+#endif
index d27600c262c2b18427b0d28feed430440cbd6452..f8568a31d0ab5fb0c8e0893176fcbf348df8b2d6 100644 (file)
@@ -100,6 +100,10 @@ struct sport_register {
 };
 #undef __BFP
 
+struct bfin_snd_platform_data {
+       const unsigned short *pin_req;
+};
+
 #define bfin_read_sport_rx32(base) \
 ({ \
        struct sport_register *__mmrs = (void *)base; \
index 77135b62818e16794db3d441debbec3c0cfb7254..9a5b2c572ebfb6b55fbe5f36add07ec3d4ed3903 100644 (file)
@@ -39,8 +39,13 @@ extern void blackfin_invalidate_entire_icache(void);
 
 static inline void flush_icache_range(unsigned start, unsigned end)
 {
-#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
-       blackfin_dcache_flush_range(start, end);
+#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK)
+       if (end <= physical_mem_end)
+               blackfin_dcache_flush_range(start, end);
+#endif
+#if defined(CONFIG_BFIN_L2_WRITEBACK)
+       if (start >= L2_START && end <= L2_START + L2_LENGTH)
+               blackfin_dcache_flush_range(start, end);
 #endif
 
        /* Make sure all write buffers in the data side of the core
@@ -52,9 +57,17 @@ static inline void flush_icache_range(unsigned start, unsigned end)
         * the pipeline.
         */
        SSYNC();
-#if defined(CONFIG_BFIN_ICACHE)
-       blackfin_icache_flush_range(start, end);
-       flush_icache_range_others(start, end);
+#if defined(CONFIG_BFIN_EXTMEM_ICACHEABLE)
+       if (end <= physical_mem_end) {
+               blackfin_icache_flush_range(start, end);
+               flush_icache_range_others(start, end);
+       }
+#endif
+#if defined(CONFIG_BFIN_L2_ICACHEABLE)
+       if (start >= L2_START && end <= L2_START + L2_LENGTH) {
+               blackfin_icache_flush_range(start, end);
+               flush_icache_range_others(start, end);
+       }
 #endif
 }
 
index 16883e582e3cd96ce9a914242837f877e3a77f16..05043786da2199cbb302563a0c1e3e62295852c2 100644 (file)
 
 #include <linux/percpu.h>
 
-struct task_struct;
-
 struct blackfin_cpudata {
        struct cpu cpu;
-       struct task_struct *idle;
        unsigned int imemctl;
        unsigned int dmemctl;
 };
index 7600fe0696af1c9cda33471b1bf8a963e43df303..8236790114575eb9e2dc4df8e21c3cbf0413376c 100644 (file)
 
 #define bfin_read(addr) \
 ({ \
-    sizeof(*(addr)) == 1 ? bfin_read8(addr)  : \
-    sizeof(*(addr)) == 2 ? bfin_read16(addr) : \
-    sizeof(*(addr)) == 4 ? bfin_read32(addr) : \
-    ({ BUG(); 0; }); \
+       sizeof(*(addr)) == 1 ? bfin_read8(addr)  : \
+       sizeof(*(addr)) == 2 ? bfin_read16(addr) : \
+       sizeof(*(addr)) == 4 ? bfin_read32(addr) : \
+       ({ BUG(); 0; }); \
 })
 #define bfin_write(addr, val) \
 do { \
@@ -69,13 +69,13 @@ do { \
 
 #define bfin_write_or(addr, bits) \
 do { \
-       void *__addr = (void *)(addr); \
+       typeof(addr) __addr = (addr); \
        bfin_write(__addr, bfin_read(__addr) | (bits)); \
 } while (0)
 
 #define bfin_write_and(addr, bits) \
 do { \
-       void *__addr = (void *)(addr); \
+       typeof(addr) __addr = (addr); \
        bfin_write(__addr, bfin_read(__addr) & (bits)); \
 } while (0)
 
index 7fbe42307b9a4ce176be29458fba04b2769a20d6..ee73f79aef1025759a27c9a27ed1f0d89120fdcf 100644 (file)
 #include <linux/types.h>
 #include <linux/linkage.h>
 
+/* init functions only */
+extern int __init init_arch_irq(void);
+extern void init_exception_vectors(void);
+extern void __init program_IAR(void);
+#ifdef init_mach_irq
+extern void __init init_mach_irq(void);
+#else
+# define init_mach_irq()
+#endif
+
 /* BASE LEVEL interrupt handler routines */
 asmlinkage void evt_exception(void);
 asmlinkage void trap(void);
@@ -37,4 +47,19 @@ extern void return_from_exception(void);
 extern int bfin_request_exception(unsigned int exception, void (*handler)(void));
 extern int bfin_free_exception(unsigned int exception, void (*handler)(void));
 
+extern asmlinkage void lower_to_irq14(void);
+extern asmlinkage void bfin_return_from_exception(void);
+extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
+extern int bfin_internal_set_wake(unsigned int irq, unsigned int state);
+
+struct irq_data;
+extern void bfin_handle_irq(unsigned irq);
+extern void bfin_ack_noop(struct irq_data *);
+extern void bfin_internal_mask_irq(unsigned int irq);
+extern void bfin_internal_unmask_irq(unsigned int irq);
+
+struct irq_desc;
+extern void bfin_demux_mac_status_irq(unsigned int, struct irq_desc *);
+extern void bfin_demux_gpio_irq(unsigned int, struct irq_desc *);
+
 #endif
index 8651afe1299027502afd3700b4394ae3dfcf0b85..3ac0c72e9fee864c370955bc6ff1d8cc64c132f1 100644 (file)
@@ -103,7 +103,11 @@ static inline void arch_kgdb_breakpoint(void)
        asm("EXCPT 2;");
 }
 #define BREAK_INSTR_SIZE       2
-#define CACHE_FLUSH_IS_SAFE    1
+#ifdef CONFIG_SMP
+# define CACHE_FLUSH_IS_SAFE   0
+#else
+# define CACHE_FLUSH_IS_SAFE   1
+#endif
 #define HW_INST_WATCHPOINT_NUM 6
 #define HW_WATCHPOINT_NUM      8
 #define TYPE_INST_WATCHPOINT   0
diff --git a/arch/blackfin/include/asm/perf_event.h b/arch/blackfin/include/asm/perf_event.h
new file mode 100644 (file)
index 0000000..3d2b171
--- /dev/null
@@ -0,0 +1 @@
+#define MAX_HWEVENTS 2
index 832d7c009a2cf5ed890a5e54a33074444b4d0e84..1066d63e62b5da4683a2a2c0bf393c72eda1b939 100644 (file)
@@ -108,8 +108,6 @@ struct pt_regs {
 extern void show_regs(struct pt_regs *);
 
 #define arch_has_single_step() (1)
-extern void user_enable_single_step(struct task_struct *child);
-extern void user_disable_single_step(struct task_struct *child);
 /* common code demands this function */
 #define ptrace_disable(child) user_disable_single_step(child)
 
diff --git a/arch/blackfin/include/mach-common/irq.h b/arch/blackfin/include/mach-common/irq.h
new file mode 100644 (file)
index 0000000..cab14e9
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Common Blackfin IRQ definitions (i.e. the CEC)
+ *
+ * Copyright 2005-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_COMMON_IRQ_H_
+#define _MACH_COMMON_IRQ_H_
+
+/*
+ * Core events interrupt source definitions
+ *
+ *  Event Source       Event Name
+ *  Emulation          EMU            0  (highest priority)
+ *  Reset              RST            1
+ *  NMI                NMI            2
+ *  Exception          EVX            3
+ *  Reserved           --             4
+ *  Hardware Error     IVHW           5
+ *  Core Timer         IVTMR          6
+ *  Peripherals        IVG7           7
+ *  Peripherals        IVG8           8
+ *  Peripherals        IVG9           9
+ *  Peripherals        IVG10         10
+ *  Peripherals        IVG11         11
+ *  Peripherals        IVG12         12
+ *  Peripherals        IVG13         13
+ *  Softirq            IVG14         14
+ *  System Call        IVG15         15  (lowest priority)
+ */
+
+/* The ABSTRACT IRQ definitions */
+#define IRQ_EMU                        0       /* Emulation */
+#define IRQ_RST                        1       /* reset */
+#define IRQ_NMI                        2       /* Non Maskable */
+#define IRQ_EVX                        3       /* Exception */
+#define IRQ_UNUSED             4       /* - unused interrupt */
+#define IRQ_HWERR              5       /* Hardware Error */
+#define IRQ_CORETMR            6       /* Core timer */
+
+#define BFIN_IRQ(x)            ((x) + 7)
+
+#define IVG7                   7
+#define IVG8                   8
+#define IVG9                   9
+#define IVG10                  10
+#define IVG11                  11
+#define IVG12                  12
+#define IVG13                  13
+#define IVG14                  14
+#define IVG15                  15
+
+#define NR_IRQS                        (NR_MACH_IRQS + NR_SPARE_IRQS)
+
+#endif
index ca5ccc777772097ee66854c18e0fa4e6cb07dbfb..d550b24d9e9b2a9fa6a78bbb3783b1031845a57e 100644 (file)
@@ -33,7 +33,10 @@ obj-$(CONFIG_EARLY_PRINTK)           += shadow_console.o
 obj-$(CONFIG_STACKTRACE)             += stacktrace.o
 obj-$(CONFIG_DEBUG_VERBOSE)          += trace.o
 obj-$(CONFIG_BFIN_PSEUDODBG_INSNS)   += pseudodbg.o
+obj-$(CONFIG_PERF_EVENTS)            += perf_event.o
 
 # the kgdb test puts code into L2 and without linker
 # relaxation, we need to force long calls to/from it
 CFLAGS_kgdb_test.o := -mlong-calls -O0
+
+obj-$(CONFIG_DEBUG_MMRS)             += debug-mmrs.o
index 6ce8dce753c9a49039a615e56cf8e83fbb8097bf..71dbaa4a48afc1263b23af017702ea82aedb2557 100644 (file)
@@ -36,6 +36,11 @@ static int __init blackfin_dma_init(void)
 
        printk(KERN_INFO "Blackfin DMA Controller\n");
 
+
+#if ANOMALY_05000480
+       bfin_write_DMAC_TC_PER(0x0111);
+#endif
+
        for (i = 0; i < MAX_DMA_CHANNELS; i++) {
                atomic_set(&dma_ch[i].chan_status, 0);
                dma_ch[i].regs = dma_io_base_addr[i];
index 170cf90735ba6cb806ee002b7041313760ebae2a..bcf8cf6fe4126d6608a560b39e2b92ade8b89a7a 100644 (file)
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <asm/blackfin.h>
 #include <asm/gpio.h>
 #include <asm/portmux.h>
 #include <linux/irq.h>
+#include <asm/irq_handler.h>
 
 #if ANOMALY_05000311 || ANOMALY_05000323
 enum {
@@ -534,7 +536,7 @@ static const unsigned int sic_iwr_irqs[] = {
 #if defined(BF533_FAMILY)
        IRQ_PROG_INTB
 #elif defined(BF537_FAMILY)
-       IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX
+       IRQ_PF_INTB_WATCH, IRQ_PORTG_INTB, IRQ_PH_INTB_MAC_TX
 #elif defined(BF538_FAMILY)
        IRQ_PORTF_INTB
 #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
@@ -1203,35 +1205,43 @@ void bfin_reset_boot_spi_cs(unsigned short pin)
 }
 
 #if defined(CONFIG_PROC_FS)
-static int gpio_proc_read(char *buf, char **start, off_t offset,
-                         int len, int *unused_i, void *unused_v)
+static int gpio_proc_show(struct seq_file *m, void *v)
 {
-       int c, irq, gpio, outlen = 0;
+       int c, irq, gpio;
 
        for (c = 0; c < MAX_RESOURCES; c++) {
                irq = is_reserved(gpio_irq, c, 1);
                gpio = is_reserved(gpio, c, 1);
                if (!check_gpio(c) && (gpio || irq))
-                       len = sprintf(buf, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c,
+                       seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c,
                                 get_label(c), (gpio && irq) ? " *" : "",
                                 get_gpio_dir(c) ? "OUTPUT" : "INPUT");
                else if (is_reserved(peri, c, 1))
-                       len = sprintf(buf, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c));
+                       seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c));
                else
                        continue;
-               buf += len;
-               outlen += len;
        }
-       return outlen;
+
+       return 0;
 }
 
+static int gpio_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, gpio_proc_show, NULL);
+}
+
+static const struct file_operations gpio_proc_ops = {
+       .open           = gpio_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static __init int gpio_register_proc(void)
 {
        struct proc_dir_entry *proc_gpio;
 
-       proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL);
-       if (proc_gpio)
-               proc_gpio->read_proc = gpio_proc_read;
+       proc_gpio = proc_create("gpio", S_IRUGO, NULL, &gpio_proc_ops);
        return proc_gpio != NULL;
 }
 __initcall(gpio_register_proc);
index 2c264b51566afa2d7ca45b8ad129fcc8384e89c0..c446591b961ddc7d922ead4be15e58ae94158687 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <asm/cacheflush.h>
 #include <asm/io.h>
+#include <asm/irq_handler.h>
 
 /* Allow people to have their own Blackfin exception handler in a module */
 EXPORT_SYMBOL(bfin_return_from_exception);
diff --git a/arch/blackfin/kernel/debug-mmrs.c b/arch/blackfin/kernel/debug-mmrs.c
new file mode 100644 (file)
index 0000000..94b1d8a
--- /dev/null
@@ -0,0 +1,1860 @@
+/*
+ * debugfs interface to core/system MMRs
+ *
+ * Copyright 2007-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/bfin_can.h>
+#include <asm/bfin_dma.h>
+#include <asm/bfin_ppi.h>
+#include <asm/bfin_serial.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/bfin_twi.h>
+
+/* Common code defines PORT_MUX on us, so redirect the MMR back locally */
+#ifdef BFIN_PORT_MUX
+#undef PORT_MUX
+#define PORT_MUX BFIN_PORT_MUX
+#endif
+
+#define _d(name, bits, addr, perms) debugfs_create_x##bits(name, perms, parent, (u##bits *)addr)
+#define d(name, bits, addr)         _d(name, bits, addr, S_IRUSR|S_IWUSR)
+#define d_RO(name, bits, addr)      _d(name, bits, addr, S_IRUSR)
+#define d_WO(name, bits, addr)      _d(name, bits, addr, S_IWUSR)
+
+#define D_RO(name, bits) d_RO(#name, bits, name)
+#define D_WO(name, bits) d_WO(#name, bits, name)
+#define D32(name)        d(#name, 32, name)
+#define D16(name)        d(#name, 16, name)
+
+#define REGS_OFF(peri, mmr) offsetof(struct bfin_##peri##_regs, mmr)
+#define __REGS(peri, sname, rname) \
+       do { \
+               struct bfin_##peri##_regs r; \
+               void *addr = (void *)(base + REGS_OFF(peri, rname)); \
+               strcpy(_buf, sname); \
+               if (sizeof(r.rname) == 2) \
+                       debugfs_create_x16(buf, S_IRUSR|S_IWUSR, parent, addr); \
+               else \
+                       debugfs_create_x32(buf, S_IRUSR|S_IWUSR, parent, addr); \
+       } while (0)
+#define REGS_STR_PFX(buf, pfx, num) \
+       ({ \
+               buf + (num >= 0 ? \
+                       sprintf(buf, #pfx "%i_", num) : \
+                       sprintf(buf, #pfx "_")); \
+       })
+#define REGS_STR_PFX_C(buf, pfx, num) \
+       ({ \
+               buf + (num >= 0 ? \
+                       sprintf(buf, #pfx "%c_", 'A' + num) : \
+                       sprintf(buf, #pfx "_")); \
+       })
+
+/*
+ * Core registers (not memory mapped)
+ */
+extern u32 last_seqstat;
+
+static int debug_cclk_get(void *data, u64 *val)
+{
+       *val = get_cclk();
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_debug_cclk, debug_cclk_get, NULL, "0x%08llx\n");
+
+static int debug_sclk_get(void *data, u64 *val)
+{
+       *val = get_sclk();
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_debug_sclk, debug_sclk_get, NULL, "0x%08llx\n");
+
+#define DEFINE_SYSREG(sr, pre, post) \
+static int sysreg_##sr##_get(void *data, u64 *val) \
+{ \
+       unsigned long tmp; \
+       pre; \
+       __asm__ __volatile__("%0 = " #sr ";" : "=d"(tmp)); \
+       *val = tmp; \
+       return 0; \
+} \
+static int sysreg_##sr##_set(void *data, u64 val) \
+{ \
+       unsigned long tmp = val; \
+       __asm__ __volatile__(#sr " = %0;" : : "d"(tmp)); \
+       post; \
+       return 0; \
+} \
+DEFINE_SIMPLE_ATTRIBUTE(fops_sysreg_##sr, sysreg_##sr##_get, sysreg_##sr##_set, "0x%08llx\n")
+
+DEFINE_SYSREG(cycles, , );
+DEFINE_SYSREG(cycles2, __asm__ __volatile__("%0 = cycles;" : "=d"(tmp)), );
+DEFINE_SYSREG(emudat, , );
+DEFINE_SYSREG(seqstat, , );
+DEFINE_SYSREG(syscfg, , CSYNC());
+#define D_SYSREG(sr) debugfs_create_file(#sr, S_IRUSR|S_IWUSR, parent, NULL, &fops_sysreg_##sr)
+
+/*
+ * CAN
+ */
+#define CAN_OFF(mmr)  REGS_OFF(can, mmr)
+#define __CAN(uname, lname) __REGS(can, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_can(struct dentry *parent, unsigned long base, int num)
+{
+       static struct dentry *am, *mb;
+       int i, j;
+       char buf[32], *_buf = REGS_STR_PFX(buf, CAN, num);
+
+       if (!am) {
+               am = debugfs_create_dir("am", parent);
+               mb = debugfs_create_dir("mb", parent);
+       }
+
+       __CAN(MC1, mc1);
+       __CAN(MD1, md1);
+       __CAN(TRS1, trs1);
+       __CAN(TRR1, trr1);
+       __CAN(TA1, ta1);
+       __CAN(AA1, aa1);
+       __CAN(RMP1, rmp1);
+       __CAN(RML1, rml1);
+       __CAN(MBTIF1, mbtif1);
+       __CAN(MBRIF1, mbrif1);
+       __CAN(MBIM1, mbim1);
+       __CAN(RFH1, rfh1);
+       __CAN(OPSS1, opss1);
+
+       __CAN(MC2, mc2);
+       __CAN(MD2, md2);
+       __CAN(TRS2, trs2);
+       __CAN(TRR2, trr2);
+       __CAN(TA2, ta2);
+       __CAN(AA2, aa2);
+       __CAN(RMP2, rmp2);
+       __CAN(RML2, rml2);
+       __CAN(MBTIF2, mbtif2);
+       __CAN(MBRIF2, mbrif2);
+       __CAN(MBIM2, mbim2);
+       __CAN(RFH2, rfh2);
+       __CAN(OPSS2, opss2);
+
+       __CAN(CLOCK, clock);
+       __CAN(TIMING, timing);
+       __CAN(DEBUG, debug);
+       __CAN(STATUS, status);
+       __CAN(CEC, cec);
+       __CAN(GIS, gis);
+       __CAN(GIM, gim);
+       __CAN(GIF, gif);
+       __CAN(CONTROL, control);
+       __CAN(INTR, intr);
+       __CAN(VERSION, version);
+       __CAN(MBTD, mbtd);
+       __CAN(EWR, ewr);
+       __CAN(ESR, esr);
+       /*__CAN(UCREG, ucreg); no longer exists */
+       __CAN(UCCNT, uccnt);
+       __CAN(UCRC, ucrc);
+       __CAN(UCCNF, uccnf);
+       __CAN(VERSION2, version2);
+
+       for (i = 0; i < 32; ++i) {
+               sprintf(_buf, "AM%02iL", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, am,
+                       (u16 *)(base + CAN_OFF(msk[i].aml)));
+               sprintf(_buf, "AM%02iH", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, am,
+                       (u16 *)(base + CAN_OFF(msk[i].amh)));
+
+               for (j = 0; j < 3; ++j) {
+                       sprintf(_buf, "MB%02i_DATA%i", i, j);
+                       debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                               (u16 *)(base + CAN_OFF(chl[i].data[j*2])));
+               }
+               sprintf(_buf, "MB%02i_LENGTH", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                       (u16 *)(base + CAN_OFF(chl[i].dlc)));
+               sprintf(_buf, "MB%02i_TIMESTAMP", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                       (u16 *)(base + CAN_OFF(chl[i].tsv)));
+               sprintf(_buf, "MB%02i_ID0", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                       (u16 *)(base + CAN_OFF(chl[i].id0)));
+               sprintf(_buf, "MB%02i_ID1", i);
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+                       (u16 *)(base + CAN_OFF(chl[i].id1)));
+       }
+}
+#define CAN(num) bfin_debug_mmrs_can(parent, CAN##num##_MC1, num)
+
+/*
+ * DMA
+ */
+#define __DMA(uname, lname) __REGS(dma, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_dma(struct dentry *parent, unsigned long base, int num, char mdma, const char *pfx)
+{
+       char buf[32], *_buf;
+
+       if (mdma)
+               _buf = buf + sprintf(buf, "%s_%c%i_", pfx, mdma, num);
+       else
+               _buf = buf + sprintf(buf, "%s%i_", pfx, num);
+
+       __DMA(NEXT_DESC_PTR, next_desc_ptr);
+       __DMA(START_ADDR, start_addr);
+       __DMA(CONFIG, config);
+       __DMA(X_COUNT, x_count);
+       __DMA(X_MODIFY, x_modify);
+       __DMA(Y_COUNT, y_count);
+       __DMA(Y_MODIFY, y_modify);
+       __DMA(CURR_DESC_PTR, curr_desc_ptr);
+       __DMA(CURR_ADDR, curr_addr);
+       __DMA(IRQ_STATUS, irq_status);
+       __DMA(PERIPHERAL_MAP, peripheral_map);
+       __DMA(CURR_X_COUNT, curr_x_count);
+       __DMA(CURR_Y_COUNT, curr_y_count);
+}
+#define _DMA(num, base, mdma, pfx) bfin_debug_mmrs_dma(parent, base, num, mdma, pfx "DMA")
+#define DMA(num)  _DMA(num, DMA##num##_NEXT_DESC_PTR, 0, "")
+#define _MDMA(num, x) \
+       do { \
+               _DMA(num, x##DMA_D##num##_CONFIG, 'D', #x); \
+               _DMA(num, x##DMA_S##num##_CONFIG, 'S', #x); \
+       } while (0)
+#define MDMA(num) _MDMA(num, M)
+#define IMDMA(num) _MDMA(num, IM)
+
+/*
+ * EPPI
+ */
+#define __EPPI(uname, lname) __REGS(eppi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_eppi(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, EPPI, num);
+       __EPPI(STATUS, status);
+       __EPPI(HCOUNT, hcount);
+       __EPPI(HDELAY, hdelay);
+       __EPPI(VCOUNT, vcount);
+       __EPPI(VDELAY, vdelay);
+       __EPPI(FRAME, frame);
+       __EPPI(LINE, line);
+       __EPPI(CLKDIV, clkdiv);
+       __EPPI(CONTROL, control);
+       __EPPI(FS1W_HBL, fs1w_hbl);
+       __EPPI(FS1P_AVPL, fs1p_avpl);
+       __EPPI(FS2W_LVB, fs2w_lvb);
+       __EPPI(FS2P_LAVF, fs2p_lavf);
+       __EPPI(CLIP, clip);
+}
+#define EPPI(num) bfin_debug_mmrs_eppi(parent, EPPI##num##_STATUS, num)
+
+/*
+ * General Purpose Timers
+ */
+#define GPTIMER_OFF(mmr) (TIMER0_##mmr - TIMER0_CONFIG)
+#define __GPTIMER(name) \
+       do { \
+               strcpy(_buf, #name); \
+               debugfs_create_x16(buf, S_IRUSR|S_IWUSR, parent, (u16 *)(base + GPTIMER_OFF(name))); \
+       } while (0)
+static void __init __maybe_unused
+bfin_debug_mmrs_gptimer(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, TIMER, num);
+       __GPTIMER(CONFIG);
+       __GPTIMER(COUNTER);
+       __GPTIMER(PERIOD);
+       __GPTIMER(WIDTH);
+}
+#define GPTIMER(num) bfin_debug_mmrs_gptimer(parent, TIMER##num##_CONFIG, num)
+
+/*
+ * Handshake MDMA
+ */
+#define __HMDMA(uname, lname) __REGS(hmdma, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_hmdma(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, HMDMA, num);
+       __HMDMA(CONTROL, control);
+       __HMDMA(ECINIT, ecinit);
+       __HMDMA(BCINIT, bcinit);
+       __HMDMA(ECURGENT, ecurgent);
+       __HMDMA(ECOVERFLOW, ecoverflow);
+       __HMDMA(ECOUNT, ecount);
+       __HMDMA(BCOUNT, bcount);
+}
+#define HMDMA(num) bfin_debug_mmrs_hmdma(parent, HMDMA##num##_CONTROL, num)
+
+/*
+ * Port/GPIO
+ */
+#define bfin_gpio_regs gpio_port_t
+#define __PORT(uname, lname) __REGS(gpio, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_port(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf;
+#ifdef __ADSPBF54x__
+       _buf = REGS_STR_PFX_C(buf, PORT, num);
+       __PORT(FER, port_fer);
+       __PORT(SET, data_set);
+       __PORT(CLEAR, data_clear);
+       __PORT(DIR_SET, dir_set);
+       __PORT(DIR_CLEAR, dir_clear);
+       __PORT(INEN, inen);
+       __PORT(MUX, port_mux);
+#else
+       _buf = buf + sprintf(buf, "PORT%cIO_", num);
+       __PORT(CLEAR, data_clear);
+       __PORT(SET, data_set);
+       __PORT(TOGGLE, toggle);
+       __PORT(MASKA, maska);
+       __PORT(MASKA_CLEAR, maska_clear);
+       __PORT(MASKA_SET, maska_set);
+       __PORT(MASKA_TOGGLE, maska_toggle);
+       __PORT(MASKB, maskb);
+       __PORT(MASKB_CLEAR, maskb_clear);
+       __PORT(MASKB_SET, maskb_set);
+       __PORT(MASKB_TOGGLE, maskb_toggle);
+       __PORT(DIR, dir);
+       __PORT(POLAR, polar);
+       __PORT(EDGE, edge);
+       __PORT(BOTH, both);
+       __PORT(INEN, inen);
+#endif
+       _buf[-1] = '\0';
+       d(buf, 16, base + REGS_OFF(gpio, data));
+}
+#define PORT(base, num) bfin_debug_mmrs_port(parent, base, num)
+
+/*
+ * PPI
+ */
+#define __PPI(uname, lname) __REGS(ppi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_ppi(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, PPI, num);
+       __PPI(CONTROL, control);
+       __PPI(STATUS, status);
+       __PPI(COUNT, count);
+       __PPI(DELAY, delay);
+       __PPI(FRAME, frame);
+}
+#define PPI(num) bfin_debug_mmrs_ppi(parent, PPI##num##_STATUS, num)
+
+/*
+ * SPI
+ */
+#define __SPI(uname, lname) __REGS(spi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_spi(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, SPI, num);
+       __SPI(CTL, ctl);
+       __SPI(FLG, flg);
+       __SPI(STAT, stat);
+       __SPI(TDBR, tdbr);
+       __SPI(RDBR, rdbr);
+       __SPI(BAUD, baud);
+       __SPI(SHADOW, shadow);
+}
+#define SPI(num) bfin_debug_mmrs_spi(parent, SPI##num##_REGBASE, num)
+
+/*
+ * SPORT
+ */
+static inline int sport_width(void *mmr)
+{
+       unsigned long lmmr = (unsigned long)mmr;
+       if ((lmmr & 0xff) == 0x10)
+               /* SPORT#_TX has 0x10 offset -> SPORT#_TCR2 has 0x04 offset */
+               lmmr -= 0xc;
+       else
+               /* SPORT#_RX has 0x18 offset -> SPORT#_RCR2 has 0x24 offset */
+               lmmr += 0xc;
+       /* extract SLEN field from control register 2 and add 1 */
+       return (bfin_read16(lmmr) & 0x1f) + 1;
+}
+static int sport_set(void *mmr, u64 val)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       if (sport_width(mmr) <= 16)
+               bfin_write16(mmr, val);
+       else
+               bfin_write32(mmr, val);
+       local_irq_restore(flags);
+       return 0;
+}
+static int sport_get(void *mmr, u64 *val)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+       if (sport_width(mmr) <= 16)
+               *val = bfin_read16(mmr);
+       else
+               *val = bfin_read32(mmr);
+       local_irq_restore(flags);
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_sport, sport_get, sport_set, "0x%08llx\n");
+/*DEFINE_SIMPLE_ATTRIBUTE(fops_sport_ro, sport_get, NULL, "0x%08llx\n");*/
+DEFINE_SIMPLE_ATTRIBUTE(fops_sport_wo, NULL, sport_set, "0x%08llx\n");
+#define SPORT_OFF(mmr) (SPORT0_##mmr - SPORT0_TCR1)
+#define _D_SPORT(name, perms, fops) \
+       do { \
+               strcpy(_buf, #name); \
+               debugfs_create_file(buf, perms, parent, (void *)(base + SPORT_OFF(name)), fops); \
+       } while (0)
+#define __SPORT_RW(name) _D_SPORT(name, S_IRUSR|S_IWUSR, &fops_sport)
+#define __SPORT_RO(name) _D_SPORT(name, S_IRUSR, &fops_sport_ro)
+#define __SPORT_WO(name) _D_SPORT(name, S_IWUSR, &fops_sport_wo)
+#define __SPORT(name, bits) \
+       do { \
+               strcpy(_buf, #name); \
+               debugfs_create_x##bits(buf, S_IRUSR|S_IWUSR, parent, (u##bits *)(base + SPORT_OFF(name))); \
+       } while (0)
+static void __init __maybe_unused
+bfin_debug_mmrs_sport(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, SPORT, num);
+       __SPORT(CHNL, 16);
+       __SPORT(MCMC1, 16);
+       __SPORT(MCMC2, 16);
+       __SPORT(MRCS0, 32);
+       __SPORT(MRCS1, 32);
+       __SPORT(MRCS2, 32);
+       __SPORT(MRCS3, 32);
+       __SPORT(MTCS0, 32);
+       __SPORT(MTCS1, 32);
+       __SPORT(MTCS2, 32);
+       __SPORT(MTCS3, 32);
+       __SPORT(RCLKDIV, 16);
+       __SPORT(RCR1, 16);
+       __SPORT(RCR2, 16);
+       __SPORT(RFSDIV, 16);
+       __SPORT_RW(RX);
+       __SPORT(STAT, 16);
+       __SPORT(TCLKDIV, 16);
+       __SPORT(TCR1, 16);
+       __SPORT(TCR2, 16);
+       __SPORT(TFSDIV, 16);
+       __SPORT_WO(TX);
+}
+#define SPORT(num) bfin_debug_mmrs_sport(parent, SPORT##num##_TCR1, num)
+
+/*
+ * TWI
+ */
+#define __TWI(uname, lname) __REGS(twi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_twi(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, TWI, num);
+       __TWI(CLKDIV, clkdiv);
+       __TWI(CONTROL, control);
+       __TWI(SLAVE_CTL, slave_ctl);
+       __TWI(SLAVE_STAT, slave_stat);
+       __TWI(SLAVE_ADDR, slave_addr);
+       __TWI(MASTER_CTL, master_ctl);
+       __TWI(MASTER_STAT, master_stat);
+       __TWI(MASTER_ADDR, master_addr);
+       __TWI(INT_STAT, int_stat);
+       __TWI(INT_MASK, int_mask);
+       __TWI(FIFO_CTL, fifo_ctl);
+       __TWI(FIFO_STAT, fifo_stat);
+       __TWI(XMT_DATA8, xmt_data8);
+       __TWI(XMT_DATA16, xmt_data16);
+       __TWI(RCV_DATA8, rcv_data8);
+       __TWI(RCV_DATA16, rcv_data16);
+}
+#define TWI(num) bfin_debug_mmrs_twi(parent, TWI##num##_CLKDIV, num)
+
+/*
+ * UART
+ */
+#define __UART(uname, lname) __REGS(uart, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_uart(struct dentry *parent, unsigned long base, int num)
+{
+       char buf[32], *_buf = REGS_STR_PFX(buf, UART, num);
+#ifdef BFIN_UART_BF54X_STYLE
+       __UART(DLL, dll);
+       __UART(DLH, dlh);
+       __UART(GCTL, gctl);
+       __UART(LCR, lcr);
+       __UART(MCR, mcr);
+       __UART(LSR, lsr);
+       __UART(MSR, msr);
+       __UART(SCR, scr);
+       __UART(IER_SET, ier_set);
+       __UART(IER_CLEAR, ier_clear);
+       __UART(THR, thr);
+       __UART(RBR, rbr);
+#else
+       __UART(DLL, dll);
+       __UART(THR, thr);
+       __UART(RBR, rbr);
+       __UART(DLH, dlh);
+       __UART(IER, ier);
+       __UART(IIR, iir);
+       __UART(LCR, lcr);
+       __UART(MCR, mcr);
+       __UART(LSR, lsr);
+       __UART(MSR, msr);
+       __UART(SCR, scr);
+       __UART(GCTL, gctl);
+#endif
+}
+#define UART(num) bfin_debug_mmrs_uart(parent, UART##num##_DLL, num)
+
+/*
+ * The actual debugfs generation
+ */
+static struct dentry *debug_mmrs_dentry;
+
+static int __init bfin_debug_mmrs_init(void)
+{
+       struct dentry *top, *parent;
+
+       pr_info("debug-mmrs: setting up Blackfin MMR debugfs\n");
+
+       top = debugfs_create_dir("blackfin", NULL);
+       if (top == NULL)
+               return -1;
+
+       parent = debugfs_create_dir("core_regs", top);
+       debugfs_create_file("cclk", S_IRUSR, parent, NULL, &fops_debug_cclk);
+       debugfs_create_file("sclk", S_IRUSR, parent, NULL, &fops_debug_sclk);
+       debugfs_create_x32("last_seqstat", S_IRUSR, parent, &last_seqstat);
+       D_SYSREG(cycles);
+       D_SYSREG(cycles2);
+       D_SYSREG(emudat);
+       D_SYSREG(seqstat);
+       D_SYSREG(syscfg);
+
+       /* Core MMRs */
+       parent = debugfs_create_dir("ctimer", top);
+       D32(TCNTL);
+       D32(TCOUNT);
+       D32(TPERIOD);
+       D32(TSCALE);
+
+       parent = debugfs_create_dir("cec", top);
+       D32(EVT0);
+       D32(EVT1);
+       D32(EVT2);
+       D32(EVT3);
+       D32(EVT4);
+       D32(EVT5);
+       D32(EVT6);
+       D32(EVT7);
+       D32(EVT8);
+       D32(EVT9);
+       D32(EVT10);
+       D32(EVT11);
+       D32(EVT12);
+       D32(EVT13);
+       D32(EVT14);
+       D32(EVT15);
+       D32(EVT_OVERRIDE);
+       D32(IMASK);
+       D32(IPEND);
+       D32(ILAT);
+       D32(IPRIO);
+
+       parent = debugfs_create_dir("debug", top);
+       D32(DBGSTAT);
+       D32(DSPID);
+
+       parent = debugfs_create_dir("mmu", top);
+       D32(SRAM_BASE_ADDRESS);
+       D32(DCPLB_ADDR0);
+       D32(DCPLB_ADDR10);
+       D32(DCPLB_ADDR11);
+       D32(DCPLB_ADDR12);
+       D32(DCPLB_ADDR13);
+       D32(DCPLB_ADDR14);
+       D32(DCPLB_ADDR15);
+       D32(DCPLB_ADDR1);
+       D32(DCPLB_ADDR2);
+       D32(DCPLB_ADDR3);
+       D32(DCPLB_ADDR4);
+       D32(DCPLB_ADDR5);
+       D32(DCPLB_ADDR6);
+       D32(DCPLB_ADDR7);
+       D32(DCPLB_ADDR8);
+       D32(DCPLB_ADDR9);
+       D32(DCPLB_DATA0);
+       D32(DCPLB_DATA10);
+       D32(DCPLB_DATA11);
+       D32(DCPLB_DATA12);
+       D32(DCPLB_DATA13);
+       D32(DCPLB_DATA14);
+       D32(DCPLB_DATA15);
+       D32(DCPLB_DATA1);
+       D32(DCPLB_DATA2);
+       D32(DCPLB_DATA3);
+       D32(DCPLB_DATA4);
+       D32(DCPLB_DATA5);
+       D32(DCPLB_DATA6);
+       D32(DCPLB_DATA7);
+       D32(DCPLB_DATA8);
+       D32(DCPLB_DATA9);
+       D32(DCPLB_FAULT_ADDR);
+       D32(DCPLB_STATUS);
+       D32(DMEM_CONTROL);
+       D32(DTEST_COMMAND);
+       D32(DTEST_DATA0);
+       D32(DTEST_DATA1);
+
+       D32(ICPLB_ADDR0);
+       D32(ICPLB_ADDR1);
+       D32(ICPLB_ADDR2);
+       D32(ICPLB_ADDR3);
+       D32(ICPLB_ADDR4);
+       D32(ICPLB_ADDR5);
+       D32(ICPLB_ADDR6);
+       D32(ICPLB_ADDR7);
+       D32(ICPLB_ADDR8);
+       D32(ICPLB_ADDR9);
+       D32(ICPLB_ADDR10);
+       D32(ICPLB_ADDR11);
+       D32(ICPLB_ADDR12);
+       D32(ICPLB_ADDR13);
+       D32(ICPLB_ADDR14);
+       D32(ICPLB_ADDR15);
+       D32(ICPLB_DATA0);
+       D32(ICPLB_DATA1);
+       D32(ICPLB_DATA2);
+       D32(ICPLB_DATA3);
+       D32(ICPLB_DATA4);
+       D32(ICPLB_DATA5);
+       D32(ICPLB_DATA6);
+       D32(ICPLB_DATA7);
+       D32(ICPLB_DATA8);
+       D32(ICPLB_DATA9);
+       D32(ICPLB_DATA10);
+       D32(ICPLB_DATA11);
+       D32(ICPLB_DATA12);
+       D32(ICPLB_DATA13);
+       D32(ICPLB_DATA14);
+       D32(ICPLB_DATA15);
+       D32(ICPLB_FAULT_ADDR);
+       D32(ICPLB_STATUS);
+       D32(IMEM_CONTROL);
+       if (!ANOMALY_05000481) {
+               D32(ITEST_COMMAND);
+               D32(ITEST_DATA0);
+               D32(ITEST_DATA1);
+       }
+
+       parent = debugfs_create_dir("perf", top);
+       D32(PFCNTR0);
+       D32(PFCNTR1);
+       D32(PFCTL);
+
+       parent = debugfs_create_dir("trace", top);
+       D32(TBUF);
+       D32(TBUFCTL);
+       D32(TBUFSTAT);
+
+       parent = debugfs_create_dir("watchpoint", top);
+       D32(WPIACTL);
+       D32(WPIA0);
+       D32(WPIA1);
+       D32(WPIA2);
+       D32(WPIA3);
+       D32(WPIA4);
+       D32(WPIA5);
+       D32(WPIACNT0);
+       D32(WPIACNT1);
+       D32(WPIACNT2);
+       D32(WPIACNT3);
+       D32(WPIACNT4);
+       D32(WPIACNT5);
+       D32(WPDACTL);
+       D32(WPDA0);
+       D32(WPDA1);
+       D32(WPDACNT0);
+       D32(WPDACNT1);
+       D32(WPSTAT);
+
+       /* System MMRs */
+#ifdef ATAPI_CONTROL
+       parent = debugfs_create_dir("atapi", top);
+       D16(ATAPI_CONTROL);
+       D16(ATAPI_DEV_ADDR);
+       D16(ATAPI_DEV_RXBUF);
+       D16(ATAPI_DEV_TXBUF);
+       D16(ATAPI_DMA_TFRCNT);
+       D16(ATAPI_INT_MASK);
+       D16(ATAPI_INT_STATUS);
+       D16(ATAPI_LINE_STATUS);
+       D16(ATAPI_MULTI_TIM_0);
+       D16(ATAPI_MULTI_TIM_1);
+       D16(ATAPI_MULTI_TIM_2);
+       D16(ATAPI_PIO_TFRCNT);
+       D16(ATAPI_PIO_TIM_0);
+       D16(ATAPI_PIO_TIM_1);
+       D16(ATAPI_REG_TIM_0);
+       D16(ATAPI_SM_STATE);
+       D16(ATAPI_STATUS);
+       D16(ATAPI_TERMINATE);
+       D16(ATAPI_UDMAOUT_TFRCNT);
+       D16(ATAPI_ULTRA_TIM_0);
+       D16(ATAPI_ULTRA_TIM_1);
+       D16(ATAPI_ULTRA_TIM_2);
+       D16(ATAPI_ULTRA_TIM_3);
+       D16(ATAPI_UMAIN_TFRCNT);
+       D16(ATAPI_XFER_LEN);
+#endif
+
+#if defined(CAN_MC1) || defined(CAN0_MC1) || defined(CAN1_MC1)
+       parent = debugfs_create_dir("can", top);
+# ifdef CAN_MC1
+       bfin_debug_mmrs_can(parent, CAN_MC1, -1);
+# endif
+# ifdef CAN0_MC1
+       CAN(0);
+# endif
+# ifdef CAN1_MC1
+       CAN(1);
+# endif
+#endif
+
+#ifdef CNT_COMMAND
+       parent = debugfs_create_dir("counter", top);
+       D16(CNT_COMMAND);
+       D16(CNT_CONFIG);
+       D32(CNT_COUNTER);
+       D16(CNT_DEBOUNCE);
+       D16(CNT_IMASK);
+       D32(CNT_MAX);
+       D32(CNT_MIN);
+       D16(CNT_STATUS);
+#endif
+
+       parent = debugfs_create_dir("dmac", top);
+#ifdef DMA_TC_CNT
+       D16(DMAC_TC_CNT);
+       D16(DMAC_TC_PER);
+#endif
+#ifdef DMAC0_TC_CNT
+       D16(DMAC0_TC_CNT);
+       D16(DMAC0_TC_PER);
+#endif
+#ifdef DMAC1_TC_CNT
+       D16(DMAC1_TC_CNT);
+       D16(DMAC1_TC_PER);
+#endif
+#ifdef DMAC1_PERIMUX
+       D16(DMAC1_PERIMUX);
+#endif
+
+#ifdef __ADSPBF561__
+       /* XXX: should rewrite the MMR map */
+# define DMA0_NEXT_DESC_PTR DMA2_0_NEXT_DESC_PTR
+# define DMA1_NEXT_DESC_PTR DMA2_1_NEXT_DESC_PTR
+# define DMA2_NEXT_DESC_PTR DMA2_2_NEXT_DESC_PTR
+# define DMA3_NEXT_DESC_PTR DMA2_3_NEXT_DESC_PTR
+# define DMA4_NEXT_DESC_PTR DMA2_4_NEXT_DESC_PTR
+# define DMA5_NEXT_DESC_PTR DMA2_5_NEXT_DESC_PTR
+# define DMA6_NEXT_DESC_PTR DMA2_6_NEXT_DESC_PTR
+# define DMA7_NEXT_DESC_PTR DMA2_7_NEXT_DESC_PTR
+# define DMA8_NEXT_DESC_PTR DMA2_8_NEXT_DESC_PTR
+# define DMA9_NEXT_DESC_PTR DMA2_9_NEXT_DESC_PTR
+# define DMA10_NEXT_DESC_PTR DMA2_10_NEXT_DESC_PTR
+# define DMA11_NEXT_DESC_PTR DMA2_11_NEXT_DESC_PTR
+# define DMA12_NEXT_DESC_PTR DMA1_0_NEXT_DESC_PTR
+# define DMA13_NEXT_DESC_PTR DMA1_1_NEXT_DESC_PTR
+# define DMA14_NEXT_DESC_PTR DMA1_2_NEXT_DESC_PTR
+# define DMA15_NEXT_DESC_PTR DMA1_3_NEXT_DESC_PTR
+# define DMA16_NEXT_DESC_PTR DMA1_4_NEXT_DESC_PTR
+# define DMA17_NEXT_DESC_PTR DMA1_5_NEXT_DESC_PTR
+# define DMA18_NEXT_DESC_PTR DMA1_6_NEXT_DESC_PTR
+# define DMA19_NEXT_DESC_PTR DMA1_7_NEXT_DESC_PTR
+# define DMA20_NEXT_DESC_PTR DMA1_8_NEXT_DESC_PTR
+# define DMA21_NEXT_DESC_PTR DMA1_9_NEXT_DESC_PTR
+# define DMA22_NEXT_DESC_PTR DMA1_10_NEXT_DESC_PTR
+# define DMA23_NEXT_DESC_PTR DMA1_11_NEXT_DESC_PTR
+#endif
+       parent = debugfs_create_dir("dma", top);
+       DMA(0);
+       DMA(1);
+       DMA(1);
+       DMA(2);
+       DMA(3);
+       DMA(4);
+       DMA(5);
+       DMA(6);
+       DMA(7);
+#ifdef DMA8_NEXT_DESC_PTR
+       DMA(8);
+       DMA(9);
+       DMA(10);
+       DMA(11);
+#endif
+#ifdef DMA12_NEXT_DESC_PTR
+       DMA(12);
+       DMA(13);
+       DMA(14);
+       DMA(15);
+       DMA(16);
+       DMA(17);
+       DMA(18);
+       DMA(19);
+#endif
+#ifdef DMA20_NEXT_DESC_PTR
+       DMA(20);
+       DMA(21);
+       DMA(22);
+       DMA(23);
+#endif
+
+       parent = debugfs_create_dir("ebiu_amc", top);
+       D32(EBIU_AMBCTL0);
+       D32(EBIU_AMBCTL1);
+       D16(EBIU_AMGCTL);
+#ifdef EBIU_MBSCTL
+       D16(EBIU_MBSCTL);
+       D32(EBIU_ARBSTAT);
+       D32(EBIU_MODE);
+       D16(EBIU_FCTL);
+#endif
+
+#ifdef EBIU_SDGCTL
+       parent = debugfs_create_dir("ebiu_sdram", top);
+# ifdef __ADSPBF561__
+       D32(EBIU_SDBCTL);
+# else
+       D16(EBIU_SDBCTL);
+# endif
+       D32(EBIU_SDGCTL);
+       D16(EBIU_SDRRC);
+       D16(EBIU_SDSTAT);
+#endif
+
+#ifdef EBIU_DDRACCT
+       parent = debugfs_create_dir("ebiu_ddr", top);
+       D32(EBIU_DDRACCT);
+       D32(EBIU_DDRARCT);
+       D32(EBIU_DDRBRC0);
+       D32(EBIU_DDRBRC1);
+       D32(EBIU_DDRBRC2);
+       D32(EBIU_DDRBRC3);
+       D32(EBIU_DDRBRC4);
+       D32(EBIU_DDRBRC5);
+       D32(EBIU_DDRBRC6);
+       D32(EBIU_DDRBRC7);
+       D32(EBIU_DDRBWC0);
+       D32(EBIU_DDRBWC1);
+       D32(EBIU_DDRBWC2);
+       D32(EBIU_DDRBWC3);
+       D32(EBIU_DDRBWC4);
+       D32(EBIU_DDRBWC5);
+       D32(EBIU_DDRBWC6);
+       D32(EBIU_DDRBWC7);
+       D32(EBIU_DDRCTL0);
+       D32(EBIU_DDRCTL1);
+       D32(EBIU_DDRCTL2);
+       D32(EBIU_DDRCTL3);
+       D32(EBIU_DDRGC0);
+       D32(EBIU_DDRGC1);
+       D32(EBIU_DDRGC2);
+       D32(EBIU_DDRGC3);
+       D32(EBIU_DDRMCCL);
+       D32(EBIU_DDRMCEN);
+       D32(EBIU_DDRQUE);
+       D32(EBIU_DDRTACT);
+       D32(EBIU_ERRADD);
+       D16(EBIU_ERRMST);
+       D16(EBIU_RSTCTL);
+#endif
+
+#ifdef EMAC_ADDRHI
+       parent = debugfs_create_dir("emac", top);
+       D32(EMAC_ADDRHI);
+       D32(EMAC_ADDRLO);
+       D32(EMAC_FLC);
+       D32(EMAC_HASHHI);
+       D32(EMAC_HASHLO);
+       D32(EMAC_MMC_CTL);
+       D32(EMAC_MMC_RIRQE);
+       D32(EMAC_MMC_RIRQS);
+       D32(EMAC_MMC_TIRQE);
+       D32(EMAC_MMC_TIRQS);
+       D32(EMAC_OPMODE);
+       D32(EMAC_RXC_ALIGN);
+       D32(EMAC_RXC_ALLFRM);
+       D32(EMAC_RXC_ALLOCT);
+       D32(EMAC_RXC_BROAD);
+       D32(EMAC_RXC_DMAOVF);
+       D32(EMAC_RXC_EQ64);
+       D32(EMAC_RXC_FCS);
+       D32(EMAC_RXC_GE1024);
+       D32(EMAC_RXC_LNERRI);
+       D32(EMAC_RXC_LNERRO);
+       D32(EMAC_RXC_LONG);
+       D32(EMAC_RXC_LT1024);
+       D32(EMAC_RXC_LT128);
+       D32(EMAC_RXC_LT256);
+       D32(EMAC_RXC_LT512);
+       D32(EMAC_RXC_MACCTL);
+       D32(EMAC_RXC_MULTI);
+       D32(EMAC_RXC_OCTET);
+       D32(EMAC_RXC_OK);
+       D32(EMAC_RXC_OPCODE);
+       D32(EMAC_RXC_PAUSE);
+       D32(EMAC_RXC_SHORT);
+       D32(EMAC_RXC_TYPED);
+       D32(EMAC_RXC_UNICST);
+       D32(EMAC_RX_IRQE);
+       D32(EMAC_RX_STAT);
+       D32(EMAC_RX_STKY);
+       D32(EMAC_STAADD);
+       D32(EMAC_STADAT);
+       D32(EMAC_SYSCTL);
+       D32(EMAC_SYSTAT);
+       D32(EMAC_TXC_1COL);
+       D32(EMAC_TXC_ABORT);
+       D32(EMAC_TXC_ALLFRM);
+       D32(EMAC_TXC_ALLOCT);
+       D32(EMAC_TXC_BROAD);
+       D32(EMAC_TXC_CRSERR);
+       D32(EMAC_TXC_DEFER);
+       D32(EMAC_TXC_DMAUND);
+       D32(EMAC_TXC_EQ64);
+       D32(EMAC_TXC_GE1024);
+       D32(EMAC_TXC_GT1COL);
+       D32(EMAC_TXC_LATECL);
+       D32(EMAC_TXC_LT1024);
+       D32(EMAC_TXC_LT128);
+       D32(EMAC_TXC_LT256);
+       D32(EMAC_TXC_LT512);
+       D32(EMAC_TXC_MACCTL);
+       D32(EMAC_TXC_MULTI);
+       D32(EMAC_TXC_OCTET);
+       D32(EMAC_TXC_OK);
+       D32(EMAC_TXC_UNICST);
+       D32(EMAC_TXC_XS_COL);
+       D32(EMAC_TXC_XS_DFR);
+       D32(EMAC_TX_IRQE);
+       D32(EMAC_TX_STAT);
+       D32(EMAC_TX_STKY);
+       D32(EMAC_VLAN1);
+       D32(EMAC_VLAN2);
+       D32(EMAC_WKUP_CTL);
+       D32(EMAC_WKUP_FFCMD);
+       D32(EMAC_WKUP_FFCRC0);
+       D32(EMAC_WKUP_FFCRC1);
+       D32(EMAC_WKUP_FFMSK0);
+       D32(EMAC_WKUP_FFMSK1);
+       D32(EMAC_WKUP_FFMSK2);
+       D32(EMAC_WKUP_FFMSK3);
+       D32(EMAC_WKUP_FFOFF);
+# ifdef EMAC_PTP_ACCR
+       D32(EMAC_PTP_ACCR);
+       D32(EMAC_PTP_ADDEND);
+       D32(EMAC_PTP_ALARMHI);
+       D32(EMAC_PTP_ALARMLO);
+       D16(EMAC_PTP_CTL);
+       D32(EMAC_PTP_FOFF);
+       D32(EMAC_PTP_FV1);
+       D32(EMAC_PTP_FV2);
+       D32(EMAC_PTP_FV3);
+       D16(EMAC_PTP_ID_OFF);
+       D32(EMAC_PTP_ID_SNAP);
+       D16(EMAC_PTP_IE);
+       D16(EMAC_PTP_ISTAT);
+       D32(EMAC_PTP_OFFSET);
+       D32(EMAC_PTP_PPS_PERIOD);
+       D32(EMAC_PTP_PPS_STARTHI);
+       D32(EMAC_PTP_PPS_STARTLO);
+       D32(EMAC_PTP_RXSNAPHI);
+       D32(EMAC_PTP_RXSNAPLO);
+       D32(EMAC_PTP_TIMEHI);
+       D32(EMAC_PTP_TIMELO);
+       D32(EMAC_PTP_TXSNAPHI);
+       D32(EMAC_PTP_TXSNAPLO);
+# endif
+#endif
+
+#if defined(EPPI0_STATUS) || defined(EPPI1_STATUS) || defined(EPPI2_STATUS)
+       parent = debugfs_create_dir("eppi", top);
+# ifdef EPPI0_STATUS
+       EPPI(0);
+# endif
+# ifdef EPPI1_STATUS
+       EPPI(1);
+# endif
+# ifdef EPPI2_STATUS
+       EPPI(2);
+# endif
+#endif
+
+       parent = debugfs_create_dir("gptimer", top);
+#ifdef TIMER_DISABLE
+       D16(TIMER_DISABLE);
+       D16(TIMER_ENABLE);
+       D32(TIMER_STATUS);
+#endif
+#ifdef TIMER_DISABLE0
+       D16(TIMER_DISABLE0);
+       D16(TIMER_ENABLE0);
+       D32(TIMER_STATUS0);
+#endif
+#ifdef TIMER_DISABLE1
+       D16(TIMER_DISABLE1);
+       D16(TIMER_ENABLE1);
+       D32(TIMER_STATUS1);
+#endif
+       /* XXX: Should convert BF561 MMR names */
+#ifdef TMRS4_DISABLE
+       D16(TMRS4_DISABLE);
+       D16(TMRS4_ENABLE);
+       D32(TMRS4_STATUS);
+       D16(TMRS8_DISABLE);
+       D16(TMRS8_ENABLE);
+       D32(TMRS8_STATUS);
+#endif
+       GPTIMER(0);
+       GPTIMER(1);
+       GPTIMER(2);
+#ifdef TIMER3_CONFIG
+       GPTIMER(3);
+       GPTIMER(4);
+       GPTIMER(5);
+       GPTIMER(6);
+       GPTIMER(7);
+#endif
+#ifdef TIMER8_CONFIG
+       GPTIMER(8);
+       GPTIMER(9);
+       GPTIMER(10);
+#endif
+#ifdef TIMER11_CONFIG
+       GPTIMER(11);
+#endif
+
+#ifdef HMDMA0_CONTROL
+       parent = debugfs_create_dir("hmdma", top);
+       HMDMA(0);
+       HMDMA(1);
+#endif
+
+#ifdef HOST_CONTROL
+       parent = debugfs_create_dir("hostdp", top);
+       D16(HOST_CONTROL);
+       D16(HOST_STATUS);
+       D16(HOST_TIMEOUT);
+#endif
+
+#ifdef IMDMA_S0_CONFIG
+       parent = debugfs_create_dir("imdma", top);
+       IMDMA(0);
+       IMDMA(1);
+#endif
+
+#ifdef KPAD_CTL
+       parent = debugfs_create_dir("keypad", top);
+       D16(KPAD_CTL);
+       D16(KPAD_PRESCALE);
+       D16(KPAD_MSEL);
+       D16(KPAD_ROWCOL);
+       D16(KPAD_STAT);
+       D16(KPAD_SOFTEVAL);
+#endif
+
+       parent = debugfs_create_dir("mdma", top);
+       MDMA(0);
+       MDMA(1);
+#ifdef MDMA_D2_CONFIG
+       MDMA(2);
+       MDMA(3);
+#endif
+
+#ifdef MXVR_CONFIG
+       parent = debugfs_create_dir("mxvr", top);
+       D16(MXVR_CONFIG);
+# ifdef MXVR_PLL_CTL_0
+       D32(MXVR_PLL_CTL_0);
+# endif
+       D32(MXVR_STATE_0);
+       D32(MXVR_STATE_1);
+       D32(MXVR_INT_STAT_0);
+       D32(MXVR_INT_STAT_1);
+       D32(MXVR_INT_EN_0);
+       D32(MXVR_INT_EN_1);
+       D16(MXVR_POSITION);
+       D16(MXVR_MAX_POSITION);
+       D16(MXVR_DELAY);
+       D16(MXVR_MAX_DELAY);
+       D32(MXVR_LADDR);
+       D16(MXVR_GADDR);
+       D32(MXVR_AADDR);
+       D32(MXVR_ALLOC_0);
+       D32(MXVR_ALLOC_1);
+       D32(MXVR_ALLOC_2);
+       D32(MXVR_ALLOC_3);
+       D32(MXVR_ALLOC_4);
+       D32(MXVR_ALLOC_5);
+       D32(MXVR_ALLOC_6);
+       D32(MXVR_ALLOC_7);
+       D32(MXVR_ALLOC_8);
+       D32(MXVR_ALLOC_9);
+       D32(MXVR_ALLOC_10);
+       D32(MXVR_ALLOC_11);
+       D32(MXVR_ALLOC_12);
+       D32(MXVR_ALLOC_13);
+       D32(MXVR_ALLOC_14);
+       D32(MXVR_SYNC_LCHAN_0);
+       D32(MXVR_SYNC_LCHAN_1);
+       D32(MXVR_SYNC_LCHAN_2);
+       D32(MXVR_SYNC_LCHAN_3);
+       D32(MXVR_SYNC_LCHAN_4);
+       D32(MXVR_SYNC_LCHAN_5);
+       D32(MXVR_SYNC_LCHAN_6);
+       D32(MXVR_SYNC_LCHAN_7);
+       D32(MXVR_DMA0_CONFIG);
+       D32(MXVR_DMA0_START_ADDR);
+       D16(MXVR_DMA0_COUNT);
+       D32(MXVR_DMA0_CURR_ADDR);
+       D16(MXVR_DMA0_CURR_COUNT);
+       D32(MXVR_DMA1_CONFIG);
+       D32(MXVR_DMA1_START_ADDR);
+       D16(MXVR_DMA1_COUNT);
+       D32(MXVR_DMA1_CURR_ADDR);
+       D16(MXVR_DMA1_CURR_COUNT);
+       D32(MXVR_DMA2_CONFIG);
+       D32(MXVR_DMA2_START_ADDR);
+       D16(MXVR_DMA2_COUNT);
+       D32(MXVR_DMA2_CURR_ADDR);
+       D16(MXVR_DMA2_CURR_COUNT);
+       D32(MXVR_DMA3_CONFIG);
+       D32(MXVR_DMA3_START_ADDR);
+       D16(MXVR_DMA3_COUNT);
+       D32(MXVR_DMA3_CURR_ADDR);
+       D16(MXVR_DMA3_CURR_COUNT);
+       D32(MXVR_DMA4_CONFIG);
+       D32(MXVR_DMA4_START_ADDR);
+       D16(MXVR_DMA4_COUNT);
+       D32(MXVR_DMA4_CURR_ADDR);
+       D16(MXVR_DMA4_CURR_COUNT);
+       D32(MXVR_DMA5_CONFIG);
+       D32(MXVR_DMA5_START_ADDR);
+       D16(MXVR_DMA5_COUNT);
+       D32(MXVR_DMA5_CURR_ADDR);
+       D16(MXVR_DMA5_CURR_COUNT);
+       D32(MXVR_DMA6_CONFIG);
+       D32(MXVR_DMA6_START_ADDR);
+       D16(MXVR_DMA6_COUNT);
+       D32(MXVR_DMA6_CURR_ADDR);
+       D16(MXVR_DMA6_CURR_COUNT);
+       D32(MXVR_DMA7_CONFIG);
+       D32(MXVR_DMA7_START_ADDR);
+       D16(MXVR_DMA7_COUNT);
+       D32(MXVR_DMA7_CURR_ADDR);
+       D16(MXVR_DMA7_CURR_COUNT);
+       D16(MXVR_AP_CTL);
+       D32(MXVR_APRB_START_ADDR);
+       D32(MXVR_APRB_CURR_ADDR);
+       D32(MXVR_APTB_START_ADDR);
+       D32(MXVR_APTB_CURR_ADDR);
+       D32(MXVR_CM_CTL);
+       D32(MXVR_CMRB_START_ADDR);
+       D32(MXVR_CMRB_CURR_ADDR);
+       D32(MXVR_CMTB_START_ADDR);
+       D32(MXVR_CMTB_CURR_ADDR);
+       D32(MXVR_RRDB_START_ADDR);
+       D32(MXVR_RRDB_CURR_ADDR);
+       D32(MXVR_PAT_DATA_0);
+       D32(MXVR_PAT_EN_0);
+       D32(MXVR_PAT_DATA_1);
+       D32(MXVR_PAT_EN_1);
+       D16(MXVR_FRAME_CNT_0);
+       D16(MXVR_FRAME_CNT_1);
+       D32(MXVR_ROUTING_0);
+       D32(MXVR_ROUTING_1);
+       D32(MXVR_ROUTING_2);
+       D32(MXVR_ROUTING_3);
+       D32(MXVR_ROUTING_4);
+       D32(MXVR_ROUTING_5);
+       D32(MXVR_ROUTING_6);
+       D32(MXVR_ROUTING_7);
+       D32(MXVR_ROUTING_8);
+       D32(MXVR_ROUTING_9);
+       D32(MXVR_ROUTING_10);
+       D32(MXVR_ROUTING_11);
+       D32(MXVR_ROUTING_12);
+       D32(MXVR_ROUTING_13);
+       D32(MXVR_ROUTING_14);
+# ifdef MXVR_PLL_CTL_1
+       D32(MXVR_PLL_CTL_1);
+# endif
+       D16(MXVR_BLOCK_CNT);
+# ifdef MXVR_CLK_CTL
+       D32(MXVR_CLK_CTL);
+# endif
+# ifdef MXVR_CDRPLL_CTL
+       D32(MXVR_CDRPLL_CTL);
+# endif
+# ifdef MXVR_FMPLL_CTL
+       D32(MXVR_FMPLL_CTL);
+# endif
+# ifdef MXVR_PIN_CTL
+       D16(MXVR_PIN_CTL);
+# endif
+# ifdef MXVR_SCLK_CNT
+       D16(MXVR_SCLK_CNT);
+# endif
+#endif
+
+#ifdef NFC_ADDR
+       parent = debugfs_create_dir("nfc", top);
+       D_WO(NFC_ADDR, 16);
+       D_WO(NFC_CMD, 16);
+       D_RO(NFC_COUNT, 16);
+       D16(NFC_CTL);
+       D_WO(NFC_DATA_RD, 16);
+       D_WO(NFC_DATA_WR, 16);
+       D_RO(NFC_ECC0, 16);
+       D_RO(NFC_ECC1, 16);
+       D_RO(NFC_ECC2, 16);
+       D_RO(NFC_ECC3, 16);
+       D16(NFC_IRQMASK);
+       D16(NFC_IRQSTAT);
+       D_WO(NFC_PGCTL, 16);
+       D_RO(NFC_READ, 16);
+       D16(NFC_RST);
+       D_RO(NFC_STAT, 16);
+#endif
+
+#ifdef OTP_CONTROL
+       parent = debugfs_create_dir("otp", top);
+       D16(OTP_CONTROL);
+       D16(OTP_BEN);
+       D16(OTP_STATUS);
+       D32(OTP_TIMING);
+       D32(OTP_DATA0);
+       D32(OTP_DATA1);
+       D32(OTP_DATA2);
+       D32(OTP_DATA3);
+#endif
+
+#ifdef PIXC_CTL
+       parent = debugfs_create_dir("pixc", top);
+       D16(PIXC_CTL);
+       D16(PIXC_PPL);
+       D16(PIXC_LPF);
+       D16(PIXC_AHSTART);
+       D16(PIXC_AHEND);
+       D16(PIXC_AVSTART);
+       D16(PIXC_AVEND);
+       D16(PIXC_ATRANSP);
+       D16(PIXC_BHSTART);
+       D16(PIXC_BHEND);
+       D16(PIXC_BVSTART);
+       D16(PIXC_BVEND);
+       D16(PIXC_BTRANSP);
+       D16(PIXC_INTRSTAT);
+       D32(PIXC_RYCON);
+       D32(PIXC_GUCON);
+       D32(PIXC_BVCON);
+       D32(PIXC_CCBIAS);
+       D32(PIXC_TC);
+#endif
+
+       parent = debugfs_create_dir("pll", top);
+       D16(PLL_CTL);
+       D16(PLL_DIV);
+       D16(PLL_LOCKCNT);
+       D16(PLL_STAT);
+       D16(VR_CTL);
+       D32(CHIPID);    /* it's part of this hardware block */
+
+#if defined(PPI_STATUS) || defined(PPI0_STATUS) || defined(PPI1_STATUS)
+       parent = debugfs_create_dir("ppi", top);
+# ifdef PPI_STATUS
+       bfin_debug_mmrs_ppi(parent, PPI_STATUS, -1);
+# endif
+# ifdef PPI0_STATUS
+       PPI(0);
+# endif
+# ifdef PPI1_STATUS
+       PPI(1);
+# endif
+#endif
+
+#ifdef PWM_CTRL
+       parent = debugfs_create_dir("pwm", top);
+       D16(PWM_CTRL);
+       D16(PWM_STAT);
+       D16(PWM_TM);
+       D16(PWM_DT);
+       D16(PWM_GATE);
+       D16(PWM_CHA);
+       D16(PWM_CHB);
+       D16(PWM_CHC);
+       D16(PWM_SEG);
+       D16(PWM_SYNCWT);
+       D16(PWM_CHAL);
+       D16(PWM_CHBL);
+       D16(PWM_CHCL);
+       D16(PWM_LSI);
+       D16(PWM_STAT2);
+#endif
+
+#ifdef RSI_CONFIG
+       parent = debugfs_create_dir("rsi", top);
+       D32(RSI_ARGUMENT);
+       D16(RSI_CEATA_CONTROL);
+       D16(RSI_CLK_CONTROL);
+       D16(RSI_COMMAND);
+       D16(RSI_CONFIG);
+       D16(RSI_DATA_CNT);
+       D16(RSI_DATA_CONTROL);
+       D16(RSI_DATA_LGTH);
+       D32(RSI_DATA_TIMER);
+       D16(RSI_EMASK);
+       D16(RSI_ESTAT);
+       D32(RSI_FIFO);
+       D16(RSI_FIFO_CNT);
+       D32(RSI_MASK0);
+       D32(RSI_MASK1);
+       D16(RSI_PID0);
+       D16(RSI_PID1);
+       D16(RSI_PID2);
+       D16(RSI_PID3);
+       D16(RSI_PWR_CONTROL);
+       D16(RSI_RD_WAIT_EN);
+       D32(RSI_RESPONSE0);
+       D32(RSI_RESPONSE1);
+       D32(RSI_RESPONSE2);
+       D32(RSI_RESPONSE3);
+       D16(RSI_RESP_CMD);
+       D32(RSI_STATUS);
+       D_WO(RSI_STATUSCL, 16);
+#endif
+
+#ifdef RTC_ALARM
+       parent = debugfs_create_dir("rtc", top);
+       D32(RTC_ALARM);
+       D16(RTC_ICTL);
+       D16(RTC_ISTAT);
+       D16(RTC_PREN);
+       D32(RTC_STAT);
+       D16(RTC_SWCNT);
+#endif
+
+#ifdef SDH_CFG
+       parent = debugfs_create_dir("sdh", top);
+       D32(SDH_ARGUMENT);
+       D16(SDH_CFG);
+       D16(SDH_CLK_CTL);
+       D16(SDH_COMMAND);
+       D_RO(SDH_DATA_CNT, 16);
+       D16(SDH_DATA_CTL);
+       D16(SDH_DATA_LGTH);
+       D32(SDH_DATA_TIMER);
+       D16(SDH_E_MASK);
+       D16(SDH_E_STATUS);
+       D32(SDH_FIFO);
+       D_RO(SDH_FIFO_CNT, 16);
+       D32(SDH_MASK0);
+       D32(SDH_MASK1);
+       D_RO(SDH_PID0, 16);
+       D_RO(SDH_PID1, 16);
+       D_RO(SDH_PID2, 16);
+       D_RO(SDH_PID3, 16);
+       D_RO(SDH_PID4, 16);
+       D_RO(SDH_PID5, 16);
+       D_RO(SDH_PID6, 16);
+       D_RO(SDH_PID7, 16);
+       D16(SDH_PWR_CTL);
+       D16(SDH_RD_WAIT_EN);
+       D_RO(SDH_RESPONSE0, 32);
+       D_RO(SDH_RESPONSE1, 32);
+       D_RO(SDH_RESPONSE2, 32);
+       D_RO(SDH_RESPONSE3, 32);
+       D_RO(SDH_RESP_CMD, 16);
+       D_RO(SDH_STATUS, 32);
+       D_WO(SDH_STATUS_CLR, 16);
+#endif
+
+#ifdef SECURE_CONTROL
+       parent = debugfs_create_dir("security", top);
+       D16(SECURE_CONTROL);
+       D16(SECURE_STATUS);
+       D32(SECURE_SYSSWT);
+#endif
+
+       parent = debugfs_create_dir("sic", top);
+       D16(SWRST);
+       D16(SYSCR);
+       D16(SIC_RVECT);
+       D32(SIC_IAR0);
+       D32(SIC_IAR1);
+       D32(SIC_IAR2);
+#ifdef SIC_IAR3
+       D32(SIC_IAR3);
+#endif
+#ifdef SIC_IAR4
+       D32(SIC_IAR4);
+       D32(SIC_IAR5);
+       D32(SIC_IAR6);
+#endif
+#ifdef SIC_IAR7
+       D32(SIC_IAR7);
+#endif
+#ifdef SIC_IAR8
+       D32(SIC_IAR8);
+       D32(SIC_IAR9);
+       D32(SIC_IAR10);
+       D32(SIC_IAR11);
+#endif
+#ifdef SIC_IMASK
+       D32(SIC_IMASK);
+       D32(SIC_ISR);
+       D32(SIC_IWR);
+#endif
+#ifdef SIC_IMASK0
+       D32(SIC_IMASK0);
+       D32(SIC_IMASK1);
+       D32(SIC_ISR0);
+       D32(SIC_ISR1);
+       D32(SIC_IWR0);
+       D32(SIC_IWR1);
+#endif
+#ifdef SIC_IMASK2
+       D32(SIC_IMASK2);
+       D32(SIC_ISR2);
+       D32(SIC_IWR2);
+#endif
+#ifdef SICB_RVECT
+       D16(SICB_SWRST);
+       D16(SICB_SYSCR);
+       D16(SICB_RVECT);
+       D32(SICB_IAR0);
+       D32(SICB_IAR1);
+       D32(SICB_IAR2);
+       D32(SICB_IAR3);
+       D32(SICB_IAR4);
+       D32(SICB_IAR5);
+       D32(SICB_IAR6);
+       D32(SICB_IAR7);
+       D32(SICB_IMASK0);
+       D32(SICB_IMASK1);
+       D32(SICB_ISR0);
+       D32(SICB_ISR1);
+       D32(SICB_IWR0);
+       D32(SICB_IWR1);
+#endif
+
+       parent = debugfs_create_dir("spi", top);
+#ifdef SPI0_REGBASE
+       SPI(0);
+#endif
+#ifdef SPI1_REGBASE
+       SPI(1);
+#endif
+#ifdef SPI2_REGBASE
+       SPI(2);
+#endif
+
+       parent = debugfs_create_dir("sport", top);
+#ifdef SPORT0_STAT
+       SPORT(0);
+#endif
+#ifdef SPORT1_STAT
+       SPORT(1);
+#endif
+#ifdef SPORT2_STAT
+       SPORT(2);
+#endif
+#ifdef SPORT3_STAT
+       SPORT(3);
+#endif
+
+#if defined(TWI_CLKDIV) || defined(TWI0_CLKDIV) || defined(TWI1_CLKDIV)
+       parent = debugfs_create_dir("twi", top);
+# ifdef TWI_CLKDIV
+       bfin_debug_mmrs_twi(parent, TWI_CLKDIV, -1);
+# endif
+# ifdef TWI0_CLKDIV
+       TWI(0);
+# endif
+# ifdef TWI1_CLKDIV
+       TWI(1);
+# endif
+#endif
+
+       parent = debugfs_create_dir("uart", top);
+#ifdef BFIN_UART_DLL
+       bfin_debug_mmrs_uart(parent, BFIN_UART_DLL, -1);
+#endif
+#ifdef UART0_DLL
+       UART(0);
+#endif
+#ifdef UART1_DLL
+       UART(1);
+#endif
+#ifdef UART2_DLL
+       UART(2);
+#endif
+#ifdef UART3_DLL
+       UART(3);
+#endif
+
+#ifdef USB_FADDR
+       parent = debugfs_create_dir("usb", top);
+       D16(USB_FADDR);
+       D16(USB_POWER);
+       D16(USB_INTRTX);
+       D16(USB_INTRRX);
+       D16(USB_INTRTXE);
+       D16(USB_INTRRXE);
+       D16(USB_INTRUSB);
+       D16(USB_INTRUSBE);
+       D16(USB_FRAME);
+       D16(USB_INDEX);
+       D16(USB_TESTMODE);
+       D16(USB_GLOBINTR);
+       D16(USB_GLOBAL_CTL);
+       D16(USB_TX_MAX_PACKET);
+       D16(USB_CSR0);
+       D16(USB_TXCSR);
+       D16(USB_RX_MAX_PACKET);
+       D16(USB_RXCSR);
+       D16(USB_COUNT0);
+       D16(USB_RXCOUNT);
+       D16(USB_TXTYPE);
+       D16(USB_NAKLIMIT0);
+       D16(USB_TXINTERVAL);
+       D16(USB_RXTYPE);
+       D16(USB_RXINTERVAL);
+       D16(USB_TXCOUNT);
+       D16(USB_EP0_FIFO);
+       D16(USB_EP1_FIFO);
+       D16(USB_EP2_FIFO);
+       D16(USB_EP3_FIFO);
+       D16(USB_EP4_FIFO);
+       D16(USB_EP5_FIFO);
+       D16(USB_EP6_FIFO);
+       D16(USB_EP7_FIFO);
+       D16(USB_OTG_DEV_CTL);
+       D16(USB_OTG_VBUS_IRQ);
+       D16(USB_OTG_VBUS_MASK);
+       D16(USB_LINKINFO);
+       D16(USB_VPLEN);
+       D16(USB_HS_EOF1);
+       D16(USB_FS_EOF1);
+       D16(USB_LS_EOF1);
+       D16(USB_APHY_CNTRL);
+       D16(USB_APHY_CALIB);
+       D16(USB_APHY_CNTRL2);
+       D16(USB_PHY_TEST);
+       D16(USB_PLLOSC_CTRL);
+       D16(USB_SRP_CLKDIV);
+       D16(USB_EP_NI0_TXMAXP);
+       D16(USB_EP_NI0_TXCSR);
+       D16(USB_EP_NI0_RXMAXP);
+       D16(USB_EP_NI0_RXCSR);
+       D16(USB_EP_NI0_RXCOUNT);
+       D16(USB_EP_NI0_TXTYPE);
+       D16(USB_EP_NI0_TXINTERVAL);
+       D16(USB_EP_NI0_RXTYPE);
+       D16(USB_EP_NI0_RXINTERVAL);
+       D16(USB_EP_NI0_TXCOUNT);
+       D16(USB_EP_NI1_TXMAXP);
+       D16(USB_EP_NI1_TXCSR);
+       D16(USB_EP_NI1_RXMAXP);
+       D16(USB_EP_NI1_RXCSR);
+       D16(USB_EP_NI1_RXCOUNT);
+       D16(USB_EP_NI1_TXTYPE);
+       D16(USB_EP_NI1_TXINTERVAL);
+       D16(USB_EP_NI1_RXTYPE);
+       D16(USB_EP_NI1_RXINTERVAL);
+       D16(USB_EP_NI1_TXCOUNT);
+       D16(USB_EP_NI2_TXMAXP);
+       D16(USB_EP_NI2_TXCSR);
+       D16(USB_EP_NI2_RXMAXP);
+       D16(USB_EP_NI2_RXCSR);
+       D16(USB_EP_NI2_RXCOUNT);
+       D16(USB_EP_NI2_TXTYPE);
+       D16(USB_EP_NI2_TXINTERVAL);
+       D16(USB_EP_NI2_RXTYPE);
+       D16(USB_EP_NI2_RXINTERVAL);
+       D16(USB_EP_NI2_TXCOUNT);
+       D16(USB_EP_NI3_TXMAXP);
+       D16(USB_EP_NI3_TXCSR);
+       D16(USB_EP_NI3_RXMAXP);
+       D16(USB_EP_NI3_RXCSR);
+       D16(USB_EP_NI3_RXCOUNT);
+       D16(USB_EP_NI3_TXTYPE);
+       D16(USB_EP_NI3_TXINTERVAL);
+       D16(USB_EP_NI3_RXTYPE);
+       D16(USB_EP_NI3_RXINTERVAL);
+       D16(USB_EP_NI3_TXCOUNT);
+       D16(USB_EP_NI4_TXMAXP);
+       D16(USB_EP_NI4_TXCSR);
+       D16(USB_EP_NI4_RXMAXP);
+       D16(USB_EP_NI4_RXCSR);
+       D16(USB_EP_NI4_RXCOUNT);
+       D16(USB_EP_NI4_TXTYPE);
+       D16(USB_EP_NI4_TXINTERVAL);
+       D16(USB_EP_NI4_RXTYPE);
+       D16(USB_EP_NI4_RXINTERVAL);
+       D16(USB_EP_NI4_TXCOUNT);
+       D16(USB_EP_NI5_TXMAXP);
+       D16(USB_EP_NI5_TXCSR);
+       D16(USB_EP_NI5_RXMAXP);
+       D16(USB_EP_NI5_RXCSR);
+       D16(USB_EP_NI5_RXCOUNT);
+       D16(USB_EP_NI5_TXTYPE);
+       D16(USB_EP_NI5_TXINTERVAL);
+       D16(USB_EP_NI5_RXTYPE);
+       D16(USB_EP_NI5_RXINTERVAL);
+       D16(USB_EP_NI5_TXCOUNT);
+       D16(USB_EP_NI6_TXMAXP);
+       D16(USB_EP_NI6_TXCSR);
+       D16(USB_EP_NI6_RXMAXP);
+       D16(USB_EP_NI6_RXCSR);
+       D16(USB_EP_NI6_RXCOUNT);
+       D16(USB_EP_NI6_TXTYPE);
+       D16(USB_EP_NI6_TXINTERVAL);
+       D16(USB_EP_NI6_RXTYPE);
+       D16(USB_EP_NI6_RXINTERVAL);
+       D16(USB_EP_NI6_TXCOUNT);
+       D16(USB_EP_NI7_TXMAXP);
+       D16(USB_EP_NI7_TXCSR);
+       D16(USB_EP_NI7_RXMAXP);
+       D16(USB_EP_NI7_RXCSR);
+       D16(USB_EP_NI7_RXCOUNT);
+       D16(USB_EP_NI7_TXTYPE);
+       D16(USB_EP_NI7_TXINTERVAL);
+       D16(USB_EP_NI7_RXTYPE);
+       D16(USB_EP_NI7_RXINTERVAL);
+       D16(USB_EP_NI7_TXCOUNT);
+       D16(USB_DMA_INTERRUPT);
+       D16(USB_DMA0CONTROL);
+       D16(USB_DMA0ADDRLOW);
+       D16(USB_DMA0ADDRHIGH);
+       D16(USB_DMA0COUNTLOW);
+       D16(USB_DMA0COUNTHIGH);
+       D16(USB_DMA1CONTROL);
+       D16(USB_DMA1ADDRLOW);
+       D16(USB_DMA1ADDRHIGH);
+       D16(USB_DMA1COUNTLOW);
+       D16(USB_DMA1COUNTHIGH);
+       D16(USB_DMA2CONTROL);
+       D16(USB_DMA2ADDRLOW);
+       D16(USB_DMA2ADDRHIGH);
+       D16(USB_DMA2COUNTLOW);
+       D16(USB_DMA2COUNTHIGH);
+       D16(USB_DMA3CONTROL);
+       D16(USB_DMA3ADDRLOW);
+       D16(USB_DMA3ADDRHIGH);
+       D16(USB_DMA3COUNTLOW);
+       D16(USB_DMA3COUNTHIGH);
+       D16(USB_DMA4CONTROL);
+       D16(USB_DMA4ADDRLOW);
+       D16(USB_DMA4ADDRHIGH);
+       D16(USB_DMA4COUNTLOW);
+       D16(USB_DMA4COUNTHIGH);
+       D16(USB_DMA5CONTROL);
+       D16(USB_DMA5ADDRLOW);
+       D16(USB_DMA5ADDRHIGH);
+       D16(USB_DMA5COUNTLOW);
+       D16(USB_DMA5COUNTHIGH);
+       D16(USB_DMA6CONTROL);
+       D16(USB_DMA6ADDRLOW);
+       D16(USB_DMA6ADDRHIGH);
+       D16(USB_DMA6COUNTLOW);
+       D16(USB_DMA6COUNTHIGH);
+       D16(USB_DMA7CONTROL);
+       D16(USB_DMA7ADDRLOW);
+       D16(USB_DMA7ADDRHIGH);
+       D16(USB_DMA7COUNTLOW);
+       D16(USB_DMA7COUNTHIGH);
+#endif
+
+#ifdef WDOG_CNT
+       parent = debugfs_create_dir("watchdog", top);
+       D32(WDOG_CNT);
+       D16(WDOG_CTL);
+       D32(WDOG_STAT);
+#endif
+#ifdef WDOGA_CNT
+       parent = debugfs_create_dir("watchdog", top);
+       D32(WDOGA_CNT);
+       D16(WDOGA_CTL);
+       D32(WDOGA_STAT);
+       D32(WDOGB_CNT);
+       D16(WDOGB_CTL);
+       D32(WDOGB_STAT);
+#endif
+
+       /* BF533 glue */
+#ifdef FIO_FLAG_D
+#define PORTFIO FIO_FLAG_D
+#endif
+       /* BF561 glue */
+#ifdef FIO0_FLAG_D
+#define PORTFIO FIO0_FLAG_D
+#endif
+#ifdef FIO1_FLAG_D
+#define PORTGIO FIO1_FLAG_D
+#endif
+#ifdef FIO2_FLAG_D
+#define PORTHIO FIO2_FLAG_D
+#endif
+       parent = debugfs_create_dir("port", top);
+#ifdef PORTFIO
+       PORT(PORTFIO, 'F');
+#endif
+#ifdef PORTGIO
+       PORT(PORTGIO, 'G');
+#endif
+#ifdef PORTHIO
+       PORT(PORTHIO, 'H');
+#endif
+
+#ifdef __ADSPBF51x__
+       D16(PORTF_FER);
+       D16(PORTF_DRIVE);
+       D16(PORTF_HYSTERESIS);
+       D16(PORTF_MUX);
+
+       D16(PORTG_FER);
+       D16(PORTG_DRIVE);
+       D16(PORTG_HYSTERESIS);
+       D16(PORTG_MUX);
+
+       D16(PORTH_FER);
+       D16(PORTH_DRIVE);
+       D16(PORTH_HYSTERESIS);
+       D16(PORTH_MUX);
+
+       D16(MISCPORT_DRIVE);
+       D16(MISCPORT_HYSTERESIS);
+#endif /* BF51x */
+
+#ifdef __ADSPBF52x__
+       D16(PORTF_FER);
+       D16(PORTF_DRIVE);
+       D16(PORTF_HYSTERESIS);
+       D16(PORTF_MUX);
+       D16(PORTF_SLEW);
+
+       D16(PORTG_FER);
+       D16(PORTG_DRIVE);
+       D16(PORTG_HYSTERESIS);
+       D16(PORTG_MUX);
+       D16(PORTG_SLEW);
+
+       D16(PORTH_FER);
+       D16(PORTH_DRIVE);
+       D16(PORTH_HYSTERESIS);
+       D16(PORTH_MUX);
+       D16(PORTH_SLEW);
+
+       D16(MISCPORT_DRIVE);
+       D16(MISCPORT_HYSTERESIS);
+       D16(MISCPORT_SLEW);
+#endif /* BF52x */
+
+#ifdef BF537_FAMILY
+       D16(PORTF_FER);
+       D16(PORTG_FER);
+       D16(PORTH_FER);
+       D16(PORT_MUX);
+#endif /* BF534 BF536 BF537 */
+
+#ifdef BF538_FAMILY
+       D16(PORTCIO_FER);
+       D16(PORTCIO);
+       D16(PORTCIO_CLEAR);
+       D16(PORTCIO_SET);
+       D16(PORTCIO_TOGGLE);
+       D16(PORTCIO_DIR);
+       D16(PORTCIO_INEN);
+
+       D16(PORTDIO);
+       D16(PORTDIO_CLEAR);
+       D16(PORTDIO_DIR);
+       D16(PORTDIO_FER);
+       D16(PORTDIO_INEN);
+       D16(PORTDIO_SET);
+       D16(PORTDIO_TOGGLE);
+
+       D16(PORTEIO);
+       D16(PORTEIO_CLEAR);
+       D16(PORTEIO_DIR);
+       D16(PORTEIO_FER);
+       D16(PORTEIO_INEN);
+       D16(PORTEIO_SET);
+       D16(PORTEIO_TOGGLE);
+#endif /* BF538 BF539 */
+
+#ifdef __ADSPBF54x__
+       {
+               int num;
+               unsigned long base;
+               char *_buf, buf[32];
+
+               base = PORTA_FER;
+               for (num = 0; num < 10; ++num) {
+                       PORT(base, num);
+                       base += sizeof(struct bfin_gpio_regs);
+               }
+
+#define __PINT(uname, lname) __REGS(pint, #uname, lname)
+               parent = debugfs_create_dir("pint", top);
+               base = PINT0_MASK_SET;
+               for (num = 0; num < 4; ++num) {
+                       _buf = REGS_STR_PFX(buf, PINT, num);
+                       __PINT(MASK_SET, mask_set);
+                       __PINT(MASK_CLEAR, mask_clear);
+                       __PINT(IRQ, irq);
+                       __PINT(ASSIGN, assign);
+                       __PINT(EDGE_SET, edge_set);
+                       __PINT(EDGE_CLEAR, edge_clear);
+                       __PINT(INVERT_SET, invert_set);
+                       __PINT(INVERT_CLEAR, invert_clear);
+                       __PINT(PINSTATE, pinstate);
+                       __PINT(LATCH, latch);
+                       base += sizeof(struct bfin_pint_regs);
+               }
+
+       }
+#endif /* BF54x */
+
+       debug_mmrs_dentry = top;
+
+       return 0;
+}
+module_init(bfin_debug_mmrs_init);
+
+static void __exit bfin_debug_mmrs_exit(void)
+{
+       debugfs_remove_recursive(debug_mmrs_dentry);
+}
+module_exit(bfin_debug_mmrs_exit);
+
+MODULE_LICENSE("GPL");
index f37019c847c9b643c04676d0a2423f870286f16c..486426f8a0d79c203d591569e298b33e7040bfdb 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/io.h>
 #include <asm/system.h>
 #include <asm/atomic.h>
+#include <asm/irq_handler.h>
 
 DEFINE_PER_CPU(struct pt_regs, __ipipe_tick_regs);
 
index 1696d34f51c2ab369e54b2b319da1c2663e74358..ff3d747154ac6ecb5f97fb8027f8f7dfcb587988 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kallsyms.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <asm/irq_handler.h>
 #include <asm/trace.h>
 #include <asm/pda.h>
 
index 401eb1d8e3b43be33a2d6fb653d9e26fa754ae2c..679d0db352564584bc2a699adfee03c04c4a4d07 100644 (file)
@@ -145,16 +145,16 @@ int check_nmi_wdt_touched(void)
 {
        unsigned int this_cpu = smp_processor_id();
        unsigned int cpu;
+       cpumask_t mask;
 
-       cpumask_t mask = cpu_online_map;
-
+       cpumask_copy(&mask, cpu_online_mask);
        if (!atomic_read(&nmi_touched[this_cpu]))
                return 0;
 
        atomic_set(&nmi_touched[this_cpu], 0);
 
-       cpu_clear(this_cpu, mask);
-       for_each_cpu_mask(cpu, mask) {
+       cpumask_clear_cpu(this_cpu, &mask);
+       for_each_cpu(cpu, &mask) {
                invalidate_dcache_range((unsigned long)(&nmi_touched[cpu]),
                                (unsigned long)(&nmi_touched[cpu]));
                if (!atomic_read(&nmi_touched[cpu]))
diff --git a/arch/blackfin/kernel/perf_event.c b/arch/blackfin/kernel/perf_event.c
new file mode 100644 (file)
index 0000000..04300f2
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Blackfin performance counters
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Ripped from SuperH version:
+ *
+ *  Copyright (C) 2009  Paul Mundt
+ *
+ * Heavily based on the x86 and PowerPC implementations.
+ *
+ * x86:
+ *  Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
+ *  Copyright (C) 2009 Jaswinder Singh Rajput
+ *  Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
+ *  Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *  Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
+ *
+ * ppc:
+ *  Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/perf_event.h>
+#include <asm/bfin_pfmon.h>
+
+/*
+ * We have two counters, and each counter can support an event type.
+ * The 'o' is PFCNTx=1 and 's' is PFCNTx=0
+ *
+ * 0x04 o pc invariant branches
+ * 0x06 o mispredicted branches
+ * 0x09 o predicted branches taken
+ * 0x0B o EXCPT insn
+ * 0x0C o CSYNC/SSYNC insn
+ * 0x0D o Insns committed
+ * 0x0E o Interrupts taken
+ * 0x0F o Misaligned address exceptions
+ * 0x80 o Code memory fetches stalled due to DMA
+ * 0x83 o 64bit insn fetches delivered
+ * 0x9A o data cache fills (bank a)
+ * 0x9B o data cache fills (bank b)
+ * 0x9C o data cache lines evicted (bank a)
+ * 0x9D o data cache lines evicted (bank b)
+ * 0x9E o data cache high priority fills
+ * 0x9F o data cache low priority fills
+ * 0x00 s loop 0 iterations
+ * 0x01 s loop 1 iterations
+ * 0x0A s CSYNC/SSYNC stalls
+ * 0x10 s DAG read/after write hazards
+ * 0x13 s RAW data hazards
+ * 0x81 s code TAG stalls
+ * 0x82 s code fill stalls
+ * 0x90 s processor to memory stalls
+ * 0x91 s data memory stalls not hidden by 0x90
+ * 0x92 s data store buffer full stalls
+ * 0x93 s data memory write buffer full stalls due to high->low priority
+ * 0x95 s data memory fill buffer stalls
+ * 0x96 s data TAG collision stalls
+ * 0x97 s data collision stalls
+ * 0x98 s data stalls
+ * 0x99 s data stalls sent to processor
+ */
+
+static const int event_map[] = {
+       /* use CYCLES cpu register */
+       [PERF_COUNT_HW_CPU_CYCLES]          = -1,
+       [PERF_COUNT_HW_INSTRUCTIONS]        = 0x0D,
+       [PERF_COUNT_HW_CACHE_REFERENCES]    = -1,
+       [PERF_COUNT_HW_CACHE_MISSES]        = 0x83,
+       [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x09,
+       [PERF_COUNT_HW_BRANCH_MISSES]       = 0x06,
+       [PERF_COUNT_HW_BUS_CYCLES]          = -1,
+};
+
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+static const int cache_events[PERF_COUNT_HW_CACHE_MAX]
+                             [PERF_COUNT_HW_CACHE_OP_MAX]
+                             [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+       [C(L1D)] = {    /* Data bank A */
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0x9A,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0,
+               },
+       },
+
+       [C(L1I)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0x83,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = 0,
+                       [C(RESULT_MISS)  ] = 0,
+               },
+       },
+
+       [C(LL)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+       },
+
+       [C(DTLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+       },
+
+       [C(ITLB)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+       },
+
+       [C(BPU)] = {
+               [C(OP_READ)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_WRITE)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+               [C(OP_PREFETCH)] = {
+                       [C(RESULT_ACCESS)] = -1,
+                       [C(RESULT_MISS)  ] = -1,
+               },
+       },
+};
+
+const char *perf_pmu_name(void)
+{
+       return "bfin";
+}
+EXPORT_SYMBOL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+       return ARRAY_SIZE(event_map);
+}
+EXPORT_SYMBOL(perf_num_counters);
+
+static u64 bfin_pfmon_read(int idx)
+{
+       return bfin_read32(PFCNTR0 + (idx * 4));
+}
+
+static void bfin_pfmon_disable(struct hw_perf_event *hwc, int idx)
+{
+       bfin_write_PFCTL(bfin_read_PFCTL() & ~PFCEN(idx, PFCEN_MASK));
+}
+
+static void bfin_pfmon_enable(struct hw_perf_event *hwc, int idx)
+{
+       u32 val, mask;
+
+       val = PFPWR;
+       if (idx) {
+               mask = ~(PFCNT1 | PFMON1 | PFCEN1 | PEMUSW1);
+               /* The packed config is for event0, so shift it to event1 slots */
+               val |= (hwc->config << (PFMON1_P - PFMON0_P));
+               val |= (hwc->config & PFCNT0) << (PFCNT1_P - PFCNT0_P);
+               bfin_write_PFCNTR1(0);
+       } else {
+               mask = ~(PFCNT0 | PFMON0 | PFCEN0 | PEMUSW0);
+               val |= hwc->config;
+               bfin_write_PFCNTR0(0);
+       }
+
+       bfin_write_PFCTL((bfin_read_PFCTL() & mask) | val);
+}
+
+static void bfin_pfmon_disable_all(void)
+{
+       bfin_write_PFCTL(bfin_read_PFCTL() & ~PFPWR);
+}
+
+static void bfin_pfmon_enable_all(void)
+{
+       bfin_write_PFCTL(bfin_read_PFCTL() | PFPWR);
+}
+
+struct cpu_hw_events {
+       struct perf_event *events[MAX_HWEVENTS];
+       unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
+};
+DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+static int hw_perf_cache_event(int config, int *evp)
+{
+       unsigned long type, op, result;
+       int ev;
+
+       /* unpack config */
+       type = config & 0xff;
+       op = (config >> 8) & 0xff;
+       result = (config >> 16) & 0xff;
+
+       if (type >= PERF_COUNT_HW_CACHE_MAX ||
+           op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+           result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+               return -EINVAL;
+
+       ev = cache_events[type][op][result];
+       if (ev == 0)
+               return -EOPNOTSUPP;
+       if (ev == -1)
+               return -EINVAL;
+       *evp = ev;
+       return 0;
+}
+
+static void bfin_perf_event_update(struct perf_event *event,
+                                  struct hw_perf_event *hwc, int idx)
+{
+       u64 prev_raw_count, new_raw_count;
+       s64 delta;
+       int shift = 0;
+
+       /*
+        * Depending on the counter configuration, they may or may not
+        * be chained, in which case the previous counter value can be
+        * updated underneath us if the lower-half overflows.
+        *
+        * Our tactic to handle this is to first atomically read and
+        * exchange a new raw count - then add that new-prev delta
+        * count to the generic counter atomically.
+        *
+        * As there is no interrupt associated with the overflow events,
+        * this is the simplest approach for maintaining consistency.
+        */
+again:
+       prev_raw_count = local64_read(&hwc->prev_count);
+       new_raw_count = bfin_pfmon_read(idx);
+
+       if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+                            new_raw_count) != prev_raw_count)
+               goto again;
+
+       /*
+        * Now we have the new raw value and have updated the prev
+        * timestamp already. We can now calculate the elapsed delta
+        * (counter-)time and add that to the generic counter.
+        *
+        * Careful, not all hw sign-extends above the physical width
+        * of the count.
+        */
+       delta = (new_raw_count << shift) - (prev_raw_count << shift);
+       delta >>= shift;
+
+       local64_add(delta, &event->count);
+}
+
+static void bfin_pmu_stop(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+
+       if (!(event->hw.state & PERF_HES_STOPPED)) {
+               bfin_pfmon_disable(hwc, idx);
+               cpuc->events[idx] = NULL;
+               event->hw.state |= PERF_HES_STOPPED;
+       }
+
+       if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) {
+               bfin_perf_event_update(event, &event->hw, idx);
+               event->hw.state |= PERF_HES_UPTODATE;
+       }
+}
+
+static void bfin_pmu_start(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+
+       if (WARN_ON_ONCE(idx == -1))
+               return;
+
+       if (flags & PERF_EF_RELOAD)
+               WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+       cpuc->events[idx] = event;
+       event->hw.state = 0;
+       bfin_pfmon_enable(hwc, idx);
+}
+
+static void bfin_pmu_del(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+       bfin_pmu_stop(event, PERF_EF_UPDATE);
+       __clear_bit(event->hw.idx, cpuc->used_mask);
+
+       perf_event_update_userpage(event);
+}
+
+static int bfin_pmu_add(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+       int ret = -EAGAIN;
+
+       perf_pmu_disable(event->pmu);
+
+       if (__test_and_set_bit(idx, cpuc->used_mask)) {
+               idx = find_first_zero_bit(cpuc->used_mask, MAX_HWEVENTS);
+               if (idx == MAX_HWEVENTS)
+                       goto out;
+
+               __set_bit(idx, cpuc->used_mask);
+               hwc->idx = idx;
+       }
+
+       bfin_pfmon_disable(hwc, idx);
+
+       event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+       if (flags & PERF_EF_START)
+               bfin_pmu_start(event, PERF_EF_RELOAD);
+
+       perf_event_update_userpage(event);
+       ret = 0;
+out:
+       perf_pmu_enable(event->pmu);
+       return ret;
+}
+
+static void bfin_pmu_read(struct perf_event *event)
+{
+       bfin_perf_event_update(event, &event->hw, event->hw.idx);
+}
+
+static int bfin_pmu_event_init(struct perf_event *event)
+{
+       struct perf_event_attr *attr = &event->attr;
+       struct hw_perf_event *hwc = &event->hw;
+       int config = -1;
+       int ret;
+
+       if (attr->exclude_hv || attr->exclude_idle)
+               return -EPERM;
+
+       /*
+        * All of the on-chip counters are "limited", in that they have
+        * no interrupts, and are therefore unable to do sampling without
+        * further work and timer assistance.
+        */
+       if (hwc->sample_period)
+               return -EINVAL;
+
+       ret = 0;
+       switch (attr->type) {
+       case PERF_TYPE_RAW:
+               config = PFMON(0, attr->config & PFMON_MASK) |
+                       PFCNT(0, !(attr->config & 0x100));
+               break;
+       case PERF_TYPE_HW_CACHE:
+               ret = hw_perf_cache_event(attr->config, &config);
+               break;
+       case PERF_TYPE_HARDWARE:
+               if (attr->config >= ARRAY_SIZE(event_map))
+                       return -EINVAL;
+
+               config = event_map[attr->config];
+               break;
+       }
+
+       if (config == -1)
+               return -EINVAL;
+
+       if (!attr->exclude_kernel)
+               config |= PFCEN(0, PFCEN_ENABLE_SUPV);
+       if (!attr->exclude_user)
+               config |= PFCEN(0, PFCEN_ENABLE_USER);
+
+       hwc->config |= config;
+
+       return ret;
+}
+
+static void bfin_pmu_enable(struct pmu *pmu)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct perf_event *event;
+       struct hw_perf_event *hwc;
+       int i;
+
+       for (i = 0; i < MAX_HWEVENTS; ++i) {
+               event = cpuc->events[i];
+               if (!event)
+                       continue;
+               hwc = &event->hw;
+               bfin_pfmon_enable(hwc, hwc->idx);
+       }
+
+       bfin_pfmon_enable_all();
+}
+
+static void bfin_pmu_disable(struct pmu *pmu)
+{
+       bfin_pfmon_disable_all();
+}
+
+static struct pmu pmu = {
+       .pmu_enable  = bfin_pmu_enable,
+       .pmu_disable = bfin_pmu_disable,
+       .event_init  = bfin_pmu_event_init,
+       .add         = bfin_pmu_add,
+       .del         = bfin_pmu_del,
+       .start       = bfin_pmu_start,
+       .stop        = bfin_pmu_stop,
+       .read        = bfin_pmu_read,
+};
+
+static void bfin_pmu_setup(int cpu)
+{
+       struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
+
+       memset(cpuhw, 0, sizeof(struct cpu_hw_events));
+}
+
+static int __cpuinit
+bfin_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (long)hcpu;
+
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+               bfin_write_PFCTL(0);
+               bfin_pmu_setup(cpu);
+               break;
+
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static int __init bfin_pmu_init(void)
+{
+       int ret;
+
+       ret = perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
+       if (!ret)
+               perf_cpu_notifier(bfin_pmu_notifier);
+
+       return ret;
+}
+early_initcall(bfin_pmu_init);
index b407bc8ad9186f05fee0f657ffec48e7aab87efe..6a660fa921b59aba0c22d0ece7747ec5abcf0eca 100644 (file)
@@ -171,10 +171,8 @@ asmlinkage int bfin_clone(struct pt_regs *regs)
        unsigned long newsp;
 
 #ifdef __ARCH_SYNC_CORE_DCACHE
-       if (current->rt.nr_cpus_allowed == num_possible_cpus()) {
-               current->cpus_allowed = cpumask_of_cpu(smp_processor_id());
-               current->rt.nr_cpus_allowed = 1;
-       }
+       if (current->rt.nr_cpus_allowed == num_possible_cpus())
+               set_cpus_allowed_ptr(current, cpumask_of(smp_processor_id()));
 #endif
 
        /* syscall2 puts clone_flags in r0 and usp in r1 */
index 53d08dee8531b1ba588fcef55a97b288a89c0054..488bdc51aaa5fd9efa71bc4e6e75dba45fc1521d 100644 (file)
@@ -23,6 +23,9 @@
 __attribute__ ((__l1_text__, __noreturn__))
 static void bfin_reset(void)
 {
+       if (!ANOMALY_05000353 && !ANOMALY_05000386)
+               bfrom_SoftReset((void *)(L1_SCRATCH_START + L1_SCRATCH_LENGTH - 20));
+
        /* Wait for completion of "system" events such as cache line
         * line fills so that we avoid infinite stalls later on as
         * much as possible.  This code is in L1, so it won't trigger
@@ -30,46 +33,40 @@ static void bfin_reset(void)
         */
        __builtin_bfin_ssync();
 
-       /* The bootrom checks to see how it was reset and will
-        * automatically perform a software reset for us when
-        * it starts executing after the core reset.
-        */
-       if (ANOMALY_05000353 || ANOMALY_05000386) {
-               /* Initiate System software reset. */
-               bfin_write_SWRST(0x7);
+       /* Initiate System software reset. */
+       bfin_write_SWRST(0x7);
 
-               /* Due to the way reset is handled in the hardware, we need
-                * to delay for 10 SCLKS.  The only reliable way to do this is
-                * to calculate the CCLK/SCLK ratio and multiply 10.  For now,
-                * we'll assume worse case which is a 1:15 ratio.
-                */
-               asm(
-                       "LSETUP (1f, 1f) LC0 = %0\n"
-                       "1: nop;"
-                       :
-                       : "a" (15 * 10)
-                       : "LC0", "LB0", "LT0"
-               );
+       /* Due to the way reset is handled in the hardware, we need
+        * to delay for 10 SCLKS.  The only reliable way to do this is
+        * to calculate the CCLK/SCLK ratio and multiply 10.  For now,
+        * we'll assume worse case which is a 1:15 ratio.
+        */
+       asm(
+               "LSETUP (1f, 1f) LC0 = %0\n"
+               "1: nop;"
+               :
+               : "a" (15 * 10)
+               : "LC0", "LB0", "LT0"
+       );
 
-               /* Clear System software reset */
-               bfin_write_SWRST(0);
+       /* Clear System software reset */
+       bfin_write_SWRST(0);
 
-               /* The BF526 ROM will crash during reset */
+       /* The BF526 ROM will crash during reset */
 #if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__)
-               bfin_read_SWRST();
+       bfin_read_SWRST();
 #endif
 
-               /* Wait for the SWRST write to complete.  Cannot rely on SSYNC
-                * though as the System state is all reset now.
-                */
-               asm(
-                       "LSETUP (1f, 1f) LC1 = %0\n"
-                       "1: nop;"
-                       :
-                       : "a" (15 * 1)
-                       : "LC1", "LB1", "LT1"
-               );
-       }
+       /* Wait for the SWRST write to complete.  Cannot rely on SSYNC
+        * though as the System state is all reset now.
+        */
+       asm(
+               "LSETUP (1f, 1f) LC1 = %0\n"
+               "1: nop;"
+               :
+               : "a" (15 * 1)
+               : "LC1", "LB1", "LT1"
+       );
 
        while (1)
                /* Issue core reset */
index 805c6132c7796b26a632c85df14b8a58d508e1de..536bd9d7e0cfb80392e3ed43b8ac8f6fb106fce0 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/cpu.h>
 #include <asm/fixed_code.h>
 #include <asm/early_printk.h>
+#include <asm/irq_handler.h>
 
 u16 _bfin_swrst;
 EXPORT_SYMBOL(_bfin_swrst);
@@ -105,6 +106,8 @@ void __cpuinit bfin_setup_caches(unsigned int cpu)
        bfin_dcache_init(dcplb_tbl[cpu]);
 #endif
 
+       bfin_setup_cpudata(cpu);
+
        /*
         * In cache coherence emulation mode, we need to have the
         * D-cache enabled before running any atomic operation which
@@ -163,7 +166,6 @@ void __cpuinit bfin_setup_cpudata(unsigned int cpu)
 {
        struct blackfin_cpudata *cpudata = &per_cpu(cpu_data, cpu);
 
-       cpudata->idle = current;
        cpudata->imemctl = bfin_read_IMEM_CONTROL();
        cpudata->dmemctl = bfin_read_DMEM_CONTROL();
 }
@@ -851,6 +853,7 @@ void __init native_machine_early_platform_add_devices(void)
 
 void __init setup_arch(char **cmdline_p)
 {
+       u32 mmr;
        unsigned long sclk, cclk;
 
        native_machine_early_platform_add_devices();
@@ -902,10 +905,10 @@ void __init setup_arch(char **cmdline_p)
        bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTLVAL);
 #endif
 #ifdef CONFIG_BFIN_HYSTERESIS_CONTROL
-       bfin_write_PORTF_HYSTERISIS(HYST_PORTF_0_15);
-       bfin_write_PORTG_HYSTERISIS(HYST_PORTG_0_15);
-       bfin_write_PORTH_HYSTERISIS(HYST_PORTH_0_15);
-       bfin_write_MISCPORT_HYSTERISIS((bfin_read_MISCPORT_HYSTERISIS() &
+       bfin_write_PORTF_HYSTERESIS(HYST_PORTF_0_15);
+       bfin_write_PORTG_HYSTERESIS(HYST_PORTG_0_15);
+       bfin_write_PORTH_HYSTERESIS(HYST_PORTH_0_15);
+       bfin_write_MISCPORT_HYSTERESIS((bfin_read_MISCPORT_HYSTERESIS() &
                                        ~HYST_NONEGPIO_MASK) | HYST_NONEGPIO);
 #endif
 
@@ -921,17 +924,14 @@ void __init setup_arch(char **cmdline_p)
                bfin_read_IMDMA_D1_IRQ_STATUS();
        }
 #endif
-       printk(KERN_INFO "Hardware Trace ");
-       if (bfin_read_TBUFCTL() & 0x1)
-               printk(KERN_CONT "Active ");
-       else
-               printk(KERN_CONT "Off ");
-       if (bfin_read_TBUFCTL() & 0x2)
-               printk(KERN_CONT "and Enabled\n");
-       else
-               printk(KERN_CONT "and Disabled\n");
 
-       printk(KERN_INFO "Boot Mode: %i\n", bfin_read_SYSCR() & 0xF);
+       mmr = bfin_read_TBUFCTL();
+       printk(KERN_INFO "Hardware Trace %s and %sabled\n",
+               (mmr & 0x1) ? "active" : "off",
+               (mmr & 0x2) ? "en" : "dis");
+
+       mmr = bfin_read_SYSCR();
+       printk(KERN_INFO "Boot Mode: %i\n", mmr & 0xF);
 
        /* Newer parts mirror SWRST bits in SYSCR */
 #if defined(CONFIG_BF53x) || defined(CONFIG_BF561) || \
@@ -939,7 +939,7 @@ void __init setup_arch(char **cmdline_p)
        _bfin_swrst = bfin_read_SWRST();
 #else
        /* Clear boot mode field */
-       _bfin_swrst = bfin_read_SYSCR() & ~0xf;
+       _bfin_swrst = mmr & ~0xf;
 #endif
 
 #ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
@@ -1036,8 +1036,6 @@ void __init setup_arch(char **cmdline_p)
 static int __init topology_init(void)
 {
        unsigned int cpu;
-       /* Record CPU-private information for the boot processor. */
-       bfin_setup_cpudata(0);
 
        for_each_possible_cpu(cpu) {
                register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu);
@@ -1283,12 +1281,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                   dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS,
                   BFIN_DLINES);
 #ifdef __ARCH_SYNC_CORE_DCACHE
-       seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", dcache_invld_count[cpu_num]);
+       seq_printf(m, "dcache flushes\t: %lu\n", dcache_invld_count[cpu_num]);
 #endif
 #ifdef __ARCH_SYNC_CORE_ICACHE
-       seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", icache_invld_count[cpu_num]);
+       seq_printf(m, "icache flushes\t: %lu\n", icache_invld_count[cpu_num]);
 #endif
 
+       seq_printf(m, "\n");
+
        if (cpu_num != num_possible_cpus() - 1)
                return 0;
 
@@ -1312,13 +1312,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                              " in data cache\n");
        }
        seq_printf(m, "board name\t: %s\n", bfin_board_name);
-       seq_printf(m, "board memory\t: %ld kB (0x%p -> 0x%p)\n",
-                physical_mem_end >> 10, (void *)0, (void *)physical_mem_end);
-       seq_printf(m, "kernel memory\t: %d kB (0x%p -> 0x%p)\n",
+       seq_printf(m, "board memory\t: %ld kB (0x%08lx -> 0x%08lx)\n",
+               physical_mem_end >> 10, 0ul, physical_mem_end);
+       seq_printf(m, "kernel memory\t: %d kB (0x%08lx -> 0x%08lx)\n",
                ((int)memory_end - (int)_rambase) >> 10,
-               (void *)_rambase,
-               (void *)memory_end);
-       seq_printf(m, "\n");
+               _rambase, memory_end);
 
        return 0;
 }
@@ -1326,7 +1324,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
        if (*pos == 0)
-               *pos = first_cpu(cpu_online_map);
+               *pos = cpumask_first(cpu_online_mask);
        if (*pos >= num_online_cpus())
                return NULL;
 
@@ -1335,7 +1333,7 @@ static void *c_start(struct seq_file *m, loff_t *pos)
 
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       *pos = next_cpu(*pos, cpu_online_map);
+       *pos = cpumask_next(*pos, cpu_online_mask);
 
        return c_start(m, pos);
 }
index 8d85c8c6f857c5dd985bd4f2bbd07b4668b157fb..3ac5b66d14aa72de5234801dbcc47e61c3a5f67d 100644 (file)
@@ -155,14 +155,8 @@ SECTIONS
                SECURITY_INITCALL
                INIT_RAM_FS
 
-               . = ALIGN(4);
                ___per_cpu_load = .;
-               ___per_cpu_start = .;
-               *(.data.percpu.first)
-               *(.data.percpu.page_aligned)
-               *(.data.percpu)
-               *(.data.percpu.shared_aligned)
-               ___per_cpu_end = .;
+               PERCPU_INPUT(32)
 
                EXIT_DATA
                __einitdata = .;
index 24918c5f7ea1d9c30379c3a219c90830f87ec763..d2f076fbbc9ee001d4cf1310f1a61559c560145e 100644 (file)
@@ -5,7 +5,7 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000371 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (0)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000467 (0)
 #define ANOMALY_05000474 (0)
 #define ANOMALY_05000475 (0)
+#define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
 
 #endif
index b657d37a3402d094b3191c5a1e4bba1a0f65a6c7..bb79627f0929532ec763516063007b45907498b9 100644 (file)
 #define bfin_write_PORTG_SLEW(val)             bfin_write16(PORTG_SLEW, val)
 #define bfin_read_PORTH_SLEW()                 bfin_read16(PORTH_SLEW)
 #define bfin_write_PORTH_SLEW(val)             bfin_write16(PORTH_SLEW, val)
-#define bfin_read_PORTF_HYSTERISIS()           bfin_read16(PORTF_HYSTERISIS)
-#define bfin_write_PORTF_HYSTERISIS(val)       bfin_write16(PORTF_HYSTERISIS, val)
-#define bfin_read_PORTG_HYSTERISIS()           bfin_read16(PORTG_HYSTERISIS)
-#define bfin_write_PORTG_HYSTERISIS(val)       bfin_write16(PORTG_HYSTERISIS, val)
-#define bfin_read_PORTH_HYSTERISIS()           bfin_read16(PORTH_HYSTERISIS)
-#define bfin_write_PORTH_HYSTERISIS(val)       bfin_write16(PORTH_HYSTERISIS, val)
+#define bfin_read_PORTF_HYSTERESIS()           bfin_read16(PORTF_HYSTERESIS)
+#define bfin_write_PORTF_HYSTERESIS(val)       bfin_write16(PORTF_HYSTERESIS, val)
+#define bfin_read_PORTG_HYSTERESIS()           bfin_read16(PORTG_HYSTERESIS)
+#define bfin_write_PORTG_HYSTERESIS(val)       bfin_write16(PORTG_HYSTERESIS, val)
+#define bfin_read_PORTH_HYSTERESIS()           bfin_read16(PORTH_HYSTERESIS)
+#define bfin_write_PORTH_HYSTERESIS(val)       bfin_write16(PORTH_HYSTERESIS, val)
 #define bfin_read_MISCPORT_DRIVE()             bfin_read16(MISCPORT_DRIVE)
 #define bfin_write_MISCPORT_DRIVE(val)         bfin_write16(MISCPORT_DRIVE, val)
 #define bfin_read_MISCPORT_SLEW()              bfin_read16(MISCPORT_SLEW)
 #define bfin_write_MISCPORT_SLEW(val)          bfin_write16(MISCPORT_SLEW, val)
-#define bfin_read_MISCPORT_HYSTERISIS()                bfin_read16(MISCPORT_HYSTERISIS)
-#define bfin_write_MISCPORT_HYSTERISIS(val)    bfin_write16(MISCPORT_HYSTERISIS, val)
+#define bfin_read_MISCPORT_HYSTERESIS()                bfin_read16(MISCPORT_HYSTERESIS)
+#define bfin_write_MISCPORT_HYSTERESIS(val)    bfin_write16(MISCPORT_HYSTERESIS, val)
 
 /* HOST Port Registers */
 
index cb1172f5075729994a12c27680b881fba226cffe..729704078cd720350c1d9388cd4e69bd07cdc536 100644 (file)
 #define PORTF_SLEW              0xFFC03230      /* Port F slew control */
 #define PORTG_SLEW              0xFFC03234      /* Port G slew control */
 #define PORTH_SLEW              0xFFC03238      /* Port H slew control */
-#define PORTF_HYSTERISIS        0xFFC03240      /* Port F Schmitt trigger control */
-#define PORTG_HYSTERISIS        0xFFC03244      /* Port G Schmitt trigger control */
-#define PORTH_HYSTERISIS        0xFFC03248      /* Port H Schmitt trigger control */
+#define PORTF_HYSTERESIS        0xFFC03240      /* Port F Schmitt trigger control */
+#define PORTG_HYSTERESIS        0xFFC03244      /* Port G Schmitt trigger control */
+#define PORTH_HYSTERESIS        0xFFC03248      /* Port H Schmitt trigger control */
 #define MISCPORT_DRIVE          0xFFC03280      /* Misc Port drive strength control */
 #define MISCPORT_SLEW           0xFFC03284      /* Misc Port slew control */
-#define MISCPORT_HYSTERISIS     0xFFC03288      /* Misc Port Schmitt trigger control */
+#define MISCPORT_HYSTERESIS     0xFFC03288      /* Misc Port Schmitt trigger control */
 
 
 /***********************************************************************************
index 435e76e31aaabd6c91145a1f3f6531e466841c16..edf8efd457dcb8c912448f583e2d23b2e02e0f00 100644 (file)
@@ -7,38 +7,9 @@
 #ifndef _BF518_IRQ_H_
 #define _BF518_IRQ_H_
 
-/*
- * Interrupt source definitions
-       Event Source    Core Event Name
-       Core        Emulation               **
-       Events         (highest priority)  EMU         0
-       Reset                   RST         1
-       NMI                     NMI         2
-       Exception               EVX         3
-       Reserved                --          4
-       Hardware Error          IVHW        5
-       Core Timer              IVTMR       6 *
-
-       .....
-
-        Software Interrupt 1    IVG14       31
-        Software Interrupt 2    --
-        (lowest priority)  IVG15       32 *
-*/
-
-#define NR_PERI_INTS    (2 * 32)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU                        0       /* Emulation */
-#define IRQ_RST                        1       /* reset */
-#define IRQ_NMI                        2       /* Non Maskable */
-#define IRQ_EVX                        3       /* Exception */
-#define IRQ_UNUSED             4       /* - unused interrupt */
-#define IRQ_HWERR              5       /* Hardware Error */
-#define IRQ_CORETMR            6       /* Core timer */
-
-#define BFIN_IRQ(x)            ((x) + 7)
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           (2 * 32)
 
 #define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
 #define IRQ_DMA0_ERROR         BFIN_IRQ(1)     /* DMA Error 0 (generic) */
 #define IRQ_UART0_ERROR                BFIN_IRQ(12)    /* UART0 Status */
 #define IRQ_UART1_ERROR                BFIN_IRQ(13)    /* UART1 Status */
 #define IRQ_RTC                        BFIN_IRQ(14)    /* RTC */
-#define IRQ_PPI                BFIN_IRQ(15)    /* DMA Channel 0 (PPI) */
+#define IRQ_PPI                        BFIN_IRQ(15)    /* DMA Channel 0 (PPI) */
 #define IRQ_SPORT0_RX          BFIN_IRQ(16)    /* DMA 3 Channel (SPORT0 RX) */
 #define IRQ_SPORT0_TX          BFIN_IRQ(17)    /* DMA 4 Channel (SPORT0 TX) */
 #define IRQ_RSI                        BFIN_IRQ(17)    /* DMA 4 Channel (RSI) */
 #define IRQ_SPORT1_RX          BFIN_IRQ(18)    /* DMA 5 Channel (SPORT1 RX/SPI) */
 #define IRQ_SPI1               BFIN_IRQ(18)    /* DMA 5 Channel (SPI1) */
 #define IRQ_SPORT1_TX          BFIN_IRQ(19)    /* DMA 6 Channel (SPORT1 TX) */
-#define IRQ_TWI                BFIN_IRQ(20)    /* TWI */
-#define IRQ_SPI0               BFIN_IRQ(21)    /* DMA 7 Channel (SPI0) */
-#define IRQ_UART0_RX           BFIN_IRQ(22)    /* DMA8 Channel (UART0 RX) */
-#define IRQ_UART0_TX           BFIN_IRQ(23)    /* DMA9 Channel (UART0 TX) */
-#define IRQ_UART1_RX           BFIN_IRQ(24)    /* DMA10 Channel (UART1 RX) */
-#define IRQ_UART1_TX           BFIN_IRQ(25)    /* DMA11 Channel (UART1 TX) */
-#define IRQ_OPTSEC             BFIN_IRQ(26)    /* OTPSEC Interrupt */
-#define IRQ_CNT                BFIN_IRQ(27)    /* GP Counter */
-#define IRQ_MAC_RX             BFIN_IRQ(28)    /* DMA1 Channel (MAC RX) */
-#define IRQ_PORTH_INTA         BFIN_IRQ(29)    /* Port H Interrupt A */
+#define IRQ_TWI                        BFIN_IRQ(20)    /* TWI */
+#define IRQ_SPI0               BFIN_IRQ(21)    /* DMA 7 Channel (SPI0) */
+#define IRQ_UART0_RX           BFIN_IRQ(22)    /* DMA8 Channel (UART0 RX) */
+#define IRQ_UART0_TX           BFIN_IRQ(23)    /* DMA9 Channel (UART0 TX) */
+#define IRQ_UART1_RX           BFIN_IRQ(24)    /* DMA10 Channel (UART1 RX) */
+#define IRQ_UART1_TX           BFIN_IRQ(25)    /* DMA11 Channel (UART1 TX) */
+#define IRQ_OPTSEC             BFIN_IRQ(26)    /* OTPSEC Interrupt */
+#define IRQ_CNT                        BFIN_IRQ(27)    /* GP Counter */
+#define IRQ_MAC_RX             BFIN_IRQ(28)    /* DMA1 Channel (MAC RX) */
+#define IRQ_PORTH_INTA         BFIN_IRQ(29)    /* Port H Interrupt A */
 #define IRQ_MAC_TX             BFIN_IRQ(30)    /* DMA2 Channel (MAC TX) */
 #define IRQ_PORTH_INTB         BFIN_IRQ(31)    /* Port H Interrupt B */
 #define IRQ_TIMER0             BFIN_IRQ(32)    /* Timer 0 */
 #define IRQ_PWM_SYNC           BFIN_IRQ(54)    /* PWM Sync Interrupt */
 #define IRQ_PTP_STAT           BFIN_IRQ(55)    /* PTP Stat Interrupt */
 
-#define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
-
-#define IRQ_PF0         71
-#define IRQ_PF1         72
-#define IRQ_PF2         73
-#define IRQ_PF3         74
-#define IRQ_PF4         75
-#define IRQ_PF5         76
-#define IRQ_PF6         77
-#define IRQ_PF7         78
-#define IRQ_PF8         79
-#define IRQ_PF9         80
-#define IRQ_PF10        81
-#define IRQ_PF11        82
-#define IRQ_PF12        83
-#define IRQ_PF13        84
-#define IRQ_PF14        85
-#define IRQ_PF15        86
-
-#define IRQ_PG0         87
-#define IRQ_PG1         88
-#define IRQ_PG2         89
-#define IRQ_PG3         90
-#define IRQ_PG4         91
-#define IRQ_PG5         92
-#define IRQ_PG6         93
-#define IRQ_PG7         94
-#define IRQ_PG8         95
-#define IRQ_PG9         96
-#define IRQ_PG10        97
-#define IRQ_PG11        98
-#define IRQ_PG12        99
-#define IRQ_PG13        100
-#define IRQ_PG14        101
-#define IRQ_PG15        102
-
-#define IRQ_PH0         103
-#define IRQ_PH1         104
-#define IRQ_PH2         105
-#define IRQ_PH3         106
-#define IRQ_PH4         107
-#define IRQ_PH5         108
-#define IRQ_PH6         109
-#define IRQ_PH7         110
-#define IRQ_PH8         111
-#define IRQ_PH9         112
-#define IRQ_PH10        113
-#define IRQ_PH11        114
-#define IRQ_PH12        115
-#define IRQ_PH13        116
-#define IRQ_PH14        117
-#define IRQ_PH15        118
-
-#define GPIO_IRQ_BASE  IRQ_PF0
-
-#define IRQ_MAC_PHYINT         119 /* PHY_INT Interrupt */
-#define IRQ_MAC_MMCINT         120 /* MMC Counter Interrupt */
-#define IRQ_MAC_RXFSINT                121 /* RX Frame-Status Interrupt */
-#define IRQ_MAC_TXFSINT                122 /* TX Frame-Status Interrupt */
-#define IRQ_MAC_WAKEDET                123 /* Wake-Up Interrupt */
-#define IRQ_MAC_RXDMAERR       124 /* RX DMA Direction Error Interrupt */
-#define IRQ_MAC_TXDMAERR       125 /* TX DMA Direction Error Interrupt */
-#define IRQ_MAC_STMDONE                126 /* Station Mgt. Transfer Done Interrupt */
-
-#define NR_MACH_IRQS   (IRQ_MAC_STMDONE + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
+#define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
+
+#define IRQ_PF0                        71
+#define IRQ_PF1                        72
+#define IRQ_PF2                        73
+#define IRQ_PF3                        74
+#define IRQ_PF4                        75
+#define IRQ_PF5                        76
+#define IRQ_PF6                        77
+#define IRQ_PF7                        78
+#define IRQ_PF8                        79
+#define IRQ_PF9                        80
+#define IRQ_PF10               81
+#define IRQ_PF11               82
+#define IRQ_PF12               83
+#define IRQ_PF13               84
+#define IRQ_PF14               85
+#define IRQ_PF15               86
+
+#define IRQ_PG0                        87
+#define IRQ_PG1                        88
+#define IRQ_PG2                        89
+#define IRQ_PG3                        90
+#define IRQ_PG4                        91
+#define IRQ_PG5                        92
+#define IRQ_PG6                        93
+#define IRQ_PG7                        94
+#define IRQ_PG8                        95
+#define IRQ_PG9                        96
+#define IRQ_PG10               97
+#define IRQ_PG11               98
+#define IRQ_PG12               99
+#define IRQ_PG13               100
+#define IRQ_PG14               101
+#define IRQ_PG15               102
+
+#define IRQ_PH0                        103
+#define IRQ_PH1                        104
+#define IRQ_PH2                        105
+#define IRQ_PH3                        106
+#define IRQ_PH4                        107
+#define IRQ_PH5                        108
+#define IRQ_PH6                        109
+#define IRQ_PH7                        110
+#define IRQ_PH8                        111
+#define IRQ_PH9                        112
+#define IRQ_PH10               113
+#define IRQ_PH11               114
+#define IRQ_PH12               115
+#define IRQ_PH13               116
+#define IRQ_PH14               117
+#define IRQ_PH15               118
+
+#define GPIO_IRQ_BASE          IRQ_PF0
+
+#define IRQ_MAC_PHYINT         119     /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT         120     /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT                121     /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT                122     /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET                123     /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR       124     /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR       125     /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE                126     /* Station Mgt. Transfer Done Interrupt */
+
+#define NR_MACH_IRQS           (IRQ_MAC_STMDONE + 1)
 
 /* IAR0 BIT FIELDS */
 #define IRQ_PLL_WAKEUP_POS     0
 #define IRQ_DMA0_ERROR_POS     4
-#define IRQ_DMAR0_BLK_POS      8
-#define IRQ_DMAR1_BLK_POS      12
-#define IRQ_DMAR0_OVR_POS      16
-#define IRQ_DMAR1_OVR_POS      20
-#define IRQ_PPI_ERROR_POS      24
-#define IRQ_MAC_ERROR_POS      28
+#define IRQ_DMAR0_BLK_POS      8
+#define IRQ_DMAR1_BLK_POS      12
+#define IRQ_DMAR0_OVR_POS      16
+#define IRQ_DMAR1_OVR_POS      20
+#define IRQ_PPI_ERROR_POS      24
+#define IRQ_MAC_ERROR_POS      28
 
 /* IAR1 BIT FIELDS */
 #define IRQ_SPORT0_ERROR_POS   0
 #define IRQ_SPORT1_ERROR_POS   4
 #define IRQ_PTP_ERROR_POS      8
-#define IRQ_UART0_ERROR_POS    16
-#define IRQ_UART1_ERROR_POS    20
-#define IRQ_RTC_POS            24
-#define IRQ_PPI_POS            28
+#define IRQ_UART0_ERROR_POS    16
+#define IRQ_UART1_ERROR_POS    20
+#define IRQ_RTC_POS            24
+#define IRQ_PPI_POS            28
 
 /* IAR2 BIT FIELDS */
 #define IRQ_SPORT0_RX_POS      0
 #define IRQ_SPORT1_RX_POS      8
 #define IRQ_SPI1_POS           8
 #define IRQ_SPORT1_TX_POS      12
-#define IRQ_TWI_POS            16
-#define IRQ_SPI0_POS           20
-#define IRQ_UART0_RX_POS       24
-#define IRQ_UART0_TX_POS       28
+#define IRQ_TWI_POS            16
+#define IRQ_SPI0_POS           20
+#define IRQ_UART0_RX_POS       24
+#define IRQ_UART0_TX_POS       28
 
 /* IAR3 BIT FIELDS */
-#define IRQ_UART1_RX_POS       0
-#define IRQ_UART1_TX_POS       4
-#define IRQ_OPTSEC_POS         8
-#define IRQ_CNT_POS            12
-#define IRQ_MAC_RX_POS         16
+#define IRQ_UART1_RX_POS       0
+#define IRQ_UART1_TX_POS       4
+#define IRQ_OPTSEC_POS         8
+#define IRQ_CNT_POS            12
+#define IRQ_MAC_RX_POS         16
 #define IRQ_PORTH_INTA_POS     20
-#define IRQ_MAC_TX_POS         24
+#define IRQ_MAC_TX_POS         24
 #define IRQ_PORTH_INTB_POS     28
 
 /* IAR4 BIT FIELDS */
 /* IAR5 BIT FIELDS */
 #define IRQ_PORTG_INTA_POS     0
 #define IRQ_PORTG_INTB_POS     4
-#define IRQ_MEM_DMA0_POS       8
-#define IRQ_MEM_DMA1_POS       12
-#define IRQ_WATCH_POS          16
+#define IRQ_MEM_DMA0_POS       8
+#define IRQ_MEM_DMA1_POS       12
+#define IRQ_WATCH_POS          16
 #define IRQ_PORTF_INTA_POS     20
 #define IRQ_PORTF_INTB_POS     24
-#define IRQ_SPI0_ERROR_POS     28
+#define IRQ_SPI0_ERROR_POS     28
 
 /* IAR6 BIT FIELDS */
-#define IRQ_SPI1_ERROR_POS     0
-#define IRQ_RSI_INT0_POS       12
-#define IRQ_RSI_INT1_POS       16
-#define IRQ_PWM_TRIP_POS       20
-#define IRQ_PWM_SYNC_POS       24
-#define IRQ_PTP_STAT_POS       28
-
-#endif                         /* _BF518_IRQ_H_ */
+#define IRQ_SPI1_ERROR_POS     0
+#define IRQ_RSI_INT0_POS       12
+#define IRQ_RSI_INT1_POS       16
+#define IRQ_PWM_TRIP_POS       20
+#define IRQ_PWM_SYNC_POS       24
+#define IRQ_PTP_STAT_POS       28
+
+#endif
index 2cd2ff6f304374d3e5c4427879f5d48e273d39f8..e67ac772066894e18a8acd8512e188f56fba6812 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
 #include <linux/spi/ad7877.h>
+#include <asm/bfin_sport.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
@@ -526,11 +527,69 @@ static struct bfin5xx_spi_chip spidev_chip_info = {
 };
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+
+static const u16 bfin_snd_pin[][7] = {
+       {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+               P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0, 0},
+       {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+               P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_TFS, 0},
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+       {
+               .pin_req = &bfin_snd_pin[0][0],
+       },
+       {
+               .pin_req = &bfin_snd_pin[1][0],
+       },
+};
+
+#define BFIN_SND_RES(x) \
+       [x] = { \
+               { \
+                       .start = SPORT##x##_TCR1, \
+                       .end = SPORT##x##_TCR1, \
+                       .flags = IORESOURCE_MEM \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_RX, \
+                       .end = CH_SPORT##x##_RX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_TX, \
+                       .end = CH_SPORT##x##_TX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = IRQ_SPORT##x##_ERROR, \
+                       .end = IRQ_SPORT##x##_ERROR, \
+                       .flags = IORESOURCE_IRQ, \
+               } \
+       }
+
+static struct resource bfin_snd_resources[][4] = {
+       BFIN_SND_RES(0),
+       BFIN_SND_RES(1),
+};
+
+static struct platform_device bfin_pcm = {
+       .name = "bfin-pcm-audio",
+       .id = -1,
+};
+#endif
+
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
 static struct platform_device bfin_i2s = {
        .name = "bfin-i2s",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
@@ -538,7 +597,11 @@ static struct platform_device bfin_i2s = {
 static struct platform_device bfin_tdm = {
        .name = "bfin-tdm",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
@@ -583,7 +646,9 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .max_speed_hz = 3125000,     /* max spi clock (SCK) speed in HZ */
                .bus_num = 0,
                .chip_select = 4,
+               .platform_data = "ad1836",
                .controller_data = &ad1836_spi_chip_info,
+               .mode = SPI_MODE_3,
        },
 #endif
 #if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
@@ -1211,6 +1276,11 @@ static struct platform_device *stamp_devices[] __initdata = {
        &ezkit_flash_device,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+       &bfin_pcm,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
        &bfin_i2s,
 #endif
index 9358afa05c90f47058f6cc522ee0a5edbbce5e21..e66a7e89cd3c621b0b7c928a153b1f57917d7b32 100644 (file)
@@ -5,14 +5,14 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
  *  - Revision E, 03/15/2010; ADSP-BF526 Blackfin Processor Anomaly List
- *  - Revision G, 08/25/2009; ADSP-BF527 Blackfin Processor Anomaly List
+ *  - Revision H, 04/29/2010; ADSP-BF527 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000483 (1)
 /* PLL_CTL Change Using bfrom_SysControl() Can Result in Processor Overclocking */
 #define ANOMALY_05000485 (_ANOMALY_BF526_BF527(< 2, < 3))
+/* The CODEC Zero-Cross Detect Feature is not Functional */
+#define ANOMALY_05000487 (1)
 /* IFLUSH sucks at life */
 #define ANOMALY_05000491 (1)
 
 #define ANOMALY_05000323 (0)
 #define ANOMALY_05000362 (1)
 #define ANOMALY_05000363 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000402 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
 
 #endif
index 618dfcdfa91ab1055e3af4ef962d132b45e8237c..2c12e879aa4ed48682f7063c4859b31a09fddfe5 100644 (file)
 #define bfin_write_PORTG_SLEW(val)             bfin_write16(PORTG_SLEW, val)
 #define bfin_read_PORTH_SLEW()                 bfin_read16(PORTH_SLEW)
 #define bfin_write_PORTH_SLEW(val)             bfin_write16(PORTH_SLEW, val)
-#define bfin_read_PORTF_HYSTERISIS()           bfin_read16(PORTF_HYSTERISIS)
-#define bfin_write_PORTF_HYSTERISIS(val)       bfin_write16(PORTF_HYSTERISIS, val)
-#define bfin_read_PORTG_HYSTERISIS()           bfin_read16(PORTG_HYSTERISIS)
-#define bfin_write_PORTG_HYSTERISIS(val)       bfin_write16(PORTG_HYSTERISIS, val)
-#define bfin_read_PORTH_HYSTERISIS()           bfin_read16(PORTH_HYSTERISIS)
-#define bfin_write_PORTH_HYSTERISIS(val)       bfin_write16(PORTH_HYSTERISIS, val)
+#define bfin_read_PORTF_HYSTERESIS()           bfin_read16(PORTF_HYSTERESIS)
+#define bfin_write_PORTF_HYSTERESIS(val)       bfin_write16(PORTF_HYSTERESIS, val)
+#define bfin_read_PORTG_HYSTERESIS()           bfin_read16(PORTG_HYSTERESIS)
+#define bfin_write_PORTG_HYSTERESIS(val)       bfin_write16(PORTG_HYSTERESIS, val)
+#define bfin_read_PORTH_HYSTERESIS()           bfin_read16(PORTH_HYSTERESIS)
+#define bfin_write_PORTH_HYSTERESIS(val)       bfin_write16(PORTH_HYSTERESIS, val)
 #define bfin_read_MISCPORT_DRIVE()             bfin_read16(MISCPORT_DRIVE)
 #define bfin_write_MISCPORT_DRIVE(val)         bfin_write16(MISCPORT_DRIVE, val)
 #define bfin_read_MISCPORT_SLEW()              bfin_read16(MISCPORT_SLEW)
 #define bfin_write_MISCPORT_SLEW(val)          bfin_write16(MISCPORT_SLEW, val)
-#define bfin_read_MISCPORT_HYSTERISIS()                bfin_read16(MISCPORT_HYSTERISIS)
-#define bfin_write_MISCPORT_HYSTERISIS(val)    bfin_write16(MISCPORT_HYSTERISIS, val)
+#define bfin_read_MISCPORT_HYSTERESIS()                bfin_read16(MISCPORT_HYSTERESIS)
+#define bfin_write_MISCPORT_HYSTERESIS(val)    bfin_write16(MISCPORT_HYSTERESIS, val)
 
 /* HOST Port Registers */
 
index 84ef11e52644cea94f70ca235a8b2888cdf0859d..37d353a19722f3242c70ccdd3776570581dab744 100644 (file)
 #define PORTF_SLEW              0xFFC03230      /* Port F slew control */
 #define PORTG_SLEW              0xFFC03234      /* Port G slew control */
 #define PORTH_SLEW              0xFFC03238      /* Port H slew control */
-#define PORTF_HYSTERISIS        0xFFC03240      /* Port F Schmitt trigger control */
-#define PORTG_HYSTERISIS        0xFFC03244      /* Port G Schmitt trigger control */
-#define PORTH_HYSTERISIS        0xFFC03248      /* Port H Schmitt trigger control */
+#define PORTF_HYSTERESIS        0xFFC03240      /* Port F Schmitt trigger control */
+#define PORTG_HYSTERESIS        0xFFC03244      /* Port G Schmitt trigger control */
+#define PORTH_HYSTERESIS        0xFFC03248      /* Port H Schmitt trigger control */
 #define MISCPORT_DRIVE          0xFFC03280      /* Misc Port drive strength control */
 #define MISCPORT_SLEW           0xFFC03284      /* Misc Port slew control */
-#define MISCPORT_HYSTERISIS     0xFFC03288      /* Misc Port Schmitt trigger control */
+#define MISCPORT_HYSTERESIS     0xFFC03288      /* Misc Port Schmitt trigger control */
 
 
 /***********************************************************************************
index 704d9253e41d35373e48643557d48dbdd05efc7d..ed7310ff819b5a2e49b23bdcc2a1983f1ef669e2 100644 (file)
@@ -7,38 +7,9 @@
 #ifndef _BF527_IRQ_H_
 #define _BF527_IRQ_H_
 
-/*
- * Interrupt source definitions
-       Event Source    Core Event Name
-       Core        Emulation               **
-       Events         (highest priority)  EMU         0
-       Reset                   RST         1
-       NMI                     NMI         2
-       Exception               EVX         3
-       Reserved                --          4
-       Hardware Error          IVHW        5
-       Core Timer              IVTMR       6 *
-
-       .....
-
-        Software Interrupt 1    IVG14       31
-        Software Interrupt 2    --
-        (lowest priority)  IVG15       32 *
-*/
-
-#define NR_PERI_INTS    (2 * 32)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU                        0       /* Emulation */
-#define IRQ_RST                        1       /* reset */
-#define IRQ_NMI                        2       /* Non Maskable */
-#define IRQ_EVX                        3       /* Exception */
-#define IRQ_UNUSED             4       /* - unused interrupt */
-#define IRQ_HWERR              5       /* Hardware Error */
-#define IRQ_CORETMR            6       /* Core timer */
-
-#define BFIN_IRQ(x)            ((x) + 7)
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           (2 * 32)
 
 #define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
 #define IRQ_DMA0_ERROR         BFIN_IRQ(1)     /* DMA Error 0 (generic) */
 #define IRQ_UART0_ERROR                BFIN_IRQ(12)    /* UART0 Status */
 #define IRQ_UART1_ERROR                BFIN_IRQ(13)    /* UART1 Status */
 #define IRQ_RTC                        BFIN_IRQ(14)    /* RTC */
-#define IRQ_PPI                BFIN_IRQ(15)    /* DMA Channel 0 (PPI/NAND) */
+#define IRQ_PPI                        BFIN_IRQ(15)    /* DMA Channel 0 (PPI/NAND) */
 #define IRQ_SPORT0_RX          BFIN_IRQ(16)    /* DMA 3 Channel (SPORT0 RX) */
 #define IRQ_SPORT0_TX          BFIN_IRQ(17)    /* DMA 4 Channel (SPORT0 TX) */
 #define IRQ_SPORT1_RX          BFIN_IRQ(18)    /* DMA 5 Channel (SPORT1 RX) */
 #define IRQ_SPORT1_TX          BFIN_IRQ(19)    /* DMA 6 Channel (SPORT1 TX) */
-#define IRQ_TWI                BFIN_IRQ(20)    /* TWI */
-#define IRQ_SPI                BFIN_IRQ(21)    /* DMA 7 Channel (SPI) */
-#define IRQ_UART0_RX           BFIN_IRQ(22)    /* DMA8 Channel (UART0 RX) */
-#define IRQ_UART0_TX           BFIN_IRQ(23)    /* DMA9 Channel (UART0 TX) */
-#define IRQ_UART1_RX           BFIN_IRQ(24)    /* DMA10 Channel (UART1 RX) */
-#define IRQ_UART1_TX           BFIN_IRQ(25)    /* DMA11 Channel (UART1 TX) */
-#define IRQ_OPTSEC             BFIN_IRQ(26)    /* OTPSEC Interrupt */
-#define IRQ_CNT                BFIN_IRQ(27)    /* GP Counter */
-#define IRQ_MAC_RX             BFIN_IRQ(28)    /* DMA1 Channel (MAC RX/HDMA) */
-#define IRQ_PORTH_INTA         BFIN_IRQ(29)    /* Port H Interrupt A */
+#define IRQ_TWI                        BFIN_IRQ(20)    /* TWI */
+#define IRQ_SPI                        BFIN_IRQ(21)    /* DMA 7 Channel (SPI) */
+#define IRQ_UART0_RX           BFIN_IRQ(22)    /* DMA8 Channel (UART0 RX) */
+#define IRQ_UART0_TX           BFIN_IRQ(23)    /* DMA9 Channel (UART0 TX) */
+#define IRQ_UART1_RX           BFIN_IRQ(24)    /* DMA10 Channel (UART1 RX) */
+#define IRQ_UART1_TX           BFIN_IRQ(25)    /* DMA11 Channel (UART1 TX) */
+#define IRQ_OPTSEC             BFIN_IRQ(26)    /* OTPSEC Interrupt */
+#define IRQ_CNT                        BFIN_IRQ(27)    /* GP Counter */
+#define IRQ_MAC_RX             BFIN_IRQ(28)    /* DMA1 Channel (MAC RX/HDMA) */
+#define IRQ_PORTH_INTA         BFIN_IRQ(29)    /* Port H Interrupt A */
 #define IRQ_MAC_TX             BFIN_IRQ(30)    /* DMA2 Channel (MAC TX/NAND) */
 #define IRQ_NFC                        BFIN_IRQ(30)    /* DMA2 Channel (MAC TX/NAND) */
 #define IRQ_PORTH_INTB         BFIN_IRQ(31)    /* Port H Interrupt B */
 #define IRQ_USB_INT2           BFIN_IRQ(54)    /* USB_INT2 Interrupt */
 #define IRQ_USB_DMA            BFIN_IRQ(55)    /* USB_DMAINT Interrupt */
 
-#define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
-
-#define IRQ_PF0         71
-#define IRQ_PF1         72
-#define IRQ_PF2         73
-#define IRQ_PF3         74
-#define IRQ_PF4         75
-#define IRQ_PF5         76
-#define IRQ_PF6         77
-#define IRQ_PF7         78
-#define IRQ_PF8         79
-#define IRQ_PF9         80
-#define IRQ_PF10        81
-#define IRQ_PF11        82
-#define IRQ_PF12        83
-#define IRQ_PF13        84
-#define IRQ_PF14        85
-#define IRQ_PF15        86
-
-#define IRQ_PG0         87
-#define IRQ_PG1         88
-#define IRQ_PG2         89
-#define IRQ_PG3         90
-#define IRQ_PG4         91
-#define IRQ_PG5         92
-#define IRQ_PG6         93
-#define IRQ_PG7         94
-#define IRQ_PG8         95
-#define IRQ_PG9         96
-#define IRQ_PG10        97
-#define IRQ_PG11        98
-#define IRQ_PG12        99
-#define IRQ_PG13        100
-#define IRQ_PG14        101
-#define IRQ_PG15        102
-
-#define IRQ_PH0         103
-#define IRQ_PH1         104
-#define IRQ_PH2         105
-#define IRQ_PH3         106
-#define IRQ_PH4         107
-#define IRQ_PH5         108
-#define IRQ_PH6         109
-#define IRQ_PH7         110
-#define IRQ_PH8         111
-#define IRQ_PH9         112
-#define IRQ_PH10        113
-#define IRQ_PH11        114
-#define IRQ_PH12        115
-#define IRQ_PH13        116
-#define IRQ_PH14        117
-#define IRQ_PH15        118
-
-#define GPIO_IRQ_BASE  IRQ_PF0
-
-#define IRQ_MAC_PHYINT         119 /* PHY_INT Interrupt */
-#define IRQ_MAC_MMCINT         120 /* MMC Counter Interrupt */
-#define IRQ_MAC_RXFSINT                121 /* RX Frame-Status Interrupt */
-#define IRQ_MAC_TXFSINT                122 /* TX Frame-Status Interrupt */
-#define IRQ_MAC_WAKEDET                123 /* Wake-Up Interrupt */
-#define IRQ_MAC_RXDMAERR       124 /* RX DMA Direction Error Interrupt */
-#define IRQ_MAC_TXDMAERR       125 /* TX DMA Direction Error Interrupt */
-#define IRQ_MAC_STMDONE                126 /* Station Mgt. Transfer Done Interrupt */
-
-#define NR_MACH_IRQS   (IRQ_MAC_STMDONE + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
+#define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
+
+#define IRQ_PF0                        71
+#define IRQ_PF1                        72
+#define IRQ_PF2                        73
+#define IRQ_PF3                        74
+#define IRQ_PF4                        75
+#define IRQ_PF5                        76
+#define IRQ_PF6                        77
+#define IRQ_PF7                        78
+#define IRQ_PF8                        79
+#define IRQ_PF9                        80
+#define IRQ_PF10               81
+#define IRQ_PF11               82
+#define IRQ_PF12               83
+#define IRQ_PF13               84
+#define IRQ_PF14               85
+#define IRQ_PF15               86
+
+#define IRQ_PG0                        87
+#define IRQ_PG1                        88
+#define IRQ_PG2                        89
+#define IRQ_PG3                        90
+#define IRQ_PG4                        91
+#define IRQ_PG5                        92
+#define IRQ_PG6                        93
+#define IRQ_PG7                        94
+#define IRQ_PG8                        95
+#define IRQ_PG9                        96
+#define IRQ_PG10               97
+#define IRQ_PG11               98
+#define IRQ_PG12               99
+#define IRQ_PG13               100
+#define IRQ_PG14               101
+#define IRQ_PG15               102
+
+#define IRQ_PH0                        103
+#define IRQ_PH1                        104
+#define IRQ_PH2                        105
+#define IRQ_PH3                        106
+#define IRQ_PH4                        107
+#define IRQ_PH5                        108
+#define IRQ_PH6                        109
+#define IRQ_PH7                        110
+#define IRQ_PH8                        111
+#define IRQ_PH9                        112
+#define IRQ_PH10               113
+#define IRQ_PH11               114
+#define IRQ_PH12               115
+#define IRQ_PH13               116
+#define IRQ_PH14               117
+#define IRQ_PH15               118
+
+#define GPIO_IRQ_BASE          IRQ_PF0
+
+#define IRQ_MAC_PHYINT         119     /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT         120     /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT                121     /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT                122     /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET                123     /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR       124     /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR       125     /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE                126     /* Station Mgt. Transfer Done Interrupt */
+
+#define NR_MACH_IRQS           (IRQ_MAC_STMDONE + 1)
 
 /* IAR0 BIT FIELDS */
 #define IRQ_PLL_WAKEUP_POS     0
 #define IRQ_DMA0_ERROR_POS     4
-#define IRQ_DMAR0_BLK_POS      8
-#define IRQ_DMAR1_BLK_POS      12
-#define IRQ_DMAR0_OVR_POS      16
-#define IRQ_DMAR1_OVR_POS      20
-#define IRQ_PPI_ERROR_POS      24
-#define IRQ_MAC_ERROR_POS      28
+#define IRQ_DMAR0_BLK_POS      8
+#define IRQ_DMAR1_BLK_POS      12
+#define IRQ_DMAR0_OVR_POS      16
+#define IRQ_DMAR1_OVR_POS      20
+#define IRQ_PPI_ERROR_POS      24
+#define IRQ_MAC_ERROR_POS      28
 
 /* IAR1 BIT FIELDS */
 #define IRQ_SPORT0_ERROR_POS   0
 #define IRQ_SPORT1_ERROR_POS   4
-#define IRQ_UART0_ERROR_POS    16
-#define IRQ_UART1_ERROR_POS    20
-#define IRQ_RTC_POS            24
-#define IRQ_PPI_POS            28
+#define IRQ_UART0_ERROR_POS    16
+#define IRQ_UART1_ERROR_POS    20
+#define IRQ_RTC_POS            24
+#define IRQ_PPI_POS            28
 
 /* IAR2 BIT FIELDS */
 #define IRQ_SPORT0_RX_POS      0
 #define IRQ_SPORT0_TX_POS      4
 #define IRQ_SPORT1_RX_POS      8
 #define IRQ_SPORT1_TX_POS      12
-#define IRQ_TWI_POS            16
-#define IRQ_SPI_POS            20
-#define IRQ_UART0_RX_POS       24
-#define IRQ_UART0_TX_POS       28
+#define IRQ_TWI_POS            16
+#define IRQ_SPI_POS            20
+#define IRQ_UART0_RX_POS       24
+#define IRQ_UART0_TX_POS       28
 
 /* IAR3 BIT FIELDS */
-#define IRQ_UART1_RX_POS       0
-#define IRQ_UART1_TX_POS       4
-#define IRQ_OPTSEC_POS         8
-#define IRQ_CNT_POS            12
-#define IRQ_MAC_RX_POS         16
+#define IRQ_UART1_RX_POS       0
+#define IRQ_UART1_TX_POS       4
+#define IRQ_OPTSEC_POS         8
+#define IRQ_CNT_POS            12
+#define IRQ_MAC_RX_POS         16
 #define IRQ_PORTH_INTA_POS     20
-#define IRQ_MAC_TX_POS         24
+#define IRQ_MAC_TX_POS         24
 #define IRQ_PORTH_INTB_POS     28
 
 /* IAR4 BIT FIELDS */
 /* IAR5 BIT FIELDS */
 #define IRQ_PORTG_INTA_POS     0
 #define IRQ_PORTG_INTB_POS     4
-#define IRQ_MEM_DMA0_POS       8
-#define IRQ_MEM_DMA1_POS       12
-#define IRQ_WATCH_POS          16
+#define IRQ_MEM_DMA0_POS       8
+#define IRQ_MEM_DMA1_POS       12
+#define IRQ_WATCH_POS          16
 #define IRQ_PORTF_INTA_POS     20
 #define IRQ_PORTF_INTB_POS     24
-#define IRQ_SPI_ERROR_POS      28
+#define IRQ_SPI_ERROR_POS      28
 
 /* IAR6 BIT FIELDS */
-#define IRQ_NFC_ERROR_POS      0
-#define IRQ_HDMA_ERROR_POS     4
-#define IRQ_HDMA_POS           8
-#define IRQ_USB_EINT_POS       12
-#define IRQ_USB_INT0_POS       16
-#define IRQ_USB_INT1_POS       20
-#define IRQ_USB_INT2_POS       24
-#define IRQ_USB_DMA_POS        28
-
-#endif                         /* _BF527_IRQ_H_ */
+#define IRQ_NFC_ERROR_POS      0
+#define IRQ_HDMA_ERROR_POS     4
+#define IRQ_HDMA_POS           8
+#define IRQ_USB_EINT_POS       12
+#define IRQ_USB_INT0_POS       16
+#define IRQ_USB_INT1_POS       20
+#define IRQ_USB_INT2_POS       24
+#define IRQ_USB_DMA_POS                28
+
+#endif
index 78f8721879180f72c630755455573be016dca955..72aa59440f825f7145874cb090865a489881a7ac 100644 (file)
@@ -5,13 +5,13 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision E, 09/18/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
+ *  - Revision F, 05/25/2010; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000443 (1)
 /* False Hardware Error when RETI Points to Invalid Memory */
 #define ANOMALY_05000461 (1)
+/* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */
+#define ANOMALY_05000462 (1)
+/* Boot Failure When SDRAM Control Signals Toggle Coming Out Of Reset */
+#define ANOMALY_05000471 (1)
 /* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */
 #define ANOMALY_05000473 (1)
 /* Possible Lockup Condition whem Modifying PLL from External Memory */
 #define ANOMALY_05000362 (1)
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000456 (0)
 #define ANOMALY_05000465 (0)
 #define ANOMALY_05000467 (0)
 #define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
 
 #endif
index 1f7e9765d954b9bbcd20d9d0d376dbd383d64848..709733754142b93f70f13acbf0d95b19a7e69940 100644 (file)
@@ -7,83 +7,36 @@
 #ifndef _BF533_IRQ_H_
 #define _BF533_IRQ_H_
 
-/*
- * Interrupt source definitions
-             Event Source    Core Event Name
-Core        Emulation               **
- Events         (highest priority)  EMU         0
-            Reset                   RST         1
-            NMI                     NMI         2
-            Exception               EVX         3
-            Reserved                --          4
-            Hardware Error          IVHW        5
-            Core Timer              IVTMR       6 *
-           PLL Wakeup Interrupt    IVG7        7
-           DMA Error (generic)     IVG7        8
-           PPI Error Interrupt     IVG7        9
-           SPORT0 Error Interrupt  IVG7        10
-           SPORT1 Error Interrupt  IVG7        11
-           SPI Error Interrupt     IVG7        12
-           UART Error Interrupt    IVG7        13
-           RTC Interrupt           IVG8        14
-           DMA0 Interrupt (PPI)    IVG8        15
-           DMA1 (SPORT0 RX)        IVG9        16
-           DMA2 (SPORT0 TX)        IVG9        17
-           DMA3 (SPORT1 RX)        IVG9        18
-           DMA4 (SPORT1 TX)        IVG9        19
-           DMA5 (PPI)              IVG10       20
-           DMA6 (UART RX)          IVG10       21
-           DMA7 (UART TX)          IVG10       22
-           Timer0                  IVG11       23
-           Timer1                  IVG11       24
-           Timer2                  IVG11       25
-           PF Interrupt A          IVG12       26
-           PF Interrupt B          IVG12       27
-           DMA8/9 Interrupt        IVG13       28
-           DMA10/11 Interrupt      IVG13       29
-           Watchdog Timer          IVG13       30
+#include <mach-common/irq.h>
 
-            Softirq                IVG14       31
-            System Call    --
-                 (lowest priority)  IVG15       32 *
- */
-#define SYS_IRQS       31
-#define NR_PERI_INTS   24
+#define NR_PERI_INTS           24
 
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define        IRQ_EMU                 0       /*Emulation */
-#define        IRQ_RST                 1       /*reset */
-#define        IRQ_NMI                 2       /*Non Maskable */
-#define        IRQ_EVX                 3       /*Exception */
-#define        IRQ_UNUSED              4       /*- unused interrupt*/
-#define        IRQ_HWERR               5       /*Hardware Error */
-#define        IRQ_CORETMR             6       /*Core timer */
+#define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
+#define IRQ_DMA_ERROR          BFIN_IRQ(1)     /* DMA Error (general) */
+#define IRQ_PPI_ERROR          BFIN_IRQ(2)     /* PPI Error Interrupt */
+#define IRQ_SPORT0_ERROR       BFIN_IRQ(3)     /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR       BFIN_IRQ(4)     /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR          BFIN_IRQ(5)     /* SPI Error Interrupt */
+#define IRQ_UART0_ERROR                BFIN_IRQ(6)     /* UART Error Interrupt */
+#define IRQ_RTC                        BFIN_IRQ(7)     /* RTC Interrupt */
+#define IRQ_PPI                        BFIN_IRQ(8)     /* DMA0 Interrupt (PPI) */
+#define IRQ_SPORT0_RX          BFIN_IRQ(9)     /* DMA1 Interrupt (SPORT0 RX) */
+#define IRQ_SPORT0_TX          BFIN_IRQ(10)    /* DMA2 Interrupt (SPORT0 TX) */
+#define IRQ_SPORT1_RX          BFIN_IRQ(11)    /* DMA3 Interrupt (SPORT1 RX) */
+#define IRQ_SPORT1_TX          BFIN_IRQ(12)    /* DMA4 Interrupt (SPORT1 TX) */
+#define IRQ_SPI                        BFIN_IRQ(13)    /* DMA5 Interrupt (SPI) */
+#define IRQ_UART0_RX           BFIN_IRQ(14)    /* DMA6 Interrupt (UART RX) */
+#define IRQ_UART0_TX           BFIN_IRQ(15)    /* DMA7 Interrupt (UART TX) */
+#define IRQ_TIMER0             BFIN_IRQ(16)    /* Timer 0 */
+#define IRQ_TIMER1             BFIN_IRQ(17)    /* Timer 1 */
+#define IRQ_TIMER2             BFIN_IRQ(18)    /* Timer 2 */
+#define IRQ_PROG_INTA          BFIN_IRQ(19)    /* Programmable Flags A (8) */
+#define IRQ_PROG_INTB          BFIN_IRQ(20)    /* Programmable Flags B (8) */
+#define IRQ_MEM_DMA0           BFIN_IRQ(21)    /* DMA8/9 Interrupt (Memory DMA Stream 0) */
+#define IRQ_MEM_DMA1           BFIN_IRQ(22)    /* DMA10/11 Interrupt (Memory DMA Stream 1) */
+#define IRQ_WATCH              BFIN_IRQ(23)    /* Watch Dog Timer */
 
-#define        IRQ_PLL_WAKEUP          7       /*PLL Wakeup Interrupt */
-#define        IRQ_DMA_ERROR           8       /*DMA Error (general) */
-#define        IRQ_PPI_ERROR           9       /*PPI Error Interrupt */
-#define        IRQ_SPORT0_ERROR        10      /*SPORT0 Error Interrupt */
-#define        IRQ_SPORT1_ERROR        11      /*SPORT1 Error Interrupt */
-#define        IRQ_SPI_ERROR           12      /*SPI Error Interrupt */
-#define        IRQ_UART0_ERROR         13      /*UART Error Interrupt */
-#define        IRQ_RTC                 14      /*RTC Interrupt */
-#define        IRQ_PPI                 15      /*DMA0 Interrupt (PPI) */
-#define        IRQ_SPORT0_RX           16      /*DMA1 Interrupt (SPORT0 RX) */
-#define        IRQ_SPORT0_TX           17      /*DMA2 Interrupt (SPORT0 TX) */
-#define        IRQ_SPORT1_RX           18      /*DMA3 Interrupt (SPORT1 RX) */
-#define        IRQ_SPORT1_TX           19      /*DMA4 Interrupt (SPORT1 TX) */
-#define        IRQ_SPI                 20      /*DMA5 Interrupt (SPI) */
-#define        IRQ_UART0_RX            21      /*DMA6 Interrupt (UART RX) */
-#define        IRQ_UART0_TX            22      /*DMA7 Interrupt (UART TX) */
-#define        IRQ_TIMER0              23      /*Timer 0 */
-#define        IRQ_TIMER1              24      /*Timer 1 */
-#define        IRQ_TIMER2              25      /*Timer 2 */
-#define        IRQ_PROG_INTA           26      /*Programmable Flags A (8) */
-#define        IRQ_PROG_INTB           27      /*Programmable Flags B (8) */
-#define        IRQ_MEM_DMA0            28      /*DMA8/9 Interrupt (Memory DMA Stream 0) */
-#define        IRQ_MEM_DMA1            29      /*DMA10/11 Interrupt (Memory DMA Stream 1) */
-#define        IRQ_WATCH               30      /*Watch Dog Timer */
+#define SYS_IRQS               31
 
 #define IRQ_PF0                        33
 #define IRQ_PF1                        34
@@ -105,46 +58,35 @@ Core        Emulation               **
 #define GPIO_IRQ_BASE          IRQ_PF0
 
 #define NR_MACH_IRQS           (IRQ_PF15 + 1)
-#define NR_IRQS                        (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7                   7
-#define IVG8                   8
-#define IVG9                   9
-#define IVG10                  10
-#define IVG11                  11
-#define IVG12                  12
-#define IVG13                  13
-#define IVG14                  14
-#define IVG15                  15
 
-/* IAR0 BIT FIELDS*/
-#define RTC_ERROR_POS                  28
-#define UART_ERROR_POS                 24
-#define SPORT1_ERROR_POS               20
-#define SPI_ERROR_POS                  16
-#define SPORT0_ERROR_POS               12
-#define PPI_ERROR_POS                  8
-#define DMA_ERROR_POS                  4
-#define PLLWAKE_ERROR_POS              0
+/* IAR0 BIT FIELDS */
+#define RTC_ERROR_POS          28
+#define UART_ERROR_POS         24
+#define SPORT1_ERROR_POS       20
+#define SPI_ERROR_POS          16
+#define SPORT0_ERROR_POS       12
+#define PPI_ERROR_POS          8
+#define DMA_ERROR_POS          4
+#define PLLWAKE_ERROR_POS      0
 
-/* IAR1 BIT FIELDS*/
-#define DMA7_UARTTX_POS                        28
-#define DMA6_UARTRX_POS                        24
-#define DMA5_SPI_POS                   20
-#define DMA4_SPORT1TX_POS              16
-#define DMA3_SPORT1RX_POS              12
-#define DMA2_SPORT0TX_POS              8
-#define DMA1_SPORT0RX_POS              4
-#define DMA0_PPI_POS                   0
+/* IAR1 BIT FIELDS */
+#define DMA7_UARTTX_POS                28
+#define DMA6_UARTRX_POS                24
+#define DMA5_SPI_POS           20
+#define DMA4_SPORT1TX_POS      16
+#define DMA3_SPORT1RX_POS      12
+#define DMA2_SPORT0TX_POS      8
+#define DMA1_SPORT0RX_POS      4
+#define DMA0_PPI_POS           0
 
-/* IAR2 BIT FIELDS*/
-#define WDTIMER_POS                    28
-#define MEMDMA1_POS                    24
-#define MEMDMA0_POS                    20
-#define PFB_POS                                16
-#define PFA_POS                                12
-#define TIMER2_POS                     8
-#define TIMER1_POS                     4
-#define TIMER0_POS                     0
+/* IAR2 BIT FIELDS */
+#define WDTIMER_POS            28
+#define MEMDMA1_POS            24
+#define MEMDMA0_POS            20
+#define PFB_POS                        16
+#define PFA_POS                        12
+#define TIMER2_POS             8
+#define TIMER1_POS             4
+#define TIMER0_POS             0
 
-#endif                         /* _BF533_IRQ_H_ */
+#endif
index 3fa335405b317c9926c6bfe5fac4c6a16ffcbfdb..e16dc456004864b9e2eaa260667a1aa545279abb 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/reboot.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
+#include <asm/bfin_sport.h>
 #ifdef CONFIG_REGULATOR_FIXED_VOLTAGE
 #include <linux/regulator/fixed.h>
 #endif
@@ -2585,27 +2586,103 @@ static struct platform_device bfin_dpmc = {
        },
 };
 
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+       defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+
+#define SPORT_REQ(x) \
+       [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
+               P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
+
+static const u16 bfin_snd_pin[][7] = {
+       SPORT_REQ(0),
+       SPORT_REQ(1),
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+       {
+               .pin_req = &bfin_snd_pin[0][0],
+       },
+       {
+               .pin_req = &bfin_snd_pin[1][0],
+       },
+};
+
+#define BFIN_SND_RES(x) \
+       [x] = { \
+               { \
+                       .start = SPORT##x##_TCR1, \
+                       .end = SPORT##x##_TCR1, \
+                       .flags = IORESOURCE_MEM \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_RX, \
+                       .end = CH_SPORT##x##_RX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_TX, \
+                       .end = CH_SPORT##x##_TX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = IRQ_SPORT##x##_ERROR, \
+                       .end = IRQ_SPORT##x##_ERROR, \
+                       .flags = IORESOURCE_IRQ, \
+               } \
+       }
+
+static struct resource bfin_snd_resources[][4] = {
+       BFIN_SND_RES(0),
+       BFIN_SND_RES(1),
+};
+
+static struct platform_device bfin_pcm = {
+       .name = "bfin-pcm-audio",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+static struct platform_device bfin_ad73311_codec_device = {
+       .name = "ad73311",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
 static struct platform_device bfin_i2s = {
        .name = "bfin-i2s",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
 static struct platform_device bfin_tdm = {
        .name = "bfin-tdm",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
@@ -2796,17 +2873,28 @@ static struct platform_device *stamp_devices[] __initdata = {
        &stamp_flash_device,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+       defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+       &bfin_pcm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+       &bfin_ad73311_codec_device,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
        &bfin_i2s,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
        &bfin_tdm,
 #endif
 
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
        &bfin_ac97,
 #endif
+
 #if defined(CONFIG_REGULATOR_AD5398) || defined(CONFIG_REGULATOR_AD5398_MODULE)
 #if defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER) || \
        defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER_MODULE)
index 43df6afd22ad71c2fca56d00e708f7493204605b..7f8e5a9f5db63ef455e38108d166d3655f3b211a 100644 (file)
@@ -5,13 +5,13 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision D, 09/18/2008; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
+ *  - Revision E, 05/25/2010; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000443 (1)
 /* False Hardware Error when RETI Points to Invalid Memory */
 #define ANOMALY_05000461 (1)
+/* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */
+#define ANOMALY_05000462 (1)
 /* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */
 #define ANOMALY_05000473 (1)
 /* Possible Lockup Condition whem Modifying PLL from External Memory */
 #define ANOMALY_05000475 (1)
 /* TESTSET Instruction Cannot Be Interrupted */
 #define ANOMALY_05000477 (1)
+/* Multiple Simultaneous Urgent DMA Requests May Cause DMA System Instability */
+#define ANOMALY_05000480 (__SILICON_REVISION__ < 3)
 /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */
 #define ANOMALY_05000481 (1)
 /* IFLUSH sucks at life */
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000456 (0)
index 1a6d617c5fcf8680597f0b5b4143be15b5590201..b6ed8235bda4cfa811810076ee2d5255660622b8 100644 (file)
 #ifndef _BF537_IRQ_H_
 #define _BF537_IRQ_H_
 
-/*
- * Interrupt source definitions
- *            Event Source    Core Event Name
- * Core       Emulation               **
- * Events         (highest priority)  EMU         0
- *            Reset                   RST         1
- *            NMI                     NMI         2
- *            Exception               EVX         3
- *            Reserved                --          4
- *            Hardware Error          IVHW        5
- *            Core Timer              IVTMR       6
- *  .....
- *
- *            Softirq                IVG14
- *            System Call    --
- *               (lowest priority)    IVG15
- */
-
-#define SYS_IRQS        39
-#define NR_PERI_INTS    32
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU             0  /*Emulation */
-#define IRQ_RST             1  /*reset */
-#define IRQ_NMI             2  /*Non Maskable */
-#define IRQ_EVX             3  /*Exception */
-#define IRQ_UNUSED          4  /*- unused interrupt*/
-#define IRQ_HWERR           5  /*Hardware Error */
-#define IRQ_CORETMR         6  /*Core timer */
-
-#define IRQ_PLL_WAKEUP      7  /*PLL Wakeup Interrupt */
-#define IRQ_DMA_ERROR       8  /*DMA Error (general) */
-#define IRQ_GENERIC_ERROR   9  /*GENERIC Error Interrupt */
-#define IRQ_RTC             10 /*RTC Interrupt */
-#define IRQ_PPI             11 /*DMA0 Interrupt (PPI) */
-#define IRQ_SPORT0_RX       12 /*DMA3 Interrupt (SPORT0 RX) */
-#define IRQ_SPORT0_TX       13 /*DMA4 Interrupt (SPORT0 TX) */
-#define IRQ_SPORT1_RX       14 /*DMA5 Interrupt (SPORT1 RX) */
-#define IRQ_SPORT1_TX       15 /*DMA6 Interrupt (SPORT1 TX) */
-#define IRQ_TWI             16 /*TWI Interrupt */
-#define IRQ_SPI             17 /*DMA7 Interrupt (SPI) */
-#define IRQ_UART0_RX        18 /*DMA8 Interrupt (UART0 RX) */
-#define IRQ_UART0_TX        19 /*DMA9 Interrupt (UART0 TX) */
-#define IRQ_UART1_RX        20 /*DMA10 Interrupt (UART1 RX) */
-#define IRQ_UART1_TX        21 /*DMA11 Interrupt (UART1 TX) */
-#define IRQ_CAN_RX          22 /*CAN Receive Interrupt */
-#define IRQ_CAN_TX          23 /*CAN Transmit Interrupt */
-#define IRQ_MAC_RX          24 /*DMA1 (Ethernet RX) Interrupt */
-#define IRQ_MAC_TX          25 /*DMA2 (Ethernet TX) Interrupt */
-#define IRQ_TIMER0            26       /*Timer 0 */
-#define IRQ_TIMER1            27       /*Timer 1 */
-#define IRQ_TIMER2            28       /*Timer 2 */
-#define IRQ_TIMER3            29       /*Timer 3 */
-#define IRQ_TIMER4            30       /*Timer 4 */
-#define IRQ_TIMER5            31       /*Timer 5 */
-#define IRQ_TIMER6            32       /*Timer 6 */
-#define IRQ_TIMER7            33       /*Timer 7 */
-#define IRQ_PROG_INTA       34 /* PF Ports F&G (PF15:0) Interrupt A */
-#define IRQ_PORTG_INTB      35 /* PF Port G (PF15:0) Interrupt B */
-#define IRQ_MEM_DMA0        36 /*(Memory DMA Stream 0) */
-#define IRQ_MEM_DMA1        37 /*(Memory DMA Stream 1) */
-#define IRQ_PROG_INTB        38        /* PF Ports F (PF15:0) Interrupt B */
-#define IRQ_WATCH           38 /*Watch Dog Timer */
-
-#define IRQ_PPI_ERROR       42 /*PPI Error Interrupt */
-#define IRQ_CAN_ERROR       43 /*CAN Error Interrupt */
-#define IRQ_MAC_ERROR       44 /*MAC Status/Error Interrupt */
-#define IRQ_SPORT0_ERROR    45 /*SPORT0 Error Interrupt */
-#define IRQ_SPORT1_ERROR    46 /*SPORT1 Error Interrupt */
-#define IRQ_SPI_ERROR       47 /*SPI Error Interrupt */
-#define IRQ_UART0_ERROR     48 /*UART Error Interrupt */
-#define IRQ_UART1_ERROR     49 /*UART Error Interrupt */
-
-#define IRQ_PF0         50
-#define IRQ_PF1         51
-#define IRQ_PF2         52
-#define IRQ_PF3         53
-#define IRQ_PF4         54
-#define IRQ_PF5         55
-#define IRQ_PF6         56
-#define IRQ_PF7         57
-#define IRQ_PF8         58
-#define IRQ_PF9         59
-#define IRQ_PF10        60
-#define IRQ_PF11        61
-#define IRQ_PF12        62
-#define IRQ_PF13        63
-#define IRQ_PF14        64
-#define IRQ_PF15        65
-
-#define IRQ_PG0         66
-#define IRQ_PG1         67
-#define IRQ_PG2         68
-#define IRQ_PG3         69
-#define IRQ_PG4         70
-#define IRQ_PG5         71
-#define IRQ_PG6         72
-#define IRQ_PG7         73
-#define IRQ_PG8         74
-#define IRQ_PG9         75
-#define IRQ_PG10        76
-#define IRQ_PG11        77
-#define IRQ_PG12        78
-#define IRQ_PG13        79
-#define IRQ_PG14        80
-#define IRQ_PG15        81
-
-#define IRQ_PH0         82
-#define IRQ_PH1         83
-#define IRQ_PH2         84
-#define IRQ_PH3         85
-#define IRQ_PH4         86
-#define IRQ_PH5         87
-#define IRQ_PH6         88
-#define IRQ_PH7         89
-#define IRQ_PH8         90
-#define IRQ_PH9         91
-#define IRQ_PH10        92
-#define IRQ_PH11        93
-#define IRQ_PH12        94
-#define IRQ_PH13        95
-#define IRQ_PH14        96
-#define IRQ_PH15        97
-
-#define GPIO_IRQ_BASE  IRQ_PF0
-
-#define IRQ_MAC_PHYINT         98 /* PHY_INT Interrupt */
-#define IRQ_MAC_MMCINT         99 /* MMC Counter Interrupt */
-#define IRQ_MAC_RXFSINT                100 /* RX Frame-Status Interrupt */
-#define IRQ_MAC_TXFSINT                101 /* TX Frame-Status Interrupt */
-#define IRQ_MAC_WAKEDET                102 /* Wake-Up Interrupt */
-#define IRQ_MAC_RXDMAERR       103 /* RX DMA Direction Error Interrupt */
-#define IRQ_MAC_TXDMAERR       104 /* TX DMA Direction Error Interrupt */
-#define IRQ_MAC_STMDONE                105 /* Station Mgt. Transfer Done Interrupt */
-
-#define NR_MACH_IRQS   (IRQ_MAC_STMDONE + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
-
-/* IAR0 BIT FIELDS*/
-#define IRQ_PLL_WAKEUP_POS  0
-#define IRQ_DMA_ERROR_POS   4
-#define IRQ_ERROR_POS       8
-#define IRQ_RTC_POS         12
-#define IRQ_PPI_POS         16
-#define IRQ_SPORT0_RX_POS   20
-#define IRQ_SPORT0_TX_POS   24
-#define IRQ_SPORT1_RX_POS   28
-
-/* IAR1 BIT FIELDS*/
-#define IRQ_SPORT1_TX_POS   0
-#define IRQ_TWI_POS         4
-#define IRQ_SPI_POS         8
-#define IRQ_UART0_RX_POS    12
-#define IRQ_UART0_TX_POS    16
-#define IRQ_UART1_RX_POS    20
-#define IRQ_UART1_TX_POS    24
-#define IRQ_CAN_RX_POS      28
-
-/* IAR2 BIT FIELDS*/
-#define IRQ_CAN_TX_POS      0
-#define IRQ_MAC_RX_POS      4
-#define IRQ_MAC_TX_POS      8
-#define IRQ_TIMER0_POS        12
-#define IRQ_TIMER1_POS        16
-#define IRQ_TIMER2_POS        20
-#define IRQ_TIMER3_POS        24
-#define IRQ_TIMER4_POS        28
-
-/* IAR3 BIT FIELDS*/
-#define IRQ_TIMER5_POS        0
-#define IRQ_TIMER6_POS        4
-#define IRQ_TIMER7_POS        8
-#define IRQ_PROG_INTA_POS   12
-#define IRQ_PORTG_INTB_POS   16
-#define IRQ_MEM_DMA0_POS    20
-#define IRQ_MEM_DMA1_POS    24
-#define IRQ_WATCH_POS       28
-
-#endif                         /* _BF537_IRQ_H_ */
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           32
+
+#define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
+#define IRQ_DMA_ERROR          BFIN_IRQ(1)     /* DMA Error (general) */
+#define IRQ_GENERIC_ERROR      BFIN_IRQ(2)     /* GENERIC Error Interrupt */
+#define IRQ_RTC                        BFIN_IRQ(3)     /* RTC Interrupt */
+#define IRQ_PPI                        BFIN_IRQ(4)     /* DMA0 Interrupt (PPI) */
+#define IRQ_SPORT0_RX          BFIN_IRQ(5)     /* DMA3 Interrupt (SPORT0 RX) */
+#define IRQ_SPORT0_TX          BFIN_IRQ(6)     /* DMA4 Interrupt (SPORT0 TX) */
+#define IRQ_SPORT1_RX          BFIN_IRQ(7)     /* DMA5 Interrupt (SPORT1 RX) */
+#define IRQ_SPORT1_TX          BFIN_IRQ(8)     /* DMA6 Interrupt (SPORT1 TX) */
+#define IRQ_TWI                        BFIN_IRQ(9)     /* TWI Interrupt */
+#define IRQ_SPI                        BFIN_IRQ(10)    /* DMA7 Interrupt (SPI) */
+#define IRQ_UART0_RX           BFIN_IRQ(11)    /* DMA8 Interrupt (UART0 RX) */
+#define IRQ_UART0_TX           BFIN_IRQ(12)    /* DMA9 Interrupt (UART0 TX) */
+#define IRQ_UART1_RX           BFIN_IRQ(13)    /* DMA10 Interrupt (UART1 RX) */
+#define IRQ_UART1_TX           BFIN_IRQ(14)    /* DMA11 Interrupt (UART1 TX) */
+#define IRQ_CAN_RX             BFIN_IRQ(15)    /* CAN Receive Interrupt */
+#define IRQ_CAN_TX             BFIN_IRQ(16)    /* CAN Transmit Interrupt */
+#define IRQ_PH_INTA_MAC_RX     BFIN_IRQ(17)    /* Port H Interrupt A & DMA1 Interrupt (Ethernet RX) */
+#define IRQ_PH_INTB_MAC_TX     BFIN_IRQ(18)    /* Port H Interrupt B & DMA2 Interrupt (Ethernet TX) */
+#define IRQ_TIMER0             BFIN_IRQ(19)    /* Timer 0 */
+#define IRQ_TIMER1             BFIN_IRQ(20)    /* Timer 1 */
+#define IRQ_TIMER2             BFIN_IRQ(21)    /* Timer 2 */
+#define IRQ_TIMER3             BFIN_IRQ(22)    /* Timer 3 */
+#define IRQ_TIMER4             BFIN_IRQ(23)    /* Timer 4 */
+#define IRQ_TIMER5             BFIN_IRQ(24)    /* Timer 5 */
+#define IRQ_TIMER6             BFIN_IRQ(25)    /* Timer 6 */
+#define IRQ_TIMER7             BFIN_IRQ(26)    /* Timer 7 */
+#define IRQ_PF_INTA_PG_INTA    BFIN_IRQ(27)    /* Ports F&G Interrupt A */
+#define IRQ_PORTG_INTB         BFIN_IRQ(28)    /* Port G Interrupt B */
+#define IRQ_MEM_DMA0           BFIN_IRQ(29)    /* (Memory DMA Stream 0) */
+#define IRQ_MEM_DMA1           BFIN_IRQ(30)    /* (Memory DMA Stream 1) */
+#define IRQ_PF_INTB_WATCH      BFIN_IRQ(31)    /* Watchdog & Port F Interrupt B */
+
+#define SYS_IRQS               39
+
+#define IRQ_PPI_ERROR          42      /* PPI Error Interrupt */
+#define IRQ_CAN_ERROR          43      /* CAN Error Interrupt */
+#define IRQ_MAC_ERROR          44      /* MAC Status/Error Interrupt */
+#define IRQ_SPORT0_ERROR       45      /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR       46      /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR          47      /* SPI Error Interrupt */
+#define IRQ_UART0_ERROR                48      /* UART Error Interrupt */
+#define IRQ_UART1_ERROR                49      /* UART Error Interrupt */
+
+#define IRQ_PF0                        50
+#define IRQ_PF1                        51
+#define IRQ_PF2                        52
+#define IRQ_PF3                        53
+#define IRQ_PF4                        54
+#define IRQ_PF5                        55
+#define IRQ_PF6                        56
+#define IRQ_PF7                        57
+#define IRQ_PF8                        58
+#define IRQ_PF9                        59
+#define IRQ_PF10               60
+#define IRQ_PF11               61
+#define IRQ_PF12               62
+#define IRQ_PF13               63
+#define IRQ_PF14               64
+#define IRQ_PF15               65
+
+#define IRQ_PG0                        66
+#define IRQ_PG1                        67
+#define IRQ_PG2                        68
+#define IRQ_PG3                        69
+#define IRQ_PG4                        70
+#define IRQ_PG5                        71
+#define IRQ_PG6                        72
+#define IRQ_PG7                        73
+#define IRQ_PG8                        74
+#define IRQ_PG9                        75
+#define IRQ_PG10               76
+#define IRQ_PG11               77
+#define IRQ_PG12               78
+#define IRQ_PG13               79
+#define IRQ_PG14               80
+#define IRQ_PG15               81
+
+#define IRQ_PH0                        82
+#define IRQ_PH1                        83
+#define IRQ_PH2                        84
+#define IRQ_PH3                        85
+#define IRQ_PH4                        86
+#define IRQ_PH5                        87
+#define IRQ_PH6                        88
+#define IRQ_PH7                        89
+#define IRQ_PH8                        90
+#define IRQ_PH9                        91
+#define IRQ_PH10               92
+#define IRQ_PH11               93
+#define IRQ_PH12               94
+#define IRQ_PH13               95
+#define IRQ_PH14               96
+#define IRQ_PH15               97
+
+#define GPIO_IRQ_BASE          IRQ_PF0
+
+#define IRQ_MAC_PHYINT         98      /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT         99      /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT                100     /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT                101     /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET                102     /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR       103     /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR       104     /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE                105     /* Station Mgt. Transfer Done Interrupt */
+
+#define IRQ_MAC_RX             106     /* DMA1 Interrupt (Ethernet RX) */
+#define IRQ_PORTH_INTA         107     /* Port H Interrupt A */
+
+#if 0 /* No Interrupt B support (yet) */
+#define IRQ_MAC_TX             108     /* DMA2 Interrupt (Ethernet TX) */
+#define IRQ_PORTH_INTB         109     /* Port H Interrupt B */
+#else
+#define IRQ_MAC_TX             IRQ_PH_INTB_MAC_TX
+#endif
+
+#define IRQ_PORTF_INTA         110     /* Port F Interrupt A */
+#define IRQ_PORTG_INTA         111     /* Port G Interrupt A */
+
+#if 0 /* No Interrupt B support (yet) */
+#define IRQ_WATCH              112     /* Watchdog Timer */
+#define IRQ_PORTF_INTB         113     /* Port F Interrupt B */
+#else
+#define IRQ_WATCH              IRQ_PF_INTB_WATCH
+#endif
+
+#define NR_MACH_IRQS           (113 + 1)
+
+/* IAR0 BIT FIELDS */
+#define IRQ_PLL_WAKEUP_POS     0
+#define IRQ_DMA_ERROR_POS      4
+#define IRQ_ERROR_POS          8
+#define IRQ_RTC_POS            12
+#define IRQ_PPI_POS            16
+#define IRQ_SPORT0_RX_POS      20
+#define IRQ_SPORT0_TX_POS      24
+#define IRQ_SPORT1_RX_POS      28
+
+/* IAR1 BIT FIELDS */
+#define IRQ_SPORT1_TX_POS      0
+#define IRQ_TWI_POS            4
+#define IRQ_SPI_POS            8
+#define IRQ_UART0_RX_POS       12
+#define IRQ_UART0_TX_POS       16
+#define IRQ_UART1_RX_POS       20
+#define IRQ_UART1_TX_POS       24
+#define IRQ_CAN_RX_POS         28
+
+/* IAR2 BIT FIELDS */
+#define IRQ_CAN_TX_POS         0
+#define IRQ_MAC_RX_POS         4
+#define IRQ_MAC_TX_POS         8
+#define IRQ_TIMER0_POS         12
+#define IRQ_TIMER1_POS         16
+#define IRQ_TIMER2_POS         20
+#define IRQ_TIMER3_POS         24
+#define IRQ_TIMER4_POS         28
+
+/* IAR3 BIT FIELDS */
+#define IRQ_TIMER5_POS         0
+#define IRQ_TIMER6_POS         4
+#define IRQ_TIMER7_POS         8
+#define IRQ_PROG_INTA_POS      12
+#define IRQ_PORTG_INTB_POS     16
+#define IRQ_MEM_DMA0_POS       20
+#define IRQ_MEM_DMA1_POS       24
+#define IRQ_WATCH_POS          28
+
+#define init_mach_irq init_mach_irq
+
+#endif
index f6500622b35d0eb85eb5e788cb7696deb4911889..2137a209a22bdc8f427c1e29c46cc42c97448e28 100644 (file)
 #include <linux/irq.h>
 #include <asm/blackfin.h>
 
+#include <asm/irq_handler.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/bfin_sport.h>
+#include <asm/bfin_can.h>
+#include <asm/bfin_dma.h>
+#include <asm/dpmc.h>
+
 void __init program_IAR(void)
 {
        /* Program the IAR0 Register with the configured priority */
@@ -51,3 +58,159 @@ void __init program_IAR(void)
 
        SSYNC();
 }
+
+#define SPI_ERR_MASK   (BIT_STAT_TXCOL | BIT_STAT_RBSY | BIT_STAT_MODF | BIT_STAT_TXE) /* SPI_STAT */
+#define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF)     /* SPORT_STAT */
+#define PPI_ERR_MASK   (0xFFFF & ~FLD) /* PPI_STATUS */
+#define EMAC_ERR_MASK  (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE) /* EMAC_SYSTAT */
+#define UART_ERR_MASK  (0x6)   /* UART_IIR */
+#define CAN_ERR_MASK   (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF)      /* CAN_GIF */
+
+static int error_int_mask;
+
+static void bf537_generic_error_mask_irq(struct irq_data *d)
+{
+       error_int_mask &= ~(1L << (d->irq - IRQ_PPI_ERROR));
+       if (!error_int_mask)
+               bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
+}
+
+static void bf537_generic_error_unmask_irq(struct irq_data *d)
+{
+       bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
+       error_int_mask |= 1L << (d->irq - IRQ_PPI_ERROR);
+}
+
+static struct irq_chip bf537_generic_error_irqchip = {
+       .name = "ERROR",
+       .irq_ack = bfin_ack_noop,
+       .irq_mask_ack = bf537_generic_error_mask_irq,
+       .irq_mask = bf537_generic_error_mask_irq,
+       .irq_unmask = bf537_generic_error_unmask_irq,
+};
+
+static void bf537_demux_error_irq(unsigned int int_err_irq,
+                                 struct irq_desc *inta_desc)
+{
+       int irq = 0;
+
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+       if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
+               irq = IRQ_MAC_ERROR;
+       else
+#endif
+       if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
+               irq = IRQ_SPORT0_ERROR;
+       else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
+               irq = IRQ_SPORT1_ERROR;
+       else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
+               irq = IRQ_PPI_ERROR;
+       else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
+               irq = IRQ_CAN_ERROR;
+       else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
+               irq = IRQ_SPI_ERROR;
+       else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
+               irq = IRQ_UART0_ERROR;
+       else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
+               irq = IRQ_UART1_ERROR;
+
+       if (irq) {
+               if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
+                       bfin_handle_irq(irq);
+               else {
+
+                       switch (irq) {
+                       case IRQ_PPI_ERROR:
+                               bfin_write_PPI_STATUS(PPI_ERR_MASK);
+                               break;
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+                       case IRQ_MAC_ERROR:
+                               bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
+                               break;
+#endif
+                       case IRQ_SPORT0_ERROR:
+                               bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
+                               break;
+
+                       case IRQ_SPORT1_ERROR:
+                               bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
+                               break;
+
+                       case IRQ_CAN_ERROR:
+                               bfin_write_CAN_GIS(CAN_ERR_MASK);
+                               break;
+
+                       case IRQ_SPI_ERROR:
+                               bfin_write_SPI_STAT(SPI_ERR_MASK);
+                               break;
+
+                       default:
+                               break;
+                       }
+
+                       pr_debug("IRQ %d:"
+                                " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
+                                irq);
+               }
+       } else
+               pr_err("%s: IRQ ?: PERIPHERAL ERROR INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
+                      __func__);
+
+}
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static int mac_rx_int_mask;
+
+static void bf537_mac_rx_mask_irq(struct irq_data *d)
+{
+       mac_rx_int_mask &= ~(1L << (d->irq - IRQ_MAC_RX));
+       if (!mac_rx_int_mask)
+               bfin_internal_mask_irq(IRQ_PH_INTA_MAC_RX);
+}
+
+static void bf537_mac_rx_unmask_irq(struct irq_data *d)
+{
+       bfin_internal_unmask_irq(IRQ_PH_INTA_MAC_RX);
+       mac_rx_int_mask |= 1L << (d->irq - IRQ_MAC_RX);
+}
+
+static struct irq_chip bf537_mac_rx_irqchip = {
+       .name = "ERROR",
+       .irq_ack = bfin_ack_noop,
+       .irq_mask_ack = bf537_mac_rx_mask_irq,
+       .irq_mask = bf537_mac_rx_mask_irq,
+       .irq_unmask = bf537_mac_rx_unmask_irq,
+};
+
+static void bf537_demux_mac_rx_irq(unsigned int int_irq,
+                                  struct irq_desc *desc)
+{
+       if (bfin_read_DMA1_IRQ_STATUS() & (DMA_DONE | DMA_ERR))
+               bfin_handle_irq(IRQ_MAC_RX);
+       else
+               bfin_demux_gpio_irq(int_irq, desc);
+}
+#endif
+
+void __init init_mach_irq(void)
+{
+       int irq;
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536)
+       /* Clear EMAC Interrupt Status bits so we can demux it later */
+       bfin_write_EMAC_SYSTAT(-1);
+#endif
+
+       irq_set_chained_handler(IRQ_GENERIC_ERROR, bf537_demux_error_irq);
+       for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
+               irq_set_chip_and_handler(irq, &bf537_generic_error_irqchip,
+                                        handle_level_irq);
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+       irq_set_chained_handler(IRQ_PH_INTA_MAC_RX, bf537_demux_mac_rx_irq);
+       irq_set_chip_and_handler(IRQ_MAC_RX, &bf537_mac_rx_irqchip, handle_level_irq);
+       irq_set_chip_and_handler(IRQ_PORTH_INTA, &bf537_mac_rx_irqchip, handle_level_irq);
+
+       irq_set_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq);
+#endif
+}
index 8774b481c78e826e45a3ee971742015434985fdf..55e7d0712a942f04e027dec473636062c1e8a5f0 100644 (file)
@@ -5,14 +5,14 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision H, 07/10/2009; ADSP-BF538/BF538F Blackfin Processor Anomaly List
- *  - Revision M, 07/10/2009; ADSP-BF539/BF539F Blackfin Processor Anomaly List
+ *  - Revision I, 05/25/2010; ADSP-BF538/BF538F Blackfin Processor Anomaly List
+ *  - Revision N, 05/25/2010; ADSP-BF539/BF539F Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000363 (0)
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000456 (0)
 #define ANOMALY_05000465 (0)
 #define ANOMALY_05000467 (0)
 #define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
 
 #endif
index 7a479d224dc79da2c1d371469110e40158d870be..07ca069d37cd29bb97a584ff3dd728161470524c 100644 (file)
@@ -7,38 +7,9 @@
 #ifndef _BF538_IRQ_H_
 #define _BF538_IRQ_H_
 
-/*
- * Interrupt source definitions
-       Event Source    Core Event Name
-       Core        Emulation               **
-       Events         (highest priority)  EMU         0
-       Reset                   RST         1
-       NMI                     NMI         2
-       Exception               EVX         3
-       Reserved                --          4
-       Hardware Error          IVHW        5
-       Core Timer              IVTMR       6 *
-
-       .....
-
-        Software Interrupt 1    IVG14       31
-        Software Interrupt 2    --
-        (lowest priority)  IVG15       32 *
-*/
-
-#define NR_PERI_INTS    (2 * 32)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU                        0       /* Emulation */
-#define IRQ_RST                        1       /* reset */
-#define IRQ_NMI                        2       /* Non Maskable */
-#define IRQ_EVX                        3       /* Exception */
-#define IRQ_UNUSED             4       /* - unused interrupt */
-#define IRQ_HWERR              5       /* Hardware Error */
-#define IRQ_CORETMR            6       /* Core timer */
-
-#define BFIN_IRQ(x)            ((x) + 7)
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           (2 * 32)
 
 #define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
 #define IRQ_DMA0_ERROR         BFIN_IRQ(1)     /* DMA Error 0 (generic) */
 
 #define SYS_IRQS               BFIN_IRQ(63)    /* 70 */
 
-#define IRQ_PF0         71
-#define IRQ_PF1         72
-#define IRQ_PF2         73
-#define IRQ_PF3         74
-#define IRQ_PF4         75
-#define IRQ_PF5         76
-#define IRQ_PF6         77
-#define IRQ_PF7         78
-#define IRQ_PF8         79
-#define IRQ_PF9         80
-#define IRQ_PF10        81
-#define IRQ_PF11        82
-#define IRQ_PF12        83
-#define IRQ_PF13        84
-#define IRQ_PF14        85
-#define IRQ_PF15        86
-
-#define GPIO_IRQ_BASE  IRQ_PF0
-
-#define NR_MACH_IRQS   (IRQ_PF15 + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
+#define IRQ_PF0                        71
+#define IRQ_PF1                        72
+#define IRQ_PF2                        73
+#define IRQ_PF3                        74
+#define IRQ_PF4                        75
+#define IRQ_PF5                        76
+#define IRQ_PF6                        77
+#define IRQ_PF7                        78
+#define IRQ_PF8                        79
+#define IRQ_PF9                        80
+#define IRQ_PF10               81
+#define IRQ_PF11               82
+#define IRQ_PF12               83
+#define IRQ_PF13               84
+#define IRQ_PF14               85
+#define IRQ_PF15               86
+
+#define GPIO_IRQ_BASE          IRQ_PF0
+
+#define NR_MACH_IRQS           (IRQ_PF15 + 1)
 
 /* IAR0 BIT FIELDS */
 #define IRQ_PLL_WAKEUP_POS     0
 #define IRQ_CAN_TX_POS         0
 #define IRQ_MEM1_DMA0_POS      4
 #define IRQ_MEM1_DMA1_POS      8
-#endif                         /* _BF538_IRQ_H_ */
+
+#endif
index 93e19a54a8803d639fd5586a155954610861dbc7..311bf9970fe716e97278611b8c7879ffabc5c0b1 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/gpio.h>
 #include <asm/nand.h>
 #include <asm/dpmc.h>
+#include <asm/bfin_sport.h>
 #include <asm/portmux.h>
 #include <asm/bfin_sdh.h>
 #include <mach/bf54x_keys.h>
@@ -956,7 +957,15 @@ static struct mtd_partition ezkit_partitions[] = {
                .offset     = MTDPART_OFS_APPEND,
        }, {
                .name       = "file system(nor)",
-               .size       = MTDPART_SIZ_FULL,
+               .size       = 0x1000000 - 0x80000 - 0x400000 - 0x8000 * 4,
+               .offset     = MTDPART_OFS_APPEND,
+       }, {
+               .name       = "config(nor)",
+               .size       = 0x8000 * 3,
+               .offset     = MTDPART_OFS_APPEND,
+       }, {
+               .name       = "u-boot env(nor)",
+               .size       = 0x8000,
                .offset     = MTDPART_OFS_APPEND,
        }
 };
@@ -1312,27 +1321,110 @@ static struct platform_device bfin_dpmc = {
        },
 };
 
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+       defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+
+#define SPORT_REQ(x) \
+       [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
+               P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
+
+static const u16 bfin_snd_pin[][7] = {
+       SPORT_REQ(0),
+       SPORT_REQ(1),
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+       {
+               .pin_req = &bfin_snd_pin[0][0],
+       },
+       {
+               .pin_req = &bfin_snd_pin[1][0],
+       },
+};
+
+#define BFIN_SND_RES(x) \
+       [x] = { \
+               { \
+                       .start = SPORT##x##_TCR1, \
+                       .end = SPORT##x##_TCR1, \
+                       .flags = IORESOURCE_MEM \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_RX, \
+                       .end = CH_SPORT##x##_RX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = CH_SPORT##x##_TX, \
+                       .end = CH_SPORT##x##_TX, \
+                       .flags = IORESOURCE_DMA, \
+               }, \
+               { \
+                       .start = IRQ_SPORT##x##_ERROR, \
+                       .end = IRQ_SPORT##x##_ERROR, \
+                       .flags = IORESOURCE_IRQ, \
+               } \
+       }
+
+static struct resource bfin_snd_resources[][4] = {
+       BFIN_SND_RES(0),
+       BFIN_SND_RES(1),
+};
+
+static struct platform_device bfin_pcm = {
+       .name = "bfin-pcm-audio",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+static struct platform_device bfin_ad73311_codec_device = {
+       .name = "ad73311",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1980) || defined(CONFIG_SND_BF5XX_SOC_AD1980_MODULE)
+static struct platform_device bfin_ad1980_codec_device = {
+       .name = "ad1980",
+       .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
 static struct platform_device bfin_i2s = {
        .name = "bfin-i2s",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
 static struct platform_device bfin_tdm = {
        .name = "bfin-tdm",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
 static struct platform_device bfin_ac97 = {
        .name = "bfin-ac97",
        .id = CONFIG_SND_BF5XX_SPORT_NUM,
-       /* TODO: add platform data here */
+       .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+       .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+       .dev = {
+               .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+       },
 };
 #endif
 
@@ -1450,6 +1542,16 @@ static struct platform_device *ezkit_devices[] __initdata = {
        &ezkit_flash_device,
 #endif
 
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+       defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+       defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+       &bfin_pcm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1980) || defined(CONFIG_SND_BF5XX_SOC_AD1980_MODULE)
+       &bfin_ad1980_codec_device,
+#endif
+
 #if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
        &bfin_i2s,
 #endif
index ffd0537295ac4d5c348bdf1e747b1f48caafc92f..9e70785bdde3434b388c7a4f0fe6ca20ab61aee3 100644 (file)
@@ -5,13 +5,13 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision I, 07/23/2009; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
+ *  - Revision J, 06/03/2010; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000481 (1)
 /* Possible USB Data Corruption When Multiple Endpoints Are Accessed by the Core */
 #define ANOMALY_05000483 (1)
+/* DDR Trim May Not Be Performed for Certain VLEV Values in OTP Page PBS00L */
+#define ANOMALY_05000484 (__SILICON_REVISION__ < 3)
 /* PLL_CTL Change Using bfrom_SysControl() Can Result in Processor Overclocking */
 #define ANOMALY_05000485 (__SILICON_REVISION__ >= 2)
 /* IFLUSH sucks at life */
 #define ANOMALY_05000412 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000475 (0)
+#define ANOMALY_05000480 (0)
 
 #endif
index 7f87787e77382279a35a75b0f65a1ea3bbbdf505..533b8095b540aec5950f3d44df16914c71a2b2ad 100644 (file)
@@ -7,38 +7,9 @@
 #ifndef _BF548_IRQ_H_
 #define _BF548_IRQ_H_
 
-/*
- * Interrupt source definitions
-            Event Source    Core Event Name
-Core        Emulation               **
-Events         (highest priority)  EMU         0
-            Reset                   RST         1
-            NMI                     NMI         2
-            Exception               EVX         3
-            Reserved                --          4
-            Hardware Error          IVHW        5
-            Core Timer              IVTMR       6 *
-
-.....
-
-            Software Interrupt 1    IVG14       31
-            Software Interrupt 2    --
-                 (lowest priority)  IVG15       32 *
- */
-
-#define NR_PERI_INTS    (32 * 3)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU                        0       /* Emulation */
-#define IRQ_RST                        1       /* reset */
-#define IRQ_NMI                        2       /* Non Maskable */
-#define IRQ_EVX                        3       /* Exception */
-#define IRQ_UNUSED             4       /* - unused interrupt*/
-#define IRQ_HWERR              5       /* Hardware Error */
-#define IRQ_CORETMR            6       /* Core timer */
+#include <mach-common/irq.h>
 
-#define BFIN_IRQ(x)            ((x) + 7)
+#define NR_PERI_INTS           (3 * 32)
 
 #define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
 #define IRQ_DMAC0_ERROR                BFIN_IRQ(1)     /* DMAC0 Status Interrupt */
@@ -311,49 +282,37 @@ Events         (highest priority)  EMU         0
 #define IRQ_PJ14               BFIN_PJ_IRQ(14)         /* N/A */
 #define IRQ_PJ15               BFIN_PJ_IRQ(15)         /* N/A */
 
-#define GPIO_IRQ_BASE  IRQ_PA0
+#define GPIO_IRQ_BASE          IRQ_PA0
 
-#define NR_MACH_IRQS   (IRQ_PJ15 + 1)
-#define NR_IRQS                (NR_MACH_IRQS + NR_SPARE_IRQS)
+#define NR_MACH_IRQS           (IRQ_PJ15 + 1)
 
 /* For compatibility reasons with existing code */
 
-#define IRQ_DMAC0_ERR          IRQ_DMAC0_ERROR
-#define IRQ_EPPI0_ERR          IRQ_EPPI0_ERROR
+#define IRQ_DMAC0_ERR          IRQ_DMAC0_ERROR
+#define IRQ_EPPI0_ERR          IRQ_EPPI0_ERROR
 #define IRQ_SPORT0_ERR         IRQ_SPORT0_ERROR
 #define IRQ_SPORT1_ERR         IRQ_SPORT1_ERROR
-#define IRQ_SPI0_ERR           IRQ_SPI0_ERROR
-#define IRQ_UART0_ERR          IRQ_UART0_ERROR
-#define IRQ_DMAC1_ERR          IRQ_DMAC1_ERROR
+#define IRQ_SPI0_ERR           IRQ_SPI0_ERROR
+#define IRQ_UART0_ERR          IRQ_UART0_ERROR
+#define IRQ_DMAC1_ERR          IRQ_DMAC1_ERROR
 #define IRQ_SPORT2_ERR         IRQ_SPORT2_ERROR
 #define IRQ_SPORT3_ERR         IRQ_SPORT3_ERROR
-#define IRQ_SPI1_ERR           IRQ_SPI1_ERROR
-#define IRQ_SPI2_ERR           IRQ_SPI2_ERROR
-#define IRQ_UART1_ERR          IRQ_UART1_ERROR
-#define IRQ_UART2_ERR          IRQ_UART2_ERROR
-#define IRQ_CAN0_ERR           IRQ_CAN0_ERROR
-#define IRQ_MXVR_ERR           IRQ_MXVR_ERROR
-#define IRQ_EPPI1_ERR                  IRQ_EPPI1_ERROR
-#define IRQ_EPPI2_ERR                  IRQ_EPPI2_ERROR
-#define IRQ_UART3_ERR          IRQ_UART3_ERROR
-#define IRQ_HOST_ERR           IRQ_HOST_ERROR
-#define IRQ_PIXC_ERR           IRQ_PIXC_ERROR
-#define IRQ_NFC_ERR            IRQ_NFC_ERROR
-#define IRQ_ATAPI_ERR          IRQ_ATAPI_ERROR
-#define IRQ_CAN1_ERR           IRQ_CAN1_ERROR
+#define IRQ_SPI1_ERR           IRQ_SPI1_ERROR
+#define IRQ_SPI2_ERR           IRQ_SPI2_ERROR
+#define IRQ_UART1_ERR          IRQ_UART1_ERROR
+#define IRQ_UART2_ERR          IRQ_UART2_ERROR
+#define IRQ_CAN0_ERR           IRQ_CAN0_ERROR
+#define IRQ_MXVR_ERR           IRQ_MXVR_ERROR
+#define IRQ_EPPI1_ERR          IRQ_EPPI1_ERROR
+#define IRQ_EPPI2_ERR          IRQ_EPPI2_ERROR
+#define IRQ_UART3_ERR          IRQ_UART3_ERROR
+#define IRQ_HOST_ERR           IRQ_HOST_ERROR
+#define IRQ_PIXC_ERR           IRQ_PIXC_ERROR
+#define IRQ_NFC_ERR            IRQ_NFC_ERROR
+#define IRQ_ATAPI_ERR          IRQ_ATAPI_ERROR
+#define IRQ_CAN1_ERR           IRQ_CAN1_ERROR
 #define IRQ_HS_DMA_ERR         IRQ_HS_DMA_ERROR
 
-
-#define IVG7            7
-#define IVG8            8
-#define IVG9            9
-#define IVG10           10
-#define IVG11           11
-#define IVG12           12
-#define IVG13           13
-#define IVG14           14
-#define IVG15           15
-
 /* IAR0 BIT FIELDS */
 #define IRQ_PLL_WAKEUP_POS     0
 #define IRQ_DMAC0_ERR_POS      4
@@ -492,4 +451,4 @@ struct bfin_pint_regs {
 
 #endif
 
-#endif /* _BF548_IRQ_H_ */
+#endif
index f667e7704197995ce186a61400d7ee19334fb491..5067984a62e78f669d4fbe99cc5eb0d62f251b4a 100644 (file)
@@ -247,7 +247,15 @@ static struct mtd_partition ezkit_partitions[] = {
                .offset     = MTDPART_OFS_APPEND,
        }, {
                .name       = "file system(nor)",
-               .size       = MTDPART_SIZ_FULL,
+               .size       = 0x800000 - 0x40000 - 0x1C0000 - 0x2000 * 8,
+               .offset     = MTDPART_OFS_APPEND,
+       }, {
+               .name       = "config(nor)",
+               .size       = 0x2000 * 7,
+               .offset     = MTDPART_OFS_APPEND,
+       }, {
+               .name       = "u-boot env(nor)",
+               .size       = 0x2000,
                .offset     = MTDPART_OFS_APPEND,
        }
 };
index 6a3499b02097af3e94b020ac0b5ebe7b731585ec..22b5ab7730271de0d52217a2e281ae7593bf7a06 100644 (file)
@@ -5,13 +5,13 @@
  * and can be replaced with that version at any time
  * DO NOT EDIT THIS FILE
  *
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
  * Licensed under the ADI BSD license.
  *   https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
  */
 
 /* This file should be up to date with:
- *  - Revision Q, 11/07/2008; ADSP-BF561 Blackfin Processor Anomaly List
+ *  - Revision R, 05/25/2010; ADSP-BF561 Blackfin Processor Anomaly List
  */
 
 #ifndef _MACH_ANOMALY_H_
 #define ANOMALY_05000428 (__SILICON_REVISION__ > 3)
 /* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
 #define ANOMALY_05000443 (1)
+/* SCKELOW Feature Is Not Functional */
+#define ANOMALY_05000458 (1)
 /* False Hardware Error when RETI Points to Invalid Memory */
 #define ANOMALY_05000461 (1)
+/* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */
+#define ANOMALY_05000462 (1)
+/* Boot Failure When SDRAM Control Signals Toggle Coming Out Of Reset */
+#define ANOMALY_05000471 (1)
 /* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */
 #define ANOMALY_05000473 (1)
 /* Possible Lockup Condition whem Modifying PLL from External Memory */
-#define ANOMALY_05000475 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000475 (1)
 /* TESTSET Instruction Cannot Be Interrupted */
 #define ANOMALY_05000477 (1)
 /* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */
 #define ANOMALY_05000353 (1)
 #define ANOMALY_05000364 (0)
 #define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
 #define ANOMALY_05000386 (1)
 #define ANOMALY_05000389 (0)
 #define ANOMALY_05000400 (0)
 #define ANOMALY_05000430 (0)
 #define ANOMALY_05000432 (0)
 #define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
 #define ANOMALY_05000447 (0)
 #define ANOMALY_05000448 (0)
 #define ANOMALY_05000456 (0)
 #define ANOMALY_05000465 (0)
 #define ANOMALY_05000467 (0)
 #define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
 #define ANOMALY_05000485 (0)
 
 #endif
index c95566ade51b0b0cd6794a861cf71995c000364c..d6998520f70f77c4cefc5dd28a5e6546aeb88333 100644 (file)
 #ifndef _BF561_IRQ_H_
 #define _BF561_IRQ_H_
 
-/***********************************************************************
- * Interrupt source definitions:
-             Event Source              Core Event Name     IRQ No
-                                               (highest priority)
-           Emulation Events                    EMU         0
-            Reset                              RST         1
-            NMI                                        NMI         2
-            Exception                          EVX         3
-            Reserved                           --          4
-            Hardware Error                     IVHW        5
-            Core Timer                         IVTMR       6 *
-
-           PLL Wakeup Interrupt                IVG7        7
-           DMA1 Error (generic)                IVG7        8
-           DMA2 Error (generic)                IVG7        9
-           IMDMA Error (generic)               IVG7        10
-           PPI1 Error Interrupt                IVG7        11
-           PPI2 Error Interrupt                IVG7        12
-           SPORT0 Error Interrupt              IVG7        13
-           SPORT1 Error Interrupt              IVG7        14
-           SPI Error Interrupt                 IVG7        15
-           UART Error Interrupt                IVG7        16
-           Reserved Interrupt                  IVG7        17
-
-           DMA1 0  Interrupt(PPI1)             IVG8        18
-           DMA1 1  Interrupt(PPI2)             IVG8        19
-           DMA1 2  Interrupt                   IVG8        20
-           DMA1 3  Interrupt                   IVG8        21
-           DMA1 4  Interrupt                   IVG8        22
-           DMA1 5  Interrupt                   IVG8        23
-           DMA1 6  Interrupt                   IVG8        24
-           DMA1 7  Interrupt                   IVG8        25
-           DMA1 8  Interrupt                   IVG8        26
-           DMA1 9  Interrupt                   IVG8        27
-           DMA1 10 Interrupt                   IVG8        28
-           DMA1 11 Interrupt                   IVG8        29
-
-           DMA2 0  (SPORT0 RX)                 IVG9        30
-           DMA2 1  (SPORT0 TX)                 IVG9        31
-           DMA2 2  (SPORT1 RX)                 IVG9        32
-           DMA2 3  (SPORT2 TX)                 IVG9        33
-           DMA2 4  (SPI)                       IVG9        34
-           DMA2 5  (UART RX)                   IVG9        35
-           DMA2 6  (UART TX)                   IVG9        36
-           DMA2 7  Interrupt                   IVG9        37
-           DMA2 8  Interrupt                   IVG9        38
-           DMA2 9  Interrupt                   IVG9        39
-           DMA2 10 Interrupt                   IVG9        40
-           DMA2 11 Interrupt                   IVG9        41
-
-           TIMER 0  Interrupt                  IVG10       42
-           TIMER 1  Interrupt                  IVG10       43
-           TIMER 2  Interrupt                  IVG10       44
-           TIMER 3  Interrupt                  IVG10       45
-           TIMER 4  Interrupt                  IVG10       46
-           TIMER 5  Interrupt                  IVG10       47
-           TIMER 6  Interrupt                  IVG10       48
-           TIMER 7  Interrupt                  IVG10       49
-           TIMER 8  Interrupt                  IVG10       50
-           TIMER 9  Interrupt                  IVG10       51
-           TIMER 10 Interrupt                  IVG10       52
-           TIMER 11 Interrupt                  IVG10       53
-
-           Programmable Flags0 A (8)           IVG11       54
-           Programmable Flags0 B (8)           IVG11       55
-           Programmable Flags1 A (8)           IVG11       56
-           Programmable Flags1 B (8)           IVG11       57
-           Programmable Flags2 A (8)           IVG11       58
-           Programmable Flags2 B (8)           IVG11       59
-
-           MDMA1 0 write/read INT              IVG8        60
-           MDMA1 1 write/read INT              IVG8        61
-
-           MDMA2 0 write/read INT              IVG9        62
-           MDMA2 1 write/read INT              IVG9        63
-
-           IMDMA 0 write/read INT              IVG12       64
-           IMDMA 1 write/read INT              IVG12       65
-
-           Watch Dog Timer                     IVG13       66
-
-           Reserved interrupt                  IVG7        67
-           Reserved interrupt                  IVG7        68
-           Supplemental interrupt 0            IVG7        69
-           supplemental interrupt 1            IVG7        70
-
-            Softirq                            IVG14
-            System Call    --
-                 (lowest priority)             IVG15
-
- **********************************************************************/
-
-#define SYS_IRQS               71
-#define NR_PERI_INTS           64
-
-/*
- * The ABSTRACT IRQ definitions
- *  the first seven of the following are fixed,
- *  the rest you change if you need to.
- */
-/* IVG 0-6*/
-#define        IRQ_EMU                 0       /* Emulation                */
-#define        IRQ_RST                 1       /* Reset                    */
-#define        IRQ_NMI                 2       /* Non Maskable Interrupt   */
-#define        IRQ_EVX                 3       /* Exception                */
-#define        IRQ_UNUSED              4       /* Reserved interrupt       */
-#define        IRQ_HWERR               5       /* Hardware Error           */
-#define        IRQ_CORETMR             6       /* Core timer               */
-
-#define IVG_BASE               7
-/* IVG 7  */
-#define        IRQ_PLL_WAKEUP          (IVG_BASE + 0)  /* PLL Wakeup Interrupt     */
-#define        IRQ_DMA1_ERROR          (IVG_BASE + 1)  /* DMA1   Error (general)   */
-#define        IRQ_DMA_ERROR           IRQ_DMA1_ERROR  /* DMA1   Error (general)   */
-#define        IRQ_DMA2_ERROR          (IVG_BASE + 2)  /* DMA2   Error (general)   */
-#define IRQ_IMDMA_ERROR                (IVG_BASE + 3)  /* IMDMA  Error Interrupt   */
-#define        IRQ_PPI1_ERROR          (IVG_BASE + 4)  /* PPI1   Error Interrupt   */
-#define        IRQ_PPI_ERROR           IRQ_PPI1_ERROR  /* PPI1   Error Interrupt   */
-#define        IRQ_PPI2_ERROR          (IVG_BASE + 5)  /* PPI2   Error Interrupt   */
-#define        IRQ_SPORT0_ERROR        (IVG_BASE + 6)  /* SPORT0 Error Interrupt   */
-#define        IRQ_SPORT1_ERROR        (IVG_BASE + 7)  /* SPORT1 Error Interrupt   */
-#define        IRQ_SPI_ERROR           (IVG_BASE + 8)  /* SPI    Error Interrupt   */
-#define        IRQ_UART_ERROR          (IVG_BASE + 9)  /* UART   Error Interrupt   */
-#define IRQ_RESERVED_ERROR     (IVG_BASE + 10) /* Reversed     Interrupt   */
-/* IVG 8  */
-#define        IRQ_DMA1_0              (IVG_BASE + 11) /* DMA1 0  Interrupt(PPI1)  */
-#define        IRQ_PPI                 IRQ_DMA1_0      /* DMA1 0  Interrupt(PPI1)  */
-#define        IRQ_PPI0                IRQ_DMA1_0      /* DMA1 0  Interrupt(PPI1)  */
-#define        IRQ_DMA1_1              (IVG_BASE + 12) /* DMA1 1  Interrupt(PPI2)  */
-#define        IRQ_PPI1                IRQ_DMA1_1      /* DMA1 1  Interrupt(PPI2)  */
-#define        IRQ_DMA1_2              (IVG_BASE + 13) /* DMA1 2  Interrupt        */
-#define        IRQ_DMA1_3              (IVG_BASE + 14) /* DMA1 3  Interrupt        */
-#define        IRQ_DMA1_4              (IVG_BASE + 15) /* DMA1 4  Interrupt        */
-#define        IRQ_DMA1_5              (IVG_BASE + 16) /* DMA1 5  Interrupt        */
-#define        IRQ_DMA1_6              (IVG_BASE + 17) /* DMA1 6  Interrupt        */
-#define        IRQ_DMA1_7              (IVG_BASE + 18) /* DMA1 7  Interrupt        */
-#define        IRQ_DMA1_8              (IVG_BASE + 19) /* DMA1 8  Interrupt        */
-#define        IRQ_DMA1_9              (IVG_BASE + 20) /* DMA1 9  Interrupt        */
-#define        IRQ_DMA1_10             (IVG_BASE + 21) /* DMA1 10 Interrupt        */
-#define        IRQ_DMA1_11             (IVG_BASE + 22) /* DMA1 11 Interrupt        */
-/* IVG 9  */
-#define        IRQ_DMA2_0              (IVG_BASE + 23) /* DMA2 0  (SPORT0 RX)      */
-#define        IRQ_SPORT0_RX           IRQ_DMA2_0      /* DMA2 0  (SPORT0 RX)      */
-#define        IRQ_DMA2_1              (IVG_BASE + 24) /* DMA2 1  (SPORT0 TX)      */
-#define        IRQ_SPORT0_TX           IRQ_DMA2_1      /* DMA2 1  (SPORT0 TX)      */
-#define        IRQ_DMA2_2              (IVG_BASE + 25) /* DMA2 2  (SPORT1 RX)      */
-#define        IRQ_SPORT1_RX           IRQ_DMA2_2      /* DMA2 2  (SPORT1 RX)      */
-#define        IRQ_DMA2_3              (IVG_BASE + 26) /* DMA2 3  (SPORT2 TX)      */
-#define        IRQ_SPORT1_TX           IRQ_DMA2_3      /* DMA2 3  (SPORT2 TX)      */
-#define        IRQ_DMA2_4              (IVG_BASE + 27) /* DMA2 4  (SPI)            */
-#define        IRQ_SPI                 IRQ_DMA2_4      /* DMA2 4  (SPI)            */
-#define        IRQ_DMA2_5              (IVG_BASE + 28) /* DMA2 5  (UART RX)        */
-#define        IRQ_UART_RX             IRQ_DMA2_5      /* DMA2 5  (UART RX)        */
-#define        IRQ_DMA2_6              (IVG_BASE + 29) /* DMA2 6  (UART TX)        */
-#define        IRQ_UART_TX             IRQ_DMA2_6      /* DMA2 6  (UART TX)        */
-#define        IRQ_DMA2_7              (IVG_BASE + 30) /* DMA2 7  Interrupt        */
-#define        IRQ_DMA2_8              (IVG_BASE + 31) /* DMA2 8  Interrupt        */
-#define        IRQ_DMA2_9              (IVG_BASE + 32) /* DMA2 9  Interrupt        */
-#define        IRQ_DMA2_10             (IVG_BASE + 33) /* DMA2 10 Interrupt        */
-#define        IRQ_DMA2_11             (IVG_BASE + 34) /* DMA2 11 Interrupt        */
-/* IVG 10 */
-#define IRQ_TIMER0             (IVG_BASE + 35) /* TIMER 0  Interrupt       */
-#define IRQ_TIMER1             (IVG_BASE + 36) /* TIMER 1  Interrupt       */
-#define IRQ_TIMER2             (IVG_BASE + 37) /* TIMER 2  Interrupt       */
-#define IRQ_TIMER3             (IVG_BASE + 38) /* TIMER 3  Interrupt       */
-#define IRQ_TIMER4             (IVG_BASE + 39) /* TIMER 4  Interrupt       */
-#define IRQ_TIMER5             (IVG_BASE + 40) /* TIMER 5  Interrupt       */
-#define IRQ_TIMER6             (IVG_BASE + 41) /* TIMER 6  Interrupt       */
-#define IRQ_TIMER7             (IVG_BASE + 42) /* TIMER 7  Interrupt       */
-#define IRQ_TIMER8             (IVG_BASE + 43) /* TIMER 8  Interrupt       */
-#define IRQ_TIMER9             (IVG_BASE + 44) /* TIMER 9  Interrupt       */
-#define IRQ_TIMER10            (IVG_BASE + 45) /* TIMER 10 Interrupt       */
-#define IRQ_TIMER11            (IVG_BASE + 46) /* TIMER 11 Interrupt       */
-/* IVG 11 */
-#define        IRQ_PROG0_INTA          (IVG_BASE + 47) /* Programmable Flags0 A (8) */
-#define        IRQ_PROG_INTA           IRQ_PROG0_INTA  /* Programmable Flags0 A (8) */
-#define        IRQ_PROG0_INTB          (IVG_BASE + 48) /* Programmable Flags0 B (8) */
-#define        IRQ_PROG_INTB           IRQ_PROG0_INTB  /* Programmable Flags0 B (8) */
-#define        IRQ_PROG1_INTA          (IVG_BASE + 49) /* Programmable Flags1 A (8) */
-#define        IRQ_PROG1_INTB          (IVG_BASE + 50) /* Programmable Flags1 B (8) */
-#define        IRQ_PROG2_INTA          (IVG_BASE + 51) /* Programmable Flags2 A (8) */
-#define        IRQ_PROG2_INTB          (IVG_BASE + 52) /* Programmable Flags2 B (8) */
-/* IVG 8  */
-#define IRQ_DMA1_WRRD0         (IVG_BASE + 53) /* MDMA1 0 write/read INT   */
-#define IRQ_DMA_WRRD0          IRQ_DMA1_WRRD0  /* MDMA1 0 write/read INT   */
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS           (2 * 32)
+
+#define IRQ_PLL_WAKEUP         BFIN_IRQ(0)     /* PLL Wakeup Interrupt */
+#define IRQ_DMA1_ERROR         BFIN_IRQ(1)     /* DMA1   Error (general) */
+#define IRQ_DMA_ERROR          IRQ_DMA1_ERROR  /* DMA1   Error (general) */
+#define IRQ_DMA2_ERROR         BFIN_IRQ(2)     /* DMA2   Error (general) */
+#define IRQ_IMDMA_ERROR                BFIN_IRQ(3)     /* IMDMA  Error Interrupt */
+#define IRQ_PPI1_ERROR         BFIN_IRQ(4)     /* PPI1   Error Interrupt */
+#define IRQ_PPI_ERROR          IRQ_PPI1_ERROR  /* PPI1   Error Interrupt */
+#define IRQ_PPI2_ERROR         BFIN_IRQ(5)     /* PPI2   Error Interrupt */
+#define IRQ_SPORT0_ERROR       BFIN_IRQ(6)     /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR       BFIN_IRQ(7)     /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR          BFIN_IRQ(8)     /* SPI    Error Interrupt */
+#define IRQ_UART_ERROR         BFIN_IRQ(9)     /* UART   Error Interrupt */
+#define IRQ_RESERVED_ERROR     BFIN_IRQ(10)    /* Reversed */
+#define IRQ_DMA1_0             BFIN_IRQ(11)    /* DMA1 0  Interrupt(PPI1) */
+#define IRQ_PPI                        IRQ_DMA1_0      /* DMA1 0  Interrupt(PPI1) */
+#define IRQ_PPI0               IRQ_DMA1_0      /* DMA1 0  Interrupt(PPI1) */
+#define IRQ_DMA1_1             BFIN_IRQ(12)    /* DMA1 1  Interrupt(PPI2) */
+#define IRQ_PPI1               IRQ_DMA1_1      /* DMA1 1  Interrupt(PPI2) */
+#define IRQ_DMA1_2             BFIN_IRQ(13)    /* DMA1 2  Interrupt */
+#define IRQ_DMA1_3             BFIN_IRQ(14)    /* DMA1 3  Interrupt */
+#define IRQ_DMA1_4             BFIN_IRQ(15)    /* DMA1 4  Interrupt */
+#define IRQ_DMA1_5             BFIN_IRQ(16)    /* DMA1 5  Interrupt */
+#define IRQ_DMA1_6             BFIN_IRQ(17)    /* DMA1 6  Interrupt */
+#define IRQ_DMA1_7             BFIN_IRQ(18)    /* DMA1 7  Interrupt */
+#define IRQ_DMA1_8             BFIN_IRQ(19)    /* DMA1 8  Interrupt */
+#define IRQ_DMA1_9             BFIN_IRQ(20)    /* DMA1 9  Interrupt */
+#define IRQ_DMA1_10            BFIN_IRQ(21)    /* DMA1 10 Interrupt */
+#define IRQ_DMA1_11            BFIN_IRQ(22)    /* DMA1 11 Interrupt */
+#define IRQ_DMA2_0             BFIN_IRQ(23)    /* DMA2 0  (SPORT0 RX) */
+#define IRQ_SPORT0_RX          IRQ_DMA2_0      /* DMA2 0  (SPORT0 RX) */
+#define IRQ_DMA2_1             BFIN_IRQ(24)    /* DMA2 1  (SPORT0 TX) */
+#define IRQ_SPORT0_TX          IRQ_DMA2_1      /* DMA2 1  (SPORT0 TX) */
+#define IRQ_DMA2_2             BFIN_IRQ(25)    /* DMA2 2  (SPORT1 RX) */
+#define IRQ_SPORT1_RX          IRQ_DMA2_2      /* DMA2 2  (SPORT1 RX) */
+#define IRQ_DMA2_3             BFIN_IRQ(26)    /* DMA2 3  (SPORT2 TX) */
+#define IRQ_SPORT1_TX          IRQ_DMA2_3      /* DMA2 3  (SPORT2 TX) */
+#define IRQ_DMA2_4             BFIN_IRQ(27)    /* DMA2 4  (SPI) */
+#define IRQ_SPI                        IRQ_DMA2_4      /* DMA2 4  (SPI) */
+#define IRQ_DMA2_5             BFIN_IRQ(28)    /* DMA2 5  (UART RX) */
+#define IRQ_UART_RX            IRQ_DMA2_5      /* DMA2 5  (UART RX) */
+#define IRQ_DMA2_6             BFIN_IRQ(29)    /* DMA2 6  (UART TX) */
+#define IRQ_UART_TX            IRQ_DMA2_6      /* DMA2 6  (UART TX) */
+#define IRQ_DMA2_7             BFIN_IRQ(30)    /* DMA2 7  Interrupt */
+#define IRQ_DMA2_8             BFIN_IRQ(31)    /* DMA2 8  Interrupt */
+#define IRQ_DMA2_9             BFIN_IRQ(32)    /* DMA2 9  Interrupt */
+#define IRQ_DMA2_10            BFIN_IRQ(33)    /* DMA2 10 Interrupt */
+#define IRQ_DMA2_11            BFIN_IRQ(34)    /* DMA2 11 Interrupt */
+#define IRQ_TIMER0             BFIN_IRQ(35)    /* TIMER 0  Interrupt */
+#define IRQ_TIMER1             BFIN_IRQ(36)    /* TIMER 1  Interrupt */
+#define IRQ_TIMER2             BFIN_IRQ(37)    /* TIMER 2  Interrupt */
+#define IRQ_TIMER3             BFIN_IRQ(38)    /* TIMER 3  Interrupt */
+#define IRQ_TIMER4             BFIN_IRQ(39)    /* TIMER 4  Interrupt */
+#define IRQ_TIMER5             BFIN_IRQ(40)    /* TIMER 5  Interrupt */
+#define IRQ_TIMER6             BFIN_IRQ(41)    /* TIMER 6  Interrupt */
+#define IRQ_TIMER7             BFIN_IRQ(42)    /* TIMER 7  Interrupt */
+#define IRQ_TIMER8             BFIN_IRQ(43)    /* TIMER 8  Interrupt */
+#define IRQ_TIMER9             BFIN_IRQ(44)    /* TIMER 9  Interrupt */
+#define IRQ_TIMER10            BFIN_IRQ(45)    /* TIMER 10 Interrupt */
+#define IRQ_TIMER11            BFIN_IRQ(46)    /* TIMER 11 Interrupt */
+#define IRQ_PROG0_INTA         BFIN_IRQ(47)    /* Programmable Flags0 A (8) */
+#define IRQ_PROG_INTA          IRQ_PROG0_INTA  /* Programmable Flags0 A (8) */
+#define IRQ_PROG0_INTB         BFIN_IRQ(48)    /* Programmable Flags0 B (8) */
+#define IRQ_PROG_INTB          IRQ_PROG0_INTB  /* Programmable Flags0 B (8) */
+#define IRQ_PROG1_INTA         BFIN_IRQ(49)    /* Programmable Flags1 A (8) */
+#define IRQ_PROG1_INTB         BFIN_IRQ(50)    /* Programmable Flags1 B (8) */
+#define IRQ_PROG2_INTA         BFIN_IRQ(51)    /* Programmable Flags2 A (8) */
+#define IRQ_PROG2_INTB         BFIN_IRQ(52)    /* Programmable Flags2 B (8) */
+#define IRQ_DMA1_WRRD0         BFIN_IRQ(53)    /* MDMA1 0 write/read INT */
+#define IRQ_DMA_WRRD0          IRQ_DMA1_WRRD0  /* MDMA1 0 write/read INT */
 #define IRQ_MEM_DMA0           IRQ_DMA1_WRRD0
-#define IRQ_DMA1_WRRD1         (IVG_BASE + 54) /* MDMA1 1 write/read INT   */
-#define IRQ_DMA_WRRD1          IRQ_DMA1_WRRD1  /* MDMA1 1 write/read INT   */
+#define IRQ_DMA1_WRRD1         BFIN_IRQ(54)    /* MDMA1 1 write/read INT */
+#define IRQ_DMA_WRRD1          IRQ_DMA1_WRRD1  /* MDMA1 1 write/read INT */
 #define IRQ_MEM_DMA1           IRQ_DMA1_WRRD1
-/* IVG 9  */
-#define IRQ_DMA2_WRRD0         (IVG_BASE + 55) /* MDMA2 0 write/read INT   */
+#define IRQ_DMA2_WRRD0         BFIN_IRQ(55)    /* MDMA2 0 write/read INT */
 #define IRQ_MEM_DMA2           IRQ_DMA2_WRRD0
-#define IRQ_DMA2_WRRD1         (IVG_BASE + 56) /* MDMA2 1 write/read INT   */
+#define IRQ_DMA2_WRRD1         BFIN_IRQ(56)    /* MDMA2 1 write/read INT */
 #define IRQ_MEM_DMA3           IRQ_DMA2_WRRD1
-/* IVG 12 */
-#define IRQ_IMDMA_WRRD0                (IVG_BASE + 57) /* IMDMA 0 write/read INT   */
+#define IRQ_IMDMA_WRRD0                BFIN_IRQ(57)    /* IMDMA 0 write/read INT */
 #define IRQ_IMEM_DMA0          IRQ_IMDMA_WRRD0
-#define IRQ_IMDMA_WRRD1                (IVG_BASE + 58) /* IMDMA 1 write/read INT   */
+#define IRQ_IMDMA_WRRD1                BFIN_IRQ(58)    /* IMDMA 1 write/read INT */
 #define IRQ_IMEM_DMA1          IRQ_IMDMA_WRRD1
-/* IVG 13 */
-#define        IRQ_WATCH               (IVG_BASE + 59) /* Watch Dog Timer          */
-/* IVG 7  */
-#define IRQ_RESERVED_1         (IVG_BASE + 60) /* Reserved interrupt       */
-#define IRQ_RESERVED_2         (IVG_BASE + 61) /* Reserved interrupt       */
-#define IRQ_SUPPLE_0           (IVG_BASE + 62) /* Supplemental interrupt 0 */
-#define IRQ_SUPPLE_1           (IVG_BASE + 63) /* supplemental interrupt 1 */
+#define IRQ_WATCH              BFIN_IRQ(59)    /* Watch Dog Timer */
+#define IRQ_RESERVED_1         BFIN_IRQ(60)    /* Reserved interrupt */
+#define IRQ_RESERVED_2         BFIN_IRQ(61)    /* Reserved interrupt */
+#define IRQ_SUPPLE_0           BFIN_IRQ(62)    /* Supplemental interrupt 0 */
+#define IRQ_SUPPLE_1           BFIN_IRQ(63)    /* supplemental interrupt 1 */
+
+#define SYS_IRQS               71
 
 #define IRQ_PF0                        73
 #define IRQ_PF1                        74
 #define GPIO_IRQ_BASE          IRQ_PF0
 
 #define NR_MACH_IRQS           (IRQ_PF47 + 1)
-#define NR_IRQS                        (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7                   7
-#define IVG8                   8
-#define IVG9                   9
-#define IVG10                  10
-#define IVG11                  11
-#define IVG12                  12
-#define IVG13                  13
-#define IVG14                  14
-#define IVG15                  15
-
-/*
- * DEFAULT PRIORITIES:
- */
-
-#define        CONFIG_DEF_PLL_WAKEUP           7
-#define        CONFIG_DEF_DMA1_ERROR           7
-#define        CONFIG_DEF_DMA2_ERROR           7
-#define CONFIG_DEF_IMDMA_ERROR         7
-#define        CONFIG_DEF_PPI1_ERROR           7
-#define        CONFIG_DEF_PPI2_ERROR           7
-#define        CONFIG_DEF_SPORT0_ERROR         7
-#define        CONFIG_DEF_SPORT1_ERROR         7
-#define        CONFIG_DEF_SPI_ERROR            7
-#define        CONFIG_DEF_UART_ERROR           7
-#define CONFIG_DEF_RESERVED_ERROR      7
-#define        CONFIG_DEF_DMA1_0               8
-#define        CONFIG_DEF_DMA1_1               8
-#define        CONFIG_DEF_DMA1_2               8
-#define        CONFIG_DEF_DMA1_3               8
-#define        CONFIG_DEF_DMA1_4               8
-#define        CONFIG_DEF_DMA1_5               8
-#define        CONFIG_DEF_DMA1_6               8
-#define        CONFIG_DEF_DMA1_7               8
-#define        CONFIG_DEF_DMA1_8               8
-#define        CONFIG_DEF_DMA1_9               8
-#define        CONFIG_DEF_DMA1_10              8
-#define        CONFIG_DEF_DMA1_11              8
-#define        CONFIG_DEF_DMA2_0               9
-#define        CONFIG_DEF_DMA2_1               9
-#define        CONFIG_DEF_DMA2_2               9
-#define        CONFIG_DEF_DMA2_3               9
-#define        CONFIG_DEF_DMA2_4               9
-#define        CONFIG_DEF_DMA2_5               9
-#define        CONFIG_DEF_DMA2_6               9
-#define        CONFIG_DEF_DMA2_7               9
-#define        CONFIG_DEF_DMA2_8               9
-#define        CONFIG_DEF_DMA2_9               9
-#define        CONFIG_DEF_DMA2_10              9
-#define        CONFIG_DEF_DMA2_11              9
-#define CONFIG_DEF_TIMER0              10
-#define CONFIG_DEF_TIMER1              10
-#define CONFIG_DEF_TIMER2              10
-#define CONFIG_DEF_TIMER3              10
-#define CONFIG_DEF_TIMER4              10
-#define CONFIG_DEF_TIMER5              10
-#define CONFIG_DEF_TIMER6              10
-#define CONFIG_DEF_TIMER7              10
-#define CONFIG_DEF_TIMER8              10
-#define CONFIG_DEF_TIMER9              10
-#define CONFIG_DEF_TIMER10             10
-#define CONFIG_DEF_TIMER11             10
-#define        CONFIG_DEF_PROG0_INTA           11
-#define        CONFIG_DEF_PROG0_INTB           11
-#define        CONFIG_DEF_PROG1_INTA           11
-#define        CONFIG_DEF_PROG1_INTB           11
-#define        CONFIG_DEF_PROG2_INTA           11
-#define        CONFIG_DEF_PROG2_INTB           11
-#define CONFIG_DEF_DMA1_WRRD0          8
-#define CONFIG_DEF_DMA1_WRRD1          8
-#define CONFIG_DEF_DMA2_WRRD0          9
-#define CONFIG_DEF_DMA2_WRRD1          9
-#define CONFIG_DEF_IMDMA_WRRD0         12
-#define CONFIG_DEF_IMDMA_WRRD1         12
-#define        CONFIG_DEF_WATCH                13
-#define CONFIG_DEF_RESERVED_1          7
-#define CONFIG_DEF_RESERVED_2          7
-#define CONFIG_DEF_SUPPLE_0            7
-#define CONFIG_DEF_SUPPLE_1            7
 
 /* IAR0 BIT FIELDS */
-#define        IRQ_PLL_WAKEUP_POS                      0
-#define        IRQ_DMA1_ERROR_POS                      4
-#define        IRQ_DMA2_ERROR_POS                      8
-#define IRQ_IMDMA_ERROR_POS                    12
-#define        IRQ_PPI0_ERROR_POS                      16
-#define        IRQ_PPI1_ERROR_POS                      20
-#define        IRQ_SPORT0_ERROR_POS            24
-#define        IRQ_SPORT1_ERROR_POS            28
+#define IRQ_PLL_WAKEUP_POS     0
+#define IRQ_DMA1_ERROR_POS     4
+#define IRQ_DMA2_ERROR_POS     8
+#define IRQ_IMDMA_ERROR_POS    12
+#define IRQ_PPI0_ERROR_POS     16
+#define IRQ_PPI1_ERROR_POS     20
+#define IRQ_SPORT0_ERROR_POS   24
+#define IRQ_SPORT1_ERROR_POS   28
+
 /* IAR1 BIT FIELDS */
-#define        IRQ_SPI_ERROR_POS                       0
-#define        IRQ_UART_ERROR_POS                      4
-#define IRQ_RESERVED_ERROR_POS         8
-#define        IRQ_DMA1_0_POS                  12
-#define        IRQ_DMA1_1_POS                  16
-#define IRQ_DMA1_2_POS                 20
-#define IRQ_DMA1_3_POS                 24
-#define IRQ_DMA1_4_POS                 28
+#define IRQ_SPI_ERROR_POS      0
+#define IRQ_UART_ERROR_POS     4
+#define IRQ_RESERVED_ERROR_POS 8
+#define IRQ_DMA1_0_POS         12
+#define IRQ_DMA1_1_POS         16
+#define IRQ_DMA1_2_POS         20
+#define IRQ_DMA1_3_POS         24
+#define IRQ_DMA1_4_POS         28
+
 /* IAR2 BIT FIELDS */
-#define IRQ_DMA1_5_POS                 0
-#define IRQ_DMA1_6_POS                 4
-#define IRQ_DMA1_7_POS                 8
-#define IRQ_DMA1_8_POS                 12
-#define IRQ_DMA1_9_POS                 16
-#define IRQ_DMA1_10_POS                        20
-#define IRQ_DMA1_11_POS                        24
-#define IRQ_DMA2_0_POS                 28
+#define IRQ_DMA1_5_POS         0
+#define IRQ_DMA1_6_POS         4
+#define IRQ_DMA1_7_POS         8
+#define IRQ_DMA1_8_POS         12
+#define IRQ_DMA1_9_POS         16
+#define IRQ_DMA1_10_POS                20
+#define IRQ_DMA1_11_POS                24
+#define IRQ_DMA2_0_POS         28
+
 /* IAR3 BIT FIELDS */
-#define IRQ_DMA2_1_POS                 0
-#define IRQ_DMA2_2_POS                 4
-#define IRQ_DMA2_3_POS                 8
-#define IRQ_DMA2_4_POS                 12
-#define IRQ_DMA2_5_POS                 16
-#define IRQ_DMA2_6_POS                 20
-#define IRQ_DMA2_7_POS                 24
-#define IRQ_DMA2_8_POS                 28
+#define IRQ_DMA2_1_POS         0
+#define IRQ_DMA2_2_POS         4
+#define IRQ_DMA2_3_POS         8
+#define IRQ_DMA2_4_POS         12
+#define IRQ_DMA2_5_POS         16
+#define IRQ_DMA2_6_POS         20
+#define IRQ_DMA2_7_POS         24
+#define IRQ_DMA2_8_POS         28
+
 /* IAR4 BIT FIELDS */
-#define IRQ_DMA2_9_POS                 0
-#define IRQ_DMA2_10_POS                        4
-#define IRQ_DMA2_11_POS                        8
-#define IRQ_TIMER0_POS                 12
-#define IRQ_TIMER1_POS                 16
-#define IRQ_TIMER2_POS                 20
-#define IRQ_TIMER3_POS                 24
-#define IRQ_TIMER4_POS                 28
+#define IRQ_DMA2_9_POS         0
+#define IRQ_DMA2_10_POS                4
+#define IRQ_DMA2_11_POS                8
+#define IRQ_TIMER0_POS         12
+#define IRQ_TIMER1_POS         16
+#define IRQ_TIMER2_POS         20
+#define IRQ_TIMER3_POS         24
+#define IRQ_TIMER4_POS         28
+
 /* IAR5 BIT FIELDS */
-#define IRQ_TIMER5_POS                 0
-#define IRQ_TIMER6_POS                 4
-#define IRQ_TIMER7_POS                 8
-#define IRQ_TIMER8_POS                 12
-#define IRQ_TIMER9_POS                 16
-#define IRQ_TIMER10_POS                        20
-#define IRQ_TIMER11_POS                        24
-#define IRQ_PROG0_INTA_POS                     28
+#define IRQ_TIMER5_POS         0
+#define IRQ_TIMER6_POS         4
+#define IRQ_TIMER7_POS         8
+#define IRQ_TIMER8_POS         12
+#define IRQ_TIMER9_POS         16
+#define IRQ_TIMER10_POS                20
+#define IRQ_TIMER11_POS                24
+#define IRQ_PROG0_INTA_POS     28
+
 /* IAR6 BIT FIELDS */
-#define IRQ_PROG0_INTB_POS                     0
-#define IRQ_PROG1_INTA_POS                     4
-#define IRQ_PROG1_INTB_POS                     8
-#define IRQ_PROG2_INTA_POS                     12
-#define IRQ_PROG2_INTB_POS                     16
-#define IRQ_DMA1_WRRD0_POS                     20
-#define IRQ_DMA1_WRRD1_POS                     24
-#define IRQ_DMA2_WRRD0_POS                     28
-/* IAR7 BIT FIELDS */
-#define IRQ_DMA2_WRRD1_POS                     0
-#define IRQ_IMDMA_WRRD0_POS                    4
-#define IRQ_IMDMA_WRRD1_POS                    8
-#define        IRQ_WDTIMER_POS                 12
-#define IRQ_RESERVED_1_POS                     16
-#define IRQ_RESERVED_2_POS                     20
-#define IRQ_SUPPLE_0_POS                       24
-#define IRQ_SUPPLE_1_POS                       28
+#define IRQ_PROG0_INTB_POS     0
+#define IRQ_PROG1_INTA_POS     4
+#define IRQ_PROG1_INTB_POS     8
+#define IRQ_PROG2_INTA_POS     12
+#define IRQ_PROG2_INTB_POS     16
+#define IRQ_DMA1_WRRD0_POS     20
+#define IRQ_DMA1_WRRD1_POS     24
+#define IRQ_DMA2_WRRD0_POS     28
 
-#endif                         /* _BF561_IRQ_H_ */
+/* IAR7 BIT FIELDS */
+#define IRQ_DMA2_WRRD1_POS     0
+#define IRQ_IMDMA_WRRD0_POS    4
+#define IRQ_IMDMA_WRRD1_POS    8
+#define IRQ_WDTIMER_POS                12
+#define IRQ_RESERVED_1_POS     16
+#define IRQ_RESERVED_2_POS     20
+#define IRQ_SUPPLE_0_POS       24
+#define IRQ_SUPPLE_1_POS       28
+
+#endif
index 7b07740cf68cdf828c101cced2e99bfe68e59613..85abd8be134382821e60af23d57c9117e875b93e 100644 (file)
@@ -24,17 +24,23 @@ static DEFINE_SPINLOCK(boot_lock);
 
 void __init platform_init_cpus(void)
 {
-       cpu_set(0, cpu_possible_map); /* CoreA */
-       cpu_set(1, cpu_possible_map); /* CoreB */
+       struct cpumask mask;
+
+       cpumask_set_cpu(0, &mask); /* CoreA */
+       cpumask_set_cpu(1, &mask); /* CoreB */
+       init_cpu_possible(&mask);
 }
 
 void __init platform_prepare_cpus(unsigned int max_cpus)
 {
+       struct cpumask mask;
+
        bfin_relocate_coreb_l1_mem();
 
        /* Both cores ought to be present on a bf561! */
-       cpu_set(0, cpu_present_map); /* CoreA */
-       cpu_set(1, cpu_present_map); /* CoreB */
+       cpumask_set_cpu(0, &mask); /* CoreA */
+       cpumask_set_cpu(1, &mask); /* CoreB */
+       init_cpu_present(&mask);
 }
 
 int __init setup_profiling_timer(unsigned int multiplier) /* not supported */
@@ -62,9 +68,6 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
        bfin_write_SICB_IWR1(IWR_DISABLE_ALL);
        SSYNC();
 
-       /* Store CPU-private information to the cpu_data array. */
-       bfin_setup_cpudata(cpu);
-
        /* We are done with local CPU inits, unblock the boot CPU. */
        set_cpu_online(cpu, true);
        spin_lock(&boot_lock);
index 5e4112e518a992c2566c14b893f5d17f05481076..f5685a496c58d648e387f4fb03c56efe9bf6cbcc 100644 (file)
@@ -85,10 +85,11 @@ static void bfin_wakeup_cpu(void)
 {
        unsigned int cpu;
        unsigned int this_cpu = smp_processor_id();
-       cpumask_t mask = cpu_online_map;
+       cpumask_t mask;
 
-       cpu_clear(this_cpu, mask);
-       for_each_cpu_mask(cpu, mask)
+       cpumask_copy(&mask, cpu_online_mask);
+       cpumask_clear_cpu(this_cpu, &mask);
+       for_each_cpu(cpu, &mask)
                platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
 }
 
index 43d9fb195c1ee7a82a548e34e08fba4802e128bc..1177369f9922533f839b5a02091506384a8addd4 100644 (file)
 #ifdef CONFIG_IPIPE
 #include <linux/ipipe.h>
 #endif
-#ifdef CONFIG_KGDB
-#include <linux/kgdb.h>
-#endif
 #include <asm/traps.h>
 #include <asm/blackfin.h>
 #include <asm/gpio.h>
 #include <asm/irq_handler.h>
 #include <asm/dpmc.h>
-#include <asm/bfin5xx_spi.h>
-#include <asm/bfin_sport.h>
-#include <asm/bfin_can.h>
 
 #define SIC_SYSIRQ(irq)        (irq - (IRQ_CORETMR + 1))
 
-#ifdef BF537_FAMILY
-# define BF537_GENERIC_ERROR_INT_DEMUX
-# define SPI_ERR_MASK   (BIT_STAT_TXCOL | BIT_STAT_RBSY | BIT_STAT_MODF | BIT_STAT_TXE)        /* SPI_STAT */
-# define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF)    /* SPORT_STAT */
-# define PPI_ERR_MASK   (0xFFFF & ~FLD)        /* PPI_STATUS */
-# define EMAC_ERR_MASK  (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE)        /* EMAC_SYSTAT */
-# define UART_ERR_MASK  (0x6)  /* UART_IIR */
-# define CAN_ERR_MASK   (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF)     /* CAN_GIF */
-#else
-# undef BF537_GENERIC_ERROR_INT_DEMUX
-#endif
-
 /*
  * NOTES:
  * - we have separated the physical Hardware interrupt from the
@@ -63,22 +45,19 @@ unsigned long bfin_irq_flags = 0x1f;
 EXPORT_SYMBOL(bfin_irq_flags);
 #endif
 
-/* The number of spurious interrupts */
-atomic_t num_spurious;
-
 #ifdef CONFIG_PM
 unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */
 unsigned vr_wakeup;
 #endif
 
-struct ivgx {
+static struct ivgx {
        /* irq number for request_irq, available in mach-bf5xx/irq.h */
        unsigned int irqno;
        /* corresponding bit in the SIC_ISR register */
        unsigned int isrflag;
 } ivg_table[NR_PERI_INTS];
 
-struct ivg_slice {
+static struct ivg_slice {
        /* position of first irq in ivg_table for given ivg */
        struct ivgx *ifirst;
        struct ivgx *istop;
@@ -125,7 +104,7 @@ static void __init search_IAR(void)
  * This is for core internal IRQs
  */
 
-static void bfin_ack_noop(struct irq_data *d)
+void bfin_ack_noop(struct irq_data *d)
 {
        /* Dummy function.  */
 }
@@ -154,26 +133,24 @@ static void bfin_core_unmask_irq(struct irq_data *d)
        return;
 }
 
-static void bfin_internal_mask_irq(unsigned int irq)
+void bfin_internal_mask_irq(unsigned int irq)
 {
-       unsigned long flags;
+       unsigned long flags = hard_local_irq_save();
 
-#ifdef CONFIG_BF53x
-       flags = hard_local_irq_save();
-       bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
-                            ~(1 << SIC_SYSIRQ(irq)));
-#else
-       unsigned mask_bank, mask_bit;
-       flags = hard_local_irq_save();
-       mask_bank = SIC_SYSIRQ(irq) / 32;
-       mask_bit = SIC_SYSIRQ(irq) % 32;
+#ifdef SIC_IMASK0
+       unsigned mask_bank = SIC_SYSIRQ(irq) / 32;
+       unsigned mask_bit = SIC_SYSIRQ(irq) % 32;
        bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
                             ~(1 << mask_bit));
-#ifdef CONFIG_SMP
+# ifdef CONFIG_SMP
        bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) &
                             ~(1 << mask_bit));
+# endif
+#else
+       bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
+                            ~(1 << SIC_SYSIRQ(irq)));
 #endif
-#endif
+
        hard_local_irq_restore(flags);
 }
 
@@ -186,33 +163,31 @@ static void bfin_internal_mask_irq_chip(struct irq_data *d)
 static void bfin_internal_unmask_irq_affinity(unsigned int irq,
                const struct cpumask *affinity)
 #else
-static void bfin_internal_unmask_irq(unsigned int irq)
+void bfin_internal_unmask_irq(unsigned int irq)
 #endif
 {
-       unsigned long flags;
+       unsigned long flags = hard_local_irq_save();
 
-#ifdef CONFIG_BF53x
-       flags = hard_local_irq_save();
-       bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
-                            (1 << SIC_SYSIRQ(irq)));
-#else
-       unsigned mask_bank, mask_bit;
-       flags = hard_local_irq_save();
-       mask_bank = SIC_SYSIRQ(irq) / 32;
-       mask_bit = SIC_SYSIRQ(irq) % 32;
-#ifdef CONFIG_SMP
+#ifdef SIC_IMASK0
+       unsigned mask_bank = SIC_SYSIRQ(irq) / 32;
+       unsigned mask_bit = SIC_SYSIRQ(irq) % 32;
+# ifdef CONFIG_SMP
        if (cpumask_test_cpu(0, affinity))
-#endif
+# endif
                bfin_write_SIC_IMASK(mask_bank,
                        bfin_read_SIC_IMASK(mask_bank) |
                        (1 << mask_bit));
-#ifdef CONFIG_SMP
+# ifdef CONFIG_SMP
        if (cpumask_test_cpu(1, affinity))
                bfin_write_SICB_IMASK(mask_bank,
                        bfin_read_SICB_IMASK(mask_bank) |
                        (1 << mask_bit));
+# endif
+#else
+       bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
+                            (1 << SIC_SYSIRQ(irq)));
 #endif
-#endif
+
        hard_local_irq_restore(flags);
 }
 
@@ -295,6 +270,8 @@ static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state)
 {
        return bfin_internal_set_wake(d->irq, state);
 }
+#else
+# define bfin_internal_set_wake_chip NULL
 #endif
 
 static struct irq_chip bfin_core_irqchip = {
@@ -315,12 +292,10 @@ static struct irq_chip bfin_internal_irqchip = {
 #ifdef CONFIG_SMP
        .irq_set_affinity = bfin_internal_set_affinity,
 #endif
-#ifdef CONFIG_PM
        .irq_set_wake = bfin_internal_set_wake_chip,
-#endif
 };
 
-static void bfin_handle_irq(unsigned irq)
+void bfin_handle_irq(unsigned irq)
 {
 #ifdef CONFIG_IPIPE
        struct pt_regs regs;    /* Contents not used. */
@@ -332,102 +307,6 @@ static void bfin_handle_irq(unsigned irq)
 #endif  /* !CONFIG_IPIPE */
 }
 
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
-static int error_int_mask;
-
-static void bfin_generic_error_mask_irq(struct irq_data *d)
-{
-       error_int_mask &= ~(1L << (d->irq - IRQ_PPI_ERROR));
-       if (!error_int_mask)
-               bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
-}
-
-static void bfin_generic_error_unmask_irq(struct irq_data *d)
-{
-       bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
-       error_int_mask |= 1L << (d->irq - IRQ_PPI_ERROR);
-}
-
-static struct irq_chip bfin_generic_error_irqchip = {
-       .name = "ERROR",
-       .irq_ack = bfin_ack_noop,
-       .irq_mask_ack = bfin_generic_error_mask_irq,
-       .irq_mask = bfin_generic_error_mask_irq,
-       .irq_unmask = bfin_generic_error_unmask_irq,
-};
-
-static void bfin_demux_error_irq(unsigned int int_err_irq,
-                                struct irq_desc *inta_desc)
-{
-       int irq = 0;
-
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
-       if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
-               irq = IRQ_MAC_ERROR;
-       else
-#endif
-       if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
-               irq = IRQ_SPORT0_ERROR;
-       else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
-               irq = IRQ_SPORT1_ERROR;
-       else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
-               irq = IRQ_PPI_ERROR;
-       else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
-               irq = IRQ_CAN_ERROR;
-       else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
-               irq = IRQ_SPI_ERROR;
-       else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
-               irq = IRQ_UART0_ERROR;
-       else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
-               irq = IRQ_UART1_ERROR;
-
-       if (irq) {
-               if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
-                       bfin_handle_irq(irq);
-               else {
-
-                       switch (irq) {
-                       case IRQ_PPI_ERROR:
-                               bfin_write_PPI_STATUS(PPI_ERR_MASK);
-                               break;
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
-                       case IRQ_MAC_ERROR:
-                               bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
-                               break;
-#endif
-                       case IRQ_SPORT0_ERROR:
-                               bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
-                               break;
-
-                       case IRQ_SPORT1_ERROR:
-                               bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
-                               break;
-
-                       case IRQ_CAN_ERROR:
-                               bfin_write_CAN_GIS(CAN_ERR_MASK);
-                               break;
-
-                       case IRQ_SPI_ERROR:
-                               bfin_write_SPI_STAT(SPI_ERR_MASK);
-                               break;
-
-                       default:
-                               break;
-                       }
-
-                       pr_debug("IRQ %d:"
-                                " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
-                                irq);
-               }
-       } else
-               printk(KERN_ERR
-                      "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
-                      " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
-                      __func__, __FILE__, __LINE__);
-
-}
-#endif                         /* BF537_GENERIC_ERROR_INT_DEMUX */
-
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
 static int mac_stat_int_mask;
 
@@ -468,7 +347,7 @@ static void bfin_mac_status_mask_irq(struct irq_data *d)
        unsigned int irq = d->irq;
 
        mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT));
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+#ifdef BF537_FAMILY
        switch (irq) {
        case IRQ_MAC_PHYINT:
                bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() & ~PHYIE);
@@ -487,7 +366,7 @@ static void bfin_mac_status_unmask_irq(struct irq_data *d)
 {
        unsigned int irq = d->irq;
 
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+#ifdef BF537_FAMILY
        switch (irq) {
        case IRQ_MAC_PHYINT:
                bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() | PHYIE);
@@ -505,12 +384,14 @@ static void bfin_mac_status_unmask_irq(struct irq_data *d)
 #ifdef CONFIG_PM
 int bfin_mac_status_set_wake(struct irq_data *d, unsigned int state)
 {
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+#ifdef BF537_FAMILY
        return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state);
 #else
        return bfin_internal_set_wake(IRQ_MAC_ERROR, state);
 #endif
 }
+#else
+# define bfin_mac_status_set_wake NULL
 #endif
 
 static struct irq_chip bfin_mac_status_irqchip = {
@@ -519,13 +400,11 @@ static struct irq_chip bfin_mac_status_irqchip = {
        .irq_mask_ack = bfin_mac_status_mask_irq,
        .irq_mask = bfin_mac_status_mask_irq,
        .irq_unmask = bfin_mac_status_unmask_irq,
-#ifdef CONFIG_PM
        .irq_set_wake = bfin_mac_status_set_wake,
-#endif
 };
 
-static void bfin_demux_mac_status_irq(unsigned int int_err_irq,
-                                struct irq_desc *inta_desc)
+void bfin_demux_mac_status_irq(unsigned int int_err_irq,
+                              struct irq_desc *inta_desc)
 {
        int i, irq = 0;
        u32 status = bfin_read_EMAC_SYSTAT();
@@ -680,29 +559,48 @@ static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type)
 }
 
 #ifdef CONFIG_PM
-int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
+static int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
 {
        return gpio_pm_wakeup_ctrl(irq_to_gpio(d->irq), state);
 }
+#else
+# define bfin_gpio_set_wake NULL
 #endif
 
-static void bfin_demux_gpio_irq(unsigned int inta_irq,
-                               struct irq_desc *desc)
+static void bfin_demux_gpio_block(unsigned int irq)
 {
-       unsigned int i, gpio, mask, irq, search = 0;
+       unsigned int gpio, mask;
+
+       gpio = irq_to_gpio(irq);
+       mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
+
+       while (mask) {
+               if (mask & 1)
+                       bfin_handle_irq(irq);
+               irq++;
+               mask >>= 1;
+       }
+}
+
+void bfin_demux_gpio_irq(unsigned int inta_irq,
+                        struct irq_desc *desc)
+{
+       unsigned int irq;
 
        switch (inta_irq) {
-#if defined(CONFIG_BF53x)
-       case IRQ_PROG_INTA:
-               irq = IRQ_PF0;
-               search = 1;
+#if defined(BF537_FAMILY)
+       case IRQ_PF_INTA_PG_INTA:
+               bfin_demux_gpio_block(IRQ_PF0);
+               irq = IRQ_PG0;
                break;
-# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
-       case IRQ_MAC_RX:
+       case IRQ_PH_INTA_MAC_RX:
                irq = IRQ_PH0;
                break;
-# endif
-#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
+#elif defined(BF533_FAMILY)
+       case IRQ_PROG_INTA:
+               irq = IRQ_PF0;
+               break;
+#elif defined(BF538_FAMILY)
        case IRQ_PORTF_INTA:
                irq = IRQ_PF0;
                break;
@@ -732,31 +630,7 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
                return;
        }
 
-       if (search) {
-               for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
-                       irq += i;
-
-                       mask = get_gpiop_data(i) & get_gpiop_maska(i);
-
-                       while (mask) {
-                               if (mask & 1)
-                                       bfin_handle_irq(irq);
-                               irq++;
-                               mask >>= 1;
-                       }
-               }
-       } else {
-                       gpio = irq_to_gpio(irq);
-                       mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
-
-                       do {
-                               if (mask & 1)
-                                       bfin_handle_irq(irq);
-                               irq++;
-                               mask >>= 1;
-                       } while (mask);
-       }
-
+       bfin_demux_gpio_block(irq);
 }
 
 #else                          /* CONFIG_BF54x */
@@ -974,15 +848,11 @@ static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type)
 }
 
 #ifdef CONFIG_PM
-u32 pint_saved_masks[NR_PINT_SYS_IRQS];
-u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
-
-int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
+static int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
 {
        u32 pint_irq;
        u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS];
        u32 bank = PINT_2_BANK(pint_val);
-       u32 pintbit = PINT_BIT(pint_val);
 
        switch (bank) {
        case 0:
@@ -1003,46 +873,14 @@ int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
 
        bfin_internal_set_wake(pint_irq, state);
 
-       if (state)
-               pint_wakeup_masks[bank] |= pintbit;
-       else
-               pint_wakeup_masks[bank] &= ~pintbit;
-
        return 0;
 }
-
-u32 bfin_pm_setup(void)
-{
-       u32 val, i;
-
-       for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
-               val = pint[i]->mask_clear;
-               pint_saved_masks[i] = val;
-               if (val ^ pint_wakeup_masks[i]) {
-                       pint[i]->mask_clear = val;
-                       pint[i]->mask_set = pint_wakeup_masks[i];
-               }
-       }
-
-       return 0;
-}
-
-void bfin_pm_restore(void)
-{
-       u32 i, val;
-
-       for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
-               val = pint_saved_masks[i];
-               if (val ^ pint_wakeup_masks[i]) {
-                       pint[i]->mask_clear = pint[i]->mask_clear;
-                       pint[i]->mask_set = val;
-               }
-       }
-}
+#else
+# define bfin_gpio_set_wake NULL
 #endif
 
-static void bfin_demux_gpio_irq(unsigned int inta_irq,
-                               struct irq_desc *desc)
+void bfin_demux_gpio_irq(unsigned int inta_irq,
+                        struct irq_desc *desc)
 {
        u32 bank, pint_val;
        u32 request, irq;
@@ -1091,9 +929,7 @@ static struct irq_chip bfin_gpio_irqchip = {
        .irq_set_type = bfin_gpio_irq_type,
        .irq_startup = bfin_gpio_irq_startup,
        .irq_shutdown = bfin_gpio_irq_shutdown,
-#ifdef CONFIG_PM
        .irq_set_wake = bfin_gpio_set_wake,
-#endif
 };
 
 void __cpuinit init_exception_vectors(void)
@@ -1127,12 +963,12 @@ int __init init_arch_irq(void)
 {
        int irq;
        unsigned long ilat = 0;
+
        /*  Disable all the peripheral intrs  - page 4-29 HW Ref manual */
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
-       || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
+#ifdef SIC_IMASK0
        bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
        bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
-# ifdef CONFIG_BF54x
+# ifdef SIC_IMASK2
        bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
 # endif
 # ifdef CONFIG_SMP
@@ -1145,11 +981,6 @@ int __init init_arch_irq(void)
 
        local_irq_disable();
 
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
-       /* Clear EMAC Interrupt Status bits so we can demux it later */
-       bfin_write_EMAC_SYSTAT(-1);
-#endif
-
 #ifdef CONFIG_BF54x
 # ifdef CONFIG_PINTx_REASSIGN
        pint[0]->assign = CONFIG_PINT0_ASSIGN;
@@ -1168,11 +999,11 @@ int __init init_arch_irq(void)
                        irq_set_chip(irq, &bfin_internal_irqchip);
 
                switch (irq) {
-#if defined(CONFIG_BF53x)
+#if defined(BF537_FAMILY)
+               case IRQ_PH_INTA_MAC_RX:
+               case IRQ_PF_INTA_PG_INTA:
+#elif defined(BF533_FAMILY)
                case IRQ_PROG_INTA:
-# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
-               case IRQ_MAC_RX:
-# endif
 #elif defined(CONFIG_BF54x)
                case IRQ_PINT0:
                case IRQ_PINT1:
@@ -1186,16 +1017,11 @@ int __init init_arch_irq(void)
                case IRQ_PROG0_INTA:
                case IRQ_PROG1_INTA:
                case IRQ_PROG2_INTA:
-#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
+#elif defined(BF538_FAMILY)
                case IRQ_PORTF_INTA:
 #endif
                        irq_set_chained_handler(irq, bfin_demux_gpio_irq);
                        break;
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
-               case IRQ_GENERIC_ERROR:
-                       irq_set_chained_handler(irq, bfin_demux_error_irq);
-                       break;
-#endif
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
                case IRQ_MAC_ERROR:
                        irq_set_chained_handler(irq,
@@ -1213,11 +1039,10 @@ int __init init_arch_irq(void)
                case IRQ_CORETMR:
 # ifdef CONFIG_SMP
                        irq_set_handler(irq, handle_percpu_irq);
-                       break;
 # else
                        irq_set_handler(irq, handle_simple_irq);
-                       break;
 # endif
+                       break;
 #endif
 
 #ifdef CONFIG_TICKSOURCE_GPTMR0
@@ -1226,26 +1051,17 @@ int __init init_arch_irq(void)
                        break;
 #endif
 
-#ifdef CONFIG_IPIPE
                default:
+#ifdef CONFIG_IPIPE
                        irq_set_handler(irq, handle_level_irq);
-                       break;
-#else /* !CONFIG_IPIPE */
-               default:
+#else
                        irq_set_handler(irq, handle_simple_irq);
+#endif
                        break;
-#endif /* !CONFIG_IPIPE */
                }
        }
 
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
-       for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
-               irq_set_chip_and_handler(irq, &bfin_generic_error_irqchip,
-                                        handle_level_irq);
-#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
-       irq_set_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq);
-#endif
-#endif
+       init_mach_irq();
 
 #if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
        for (irq = IRQ_MAC_PHYINT; irq <= IRQ_MAC_STMDONE; irq++)
@@ -1307,53 +1123,54 @@ int __init init_arch_irq(void)
 #ifdef CONFIG_DO_IRQ_L1
 __attribute__((l1_text))
 #endif
-void do_irq(int vec, struct pt_regs *fp)
+static int vec_to_irq(int vec)
 {
-       if (vec == EVT_IVTMR_P) {
-               vec = IRQ_CORETMR;
-       } else {
-               struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
-               struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
-#if defined(SIC_ISR0)
-               unsigned long sic_status[3];
+       struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
+       struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
+       unsigned long sic_status[3];
+
+       if (likely(vec == EVT_IVTMR_P))
+               return IRQ_CORETMR;
 
-               if (smp_processor_id()) {
+#ifdef SIC_ISR
+       sic_status[0] = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
+#else
+       if (smp_processor_id()) {
 # ifdef SICB_ISR0
-                       /* This will be optimized out in UP mode. */
-                       sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
-                       sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
-# endif
-               } else {
-                       sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
-                       sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
-               }
-# ifdef SIC_ISR2
-               sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
+               /* This will be optimized out in UP mode. */
+               sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
+               sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
 # endif
-               for (;; ivg++) {
-                       if (ivg >= ivg_stop) {
-                               atomic_inc(&num_spurious);
-                               return;
-                       }
-                       if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
-                               break;
-               }
-#else
-               unsigned long sic_status;
-
-               sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
+       } else {
+               sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
+               sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
+       }
+#endif
+#ifdef SIC_ISR2
+       sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
+#endif
 
-               for (;; ivg++) {
-                       if (ivg >= ivg_stop) {
-                               atomic_inc(&num_spurious);
-                               return;
-                       } else if (sic_status & ivg->isrflag)
-                               break;
-               }
+       for (;; ivg++) {
+               if (ivg >= ivg_stop)
+                       return -1;
+#ifdef SIC_ISR
+               if (sic_status[0] & ivg->isrflag)
+#else
+               if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
 #endif
-               vec = ivg->irqno;
+                       return ivg->irqno;
        }
-       asm_do_IRQ(vec, fp);
+}
+
+#ifdef CONFIG_DO_IRQ_L1
+__attribute__((l1_text))
+#endif
+void do_irq(int vec, struct pt_regs *fp)
+{
+       int irq = vec_to_irq(vec);
+       if (irq == -1)
+               return;
+       asm_do_IRQ(irq, fp);
 }
 
 #ifdef CONFIG_IPIPE
@@ -1391,40 +1208,9 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
        struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
        int irq, s = 0;
 
-       if (likely(vec == EVT_IVTMR_P))
-               irq = IRQ_CORETMR;
-       else {
-#if defined(SIC_ISR0)
-               unsigned long sic_status[3];
-
-               sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
-               sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
-# ifdef SIC_ISR2
-               sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
-# endif
-               for (;; ivg++) {
-                       if (ivg >= ivg_stop) {
-                               atomic_inc(&num_spurious);
-                               return 0;
-                       }
-                       if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
-                               break;
-               }
-#else
-               unsigned long sic_status;
-
-               sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
-
-               for (;; ivg++) {
-                       if (ivg >= ivg_stop) {
-                               atomic_inc(&num_spurious);
-                               return 0;
-                       } else if (sic_status & ivg->isrflag)
-                               break;
-               }
-#endif
-               irq = ivg->irqno;
-       }
+       irq = vec_to_irq(vec);
+       if (irq == -1)
+               return 0;
 
        if (irq == IRQ_SYSTMR) {
 #if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0)
index 1fbd94c4445700d24ac882cd7515dac3c159db4f..35e7e1eb0188f58de9fe39ed50af1538b5802e69 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/cacheflush.h>
+#include <asm/irq_handler.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -96,7 +97,7 @@ static void ipi_cpu_stop(unsigned int cpu)
        dump_stack();
        spin_unlock(&stop_lock);
 
-       cpu_clear(cpu, cpu_online_map);
+       set_cpu_online(cpu, false);
 
        local_irq_disable();
 
@@ -146,7 +147,7 @@ static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
                 */
                resync_core_dcache();
 #endif
-               cpu_clear(cpu, *msg->call_struct.waitmask);
+               cpumask_clear_cpu(cpu, msg->call_struct.waitmask);
        }
 }
 
@@ -222,9 +223,10 @@ static inline void smp_send_message(cpumask_t callmap, unsigned long type,
        struct ipi_message_queue *msg_queue;
        struct ipi_message *msg;
        unsigned long flags, next_msg;
-       cpumask_t waitmask = callmap; /* waitmask is shared by all cpus */
+       cpumask_t waitmask; /* waitmask is shared by all cpus */
 
-       for_each_cpu_mask(cpu, callmap) {
+       cpumask_copy(&waitmask, &callmap);
+       for_each_cpu(cpu, &callmap) {
                msg_queue = &per_cpu(ipi_msg_queue, cpu);
                spin_lock_irqsave(&msg_queue->lock, flags);
                if (msg_queue->count < BFIN_IPI_MSGQ_LEN) {
@@ -246,7 +248,7 @@ static inline void smp_send_message(cpumask_t callmap, unsigned long type,
        }
 
        if (wait) {
-               while (!cpus_empty(waitmask))
+               while (!cpumask_empty(&waitmask))
                        blackfin_dcache_invalidate_range(
                                (unsigned long)(&waitmask),
                                (unsigned long)(&waitmask));
@@ -265,9 +267,9 @@ int smp_call_function(void (*func)(void *info), void *info, int wait)
        cpumask_t callmap;
 
        preempt_disable();
-       callmap = cpu_online_map;
-       cpu_clear(smp_processor_id(), callmap);
-       if (!cpus_empty(callmap))
+       cpumask_copy(&callmap, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &callmap);
+       if (!cpumask_empty(&callmap))
                smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait);
 
        preempt_enable();
@@ -284,8 +286,8 @@ int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
 
        if (cpu_is_offline(cpu))
                return 0;
-       cpus_clear(callmap);
-       cpu_set(cpu, callmap);
+       cpumask_clear(&callmap);
+       cpumask_set_cpu(cpu, &callmap);
 
        smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait);
 
@@ -308,9 +310,9 @@ void smp_send_stop(void)
        cpumask_t callmap;
 
        preempt_disable();
-       callmap = cpu_online_map;
-       cpu_clear(smp_processor_id(), callmap);
-       if (!cpus_empty(callmap))
+       cpumask_copy(&callmap, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &callmap);
+       if (!cpumask_empty(&callmap))
                smp_send_message(callmap, BFIN_IPI_CPU_STOP, NULL, NULL, 0);
 
        preempt_enable();
index dfd304a4a3ea113a25f23befd8ba8f0078b4bc79..29d98faa1efdacd4a9cf93723fb268ab91dcbc85 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/rtc.h>
 #include <linux/slab.h>
@@ -764,7 +765,7 @@ EXPORT_SYMBOL(sram_alloc_with_lsl);
 /* Need to keep line of output the same.  Currently, that is 44 bytes
  * (including newline).
  */
-static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
+static int _sram_proc_show(struct seq_file *m, const char *desc,
                struct sram_piece *pfree_head,
                struct sram_piece *pused_head)
 {
@@ -773,13 +774,13 @@ static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
        if (!pfree_head || !pused_head)
                return -1;
 
-       *len += sprintf(&buf[*len], "--- SRAM %-14s Size   PID State     \n", desc);
+       seq_printf(m, "--- SRAM %-14s Size   PID State     \n", desc);
 
        /* search the relevant memory slot */
        pslot = pused_head->next;
 
        while (pslot != NULL) {
-               *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+               seq_printf(m, "%p-%p %10i %5i %-10s\n",
                        pslot->paddr, pslot->paddr + pslot->size,
                        pslot->size, pslot->pid, "ALLOCATED");
 
@@ -789,7 +790,7 @@ static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
        pslot = pfree_head->next;
 
        while (pslot != NULL) {
-               *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+               seq_printf(m, "%p-%p %10i %5i %-10s\n",
                        pslot->paddr, pslot->paddr + pslot->size,
                        pslot->size, pslot->pid, "FREE");
 
@@ -798,54 +799,62 @@ static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
 
        return 0;
 }
-static int sram_proc_read(char *buf, char **start, off_t offset, int count,
-               int *eof, void *data)
+static int sram_proc_show(struct seq_file *m, void *v)
 {
-       int len = 0;
        unsigned int cpu;
 
        for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
-               if (_sram_proc_read(buf, &len, count, "Scratchpad",
+               if (_sram_proc_show(m, "Scratchpad",
                        &per_cpu(free_l1_ssram_head, cpu), &per_cpu(used_l1_ssram_head, cpu)))
                        goto not_done;
 #if L1_DATA_A_LENGTH != 0
-               if (_sram_proc_read(buf, &len, count, "L1 Data A",
+               if (_sram_proc_show(m, "L1 Data A",
                        &per_cpu(free_l1_data_A_sram_head, cpu),
                        &per_cpu(used_l1_data_A_sram_head, cpu)))
                        goto not_done;
 #endif
 #if L1_DATA_B_LENGTH != 0
-               if (_sram_proc_read(buf, &len, count, "L1 Data B",
+               if (_sram_proc_show(m, "L1 Data B",
                        &per_cpu(free_l1_data_B_sram_head, cpu),
                        &per_cpu(used_l1_data_B_sram_head, cpu)))
                        goto not_done;
 #endif
 #if L1_CODE_LENGTH != 0
-               if (_sram_proc_read(buf, &len, count, "L1 Instruction",
+               if (_sram_proc_show(m, "L1 Instruction",
                        &per_cpu(free_l1_inst_sram_head, cpu),
                        &per_cpu(used_l1_inst_sram_head, cpu)))
                        goto not_done;
 #endif
        }
 #if L2_LENGTH != 0
-       if (_sram_proc_read(buf, &len, count, "L2", &free_l2_sram_head,
-               &used_l2_sram_head))
+       if (_sram_proc_show(m, "L2", &free_l2_sram_head, &used_l2_sram_head))
                goto not_done;
 #endif
-       *eof = 1;
  not_done:
-       return len;
+       return 0;
+}
+
+static int sram_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, sram_proc_show, NULL);
 }
 
+static const struct file_operations sram_proc_ops = {
+       .open           = sram_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
 static int __init sram_proc_init(void)
 {
        struct proc_dir_entry *ptr;
-       ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
+
+       ptr = proc_create("sram", S_IRUGO, NULL, &sram_proc_ops);
        if (!ptr) {
                printk(KERN_WARNING "unable to create /proc/sram\n");
                return -1;
        }
-       ptr->read_proc = sram_proc_read;
        return 0;
 }
 late_initcall(sram_proc_init);
index 68a1a5901ca5acd59dedeb64ec7f7f588c16070c..5ebe6e841820ec45a5a653d66993b7b2b5952bef 100644 (file)
@@ -266,11 +266,11 @@ static int irq_cpu(int irq)
 
 
        /* Let the interrupt stay if possible */
-       if (cpu_isset(cpu, irq_allocations[irq - FIRST_IRQ].mask))
+       if (cpumask_test_cpu(cpu, &irq_allocations[irq - FIRST_IRQ].mask))
                goto out;
 
        /* IRQ must be moved to another CPU. */
-       cpu = first_cpu(irq_allocations[irq - FIRST_IRQ].mask);
+       cpu = cpumask_first(&irq_allocations[irq - FIRST_IRQ].mask);
        irq_allocations[irq - FIRST_IRQ].cpu = cpu;
 out:
        spin_unlock_irqrestore(&irq_lock, flags);
index 66cc75657e2f3782e6431b249fdf6f9fe5dc30fb..a0843a71aaeed9eb47ed62b121f7e997bfc0c85d 100644 (file)
@@ -81,7 +81,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 
        /* Mark all possible CPUs as present */
        for (i = 0; i < max_cpus; i++)
-           cpu_set(i, phys_cpu_present_map);
+               cpumask_set_cpu(i, &phys_cpu_present_map);
 }
 
 void __devinit smp_prepare_boot_cpu(void)
@@ -98,7 +98,7 @@ void __devinit smp_prepare_boot_cpu(void)
        SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
 
        set_cpu_online(0, true);
-       cpu_set(0, phys_cpu_present_map);
+       cpumask_set_cpu(0, &phys_cpu_present_map);
        set_cpu_possible(0, true);
 }
 
@@ -112,8 +112,9 @@ smp_boot_one_cpu(int cpuid)
 {
        unsigned timeout;
        struct task_struct *idle;
-       cpumask_t cpu_mask = CPU_MASK_NONE;
+       cpumask_t cpu_mask;
 
+       cpumask_clear(&cpu_mask);
        idle = fork_idle(cpuid);
        if (IS_ERR(idle))
                panic("SMP: fork failed for CPU:%d", cpuid);
@@ -125,10 +126,10 @@ smp_boot_one_cpu(int cpuid)
        cpu_now_booting = cpuid;
 
        /* Kick it */
-       cpu_set(cpuid, cpu_online_map);
-       cpu_set(cpuid, cpu_mask);
+       set_cpu_online(cpuid, true);
+       cpumask_set_cpu(cpuid, &cpu_mask);
        send_ipi(IPI_BOOT, 0, cpu_mask);
-       cpu_clear(cpuid, cpu_online_map);
+       set_cpu_online(cpuid, false);
 
        /* Wait for CPU to come online */
        for (timeout = 0; timeout < 10000; timeout++) {
@@ -176,7 +177,7 @@ void __init smp_callin(void)
        notify_cpu_starting(cpu);
        local_irq_enable();
 
-       cpu_set(cpu, cpu_online_map);
+       set_cpu_online(cpu, true);
        cpu_idle();
 }
 
@@ -214,8 +215,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
 
 void smp_send_reschedule(int cpu)
 {
-       cpumask_t cpu_mask = CPU_MASK_NONE;
-       cpu_set(cpu, cpu_mask);
+       cpumask_t cpu_mask;
+       cpumask_clear(&cpu_mask);
+       cpumask_set_cpu(cpu, &cpu_mask);
        send_ipi(IPI_SCHEDULE, 0, cpu_mask);
 }
 
@@ -232,7 +234,7 @@ void flush_tlb_common(struct mm_struct* mm, struct vm_area_struct* vma, unsigned
 
        spin_lock_irqsave(&tlbstate_lock, flags);
        cpu_mask = (mm == FLUSH_ALL ? cpu_all_mask : *mm_cpumask(mm));
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
        flush_mm = mm;
        flush_vma = vma;
        flush_addr = addr;
@@ -277,10 +279,10 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
        int ret = 0;
 
        /* Calculate CPUs to send to. */
-       cpus_and(cpu_mask, cpu_mask, cpu_online_map);
+       cpumask_and(&cpu_mask, &cpu_mask, cpu_online_mask);
 
        /* Send the IPI. */
-       for_each_cpu_mask(i, cpu_mask)
+       for_each_cpu(i, &cpu_mask)
        {
                ipi.vector |= vector;
                REG_WR(intr_vect, irq_regs[i], rw_ipi, ipi);
@@ -288,7 +290,7 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
 
        /* Wait for IPI to finish on other CPUS */
        if (wait) {
-               for_each_cpu_mask(i, cpu_mask) {
+               for_each_cpu(i, &cpu_mask) {
                         int j;
                         for (j = 0 ; j < 1000; j++) {
                                ipi = REG_RD(intr_vect, irq_regs[i], rw_ipi);
@@ -314,11 +316,12 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
  */
 int smp_call_function(void (*func)(void *info), void *info, int wait)
 {
-       cpumask_t cpu_mask = CPU_MASK_ALL;
+       cpumask_t cpu_mask;
        struct call_data_struct data;
        int ret;
 
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_setall(&cpu_mask);
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
 
        WARN_ON(irqs_disabled());
 
index df33ab89d70f0083c99380db30faaa8114d7512e..d72ab58fd83e743cdeba8cac08e02634cc8f552b 100644 (file)
@@ -13,8 +13,6 @@
 #include <linux/bootmem.h>
 #include <asm/tlb.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long empty_zero_page;
 
 extern char _stext, _edata, _etext; /* From linkerscript */
index ed64588ac3a76662935dc1fddd1b9e015ebaa475..fbe5f0dbae06eb588d3d6be5106e5ffeeaebdf9b 100644 (file)
@@ -41,8 +41,6 @@
 
 #undef DEBUG
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
index 23cce999eb1cadaef129afa9d342ca3bc87c2d54..c3ffe3e54edc1a0457359b2c198d555330d09bf7 100644 (file)
 #include <asm/machvec.h>
 
 #ifdef CONFIG_SMP
-# define FREE_PTE_NR           2048
 # define tlb_fast_mode(tlb)    ((tlb)->nr == ~0U)
 #else
-# define FREE_PTE_NR           0
 # define tlb_fast_mode(tlb)    (1)
 #endif
 
+/*
+ * If we can't allocate a page to make a big batch of page pointers
+ * to work on, then just handle a few from the on-stack structure.
+ */
+#define        IA64_GATHER_BUNDLE      8
+
 struct mmu_gather {
        struct mm_struct        *mm;
        unsigned int            nr;             /* == ~0U => fast mode */
+       unsigned int            max;
        unsigned char           fullmm;         /* non-zero means full mm flush */
        unsigned char           need_flush;     /* really unmapped some PTEs? */
        unsigned long           start_addr;
        unsigned long           end_addr;
-       struct page             *pages[FREE_PTE_NR];
+       struct page             **pages;
+       struct page             *local[IA64_GATHER_BUNDLE];
 };
 
 struct ia64_tr_entry {
@@ -90,9 +96,6 @@ extern struct ia64_tr_entry *ia64_idtrs[NR_CPUS];
 #define RR_RID_MASK    0x00000000ffffff00L
 #define RR_TO_RID(val)         ((val >> 8) & 0xffffff)
 
-/* Users of the generic TLB shootdown code must declare this storage space. */
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * Flush the TLB for address range START to END and, if not in fast mode, release the
  * freed pages that where gathered up to this point.
@@ -147,15 +150,23 @@ ia64_tlb_flush_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long e
        }
 }
 
-/*
- * Return a pointer to an initialized struct mmu_gather.
- */
-static inline struct mmu_gather *
-tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void __tlb_alloc_page(struct mmu_gather *tlb)
 {
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+       unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
 
+       if (addr) {
+               tlb->pages = (void *)addr;
+               tlb->max = PAGE_SIZE / sizeof(void *);
+       }
+}
+
+
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
+{
        tlb->mm = mm;
+       tlb->max = ARRAY_SIZE(tlb->local);
+       tlb->pages = tlb->local;
        /*
         * Use fast mode if only 1 CPU is online.
         *
@@ -172,7 +183,6 @@ tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
        tlb->nr = (num_online_cpus() == 1) ? ~0U : 0;
        tlb->fullmm = full_mm_flush;
        tlb->start_addr = ~0UL;
-       return tlb;
 }
 
 /*
@@ -180,7 +190,7 @@ tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
  * collected.
  */
 static inline void
-tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
+tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 {
        /*
         * Note: tlb->nr may be 0 at this point, so we can't rely on tlb->start_addr and
@@ -191,7 +201,8 @@ tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
        /* keep the page table cache within bounds */
        check_pgt_cache();
 
-       put_cpu_var(mmu_gathers);
+       if (tlb->pages != tlb->local)
+               free_pages((unsigned long)tlb->pages, 0);
 }
 
 /*
@@ -199,18 +210,33 @@ tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
  * must be delayed until after the TLB has been flushed (see comments at the beginning of
  * this file).
  */
-static inline void
-tlb_remove_page (struct mmu_gather *tlb, struct page *page)
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        tlb->need_flush = 1;
 
        if (tlb_fast_mode(tlb)) {
                free_page_and_swap_cache(page);
-               return;
+               return 1; /* avoid calling tlb_flush_mmu */
        }
+
+       if (!tlb->nr && tlb->pages == tlb->local)
+               __tlb_alloc_page(tlb);
+
        tlb->pages[tlb->nr++] = page;
-       if (tlb->nr >= FREE_PTE_NR)
-               ia64_tlb_flush_mmu(tlb, tlb->start_addr, tlb->end_addr);
+       VM_BUG_ON(tlb->nr > tlb->max);
+
+       return tlb->max - tlb->nr;
+}
+
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+       ia64_tlb_flush_mmu(tlb, tlb->start_addr, tlb->end_addr);
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       if (!__tlb_remove_page(tlb, page))
+               tlb_flush_mmu(tlb);
 }
 
 /*
index 9a018cde5d84d5c3718c3fef41d6557aa392d14b..f114a3b14c6ad73c7fa6afbe950375f46d98b876 100644 (file)
@@ -44,13 +44,16 @@ void show_mem(unsigned int filter)
        pg_data_t *pgdat;
 
        printk(KERN_INFO "Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
        printk(KERN_INFO "Node memory in pages:\n");
        for_each_online_pgdat(pgdat) {
                unsigned long present;
                unsigned long flags;
                int shared = 0, cached = 0, reserved = 0;
+               int nid = pgdat->node_id;
 
+               if (skip_free_areas_node(filter, nid))
+                       continue;
                pgdat_resize_lock(pgdat, &flags);
                present = pgdat->node_present_pages;
                for(i = 0; i < pgdat->node_spanned_pages; i++) {
@@ -64,8 +67,7 @@ void show_mem(unsigned int filter)
                                if (max_gap < LARGE_GAP)
                                        continue;
 #endif
-                               i = vmemmap_find_next_valid_pfn(pgdat->node_id,
-                                        i) - 1;
+                               i = vmemmap_find_next_valid_pfn(nid, i) - 1;
                                continue;
                        }
                        if (PageReserved(page))
@@ -81,7 +83,7 @@ void show_mem(unsigned int filter)
                total_cached += cached;
                total_shared += shared;
                printk(KERN_INFO "Node %4d:  RAM: %11ld, rsvd: %8d, "
-                      "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+                      "shrd: %10d, swpd: %10d\n", nid,
                       present, reserved, shared, cached);
        }
        printk(KERN_INFO "%ld pages of RAM\n", total_present);
index 82ab1bc6afb1236460c0e380a2a5fbf61a5b8e1b..c641333cd997635f1c885d12d895459111168e4a 100644 (file)
@@ -622,13 +622,16 @@ void show_mem(unsigned int filter)
        pg_data_t *pgdat;
 
        printk(KERN_INFO "Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
        printk(KERN_INFO "Node memory in pages:\n");
        for_each_online_pgdat(pgdat) {
                unsigned long present;
                unsigned long flags;
                int shared = 0, cached = 0, reserved = 0;
+               int nid = pgdat->node_id;
 
+               if (skip_free_areas_node(filter, nid))
+                       continue;
                pgdat_resize_lock(pgdat, &flags);
                present = pgdat->node_present_pages;
                for(i = 0; i < pgdat->node_spanned_pages; i++) {
@@ -638,8 +641,7 @@ void show_mem(unsigned int filter)
                        if (pfn_valid(pgdat->node_start_pfn + i))
                                page = pfn_to_page(pgdat->node_start_pfn + i);
                        else {
-                               i = vmemmap_find_next_valid_pfn(pgdat->node_id,
-                                        i) - 1;
+                               i = vmemmap_find_next_valid_pfn(nid, i) - 1;
                                continue;
                        }
                        if (PageReserved(page))
@@ -655,7 +657,7 @@ void show_mem(unsigned int filter)
                total_cached += cached;
                total_shared += shared;
                printk(KERN_INFO "Node %4d:  RAM: %11ld, rsvd: %8d, "
-                      "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+                      "shrd: %10d, swpd: %10d\n", nid,
                       present, reserved, shared, cached);
        }
        printk(KERN_INFO "%ld pages of RAM\n", total_present);
index ed41759efcac3b76e44d9a6b87c0c379448b4c5c..00cb0e26c64e02cd9663c381fa359e22f6c8104a 100644 (file)
@@ -36,8 +36,6 @@
 #include <asm/mca.h>
 #include <asm/paravirt.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 extern void ia64_tlb_init (void);
 
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
index 2e1019ddbb2233667604f312b0597a32a1206a4d..bb1afc1a31ccb8de1f748949b79c1d6c962a5c35 100644 (file)
@@ -9,15 +9,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config DEBUG_PAGEALLOC
        bool "Debug page memory allocations"
        depends on DEBUG_KERNEL && BROKEN
index e67ded1aab9100df5d478573945166b70a7b4105..8accc1bb026323552b534b70c51e28fb82cd19e9 100644 (file)
@@ -94,8 +94,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
 #define NO_PROC_ID (0xff)      /* No processor magic marker */
 
-#define PROC_CHANGE_PENALTY    (15)    /* Schedule penalty */
-
 /*
  * M32R-mp IPI
  */
index 5d2858f6eede4283bbb7c61717d021e3cf60797c..2c468e8b5853203099f2125c081d81fd9b6b665e 100644 (file)
@@ -149,6 +149,7 @@ unsigned long __init zone_sizes_init(void)
                zholes_size[ZONE_DMA] = mp->holes;
                holes += zholes_size[ZONE_DMA];
 
+               node_set_state(nid, N_NORMAL_MEMORY);
                free_area_init_node(nid, zones_size, start_pfn, zholes_size);
        }
 
index 73e2205ebf5afba2c17ca848701c0ae026f52fab..78b660e903da0d38ffba80724271b56dc9f1e3f7 100644 (file)
@@ -35,8 +35,6 @@ extern char __init_begin, __init_end;
 
 pgd_t swapper_pg_dir[1024];
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * Cache of MMU context last used.
  */
index 8bc842554e5b4618ad3e77208dc5872cd184fef2..9113c2f1760735f8134aee0ab0e6ff7a8aea9b7a 100644 (file)
@@ -32,8 +32,6 @@
 #include <asm/sections.h>
 #include <asm/tlb.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 pg_data_t pg_data_map[MAX_NUMNODES];
 EXPORT_SYMBOL(pg_data_map);
 
index c8437866d3b75f3bde5d7c5fad00f9d624e9d58e..213f2d67166960de3a966e7443136c0b934faaa6 100644 (file)
@@ -32,8 +32,6 @@ unsigned int __page_offset;
 EXPORT_SYMBOL(__page_offset);
 
 #else
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 static int init_bootmem_done;
 #endif /* CONFIG_MMU */
 
index 5358f90b4dd2ccee0c6767a01ebbc4f238f77976..83ed00a5644ac1b72286adbf81a95b40219462ba 100644 (file)
@@ -76,15 +76,6 @@ config DEBUG_STACKOVERFLOW
          provides another way to check stack overflow happened on kernel mode
          stack usually caused by nested interruption.
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config SMTC_IDLE_HOOK_DEBUG
        bool "Enable additional debug checks before going into CPU idle loop"
        depends on DEBUG_KERNEL && MIPS_MT_SMTC
index 279599e9a779fa80fe4e237d353aa5fe916dedab..1aadeb42c5a59ebd3f696478f29252e77adeea42 100644 (file)
@@ -64,8 +64,6 @@
 
 #endif /* CONFIG_MIPS_MT_SMTC */
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * We have up to 8 empty zeroed pages so we can map one of the right colour
  * when needed.  This is necessary only on R4000 / R4400 SC and MC versions
index 86af0d7d07719aab1c3435b71adb44ded4fee730..2623d19f4f4c5bfebfa79f0cc6c3be60b1352081 100644 (file)
@@ -87,7 +87,7 @@ static void mn10300_cpupic_mask_ack(struct irq_data *d)
                tmp2 = GxICR(irq);
 
                irq_affinity_online[irq] =
-                       any_online_cpu(*d->affinity);
+                       cpumask_any_and(d->affinity, cpu_online_mask);
                CROSS_GxICR(irq, irq_affinity_online[irq]) =
                        (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT;
                tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
@@ -124,7 +124,8 @@ static void mn10300_cpupic_unmask_clear(struct irq_data *d)
        } else {
                tmp = GxICR(irq);
 
-               irq_affinity_online[irq] = any_online_cpu(*d->affinity);
+               irq_affinity_online[irq] = cpumask_any_and(d->affinity,
+                                                          cpu_online_mask);
                CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
                tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
        }
@@ -366,11 +367,11 @@ void migrate_irqs(void)
                if (irqd_is_per_cpu(data))
                        continue;
 
-               if (cpu_isset(self, data->affinity) &&
-                   !cpus_intersects(irq_affinity[irq], cpu_online_map)) {
+               if (cpumask_test_cpu(self, &data->affinity) &&
+                   !cpumask_intersects(&irq_affinity[irq], cpu_online_mask)) {
                        int cpu_id;
-                       cpu_id = first_cpu(cpu_online_map);
-                       cpu_set(cpu_id, data->affinity);
+                       cpu_id = cpumask_first(cpu_online_mask);
+                       cpumask_set_cpu(cpu_id, &data->affinity);
                }
                /* We need to operate irq_affinity_online atomically. */
                arch_local_cli_save(flags);
@@ -381,7 +382,8 @@ void migrate_irqs(void)
                        GxICR(irq) = x & GxICR_LEVEL;
                        tmp = GxICR(irq);
 
-                       new = any_online_cpu(data->affinity);
+                       new = cpumask_any_and(&data->affinity,
+                                             cpu_online_mask);
                        irq_affinity_online[irq] = new;
 
                        CROSS_GxICR(irq, new) =
index 83fb2791223134aece3c8d29587dc810aed87d31..9242e9fcc56487d41a4c37c2019d7a4ed2614eec 100644 (file)
@@ -309,7 +309,7 @@ static void send_IPI_mask(const cpumask_t *cpumask, int irq)
        u16 tmp;
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (cpu_isset(i, *cpumask)) {
+               if (cpumask_test_cpu(i, cpumask)) {
                        /* send IPI */
                        tmp = CROSS_GxICR(irq, i);
                        CROSS_GxICR(irq, i) =
@@ -342,8 +342,8 @@ void send_IPI_allbutself(int irq)
 {
        cpumask_t cpumask;
 
-       cpumask = cpu_online_map;
-       cpu_clear(smp_processor_id(), cpumask);
+       cpumask_copy(&cpumask, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &cpumask);
        send_IPI_mask(&cpumask, irq);
 }
 
@@ -393,8 +393,8 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
 
        data.func = func;
        data.info = info;
-       data.started = cpu_online_map;
-       cpu_clear(smp_processor_id(), data.started);
+       cpumask_copy(&data.started, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &data.started);
        data.wait = wait;
        if (wait)
                data.finished = data.started;
@@ -410,14 +410,14 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
        if (CALL_FUNCTION_NMI_IPI_TIMEOUT > 0) {
                for (cnt = 0;
                     cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
-                            !cpus_empty(data.started);
+                            !cpumask_empty(&data.started);
                     cnt++)
                        mdelay(1);
 
                if (wait && cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT) {
                        for (cnt = 0;
                             cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
-                                    !cpus_empty(data.finished);
+                                    !cpumask_empty(&data.finished);
                             cnt++)
                                mdelay(1);
                }
@@ -428,10 +428,10 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
        } else {
                /* If timeout value is zero, wait until cpumask has been
                 * cleared */
-               while (!cpus_empty(data.started))
+               while (!cpumask_empty(&data.started))
                        barrier();
                if (wait)
-                       while (!cpus_empty(data.finished))
+                       while (!cpumask_empty(&data.finished))
                                barrier();
        }
 
@@ -472,12 +472,12 @@ void stop_this_cpu(void *unused)
 #endif /* CONFIG_GDBSTUB */
 
        flags = arch_local_cli_save();
-       cpu_clear(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), false);
 
        while (!stopflag)
                cpu_relax();
 
-       cpu_set(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), true);
        arch_local_irq_restore(flags);
 }
 
@@ -529,12 +529,13 @@ void smp_nmi_call_function_interrupt(void)
         * execute the function
         */
        smp_mb();
-       cpu_clear(smp_processor_id(), nmi_call_data->started);
+       cpumask_clear_cpu(smp_processor_id(), &nmi_call_data->started);
        (*func)(info);
 
        if (wait) {
                smp_mb();
-               cpu_clear(smp_processor_id(), nmi_call_data->finished);
+               cpumask_clear_cpu(smp_processor_id(),
+                                 &nmi_call_data->finished);
        }
 }
 
@@ -657,7 +658,7 @@ int __init start_secondary(void *unused)
 {
        smp_cpu_init();
        smp_callin();
-       while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
+       while (!cpumask_test_cpu(smp_processor_id(), &smp_commenced_mask))
                cpu_relax();
 
        local_flush_tlb();
@@ -780,13 +781,14 @@ static int __init do_boot_cpu(int phy_id)
 
        if (send_status == 0) {
                /* Allow AP to start initializing */
-               cpu_set(cpu_id, cpu_callout_map);
+               cpumask_set_cpu(cpu_id, &cpu_callout_map);
 
                /* Wait for setting cpu_callin_map */
                timeout = 0;
                do {
                        udelay(1000);
-                       callin_status = cpu_isset(cpu_id, cpu_callin_map);
+                       callin_status = cpumask_test_cpu(cpu_id,
+                                                        &cpu_callin_map);
                } while (callin_status == 0 && timeout++ < 5000);
 
                if (callin_status == 0)
@@ -796,9 +798,9 @@ static int __init do_boot_cpu(int phy_id)
        }
 
        if (send_status == GxICR_REQUEST || callin_status == 0) {
-               cpu_clear(cpu_id, cpu_callout_map);
-               cpu_clear(cpu_id, cpu_callin_map);
-               cpu_clear(cpu_id, cpu_initialized);
+               cpumask_clear_cpu(cpu_id, &cpu_callout_map);
+               cpumask_clear_cpu(cpu_id, &cpu_callin_map);
+               cpumask_clear_cpu(cpu_id, &cpu_initialized);
                cpucount--;
                return 1;
        }
@@ -833,7 +835,7 @@ static void __init smp_callin(void)
        cpu = smp_processor_id();
        timeout = jiffies + (2 * HZ);
 
-       if (cpu_isset(cpu, cpu_callin_map)) {
+       if (cpumask_test_cpu(cpu, &cpu_callin_map)) {
                printk(KERN_ERR "CPU#%d already present.\n", cpu);
                BUG();
        }
@@ -841,7 +843,7 @@ static void __init smp_callin(void)
 
        /* Wait for AP startup 2s total */
        while (time_before(jiffies, timeout)) {
-               if (cpu_isset(cpu, cpu_callout_map))
+               if (cpumask_test_cpu(cpu, &cpu_callout_map))
                        break;
                cpu_relax();
        }
@@ -861,11 +863,11 @@ static void __init smp_callin(void)
        smp_store_cpu_info(cpu);
 
        /* Allow the boot processor to continue */
-       cpu_set(cpu, cpu_callin_map);
+       cpumask_set_cpu(cpu, &cpu_callin_map);
 }
 
 /**
- * smp_online - Set cpu_online_map
+ * smp_online - Set cpu_online_mask
  */
 static void __init smp_online(void)
 {
@@ -875,7 +877,7 @@ static void __init smp_online(void)
 
        local_irq_enable();
 
-       cpu_set(cpu, cpu_online_map);
+       set_cpu_online(cpu, true);
        smp_wmb();
 }
 
@@ -892,13 +894,13 @@ void __init smp_cpus_done(unsigned int max_cpus)
 /*
  * smp_prepare_boot_cpu - Set up stuff for the boot processor.
  *
- * Set up the cpu_online_map, cpu_callout_map and cpu_callin_map of the boot
+ * Set up the cpu_online_mask, cpu_callout_map and cpu_callin_map of the boot
  * processor (CPU 0).
  */
 void __devinit smp_prepare_boot_cpu(void)
 {
-       cpu_set(0, cpu_callout_map);
-       cpu_set(0, cpu_callin_map);
+       cpumask_set_cpu(0, &cpu_callout_map);
+       cpumask_set_cpu(0, &cpu_callin_map);
        current_thread_info()->cpu = 0;
 }
 
@@ -931,16 +933,16 @@ int __devinit __cpu_up(unsigned int cpu)
                run_wakeup_cpu(cpu);
 #endif /* CONFIG_HOTPLUG_CPU */
 
-       cpu_set(cpu, smp_commenced_mask);
+       cpumask_set_cpu(cpu, &smp_commenced_mask);
 
        /* Wait 5s total for a response */
        for (timeout = 0 ; timeout < 5000 ; timeout++) {
-               if (cpu_isset(cpu, cpu_online_map))
+               if (cpu_online(cpu))
                        break;
                udelay(1000);
        }
 
-       BUG_ON(!cpu_isset(cpu, cpu_online_map));
+       BUG_ON(!cpu_online(cpu));
        return 0;
 }
 
@@ -986,7 +988,7 @@ int __cpu_disable(void)
                return -EBUSY;
 
        migrate_irqs();
-       cpu_clear(cpu, current->active_mm->cpu_vm_mask);
+       cpumask_clear_cpu(cpu, &mm_cpumask(current->active_mm));
        return 0;
 }
 
@@ -1091,13 +1093,13 @@ static int hotplug_cpu_nmi_call_function(cpumask_t cpumask,
        do {
                mn10300_local_dcache_inv_range(start, end);
                barrier();
-       } while (!cpus_empty(nmi_call_func_mask_data.started));
+       } while (!cpumask_empty(&nmi_call_func_mask_data.started));
 
        if (wait) {
                do {
                        mn10300_local_dcache_inv_range(start, end);
                        barrier();
-               } while (!cpus_empty(nmi_call_func_mask_data.finished));
+               } while (!cpumask_empty(&nmi_call_func_mask_data.finished));
        }
 
        spin_unlock(&smp_nmi_call_lock);
@@ -1108,9 +1110,9 @@ static void restart_wakeup_cpu(void)
 {
        unsigned int cpu = smp_processor_id();
 
-       cpu_set(cpu, cpu_callin_map);
+       cpumask_set_cpu(cpu, &cpu_callin_map);
        local_flush_tlb();
-       cpu_set(cpu, cpu_online_map);
+       set_cpu_online(cpu, true);
        smp_wmb();
 }
 
@@ -1141,8 +1143,9 @@ static void sleep_cpu(void *unused)
 static void run_sleep_cpu(unsigned int cpu)
 {
        unsigned long flags;
-       cpumask_t cpumask = cpumask_of(cpu);
+       cpumask_t cpumask;
 
+       cpumask_copy(&cpumask, &cpumask_of(cpu));
        flags = arch_local_cli_save();
        hotplug_cpu_nmi_call_function(cpumask, prepare_sleep_cpu, NULL, 1);
        hotplug_cpu_nmi_call_function(cpumask, sleep_cpu, NULL, 0);
index 4a6e9a4b5b27d866048d99270ed6a030f8d4dd57..2d23b9eeee62eef7d1164c54b17a2f3c463c6b9e 100644 (file)
@@ -74,7 +74,7 @@ void smp_cache_interrupt(void)
                break;
        }
 
-       cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+       cpumask_clear_cpu(smp_processor_id(), &smp_cache_ipi_map);
 }
 
 /**
@@ -94,12 +94,12 @@ void smp_cache_call(unsigned long opr_mask,
        smp_cache_mask = opr_mask;
        smp_cache_start = start;
        smp_cache_end = end;
-       smp_cache_ipi_map = cpu_online_map;
-       cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+       cpumask_copy(&smp_cache_ipi_map, cpu_online_mask);
+       cpumask_clear_cpu(smp_processor_id(), &smp_cache_ipi_map);
 
        send_IPI_allbutself(FLUSH_CACHE_IPI);
 
-       while (!cpus_empty(smp_cache_ipi_map))
+       while (!cpumask_empty(&smp_cache_ipi_map))
                /* nothing. lockup detection does not belong here */
                mb();
 }
index 48907cc3bdb77311526c1b1ca173b20983091f8d..13801824e3ee298afda7db2ee5d0613266ed6ccd 100644 (file)
@@ -37,8 +37,6 @@
 #include <asm/tlb.h>
 #include <asm/sections.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long highstart_pfn, highend_pfn;
 
 #ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
index 0b6a5ad1960e6dad2e665a489b7bccf2d61f9034..9a777498a916a3c8042dee0a3abf9ba960a122ba 100644 (file)
@@ -64,7 +64,7 @@ void smp_flush_tlb(void *unused)
 
        cpu_id = get_cpu();
 
-       if (!cpu_isset(cpu_id, flush_cpumask))
+       if (!cpumask_test_cpu(cpu_id, &flush_cpumask))
                /* This was a BUG() but until someone can quote me the line
                 * from the intel manual that guarantees an IPI to multiple
                 * CPUs is retried _only_ on the erroring CPUs its staying as a
@@ -80,7 +80,7 @@ void smp_flush_tlb(void *unused)
                local_flush_tlb_page(flush_mm, flush_va);
 
        smp_mb__before_clear_bit();
-       cpu_clear(cpu_id, flush_cpumask);
+       cpumask_clear_cpu(cpu_id, &flush_cpumask);
        smp_mb__after_clear_bit();
 out:
        put_cpu();
@@ -103,11 +103,11 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
         * - we do not send IPIs to as-yet unbooted CPUs.
         */
        BUG_ON(!mm);
-       BUG_ON(cpus_empty(cpumask));
-       BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+       BUG_ON(cpumask_empty(&cpumask));
+       BUG_ON(cpumask_test_cpu(smp_processor_id(), &cpumask));
 
-       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));
 
        /* I'm not happy about this global shared spinlock in the MM hot path,
         * but we'll see how contended it is.
@@ -128,7 +128,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
        /* FIXME: if NR_CPUS>=3, change send_IPI_mask */
        smp_call_function(smp_flush_tlb, NULL, 1);
 
-       while (!cpus_empty(flush_cpumask))
+       while (!cpumask_empty(&flush_cpumask))
                /* Lockup detection does not belong here */
                smp_mb();
 
@@ -146,11 +146,11 @@ void flush_tlb_mm(struct mm_struct *mm)
        cpumask_t cpu_mask;
 
        preempt_disable();
-       cpu_mask = mm->cpu_vm_mask;
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_copy(&cpu_mask, mm_cpumask(mm));
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
 
        local_flush_tlb();
-       if (!cpus_empty(cpu_mask))
+       if (!cpumask_empty(&cpu_mask))
                flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
 
        preempt_enable();
@@ -165,11 +165,11 @@ void flush_tlb_current_task(void)
        cpumask_t cpu_mask;
 
        preempt_disable();
-       cpu_mask = mm->cpu_vm_mask;
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_copy(&cpu_mask, mm_cpumask(mm));
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
 
        local_flush_tlb();
-       if (!cpus_empty(cpu_mask))
+       if (!cpumask_empty(&cpu_mask))
                flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
 
        preempt_enable();
@@ -186,11 +186,11 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
        cpumask_t cpu_mask;
 
        preempt_disable();
-       cpu_mask = mm->cpu_vm_mask;
-       cpu_clear(smp_processor_id(), cpu_mask);
+       cpumask_copy(&cpu_mask, mm_cpumask(mm));
+       cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
 
        local_flush_tlb_page(mm, va);
-       if (!cpus_empty(cpu_mask))
+       if (!cpumask_empty(&cpu_mask))
                flush_tlb_others(cpu_mask, mm, va);
 
        preempt_enable();
index 2e73623feb6ba28d4590eafc02b573f8acb7c2c4..e8f8037d872bc91c794f50ba5fd7a0f8eb996232 100644 (file)
@@ -33,15 +33,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
 #endif /* !ASSEMBLY */
 
-/*
- *     This magic constant controls our willingness to transfer
- *      a process across CPUs. Such a transfer incurs cache and tlb
- *      misses. The current value is inherited from i386. Still needs
- *      to be tuned for parisc.
- */
-#define PROC_CHANGE_PENALTY    15              /* Schedule penalty */
-
 #define raw_smp_processor_id() (current_thread_info()->cpu)
 
 #else /* CONFIG_SMP */
index 5fa1e273006e2a673ed62aecdb62127a7a5e1a6b..82f364e209fc5a059f1be77fd5563e7c4a70c122 100644 (file)
@@ -31,8 +31,6 @@
 #include <asm/mmzone.h>
 #include <asm/sections.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 extern int  data_start;
 
 #ifdef CONFIG_DISCONTIGMEM
@@ -686,7 +684,7 @@ void show_mem(unsigned int filter)
        int shared = 0, cached = 0;
 
        printk(KERN_INFO "Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
 #ifndef CONFIG_DISCONTIGMEM
        i = max_mapnr;
        while (i-- > 0) {
index a3128ca0fe11c18edec56c175eaf39656ff4ebc8..423145a6f7ba09da24f8058fe32af6d869a636f7 100644 (file)
@@ -140,6 +140,7 @@ config PPC
        select IRQ_PER_CPU
        select GENERIC_IRQ_SHOW
        select GENERIC_IRQ_SHOW_LEVEL
+       select HAVE_RCU_TABLE_FREE if SMP
 
 config EARLY_PRINTK
        bool
index a597dd77b9035ba9b2eda6766b98b47a0e9770f4..e72dcf6a421d8581cc0e3b7fd231b2b3ebcf644c 100644 (file)
@@ -35,27 +35,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
-config DEBUG_PER_CPU_MAPS
-       bool "Debug access to per_cpu maps"
-       depends on DEBUG_KERNEL
-       depends on SMP
-       default n
-       ---help---
-         Say Y to verify that the per_cpu map being accessed has
-         been setup.  Adds a fair amount of code to kernel memory
-         and decreases performance.
-
-         Say N if unsure.
-
 config HCALL_STATS
        bool "Hypervisor call instrumentation"
        depends on PPC_PSERIES && DEBUG_FS && TRACEPOINTS
index 761faa7b6964e3dd6601e2acca95796f84fcfe44..ac1eb320c7b4a9925d5071584333ac35c97ea679 100644 (file)
                        sleep = <&pmc 0x00300000>;
                };
 
+               ptp_clock@24E00 {
+                       compatible = "fsl,etsec-ptp";
+                       reg = <0x24E00 0xB0>;
+                       interrupts = <12 0x8 13 0x8>;
+                       interrupt-parent = < &ipic >;
+                       fsl,tclk-period = <10>;
+                       fsl,tmr-prsc    = <100>;
+                       fsl,tmr-add     = <0x999999A4>;
+                       fsl,tmr-fiper1  = <0x3B9AC9F6>;
+                       fsl,tmr-fiper2  = <0x00018696>;
+                       fsl,max-adj     = <659999998>;
+               };
+
                enet0: ethernet@24000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
index cafc1285c140778990d04e3096f81bcc032f0ffd..f6c04d25e91681c06628ecc5eda09afd153ab81d 100644 (file)
                        };
                };
 
+               ptp_clock@24E00 {
+                       compatible = "fsl,etsec-ptp";
+                       reg = <0x24E00 0xB0>;
+                       interrupts = <68 2 69 2 70 2 71 2>;
+                       interrupt-parent = < &mpic >;
+                       fsl,tclk-period = <5>;
+                       fsl,tmr-prsc = <200>;
+                       fsl,tmr-add = <0xAAAAAAAB>;
+                       fsl,tmr-fiper1 = <0x3B9AC9FB>;
+                       fsl,tmr-fiper2 = <0x3B9AC9FB>;
+                       fsl,max-adj = <499999999>;
+               };
+
                enet0: ethernet@24000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
index 2bcf3683d223510ef2b7988c494af466c5dc8297..dae403100f2f8f798c2e81f02e4355d494efe57c 100644 (file)
 
                };
 
+               ptp_clock@24E00 {
+                       compatible = "fsl,etsec-ptp";
+                       reg = <0x24E00 0xB0>;
+                       interrupts = <68 2 69 2 70 2>;
+                       interrupt-parent = < &mpic >;
+                       fsl,tclk-period = <5>;
+                       fsl,tmr-prsc = <200>;
+                       fsl,tmr-add = <0xCCCCCCCD>;
+                       fsl,tmr-fiper1 = <0x3B9AC9FB>;
+                       fsl,tmr-fiper2 = <0x0001869B>;
+                       fsl,max-adj = <249999999>;
+               };
+
                enet0: ethernet@24000 {
                        tbi-handle = <&tbi0>;
                        phy-handle = <&phy0>;
index 3782a58f13beab7ac6adc4c0f80c0f844e8d4060..1d7a05f3021e058bd59eabb6fd049446accf7073 100644 (file)
                        status = "disabled";
                };
 
+               ptp_clock@24E00 {
+                       compatible = "fsl,etsec-ptp";
+                       reg = <0x24E00 0xB0>;
+                       interrupts = <68 2 69 2 70 2>;
+                       interrupt-parent = < &mpic >;
+                       fsl,tclk-period = <5>;
+                       fsl,tmr-prsc = <200>;
+                       fsl,tmr-add = <0xCCCCCCCD>;
+                       fsl,tmr-fiper1 = <0x3B9AC9FB>;
+                       fsl,tmr-fiper2 = <0x0001869B>;
+                       fsl,max-adj = <249999999>;
+               };
+
                enet0: ethernet@24000 {
                        fixed-link = <1 1 1000 0 0>;
                        phy-connection-type = "rgmii-id";
index abe8532bd14e4dfc27693cfadce3d49a78380881..bf301ac62f35a0c1da1ed7b9cae0de43c95d0df0 100644 (file)
@@ -31,14 +31,29 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
 #endif
 
 #ifdef CONFIG_SMP
-extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift);
-extern void pte_free_finish(void);
+struct mmu_gather;
+extern void tlb_remove_table(struct mmu_gather *, void *);
+
+static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
+{
+       unsigned long pgf = (unsigned long)table;
+       BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
+       pgf |= shift;
+       tlb_remove_table(tlb, (void *)pgf);
+}
+
+static inline void __tlb_remove_table(void *_table)
+{
+       void *table = (void *)((unsigned long)_table & ~MAX_PGTABLE_INDEX_SIZE);
+       unsigned shift = (unsigned long)_table & MAX_PGTABLE_INDEX_SIZE;
+
+       pgtable_free(table, shift);
+}
 #else /* CONFIG_SMP */
 static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
 {
        pgtable_free(table, shift);
 }
-static inline void pte_free_finish(void) { }
 #endif /* !CONFIG_SMP */
 
 static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage,
index d8529ef13b2329352a6b85a92adb2574ed768607..37c353e8af7c783fba4b8510e259b714bcc05f55 100644 (file)
@@ -139,10 +139,12 @@ static inline struct thread_info *current_thread_info(void)
 #define TLF_NAPPING            0       /* idle thread enabled NAP mode */
 #define TLF_SLEEPING           1       /* suspend code enabled SLEEP mode */
 #define TLF_RESTORE_SIGMASK    2       /* Restore signal mask in do_signal */
+#define TLF_LAZY_MMU           3       /* tlb_batch is active */
 
 #define _TLF_NAPPING           (1 << TLF_NAPPING)
 #define _TLF_SLEEPING          (1 << TLF_SLEEPING)
 #define _TLF_RESTORE_SIGMASK   (1 << TLF_RESTORE_SIGMASK)
+#define _TLF_LAZY_MMU          (1 << TLF_LAZY_MMU)
 
 #ifndef __ASSEMBLY__
 #define HAVE_SET_RESTORE_SIGMASK       1
index 095043d79946cfbfd8c9f15e56584ef393192456..91e52df3d81d19ec7a22bba96fee3ea2d12b4002 100644 (file)
@@ -395,6 +395,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
        struct thread_struct *new_thread, *old_thread;
        unsigned long flags;
        struct task_struct *last;
+#ifdef CONFIG_PPC_BOOK3S_64
+       struct ppc64_tlb_batch *batch;
+#endif
 
 #ifdef CONFIG_SMP
        /* avoid complexity of lazy save/restore of fpu
@@ -513,7 +516,17 @@ struct task_struct *__switch_to(struct task_struct *prev,
                old_thread->accum_tb += (current_tb - start_tb);
                new_thread->start_tb = current_tb;
        }
-#endif
+#endif /* CONFIG_PPC64 */
+
+#ifdef CONFIG_PPC_BOOK3S_64
+       batch = &__get_cpu_var(ppc64_tlb_batch);
+       if (batch->active) {
+               current_thread_info()->local_flags |= _TLF_LAZY_MMU;
+               if (batch->index)
+                       __flush_tlb_pending(batch);
+               batch->active = 0;
+       }
+#endif /* CONFIG_PPC_BOOK3S_64 */
 
        local_irq_save(flags);
 
@@ -528,6 +541,14 @@ struct task_struct *__switch_to(struct task_struct *prev,
        hard_irq_disable();
        last = _switch(old_thread, new_thread);
 
+#ifdef CONFIG_PPC_BOOK3S_64
+       if (current_thread_info()->local_flags & _TLF_LAZY_MMU) {
+               current_thread_info()->local_flags &= ~_TLF_LAZY_MMU;
+               batch = &__get_cpu_var(ppc64_tlb_batch);
+               batch->active = 1;
+       }
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
        local_irq_restore(flags);
 
        return last;
index 6a3997f98dfb90a2f3d01da4b53156c2098a38f8..af40c8768a7824095878c475791053987ed57c4d 100644 (file)
 
 #include "mmu_decl.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;
-
-struct pte_freelist_batch
-{
-       struct rcu_head rcu;
-       unsigned int    index;
-       unsigned long   tables[0];
-};
-
-#define PTE_FREELIST_SIZE \
-       ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \
-         / sizeof(unsigned long))
-
-static void pte_free_smp_sync(void *arg)
-{
-       /* Do nothing, just ensure we sync with all CPUs */
-}
-
-/* This is only called when we are critically out of memory
- * (and fail to get a page in pte_free_tlb).
- */
-static void pgtable_free_now(void *table, unsigned shift)
-{
-       pte_freelist_forced_free++;
-
-       smp_call_function(pte_free_smp_sync, NULL, 1);
-
-       pgtable_free(table, shift);
-}
-
-static void pte_free_rcu_callback(struct rcu_head *head)
-{
-       struct pte_freelist_batch *batch =
-               container_of(head, struct pte_freelist_batch, rcu);
-       unsigned int i;
-
-       for (i = 0; i < batch->index; i++) {
-               void *table = (void *)(batch->tables[i] & ~MAX_PGTABLE_INDEX_SIZE);
-               unsigned shift = batch->tables[i] & MAX_PGTABLE_INDEX_SIZE;
-
-               pgtable_free(table, shift);
-       }
-
-       free_page((unsigned long)batch);
-}
-
-static void pte_free_submit(struct pte_freelist_batch *batch)
-{
-       call_rcu_sched(&batch->rcu, pte_free_rcu_callback);
-}
-
-void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
-{
-       /* This is safe since tlb_gather_mmu has disabled preemption */
-       struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
-       unsigned long pgf;
-
-       if (atomic_read(&tlb->mm->mm_users) < 2 ||
-           cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){
-               pgtable_free(table, shift);
-               return;
-       }
-
-       if (*batchp == NULL) {
-               *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
-               if (*batchp == NULL) {
-                       pgtable_free_now(table, shift);
-                       return;
-               }
-               (*batchp)->index = 0;
-       }
-       BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
-       pgf = (unsigned long)table | shift;
-       (*batchp)->tables[(*batchp)->index++] = pgf;
-       if ((*batchp)->index == PTE_FREELIST_SIZE) {
-               pte_free_submit(*batchp);
-               *batchp = NULL;
-       }
-}
-
-void pte_free_finish(void)
-{
-       /* This is safe since tlb_gather_mmu has disabled preemption */
-       struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
-
-       if (*batchp == NULL)
-               return;
-       pte_free_submit(*batchp);
-       *batchp = NULL;
-}
-
-#endif /* CONFIG_SMP */
-
 static inline int is_exec_fault(void)
 {
        return current->thread.regs && TRAP(current->thread.regs) == 0x400;
index 690566b66e8ea233cd0f40f4850d6ad8f1bc307d..27b863c14941a9406ced93e2f534825171d2bf85 100644 (file)
@@ -71,9 +71,6 @@ void tlb_flush(struct mmu_gather *tlb)
                 */
                _tlbia();
        }
-
-       /* Push out batch of freed page tables */
-       pte_free_finish();
 }
 
 /*
index c14d09f614f362ef67e04744bc5db8f62b8947cc..31f18207970ba6aa01d7370784bf2d810465f413 100644 (file)
@@ -155,7 +155,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
 
 void tlb_flush(struct mmu_gather *tlb)
 {
-       struct ppc64_tlb_batch *tlbbatch = &__get_cpu_var(ppc64_tlb_batch);
+       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
@@ -164,8 +164,7 @@ void tlb_flush(struct mmu_gather *tlb)
        if (tlbbatch->index)
                __flush_tlb_pending(tlbbatch);
 
-       /* Push out batch of freed page tables */
-       pte_free_finish();
+       put_cpu_var(ppc64_tlb_batch);
 }
 
 /**
index 2a030d89bbc6e65a847a29f6c4bf012f2e6188b0..0bdad3aecc670aa6379adc093cdb49054322a1a0 100644 (file)
@@ -299,9 +299,6 @@ 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();
 }
 
 /*
index 9074a54c4d10f843320ae85819895024dbf5d67f..77eee5477a52fa8ce8404d8c6fd8a4fdfdac51f5 100644 (file)
 #include <asm/smp.h>
 #include <asm/tlbflush.h>
 
-#ifndef CONFIG_SMP
-#define TLB_NR_PTRS    1
-#else
-#define TLB_NR_PTRS    508
-#endif
-
 struct mmu_gather {
        struct mm_struct *mm;
        unsigned int fullmm;
        unsigned int nr_ptes;
        unsigned int nr_pxds;
-       void *array[TLB_NR_PTRS];
+       unsigned int max;
+       void **array;
+       void *local[8];
 };
 
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
-static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm,
-                                               unsigned int full_mm_flush)
+static inline void __tlb_alloc_page(struct mmu_gather *tlb)
 {
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+       unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
 
+       if (addr) {
+               tlb->array = (void *) addr;
+               tlb->max = PAGE_SIZE / sizeof(void *);
+       }
+}
+
+static inline void tlb_gather_mmu(struct mmu_gather *tlb,
+                                 struct mm_struct *mm,
+                                 unsigned int full_mm_flush)
+{
        tlb->mm = mm;
+       tlb->max = ARRAY_SIZE(tlb->local);
+       tlb->array = tlb->local;
        tlb->fullmm = full_mm_flush;
-       tlb->nr_ptes = 0;
-       tlb->nr_pxds = TLB_NR_PTRS;
        if (tlb->fullmm)
                __tlb_flush_mm(mm);
-       return tlb;
+       else
+               __tlb_alloc_page(tlb);
+       tlb->nr_ptes = 0;
+       tlb->nr_pxds = tlb->max;
 }
 
-static inline void tlb_flush_mmu(struct mmu_gather *tlb,
-                                unsigned long start, unsigned long end)
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
 {
-       if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS))
+       if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < tlb->max))
                __tlb_flush_mm(tlb->mm);
        while (tlb->nr_ptes > 0)
                page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]);
-       while (tlb->nr_pxds < TLB_NR_PTRS)
+       while (tlb->nr_pxds < tlb->max)
                crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]);
 }
 
 static inline void tlb_finish_mmu(struct mmu_gather *tlb,
                                  unsigned long start, unsigned long end)
 {
-       tlb_flush_mmu(tlb, start, end);
+       tlb_flush_mmu(tlb);
 
        rcu_table_freelist_finish();
 
        /* keep the page table cache within bounds */
        check_pgt_cache();
 
-       put_cpu_var(mmu_gathers);
+       if (tlb->array != tlb->local)
+               free_pages((unsigned long) tlb->array, 0);
 }
 
 /*
  * Release the page cache reference for a pte removed by
- * tlb_ptep_clear_flush. In both flush modes the tlb fo a page cache page
+ * tlb_ptep_clear_flush. In both flush modes the tlb for a page cache page
  * has already been freed, so just do free_page_and_swap_cache.
  */
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       free_page_and_swap_cache(page);
+       return 1; /* avoid calling tlb_flush_mmu */
+}
+
 static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        free_page_and_swap_cache(page);
@@ -103,7 +115,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
        if (!tlb->fullmm) {
                tlb->array[tlb->nr_ptes++] = pte;
                if (tlb->nr_ptes >= tlb->nr_pxds)
-                       tlb_flush_mmu(tlb, 0, 0);
+                       tlb_flush_mmu(tlb);
        } else
                page_table_free(tlb->mm, (unsigned long *) pte);
 }
@@ -124,7 +136,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
        if (!tlb->fullmm) {
                tlb->array[--tlb->nr_pxds] = pmd;
                if (tlb->nr_ptes >= tlb->nr_pxds)
-                       tlb_flush_mmu(tlb, 0, 0);
+                       tlb_flush_mmu(tlb);
        } else
                crst_table_free(tlb->mm, (unsigned long *) pmd);
 #endif
@@ -146,7 +158,7 @@ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
        if (!tlb->fullmm) {
                tlb->array[--tlb->nr_pxds] = pud;
                if (tlb->nr_ptes >= tlb->nr_pxds)
-                       tlb_flush_mmu(tlb, 0, 0);
+                       tlb_flush_mmu(tlb);
        } else
                crst_table_free(tlb->mm, (unsigned long *) pud);
 #endif
index 8d4330642512554edffaccd51cd7954f18897e1d..14c6fae6fe6ba61e8ae0afbdfdd821464ae3a00b 100644 (file)
@@ -36,7 +36,6 @@ struct rcu_table_freelist {
        ((PAGE_SIZE - sizeof(struct rcu_table_freelist)) \
          / sizeof(unsigned long))
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist);
 
 static void __page_table_free(struct mm_struct *mm, unsigned long *table);
index 451ed54ce64609c0875a0d4db8503c2222ed7263..a1f346df0a710bd5441fbf6ceb46a8fe47927c2e 100644 (file)
@@ -16,15 +16,6 @@ config CMDLINE
          other cases you can specify kernel args so that you don't have
          to set them up in board prom initialization routines.
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config RUNTIME_DEBUG
        bool "Enable run-time debugging"
        depends on DEBUG_KERNEL
index 50fdec54c70a75c6aabd281263139f4dca54a6ef..cee6bce1e30c3663490e05d66725f89c907e62a9 100644 (file)
@@ -38,8 +38,6 @@
 #include <asm/sections.h>
 #include <asm/tlb.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long empty_zero_page;
 EXPORT_SYMBOL_GPL(empty_zero_page);
 
index 1553d56cf4e08f30e2454c4a20e85307059af331..c1d5a820b1aa3f64e72475203515b6a4303c1c0f 100644 (file)
@@ -28,15 +28,6 @@ config STACK_DEBUG
          every function call and will therefore incur a major
          performance hit. Most users should say N.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config 4KSTACKS
        bool "Use 4Kb for kernel stacks instead of 8Kb"
        depends on DEBUG_KERNEL && (MMU || BROKEN) && !PAGE_SIZE_64KB
index 75abb38dffd5d479e0b848615b7df115b72abad5..6c308d8b9a50a96335a170fb13aa8069f619782a 100644 (file)
@@ -23,8 +23,6 @@ struct mmu_gather {
        unsigned long           start, end;
 };
 
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 static inline void init_tlb_gather(struct mmu_gather *tlb)
 {
        tlb->start = TASK_SIZE;
@@ -36,17 +34,13 @@ static inline void init_tlb_gather(struct mmu_gather *tlb)
        }
 }
 
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
 {
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
        tlb->mm = mm;
        tlb->fullmm = full_mm_flush;
 
        init_tlb_gather(tlb);
-
-       return tlb;
 }
 
 static inline void
@@ -57,8 +51,6 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 
        /* keep the page table cache within bounds */
        check_pgt_cache();
-
-       put_cpu_var(mmu_gathers);
 }
 
 static inline void
@@ -91,7 +83,21 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
        }
 }
 
-#define tlb_remove_page(tlb,page)      free_page_and_swap_cache(page)
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+}
+
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       free_page_and_swap_cache(page);
+       return 1; /* avoid calling tlb_flush_mmu */
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       __tlb_remove_page(tlb, page);
+}
+
 #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)
index 0d3f912e3334b1ecd07e5ec7c34b9ee84326bb56..58a93fb3d965055739e8484f0a1045bf338e0194 100644 (file)
@@ -28,7 +28,6 @@
 #include <asm/cache.h>
 #include <asm/sizes.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 void __init generic_mem_init(void)
index d9a795efbc045ea548f1fc60adf1d59cbe1437c3..6db35fba79fd2fe77977cbf47b053d2608b0e98a 100644 (file)
@@ -6,15 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
 
 source "lib/Kconfig.debug"
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config DEBUG_DCFLUSH
        bool "D-cache flush debugging"
        depends on SPARC64 && DEBUG_KERNEL
index 5bdfa2c6e4006eb315e50a30c7df82c12b147d73..4e5e0878144f3331835f8327e334db1dc97872cf 100644 (file)
@@ -78,4 +78,7 @@ static inline void check_pgt_cache(void)
        quicklist_trim(0, NULL, 25, 16);
 }
 
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
+
 #endif /* _SPARC64_PGALLOC_H */
index b77128c80524fb7166a83d7411bd0c1a66acc5fb..1e03c5a6b4f73b30775f763ec014a61f409cf400 100644 (file)
@@ -655,9 +655,11 @@ static inline int pte_special(pte_t pte)
 #define pte_unmap(pte)                 do { } while (0)
 
 /* Actual page table PTE updates.  */
-extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig);
+extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
+                         pte_t *ptep, pte_t orig, int fullmm);
 
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
+static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
+                            pte_t *ptep, pte_t pte, int fullmm)
 {
        pte_t orig = *ptep;
 
@@ -670,12 +672,19 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *p
         *             and SUN4V pte layout, so this inline test is fine.
         */
        if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID))
-               tlb_batch_add(mm, addr, ptep, orig);
+               tlb_batch_add(mm, addr, ptep, orig, fullmm);
 }
 
+#define set_pte_at(mm,addr,ptep,pte)   \
+       __set_pte_at((mm), (addr), (ptep), (pte), 0)
+
 #define pte_clear(mm,addr,ptep)                \
        set_pte_at((mm), (addr), (ptep), __pte(0UL))
 
+#define __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL
+#define pte_clear_not_present_full(mm,addr,ptep,fullmm)        \
+       __set_pte_at((mm), (addr), (ptep), __pte(0UL), (fullmm))
+
 #ifdef DCACHE_ALIASING_POSSIBLE
 #define __HAVE_ARCH_MOVE_PTE
 #define move_pte(pte, prot, old_addr, new_addr)                                \
index dca406b9b6fc5b9b6400732d6abe3a9f1e9e528d..190e18913cc6968213cb468b07963db26f965ebd 100644 (file)
@@ -7,66 +7,11 @@
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
 
-#define TLB_BATCH_NR   192
-
-/*
- * For UP we don't need to worry about TLB flush
- * and page free order so much..
- */
-#ifdef CONFIG_SMP
-  #define FREE_PTE_NR  506
-  #define tlb_fast_mode(bp) ((bp)->pages_nr == ~0U)
-#else
-  #define FREE_PTE_NR  1
-  #define tlb_fast_mode(bp) 1
-#endif
-
-struct mmu_gather {
-       struct mm_struct *mm;
-       unsigned int pages_nr;
-       unsigned int need_flush;
-       unsigned int fullmm;
-       unsigned int tlb_nr;
-       unsigned long vaddrs[TLB_BATCH_NR];
-       struct page *pages[FREE_PTE_NR];
-};
-
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 #ifdef CONFIG_SMP
 extern void smp_flush_tlb_pending(struct mm_struct *,
                                  unsigned long, unsigned long *);
 #endif
 
-extern void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *);
-extern void flush_tlb_pending(void);
-
-static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
-{
-       struct mmu_gather *mp = &get_cpu_var(mmu_gathers);
-
-       BUG_ON(mp->tlb_nr);
-
-       mp->mm = mm;
-       mp->pages_nr = num_online_cpus() > 1 ? 0U : ~0U;
-       mp->fullmm = full_mm_flush;
-
-       return mp;
-}
-
-
-static inline void tlb_flush_mmu(struct mmu_gather *mp)
-{
-       if (!mp->fullmm)
-               flush_tlb_pending();
-       if (mp->need_flush) {
-               free_pages_and_swap_cache(mp->pages, mp->pages_nr);
-               mp->pages_nr = 0;
-               mp->need_flush = 0;
-       }
-
-}
-
 #ifdef CONFIG_SMP
 extern void smp_flush_tlb_mm(struct mm_struct *mm);
 #define do_flush_tlb_mm(mm) smp_flush_tlb_mm(mm)
@@ -74,38 +19,14 @@ extern void smp_flush_tlb_mm(struct mm_struct *mm);
 #define do_flush_tlb_mm(mm) __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT)
 #endif
 
-static inline void tlb_finish_mmu(struct mmu_gather *mp, unsigned long start, unsigned long end)
-{
-       tlb_flush_mmu(mp);
-
-       if (mp->fullmm)
-               mp->fullmm = 0;
-
-       /* keep the page table cache within bounds */
-       check_pgt_cache();
-
-       put_cpu_var(mmu_gathers);
-}
-
-static inline void tlb_remove_page(struct mmu_gather *mp, struct page *page)
-{
-       if (tlb_fast_mode(mp)) {
-               free_page_and_swap_cache(page);
-               return;
-       }
-       mp->need_flush = 1;
-       mp->pages[mp->pages_nr++] = page;
-       if (mp->pages_nr >= FREE_PTE_NR)
-               tlb_flush_mmu(mp);
-}
-
-#define tlb_remove_tlb_entry(mp,ptep,addr) do { } while (0)
-#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)
+extern void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *);
+extern void flush_tlb_pending(void);
 
-#define tlb_migrate_finish(mm) do { } while (0)
 #define tlb_start_vma(tlb, vma) do { } while (0)
 #define tlb_end_vma(tlb, vma)  do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
+#define tlb_flush(tlb) flush_tlb_pending()
+
+#include <asm-generic/tlb.h>
 
 #endif /* _SPARC64_TLB_H */
index fbb675dbe0c92abe8bead2c0a46c58451fa4d0e1..2ef463494153a65adec7c7a59a37c0095fda2649 100644 (file)
@@ -5,9 +5,17 @@
 #include <asm/mmu_context.h>
 
 /* TSB flush operations. */
-struct mmu_gather;
+
+#define TLB_BATCH_NR   192
+
+struct tlb_batch {
+       struct mm_struct *mm;
+       unsigned long tlb_nr;
+       unsigned long vaddrs[TLB_BATCH_NR];
+};
+
 extern void flush_tsb_kernel_range(unsigned long start, unsigned long end);
-extern void flush_tsb_user(struct mmu_gather *mp);
+extern void flush_tsb_user(struct tlb_batch *tb);
 
 /* TLB flush operations. */
 
index 3609bdee9ed294d1d6b88cea15fbc92a7ac2297a..3249d3f3234d5535fa9381e47702eeeba809a10c 100644 (file)
@@ -82,7 +82,7 @@ static void prom_sync_me(void)
                             "nop\n\t" : : "r" (&trapbase));
 
        prom_printf("PROM SYNC COMMAND...\n");
-       show_free_areas();
+       show_free_areas(0);
        if(current->pid != 0) {
                local_irq_enable();
                sys_sync();
index 4c31e2b6e71b8bd49451ab2d6f4381e82bfbd9ae..ca217327e8d27bb41c7fe1dac29be90e65919d41 100644 (file)
@@ -37,8 +37,6 @@
 #include <asm/prom.h>
 #include <asm/leon.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long *sparc_valid_addr_bitmap;
 EXPORT_SYMBOL(sparc_valid_addr_bitmap);
 
@@ -78,7 +76,7 @@ void __init kmap_init(void)
 void show_mem(unsigned int filter)
 {
        printk("Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
        printk("Free swap:       %6ldkB\n",
               nr_swap_pages << (PAGE_SHIFT-10));
        printk("%ld pages of RAM\n", totalram_pages);
index d8f21e24a82f8c98f0a708bd1a493058a51b49bb..b1f279cd00bfd96afb039e917a0692ce440beaeb 100644 (file)
 
 /* Heavily inspired by the ppc64 code.  */
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);
 
 void flush_tlb_pending(void)
 {
-       struct mmu_gather *mp = &get_cpu_var(mmu_gathers);
+       struct tlb_batch *tb = &get_cpu_var(tlb_batch);
 
-       if (mp->tlb_nr) {
-               flush_tsb_user(mp);
+       if (tb->tlb_nr) {
+               flush_tsb_user(tb);
 
-               if (CTX_VALID(mp->mm->context)) {
+               if (CTX_VALID(tb->mm->context)) {
 #ifdef CONFIG_SMP
-                       smp_flush_tlb_pending(mp->mm, mp->tlb_nr,
-                                             &mp->vaddrs[0]);
+                       smp_flush_tlb_pending(tb->mm, tb->tlb_nr,
+                                             &tb->vaddrs[0]);
 #else
-                       __flush_tlb_pending(CTX_HWBITS(mp->mm->context),
-                                           mp->tlb_nr, &mp->vaddrs[0]);
+                       __flush_tlb_pending(CTX_HWBITS(tb->mm->context),
+                                           tb->tlb_nr, &tb->vaddrs[0]);
 #endif
                }
-               mp->tlb_nr = 0;
+               tb->tlb_nr = 0;
        }
 
-       put_cpu_var(mmu_gathers);
+       put_cpu_var(tlb_batch);
 }
 
-void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig)
+void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
+                  pte_t *ptep, pte_t orig, int fullmm)
 {
-       struct mmu_gather *mp = &__get_cpu_var(mmu_gathers);
+       struct tlb_batch *tb = &get_cpu_var(tlb_batch);
        unsigned long nr;
 
        vaddr &= PAGE_MASK;
@@ -77,21 +78,25 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t
 
 no_cache_flush:
 
-       if (mp->fullmm)
+       if (fullmm) {
+               put_cpu_var(tlb_batch);
                return;
+       }
 
-       nr = mp->tlb_nr;
+       nr = tb->tlb_nr;
 
-       if (unlikely(nr != 0 && mm != mp->mm)) {
+       if (unlikely(nr != 0 && mm != tb->mm)) {
                flush_tlb_pending();
                nr = 0;
        }
 
        if (nr == 0)
-               mp->mm = mm;
+               tb->mm = mm;
 
-       mp->vaddrs[nr] = vaddr;
-       mp->tlb_nr = ++nr;
+       tb->vaddrs[nr] = vaddr;
+       tb->tlb_nr = ++nr;
        if (nr >= TLB_BATCH_NR)
                flush_tlb_pending();
+
+       put_cpu_var(tlb_batch);
 }
index 101d7c82870be8a704a2ab84f07d97a2d890f37a..94846151349991387435c0a61a925b93b09debb2 100644 (file)
@@ -47,12 +47,13 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
        }
 }
 
-static void __flush_tsb_one(struct mmu_gather *mp, unsigned long hash_shift, unsigned long tsb, unsigned long nentries)
+static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift,
+                           unsigned long tsb, unsigned long nentries)
 {
        unsigned long i;
 
-       for (i = 0; i < mp->tlb_nr; i++) {
-               unsigned long v = mp->vaddrs[i];
+       for (i = 0; i < tb->tlb_nr; i++) {
+               unsigned long v = tb->vaddrs[i];
                unsigned long tag, ent, hash;
 
                v &= ~0x1UL;
@@ -65,9 +66,9 @@ static void __flush_tsb_one(struct mmu_gather *mp, unsigned long hash_shift, uns
        }
 }
 
-void flush_tsb_user(struct mmu_gather *mp)
+void flush_tsb_user(struct tlb_batch *tb)
 {
-       struct mm_struct *mm = mp->mm;
+       struct mm_struct *mm = tb->mm;
        unsigned long nentries, base, flags;
 
        spin_lock_irqsave(&mm->context.lock, flags);
@@ -76,7 +77,7 @@ void flush_tsb_user(struct mmu_gather *mp)
        nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
        if (tlb_type == cheetah_plus || tlb_type == hypervisor)
                base = __pa(base);
-       __flush_tsb_one(mp, PAGE_SHIFT, base, nentries);
+       __flush_tsb_one(tb, PAGE_SHIFT, base, nentries);
 
 #ifdef CONFIG_HUGETLB_PAGE
        if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
@@ -84,7 +85,7 @@ void flush_tsb_user(struct mmu_gather *mp)
                nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;
                if (tlb_type == cheetah_plus || tlb_type == hypervisor)
                        base = __pa(base);
-               __flush_tsb_one(mp, HPAGE_SHIFT, base, nentries);
+               __flush_tsb_one(tb, HPAGE_SHIFT, base, nentries);
        }
 #endif
        spin_unlock_irqrestore(&mm->context.lock, flags);
index e32b0c23c4c815870ac0dac9358ea97af1e8cd05..635e1bfb1c5d373d8d38c6c94801fd2c6077ebeb 100644 (file)
@@ -339,6 +339,14 @@ config NO_IOPORT
 
 source "drivers/pci/Kconfig"
 
+config HOTPLUG
+       bool "Support for hot-pluggable devices"
+       ---help---
+         Say Y here if you want to plug devices into your computer while
+         the system is running, and be able to use them quickly.  In many
+         cases, the devices can likewise be unplugged at any time too.
+         One well-known example of this is USB.
+
 source "drivers/pci/hotplug/Kconfig"
 
 endmenu
index 9bc161a02c71ba65ef8e1394cb1617738533bd9e..ddbfc3322d7f461e693614405ac5ce2aee930148 100644 (file)
@@ -21,15 +21,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
 config DEBUG_EXTRA_FLAGS
        string "Additional compiler arguments when building with '-g'"
        depends on DEBUG_INFO
diff --git a/arch/tile/configs/tile_defconfig b/arch/tile/configs/tile_defconfig
deleted file mode 100644 (file)
index 0fe5444..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
-CONFIG_EXPERT=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_PROFILING=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_HZ_100=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_NETDEVICES=y
-CONFIG_TUN=y
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-# CONFIG_HID_SUPPORT is not set
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_INTF_SYSFS is not set
-# CONFIG_RTC_INTF_PROC is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_FUSE_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=m
-CONFIG_TMPFS=y
-CONFIG_HUGETLBFS=y
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_FRAME_WARN=2048
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DETECT_HUNG_TASK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_VM=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_EXTRA_FLAGS="-femit-struct-debug-baseonly"
diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig
new file mode 100644 (file)
index 0000000..09f1c7f
--- /dev/null
@@ -0,0 +1,1833 @@
+#
+# Automatically generated make config: don't edit
+# Linux/tilegx 2.6.39-rc5 Kernel Configuration
+# Wed May  4 11:08:04 2011
+#
+CONFIG_TILE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_HAVE_ARCH_ALLOC_REMAP=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_DEFAULT_MIGRATION_COST=10000000
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SMP=y
+# CONFIG_DEBUG_COPY_FROM_USER is not set
+CONFIG_HVC_TILE=y
+CONFIG_TILEGX=y
+CONFIG_64BIT=y
+CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tilegx_defconfig"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_FHANDLE is not set
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PENDING_IRQ=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=64
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_NS=y
+# CONFIG_CGROUP_FREEZER is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+# CONFIG_DEBUG_BLK_CGROUP is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_MM_OWNER=y
+# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=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_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_INTEGRITY=y
+# CONFIG_BLK_DEV_THROTTLING is not set
+CONFIG_BLOCK_COMPAT=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CFQ_GROUP_IOSCHED=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_PADATA=y
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+
+#
+# Tilera-specific configuration
+#
+CONFIG_NR_CPUS=100
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+# CONFIG_KEXEC is not set
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+# CONFIG_HIGHMEM is not set
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=2
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_DISCONTIGMEM_MANUAL=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_VMALLOC_RESERVE=0x1000000
+CONFIG_HARDWALL=y
+CONFIG_KERNEL_PL=1
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_NO_IOMEM is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_DEBUG=y
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_COMPAT_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=m
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_CLASSID=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+# CONFIG_NET_IPGRE_DEMUX is not set
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_IPV6_SUBTREES is not set
+CONFIG_IPV6_MROUTE=y
+# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETLABEL=y
+CONFIG_NETWORK_SECMARK=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING 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=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_BROADCAST=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+# CONFIG_NF_CONNTRACK_SNMP is not set
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+# CONFIG_NF_CT_NETLINK is not set
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+
+#
+# Xtables targets
+#
+# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_OSF=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+# CONFIG_IP_SET is not set
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_AH_ESP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+CONFIG_IP_VS_PROTO_SCTP=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+# CONFIG_IP_VS_DH is not set
+# CONFIG_IP_VS_SH is not set
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_NFCT is not set
+# CONFIG_IP_VS_PE_SIP is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+# CONFIG_NF_NAT is not set
+CONFIG_IP_NF_MANGLE=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+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=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_IP6=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+CONFIG_BRIDGE_EBT_NFLOG=m
+# 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_RDS=m
+CONFIG_RDS_TCP=m
+# CONFIG_RDS_DEBUG is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+CONFIG_NET_DSA=y
+CONFIG_NET_DSA_TAG_DSA=y
+CONFIG_NET_DSA_TAG_EDSA=y
+CONFIG_NET_DSA_TAG_TRAILER=y
+CONFIG_NET_DSA_MV88E6XXX=y
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6XXX_NEED_PPU=y
+CONFIG_NET_DSA_MV88E6131=y
+CONFIG_NET_DSA_MV88E6123_61_65=y
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# 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 is not set
+CONFIG_PHONET=m
+# CONFIG_IEEE802154 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_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+# CONFIG_NET_SCH_SFB is not set
+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=m
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_CHOKE is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+# CONFIG_NET_ACT_CSUM is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_SCH_FIFO=y
+CONFIG_DCB=y
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+
+#
+# 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_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_ATA_OVER_ETH=y
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_SENSORS_LIS3_I2C is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=m
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_TGT=m
+# 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
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# 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_ATTRS=m
+# 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_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=m
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+
+#
+# Controllers with non-SFF native interface
+#
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_AHCI_PLATFORM is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_SATA_ACARD_AHCI is not set
+CONFIG_SATA_SIL24=m
+CONFIG_ATA_SFF=y
+
+#
+# SFF controllers with custom DMA interface
+#
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_ATA_BMDMA=y
+
+#
+# SATA SFF controllers with BMDMA
+#
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARASAN_CF is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
+# PIO-only SFF controllers
+#
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_AUTODETECT=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MULTICORE_RAID456=y
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+# CONFIG_DM_RAID is not set
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_DELAY=m
+CONFIG_DM_UEVENT=y
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+CONFIG_IFB=m
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+CONFIG_VETH=m
+# CONFIG_ARCNET is not set
+# CONFIG_MII 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_BCM63XX_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_MICREL_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+CONFIG_E1000E=m
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_TILE_NET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 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
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# 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 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_N_GSM is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MFD_HSU is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_TTY_PRINTK is not set
+CONFIG_HVC_DRIVER=y
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_MUX is not set
+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_INTEL_MID is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+# CONFIG_I2C_EG20T 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_STUB 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_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGA_ARB is not set
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO is not set
+# 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
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_NFC_DEVICES is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC 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_DS3232 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_ISL12022 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_BQ32K 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_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_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_TILE=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_FS_XIP=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_JBD2_DEBUG=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+# CONFIG_OCFS2_FS is not set
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=m
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+# CONFIG_FSCACHE_HISTOGRAM is not set
+# CONFIG_FSCACHE_DEBUG is not set
+# CONFIG_FSCACHE_OBJECT_LIST is not set
+CONFIG_CACHEFILES=m
+# CONFIG_CACHEFILES_DEBUG is not set
+# CONFIG_CACHEFILES_HISTOGRAM is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+# 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=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_CONFIGFS_FS=m
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_ECRYPT_FS=m
+# 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_LOGFS is not set
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_XZ is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# 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_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_PNFS_FILE_LAYOUT=m
+CONFIG_NFS_FSCACHE=y
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFS_USE_NEW_IDMAPPER is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_DEPRECATED=y
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_CEPH_FS is not set
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+# CONFIG_CIFS_ACL is not set
+CONFIG_CIFS_EXPERIMENTAL=y
+# 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=y
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+CONFIG_DLM=m
+CONFIG_DLM_DEBUG=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER 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
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_DEBUG_VM=y
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+CONFIG_DEBUG_CREDENTIALS=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BUILD_DOCSRC is not set
+CONFIG_DYNAMIC_DEBUG=y
+# CONFIG_ATOMIC64_SELFTEST is not set
+CONFIG_ASYNC_RAID6_TEST=m
+# CONFIG_SAMPLES is not set
+# CONFIG_TEST_KSTRTOX is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_EXTRA_FLAGS=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+# CONFIG_SECURITY_PATH is not set
+CONFIG_LSM_MMAP_MIN_ADDR=65536
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
+# CONFIG_SECURITY_SMACK is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_SECURITY_APPARMOR is not set
+# CONFIG_IMA is not set
+CONFIG_DEFAULT_SECURITY_SELINUX=y
+# CONFIG_DEFAULT_SECURITY_DAC is not set
+CONFIG_DEFAULT_SECURITY="selinux"
+CONFIG_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
+CONFIG_ASYNC_PQ=m
+CONFIG_ASYNC_RAID6_RECOV=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_HIFN_795X=m
+CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_RAID6_PQ=m
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig
new file mode 100644 (file)
index 0000000..f58dc36
--- /dev/null
@@ -0,0 +1,1163 @@
+#
+# Automatically generated make config: don't edit
+# Linux/tile 2.6.39-rc5 Kernel Configuration
+# Tue May  3 09:15:02 2011
+#
+CONFIG_TILE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_HAVE_ARCH_ALLOC_REMAP=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_DEFAULT_MIGRATION_COST=10000000
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SMP=y
+# CONFIG_DEBUG_COPY_FROM_USER is not set
+CONFIG_HVC_TILE=y
+# CONFIG_TILEGX is not set
+CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tile_defconfig"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# 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_FHANDLE=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PENDING_IRQ=y
+
+#
+# RCU Subsystem
+#
+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_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=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_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+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_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+
+#
+# Tilera-specific configuration
+#
+CONFIG_NR_CPUS=64
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+# CONFIG_KEXEC is not set
+CONFIG_HIGHMEM=y
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=2
+# CONFIG_VMSPLIT_3_75G is not set
+# CONFIG_VMSPLIT_3_5G is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2_75G is not set
+# CONFIG_VMSPLIT_2_5G is not set
+# CONFIG_VMSPLIT_2_25G is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_DISCONTIGMEM_MANUAL=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_VMALLOC_RESERVE=0x1000000
+CONFIG_HARDWALL=y
+CONFIG_KERNEL_PL=1
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_NO_IOMEM is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_KCORE_ELF=y
+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_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+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=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_IP_MROUTE 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 is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+# 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=y
+# 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=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+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_NETWORK_PHY_TIMESTAMPING is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP 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
+# CONFIG_BATMAN_ADV is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+
+#
+# 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
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 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_RBD is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# 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 is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# 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_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_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O 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_ARCNET is not set
+# CONFIG_MII is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_TILE_NET=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 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
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# 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 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_N_GSM is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MFD_HSU is not set
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_TTY_PRINTK is not set
+CONFIG_HVC_DRIVER=y
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_RAMOOPS is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SCH5627 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO is not set
+# 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
+# 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=y
+# 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_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_NFC_DEVICES is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_EDAC=y
+
+#
+# Reporting subsystems
+#
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_EDAC_TILE=y
+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 is not set
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# 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_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_TILE=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY 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_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL 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=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+# 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_LOGFS 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_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_CEPH_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=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 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+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_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER 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
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_INFO_REDUCED is not set
+CONFIG_DEBUG_VM=y
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_TEST_KSTRTOX is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_EXTRA_FLAGS="-femit-struct-debug-baseonly"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=m
+# 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_PCRYPT 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
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# 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=m
+# 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=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=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_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+CONFIG_HAVE_KVM=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/tile/include/arch/chip_tilegx.h b/arch/tile/include/arch/chip_tilegx.h
new file mode 100644 (file)
index 0000000..ea8e4f2
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+/*
+ * @file
+ * Global header file.
+ * This header file specifies defines for TILE-Gx.
+ */
+
+#ifndef __ARCH_CHIP_H__
+#define __ARCH_CHIP_H__
+
+/** Specify chip version.
+ * When possible, prefer the CHIP_xxx symbols below for future-proofing.
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip__ symbol.
+ */
+#define TILE_CHIP 10
+
+/** Specify chip revision.
+ * This provides for the case of a respin of a particular chip type;
+ * the normal value for this symbol is "0".
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip_rev__ symbol.
+ */
+#define TILE_CHIP_REV 0
+
+/** The name of this architecture. */
+#define CHIP_ARCH_NAME "tilegx"
+
+/** The ELF e_machine type for binaries for this chip. */
+#define CHIP_ELF_TYPE() EM_TILEGX
+
+/** The alternate ELF e_machine type for binaries for this chip. */
+#define CHIP_COMPAT_ELF_TYPE() 0x2597
+
+/** What is the native word size of the machine? */
+#define CHIP_WORD_SIZE() 64
+
+/** How many bits of a virtual address are used. Extra bits must be
+ * the sign extension of the low bits.
+ */
+#define CHIP_VA_WIDTH() 42
+
+/** How many bits are in a physical address? */
+#define CHIP_PA_WIDTH() 40
+
+/** Size of the L2 cache, in bytes. */
+#define CHIP_L2_CACHE_SIZE() 262144
+
+/** Log size of an L2 cache line in bytes. */
+#define CHIP_L2_LOG_LINE_SIZE() 6
+
+/** Size of an L2 cache line, in bytes. */
+#define CHIP_L2_LINE_SIZE() (1 << CHIP_L2_LOG_LINE_SIZE())
+
+/** Associativity of the L2 cache. */
+#define CHIP_L2_ASSOC() 8
+
+/** Size of the L1 data cache, in bytes. */
+#define CHIP_L1D_CACHE_SIZE() 32768
+
+/** Log size of an L1 data cache line in bytes. */
+#define CHIP_L1D_LOG_LINE_SIZE() 6
+
+/** Size of an L1 data cache line, in bytes. */
+#define CHIP_L1D_LINE_SIZE() (1 << CHIP_L1D_LOG_LINE_SIZE())
+
+/** Associativity of the L1 data cache. */
+#define CHIP_L1D_ASSOC() 2
+
+/** Size of the L1 instruction cache, in bytes. */
+#define CHIP_L1I_CACHE_SIZE() 32768
+
+/** Log size of an L1 instruction cache line in bytes. */
+#define CHIP_L1I_LOG_LINE_SIZE() 6
+
+/** Size of an L1 instruction cache line, in bytes. */
+#define CHIP_L1I_LINE_SIZE() (1 << CHIP_L1I_LOG_LINE_SIZE())
+
+/** Associativity of the L1 instruction cache. */
+#define CHIP_L1I_ASSOC() 2
+
+/** Stride with which flush instructions must be issued. */
+#define CHIP_FLUSH_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Stride with which inv instructions must be issued. */
+#define CHIP_INV_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Stride with which finv instructions must be issued. */
+#define CHIP_FINV_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Can the local cache coherently cache data that is homed elsewhere? */
+#define CHIP_HAS_COHERENT_LOCAL_CACHE() 1
+
+/** How many simultaneous outstanding victims can the L2 cache have? */
+#define CHIP_MAX_OUTSTANDING_VICTIMS() 128
+
+/** Does the TLB support the NC and NOALLOC bits? */
+#define CHIP_HAS_NC_AND_NOALLOC_BITS() 1
+
+/** Does the chip support hash-for-home caching? */
+#define CHIP_HAS_CBOX_HOME_MAP() 1
+
+/** Number of entries in the chip's home map tables. */
+#define CHIP_CBOX_HOME_MAP_SIZE() 128
+
+/** Do uncacheable requests miss in the cache regardless of whether
+ * there is matching data? */
+#define CHIP_HAS_ENFORCED_UNCACHEABLE_REQUESTS() 1
+
+/** Does the mf instruction wait for victims? */
+#define CHIP_HAS_MF_WAITS_FOR_VICTIMS() 0
+
+/** Does the chip have an "inv" instruction that doesn't also flush? */
+#define CHIP_HAS_INV() 1
+
+/** Does the chip have a "wh64" instruction? */
+#define CHIP_HAS_WH64() 1
+
+/** Does this chip have a 'dword_align' instruction? */
+#define CHIP_HAS_DWORD_ALIGN() 0
+
+/** Number of performance counters. */
+#define CHIP_PERFORMANCE_COUNTERS() 4
+
+/** Does this chip have auxiliary performance counters? */
+#define CHIP_HAS_AUX_PERF_COUNTERS() 1
+
+/** Is the CBOX_MSR1 SPR supported? */
+#define CHIP_HAS_CBOX_MSR1() 0
+
+/** Is the TILE_RTF_HWM SPR supported? */
+#define CHIP_HAS_TILE_RTF_HWM() 1
+
+/** Is the TILE_WRITE_PENDING SPR supported? */
+#define CHIP_HAS_TILE_WRITE_PENDING() 0
+
+/** Is the PROC_STATUS SPR supported? */
+#define CHIP_HAS_PROC_STATUS_SPR() 1
+
+/** Is the DSTREAM_PF SPR supported? */
+#define CHIP_HAS_DSTREAM_PF() 1
+
+/** Log of the number of mshims we have. */
+#define CHIP_LOG_NUM_MSHIMS() 2
+
+/** Are the bases of the interrupt vector areas fixed? */
+#define CHIP_HAS_FIXED_INTVEC_BASE() 0
+
+/** Are the interrupt masks split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_INTR_MASK() 0
+
+/** Is the cycle count split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_CYCLE() 0
+
+/** Does the chip have a static network? */
+#define CHIP_HAS_SN() 0
+
+/** Does the chip have a static network processor? */
+#define CHIP_HAS_SN_PROC() 0
+
+/** Size of the L1 static network processor instruction cache, in bytes. */
+/* #define CHIP_L1SNI_CACHE_SIZE() -- does not apply to chip 10 */
+
+/** Does the chip have DMA support in each tile? */
+#define CHIP_HAS_TILE_DMA() 0
+
+/** Does the chip have the second revision of the directly accessible
+ *  dynamic networks?  This encapsulates a number of characteristics,
+ *  including the absence of the catch-all, the absence of inline message
+ *  tags, the absence of support for network context-switching, and so on.
+ */
+#define CHIP_HAS_REV1_XDN() 1
+
+/** Does the chip have cmpexch and similar (fetchadd, exch, etc.)? */
+#define CHIP_HAS_CMPEXCH() 1
+
+/** Does the chip have memory-mapped I/O support? */
+#define CHIP_HAS_MMIO() 1
+
+/** Does the chip have post-completion interrupts? */
+#define CHIP_HAS_POST_COMPLETION_INTERRUPTS() 1
+
+/** Does the chip have native single step support? */
+#define CHIP_HAS_SINGLE_STEP() 1
+
+#ifndef __OPEN_SOURCE__  /* features only relevant to hypervisor-level code */
+
+/** How many entries are present in the instruction TLB? */
+#define CHIP_ITLB_ENTRIES() 16
+
+/** How many entries are present in the data TLB? */
+#define CHIP_DTLB_ENTRIES() 32
+
+/** How many MAF entries does the XAUI shim have? */
+#define CHIP_XAUI_MAF_ENTRIES() 32
+
+/** Does the memory shim have a source-id table? */
+#define CHIP_HAS_MSHIM_SRCID_TABLE() 0
+
+/** Does the L1 instruction cache clear on reset? */
+#define CHIP_HAS_L1I_CLEAR_ON_RESET() 1
+
+/** Does the chip come out of reset with valid coordinates on all tiles?
+ * Note that if defined, this also implies that the upper left is 1,1.
+ */
+#define CHIP_HAS_VALID_TILE_COORD_RESET() 1
+
+/** Does the chip have unified packet formats? */
+#define CHIP_HAS_UNIFIED_PACKET_FORMATS() 1
+
+/** Does the chip support write reordering? */
+#define CHIP_HAS_WRITE_REORDERING() 1
+
+/** Does the chip support Y-X routing as well as X-Y? */
+#define CHIP_HAS_Y_X_ROUTING() 1
+
+/** Is INTCTRL_3 managed with the correct MPL? */
+#define CHIP_HAS_INTCTRL_3_STATUS_FIX() 1
+
+/** Is it possible to configure the chip to be big-endian? */
+#define CHIP_HAS_BIG_ENDIAN_CONFIG() 1
+
+/** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */
+#define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 0
+
+/** Is the DIAG_TRACE_WAY SPR supported? */
+#define CHIP_HAS_DIAG_TRACE_WAY() 0
+
+/** Is the MEM_STRIPE_CONFIG SPR supported? */
+#define CHIP_HAS_MEM_STRIPE_CONFIG() 1
+
+/** Are the TLB_PERF SPRs supported? */
+#define CHIP_HAS_TLB_PERF() 1
+
+/** Is the VDN_SNOOP_SHIM_CTL SPR supported? */
+#define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 0
+
+/** Does the chip support rev1 DMA packets? */
+#define CHIP_HAS_REV1_DMA_PACKETS() 1
+
+/** Does the chip have an IPI shim? */
+#define CHIP_HAS_IPI() 1
+
+#endif /* !__OPEN_SOURCE__ */
+#endif /* __ARCH_CHIP_H__ */
index 5c87c90163389bc3b6a9a265a4fbc1dea6256cc6..762eafa8a11ec95af2928e9c045549ff59c4604e 100644 (file)
@@ -16,7 +16,7 @@
 /**
  * @file
  *
- * Support for invalidating bytes in the instruction
+ * Support for invalidating bytes in the instruction cache.
  */
 
 #ifndef __ARCH_ICACHE_H__
  *
  * @param addr The start of memory to be invalidated.
  * @param size The number of bytes to be invalidated.
- * @param page_size The system's page size, typically the PAGE_SIZE constant
- * in sys/page.h.  This value must be a power of two no larger
- * than the page containing the code to be invalidated. If the value
- * is smaller than the actual page size, this function will still
- * work, but may run slower than necessary.
+ * @param page_size The system's page size, e.g. getpagesize() in userspace.
+ * This value must be a power of two no larger than the page containing
+ * the code to be invalidated. If the value is smaller than the actual page
+ * size, this function will still work, but may run slower than necessary.
  */
 static __inline void
 invalidate_icache(const void* addr, unsigned long size,
diff --git a/arch/tile/include/arch/interrupts_64.h b/arch/tile/include/arch/interrupts_64.h
new file mode 100644 (file)
index 0000000..5bb58b2
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef __ARCH_INTERRUPTS_H__
+#define __ARCH_INTERRUPTS_H__
+
+/** Mask for an interrupt. */
+#ifdef __ASSEMBLER__
+/* Note: must handle breaking interrupts into high and low words manually. */
+#define INT_MASK(intno) (1 << (intno))
+#else
+#define INT_MASK(intno) (1ULL << (intno))
+#endif
+
+
+/** Where a given interrupt executes */
+#define INTERRUPT_VECTOR(i, pl) (0xFC000000 + ((pl) << 24) + ((i) << 8))
+
+/** Where to store a vector for a given interrupt. */
+#define USER_INTERRUPT_VECTOR(i) INTERRUPT_VECTOR(i, 0)
+
+/** The base address of user-level interrupts. */
+#define USER_INTERRUPT_VECTOR_BASE INTERRUPT_VECTOR(0, 0)
+
+
+/** Additional synthetic interrupt. */
+#define INT_BREAKPOINT (63)
+
+#define INT_MEM_ERROR    0
+#define INT_SINGLE_STEP_3    1
+#define INT_SINGLE_STEP_2    2
+#define INT_SINGLE_STEP_1    3
+#define INT_SINGLE_STEP_0    4
+#define INT_IDN_COMPLETE    5
+#define INT_UDN_COMPLETE    6
+#define INT_ITLB_MISS    7
+#define INT_ILL    8
+#define INT_GPV    9
+#define INT_IDN_ACCESS   10
+#define INT_UDN_ACCESS   11
+#define INT_SWINT_3   12
+#define INT_SWINT_2   13
+#define INT_SWINT_1   14
+#define INT_SWINT_0   15
+#define INT_ILL_TRANS   16
+#define INT_UNALIGN_DATA   17
+#define INT_DTLB_MISS   18
+#define INT_DTLB_ACCESS   19
+#define INT_IDN_FIREWALL   20
+#define INT_UDN_FIREWALL   21
+#define INT_TILE_TIMER   22
+#define INT_AUX_TILE_TIMER   23
+#define INT_IDN_TIMER   24
+#define INT_UDN_TIMER   25
+#define INT_IDN_AVAIL   26
+#define INT_UDN_AVAIL   27
+#define INT_IPI_3   28
+#define INT_IPI_2   29
+#define INT_IPI_1   30
+#define INT_IPI_0   31
+#define INT_PERF_COUNT   32
+#define INT_AUX_PERF_COUNT   33
+#define INT_INTCTRL_3   34
+#define INT_INTCTRL_2   35
+#define INT_INTCTRL_1   36
+#define INT_INTCTRL_0   37
+#define INT_BOOT_ACCESS   38
+#define INT_WORLD_ACCESS   39
+#define INT_I_ASID   40
+#define INT_D_ASID   41
+#define INT_DOUBLE_FAULT   42
+
+#define NUM_INTERRUPTS 43
+
+#ifndef __ASSEMBLER__
+#define QUEUED_INTERRUPTS ( \
+    INT_MASK(INT_MEM_ERROR) | \
+    INT_MASK(INT_IDN_COMPLETE) | \
+    INT_MASK(INT_UDN_COMPLETE) | \
+    INT_MASK(INT_IDN_FIREWALL) | \
+    INT_MASK(INT_UDN_FIREWALL) | \
+    INT_MASK(INT_TILE_TIMER) | \
+    INT_MASK(INT_AUX_TILE_TIMER) | \
+    INT_MASK(INT_IDN_TIMER) | \
+    INT_MASK(INT_UDN_TIMER) | \
+    INT_MASK(INT_IDN_AVAIL) | \
+    INT_MASK(INT_UDN_AVAIL) | \
+    INT_MASK(INT_IPI_3) | \
+    INT_MASK(INT_IPI_2) | \
+    INT_MASK(INT_IPI_1) | \
+    INT_MASK(INT_IPI_0) | \
+    INT_MASK(INT_PERF_COUNT) | \
+    INT_MASK(INT_AUX_PERF_COUNT) | \
+    INT_MASK(INT_INTCTRL_3) | \
+    INT_MASK(INT_INTCTRL_2) | \
+    INT_MASK(INT_INTCTRL_1) | \
+    INT_MASK(INT_INTCTRL_0) | \
+    INT_MASK(INT_BOOT_ACCESS) | \
+    INT_MASK(INT_WORLD_ACCESS) | \
+    INT_MASK(INT_I_ASID) | \
+    INT_MASK(INT_D_ASID) | \
+    INT_MASK(INT_DOUBLE_FAULT) | \
+    0)
+#define NONQUEUED_INTERRUPTS ( \
+    INT_MASK(INT_SINGLE_STEP_3) | \
+    INT_MASK(INT_SINGLE_STEP_2) | \
+    INT_MASK(INT_SINGLE_STEP_1) | \
+    INT_MASK(INT_SINGLE_STEP_0) | \
+    INT_MASK(INT_ITLB_MISS) | \
+    INT_MASK(INT_ILL) | \
+    INT_MASK(INT_GPV) | \
+    INT_MASK(INT_IDN_ACCESS) | \
+    INT_MASK(INT_UDN_ACCESS) | \
+    INT_MASK(INT_SWINT_3) | \
+    INT_MASK(INT_SWINT_2) | \
+    INT_MASK(INT_SWINT_1) | \
+    INT_MASK(INT_SWINT_0) | \
+    INT_MASK(INT_ILL_TRANS) | \
+    INT_MASK(INT_UNALIGN_DATA) | \
+    INT_MASK(INT_DTLB_MISS) | \
+    INT_MASK(INT_DTLB_ACCESS) | \
+    0)
+#define CRITICAL_MASKED_INTERRUPTS ( \
+    INT_MASK(INT_MEM_ERROR) | \
+    INT_MASK(INT_SINGLE_STEP_3) | \
+    INT_MASK(INT_SINGLE_STEP_2) | \
+    INT_MASK(INT_SINGLE_STEP_1) | \
+    INT_MASK(INT_SINGLE_STEP_0) | \
+    INT_MASK(INT_IDN_COMPLETE) | \
+    INT_MASK(INT_UDN_COMPLETE) | \
+    INT_MASK(INT_IDN_FIREWALL) | \
+    INT_MASK(INT_UDN_FIREWALL) | \
+    INT_MASK(INT_TILE_TIMER) | \
+    INT_MASK(INT_AUX_TILE_TIMER) | \
+    INT_MASK(INT_IDN_TIMER) | \
+    INT_MASK(INT_UDN_TIMER) | \
+    INT_MASK(INT_IDN_AVAIL) | \
+    INT_MASK(INT_UDN_AVAIL) | \
+    INT_MASK(INT_IPI_3) | \
+    INT_MASK(INT_IPI_2) | \
+    INT_MASK(INT_IPI_1) | \
+    INT_MASK(INT_IPI_0) | \
+    INT_MASK(INT_PERF_COUNT) | \
+    INT_MASK(INT_AUX_PERF_COUNT) | \
+    INT_MASK(INT_INTCTRL_3) | \
+    INT_MASK(INT_INTCTRL_2) | \
+    INT_MASK(INT_INTCTRL_1) | \
+    INT_MASK(INT_INTCTRL_0) | \
+    0)
+#define CRITICAL_UNMASKED_INTERRUPTS ( \
+    INT_MASK(INT_ITLB_MISS) | \
+    INT_MASK(INT_ILL) | \
+    INT_MASK(INT_GPV) | \
+    INT_MASK(INT_IDN_ACCESS) | \
+    INT_MASK(INT_UDN_ACCESS) | \
+    INT_MASK(INT_SWINT_3) | \
+    INT_MASK(INT_SWINT_2) | \
+    INT_MASK(INT_SWINT_1) | \
+    INT_MASK(INT_SWINT_0) | \
+    INT_MASK(INT_ILL_TRANS) | \
+    INT_MASK(INT_UNALIGN_DATA) | \
+    INT_MASK(INT_DTLB_MISS) | \
+    INT_MASK(INT_DTLB_ACCESS) | \
+    INT_MASK(INT_BOOT_ACCESS) | \
+    INT_MASK(INT_WORLD_ACCESS) | \
+    INT_MASK(INT_I_ASID) | \
+    INT_MASK(INT_D_ASID) | \
+    INT_MASK(INT_DOUBLE_FAULT) | \
+    0)
+#define MASKABLE_INTERRUPTS ( \
+    INT_MASK(INT_MEM_ERROR) | \
+    INT_MASK(INT_SINGLE_STEP_3) | \
+    INT_MASK(INT_SINGLE_STEP_2) | \
+    INT_MASK(INT_SINGLE_STEP_1) | \
+    INT_MASK(INT_SINGLE_STEP_0) | \
+    INT_MASK(INT_IDN_COMPLETE) | \
+    INT_MASK(INT_UDN_COMPLETE) | \
+    INT_MASK(INT_IDN_FIREWALL) | \
+    INT_MASK(INT_UDN_FIREWALL) | \
+    INT_MASK(INT_TILE_TIMER) | \
+    INT_MASK(INT_AUX_TILE_TIMER) | \
+    INT_MASK(INT_IDN_TIMER) | \
+    INT_MASK(INT_UDN_TIMER) | \
+    INT_MASK(INT_IDN_AVAIL) | \
+    INT_MASK(INT_UDN_AVAIL) | \
+    INT_MASK(INT_IPI_3) | \
+    INT_MASK(INT_IPI_2) | \
+    INT_MASK(INT_IPI_1) | \
+    INT_MASK(INT_IPI_0) | \
+    INT_MASK(INT_PERF_COUNT) | \
+    INT_MASK(INT_AUX_PERF_COUNT) | \
+    INT_MASK(INT_INTCTRL_3) | \
+    INT_MASK(INT_INTCTRL_2) | \
+    INT_MASK(INT_INTCTRL_1) | \
+    INT_MASK(INT_INTCTRL_0) | \
+    0)
+#define UNMASKABLE_INTERRUPTS ( \
+    INT_MASK(INT_ITLB_MISS) | \
+    INT_MASK(INT_ILL) | \
+    INT_MASK(INT_GPV) | \
+    INT_MASK(INT_IDN_ACCESS) | \
+    INT_MASK(INT_UDN_ACCESS) | \
+    INT_MASK(INT_SWINT_3) | \
+    INT_MASK(INT_SWINT_2) | \
+    INT_MASK(INT_SWINT_1) | \
+    INT_MASK(INT_SWINT_0) | \
+    INT_MASK(INT_ILL_TRANS) | \
+    INT_MASK(INT_UNALIGN_DATA) | \
+    INT_MASK(INT_DTLB_MISS) | \
+    INT_MASK(INT_DTLB_ACCESS) | \
+    INT_MASK(INT_BOOT_ACCESS) | \
+    INT_MASK(INT_WORLD_ACCESS) | \
+    INT_MASK(INT_I_ASID) | \
+    INT_MASK(INT_D_ASID) | \
+    INT_MASK(INT_DOUBLE_FAULT) | \
+    0)
+#define SYNC_INTERRUPTS ( \
+    INT_MASK(INT_SINGLE_STEP_3) | \
+    INT_MASK(INT_SINGLE_STEP_2) | \
+    INT_MASK(INT_SINGLE_STEP_1) | \
+    INT_MASK(INT_SINGLE_STEP_0) | \
+    INT_MASK(INT_IDN_COMPLETE) | \
+    INT_MASK(INT_UDN_COMPLETE) | \
+    INT_MASK(INT_ITLB_MISS) | \
+    INT_MASK(INT_ILL) | \
+    INT_MASK(INT_GPV) | \
+    INT_MASK(INT_IDN_ACCESS) | \
+    INT_MASK(INT_UDN_ACCESS) | \
+    INT_MASK(INT_SWINT_3) | \
+    INT_MASK(INT_SWINT_2) | \
+    INT_MASK(INT_SWINT_1) | \
+    INT_MASK(INT_SWINT_0) | \
+    INT_MASK(INT_ILL_TRANS) | \
+    INT_MASK(INT_UNALIGN_DATA) | \
+    INT_MASK(INT_DTLB_MISS) | \
+    INT_MASK(INT_DTLB_ACCESS) | \
+    0)
+#define NON_SYNC_INTERRUPTS ( \
+    INT_MASK(INT_MEM_ERROR) | \
+    INT_MASK(INT_IDN_FIREWALL) | \
+    INT_MASK(INT_UDN_FIREWALL) | \
+    INT_MASK(INT_TILE_TIMER) | \
+    INT_MASK(INT_AUX_TILE_TIMER) | \
+    INT_MASK(INT_IDN_TIMER) | \
+    INT_MASK(INT_UDN_TIMER) | \
+    INT_MASK(INT_IDN_AVAIL) | \
+    INT_MASK(INT_UDN_AVAIL) | \
+    INT_MASK(INT_IPI_3) | \
+    INT_MASK(INT_IPI_2) | \
+    INT_MASK(INT_IPI_1) | \
+    INT_MASK(INT_IPI_0) | \
+    INT_MASK(INT_PERF_COUNT) | \
+    INT_MASK(INT_AUX_PERF_COUNT) | \
+    INT_MASK(INT_INTCTRL_3) | \
+    INT_MASK(INT_INTCTRL_2) | \
+    INT_MASK(INT_INTCTRL_1) | \
+    INT_MASK(INT_INTCTRL_0) | \
+    INT_MASK(INT_BOOT_ACCESS) | \
+    INT_MASK(INT_WORLD_ACCESS) | \
+    INT_MASK(INT_I_ASID) | \
+    INT_MASK(INT_D_ASID) | \
+    INT_MASK(INT_DOUBLE_FAULT) | \
+    0)
+#endif /* !__ASSEMBLER__ */
+#endif /* !__ARCH_INTERRUPTS_H__ */
index 442fcba0d12266db8ed8febd68c62a101a7b3ab6..f548efeb2de3f7fc005f90854a80d1b4941e3a98 100644 (file)
  *   more details.
  */
 
+/* Include the proper base SPR definition file. */
+#ifdef __tilegx__
+#include <arch/spr_def_64.h>
+#else
+#include <arch/spr_def_32.h>
+#endif
+
+#ifdef __KERNEL__
+
 /*
  * In addition to including the proper base SPR definition file, depending
  * on machine architecture, this file defines several macros which allow
@@ -29,7 +38,6 @@
 #define _concat4(a, b, c, d)  __concat4(a, b, c, d)
 
 #ifdef __tilegx__
-#include <arch/spr_def_64.h>
 
 /* TILE-Gx dependent, protection-level dependent SPRs. */
 
@@ -65,7 +73,6 @@
        _concat4(INT_SINGLE_STEP_, CONFIG_KERNEL_PL,,)
 
 #else
-#include <arch/spr_def_32.h>
 
 /* TILEPro dependent, protection-level dependent SPRs. */
 
        _concat4(SPR_INTCTRL_, CONFIG_KERNEL_PL, _STATUS,)
 #define INT_INTCTRL_K \
        _concat4(INT_INTCTRL_, CONFIG_KERNEL_PL,,)
+
+#endif /* __KERNEL__ */
diff --git a/arch/tile/include/arch/spr_def_64.h b/arch/tile/include/arch/spr_def_64.h
new file mode 100644 (file)
index 0000000..cd3e5f9
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef __DOXYGEN__
+
+#ifndef __ARCH_SPR_DEF_H__
+#define __ARCH_SPR_DEF_H__
+
+#define SPR_AUX_PERF_COUNT_0 0x2105
+#define SPR_AUX_PERF_COUNT_1 0x2106
+#define SPR_AUX_PERF_COUNT_CTL 0x2107
+#define SPR_AUX_PERF_COUNT_STS 0x2108
+#define SPR_CMPEXCH_VALUE 0x2780
+#define SPR_CYCLE 0x2781
+#define SPR_DONE 0x2705
+#define SPR_DSTREAM_PF 0x2706
+#define SPR_EVENT_BEGIN 0x2782
+#define SPR_EVENT_END 0x2783
+#define SPR_EX_CONTEXT_0_0 0x2580
+#define SPR_EX_CONTEXT_0_1 0x2581
+#define SPR_EX_CONTEXT_0_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_0_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_0_1__PL_MASK  0x3
+#define SPR_EX_CONTEXT_0_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_0_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_0_1__ICS_MASK  0x4
+#define SPR_EX_CONTEXT_1_0 0x2480
+#define SPR_EX_CONTEXT_1_1 0x2481
+#define SPR_EX_CONTEXT_1_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_1_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_1_1__PL_MASK  0x3
+#define SPR_EX_CONTEXT_1_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_1_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_1_1__ICS_MASK  0x4
+#define SPR_EX_CONTEXT_2_0 0x2380
+#define SPR_EX_CONTEXT_2_1 0x2381
+#define SPR_EX_CONTEXT_2_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_2_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_2_1__PL_MASK  0x3
+#define SPR_EX_CONTEXT_2_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_2_1__ICS_MASK  0x4
+#define SPR_FAIL 0x2707
+#define SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK 0x1
+#define SPR_INTCTRL_0_STATUS 0x2505
+#define SPR_INTCTRL_1_STATUS 0x2405
+#define SPR_INTCTRL_2_STATUS 0x2305
+#define SPR_INTERRUPT_CRITICAL_SECTION 0x2708
+#define SPR_INTERRUPT_MASK_0 0x2506
+#define SPR_INTERRUPT_MASK_1 0x2406
+#define SPR_INTERRUPT_MASK_2 0x2306
+#define SPR_INTERRUPT_MASK_RESET_0 0x2507
+#define SPR_INTERRUPT_MASK_RESET_1 0x2407
+#define SPR_INTERRUPT_MASK_RESET_2 0x2307
+#define SPR_INTERRUPT_MASK_SET_0 0x2508
+#define SPR_INTERRUPT_MASK_SET_1 0x2408
+#define SPR_INTERRUPT_MASK_SET_2 0x2308
+#define SPR_INTERRUPT_VECTOR_BASE_0 0x2509
+#define SPR_INTERRUPT_VECTOR_BASE_1 0x2409
+#define SPR_INTERRUPT_VECTOR_BASE_2 0x2309
+#define SPR_INTERRUPT_VECTOR_BASE_3 0x2209
+#define SPR_IPI_EVENT_0 0x1f05
+#define SPR_IPI_EVENT_1 0x1e05
+#define SPR_IPI_EVENT_2 0x1d05
+#define SPR_IPI_EVENT_RESET_0 0x1f06
+#define SPR_IPI_EVENT_RESET_1 0x1e06
+#define SPR_IPI_EVENT_RESET_2 0x1d06
+#define SPR_IPI_EVENT_SET_0 0x1f07
+#define SPR_IPI_EVENT_SET_1 0x1e07
+#define SPR_IPI_EVENT_SET_2 0x1d07
+#define SPR_IPI_MASK_0 0x1f08
+#define SPR_IPI_MASK_1 0x1e08
+#define SPR_IPI_MASK_2 0x1d08
+#define SPR_IPI_MASK_RESET_0 0x1f09
+#define SPR_IPI_MASK_RESET_1 0x1e09
+#define SPR_IPI_MASK_RESET_2 0x1d09
+#define SPR_IPI_MASK_SET_0 0x1f0a
+#define SPR_IPI_MASK_SET_1 0x1e0a
+#define SPR_IPI_MASK_SET_2 0x1d0a
+#define SPR_MPL_AUX_TILE_TIMER_SET_0 0x1700
+#define SPR_MPL_AUX_TILE_TIMER_SET_1 0x1701
+#define SPR_MPL_AUX_TILE_TIMER_SET_2 0x1702
+#define SPR_MPL_INTCTRL_0_SET_0 0x2500
+#define SPR_MPL_INTCTRL_0_SET_1 0x2501
+#define SPR_MPL_INTCTRL_0_SET_2 0x2502
+#define SPR_MPL_INTCTRL_1_SET_0 0x2400
+#define SPR_MPL_INTCTRL_1_SET_1 0x2401
+#define SPR_MPL_INTCTRL_1_SET_2 0x2402
+#define SPR_MPL_INTCTRL_2_SET_0 0x2300
+#define SPR_MPL_INTCTRL_2_SET_1 0x2301
+#define SPR_MPL_INTCTRL_2_SET_2 0x2302
+#define SPR_MPL_UDN_ACCESS_SET_0 0x0b00
+#define SPR_MPL_UDN_ACCESS_SET_1 0x0b01
+#define SPR_MPL_UDN_ACCESS_SET_2 0x0b02
+#define SPR_MPL_UDN_AVAIL_SET_0 0x1b00
+#define SPR_MPL_UDN_AVAIL_SET_1 0x1b01
+#define SPR_MPL_UDN_AVAIL_SET_2 0x1b02
+#define SPR_MPL_UDN_COMPLETE_SET_0 0x0600
+#define SPR_MPL_UDN_COMPLETE_SET_1 0x0601
+#define SPR_MPL_UDN_COMPLETE_SET_2 0x0602
+#define SPR_MPL_UDN_FIREWALL_SET_0 0x1500
+#define SPR_MPL_UDN_FIREWALL_SET_1 0x1501
+#define SPR_MPL_UDN_FIREWALL_SET_2 0x1502
+#define SPR_MPL_UDN_TIMER_SET_0 0x1900
+#define SPR_MPL_UDN_TIMER_SET_1 0x1901
+#define SPR_MPL_UDN_TIMER_SET_2 0x1902
+#define SPR_MPL_WORLD_ACCESS_SET_0 0x2700
+#define SPR_MPL_WORLD_ACCESS_SET_1 0x2701
+#define SPR_MPL_WORLD_ACCESS_SET_2 0x2702
+#define SPR_PASS 0x2709
+#define SPR_PERF_COUNT_0 0x2005
+#define SPR_PERF_COUNT_1 0x2006
+#define SPR_PERF_COUNT_CTL 0x2007
+#define SPR_PERF_COUNT_DN_CTL 0x2008
+#define SPR_PERF_COUNT_STS 0x2009
+#define SPR_PROC_STATUS 0x2784
+#define SPR_SIM_CONTROL 0x2785
+#define SPR_SINGLE_STEP_CONTROL_0 0x0405
+#define SPR_SINGLE_STEP_CONTROL_0__CANCELED_MASK  0x1
+#define SPR_SINGLE_STEP_CONTROL_0__INHIBIT_MASK  0x2
+#define SPR_SINGLE_STEP_CONTROL_1 0x0305
+#define SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK  0x1
+#define SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK  0x2
+#define SPR_SINGLE_STEP_CONTROL_2 0x0205
+#define SPR_SINGLE_STEP_CONTROL_2__CANCELED_MASK  0x1
+#define SPR_SINGLE_STEP_CONTROL_2__INHIBIT_MASK  0x2
+#define SPR_SINGLE_STEP_EN_0_0 0x250a
+#define SPR_SINGLE_STEP_EN_0_1 0x240a
+#define SPR_SINGLE_STEP_EN_0_2 0x230a
+#define SPR_SINGLE_STEP_EN_1_0 0x250b
+#define SPR_SINGLE_STEP_EN_1_1 0x240b
+#define SPR_SINGLE_STEP_EN_1_2 0x230b
+#define SPR_SINGLE_STEP_EN_2_0 0x250c
+#define SPR_SINGLE_STEP_EN_2_1 0x240c
+#define SPR_SINGLE_STEP_EN_2_2 0x230c
+#define SPR_SYSTEM_SAVE_0_0 0x2582
+#define SPR_SYSTEM_SAVE_0_1 0x2583
+#define SPR_SYSTEM_SAVE_0_2 0x2584
+#define SPR_SYSTEM_SAVE_0_3 0x2585
+#define SPR_SYSTEM_SAVE_1_0 0x2482
+#define SPR_SYSTEM_SAVE_1_1 0x2483
+#define SPR_SYSTEM_SAVE_1_2 0x2484
+#define SPR_SYSTEM_SAVE_1_3 0x2485
+#define SPR_SYSTEM_SAVE_2_0 0x2382
+#define SPR_SYSTEM_SAVE_2_1 0x2383
+#define SPR_SYSTEM_SAVE_2_2 0x2384
+#define SPR_SYSTEM_SAVE_2_3 0x2385
+#define SPR_TILE_COORD 0x270b
+#define SPR_TILE_RTF_HWM 0x270c
+#define SPR_TILE_TIMER_CONTROL 0x1605
+#define SPR_UDN_AVAIL_EN 0x1b05
+#define SPR_UDN_DATA_AVAIL 0x0b80
+#define SPR_UDN_DEADLOCK_TIMEOUT 0x1906
+#define SPR_UDN_DEMUX_COUNT_0 0x0b05
+#define SPR_UDN_DEMUX_COUNT_1 0x0b06
+#define SPR_UDN_DEMUX_COUNT_2 0x0b07
+#define SPR_UDN_DEMUX_COUNT_3 0x0b08
+#define SPR_UDN_DIRECTION_PROTECT 0x1505
+
+#endif /* !defined(__ARCH_SPR_DEF_H__) */
+
+#endif /* !defined(__DOXYGEN__) */
index 75a16028a95294ebfb67fbcca5e3c0b404a57bcb..739cfe0499d1da5e682f342e0c2ade78d8905e00 100644 (file)
@@ -130,17 +130,52 @@ static inline int atomic_read(const atomic_t *v)
  */
 #define atomic_inc_not_zero(v)         atomic_add_unless((v), 1, 0)
 
-
-/*
- * We define xchg() and cmpxchg() in the included headers.
- * Note that we do not define __HAVE_ARCH_CMPXCHG, since that would imply
- * that cmpxchg() is an efficient operation, which is not particularly true.
- */
-
 /* Nonexistent functions intended to cause link errors. */
 extern unsigned long __xchg_called_with_bad_pointer(void);
 extern unsigned long __cmpxchg_called_with_bad_pointer(void);
 
+#define xchg(ptr, x)                                                   \
+       ({                                                              \
+               typeof(*(ptr)) __x;                                     \
+               switch (sizeof(*(ptr))) {                               \
+               case 4:                                                 \
+                       __x = (typeof(__x))(typeof(__x-__x))atomic_xchg( \
+                               (atomic_t *)(ptr),                      \
+                               (u32)(typeof((x)-(x)))(x));             \
+                       break;                                          \
+               case 8:                                                 \
+                       __x = (typeof(__x))(typeof(__x-__x))atomic64_xchg( \
+                               (atomic64_t *)(ptr),                    \
+                               (u64)(typeof((x)-(x)))(x));             \
+                       break;                                          \
+               default:                                                \
+                       __xchg_called_with_bad_pointer();               \
+               }                                                       \
+               __x;                                                    \
+       })
+
+#define cmpxchg(ptr, o, n)                                             \
+       ({                                                              \
+               typeof(*(ptr)) __x;                                     \
+               switch (sizeof(*(ptr))) {                               \
+               case 4:                                                 \
+                       __x = (typeof(__x))(typeof(__x-__x))atomic_cmpxchg( \
+                               (atomic_t *)(ptr),                      \
+                               (u32)(typeof((o)-(o)))(o),              \
+                               (u32)(typeof((n)-(n)))(n));             \
+                       break;                                          \
+               case 8:                                                 \
+                       __x = (typeof(__x))(typeof(__x-__x))atomic64_cmpxchg( \
+                               (atomic64_t *)(ptr),                    \
+                               (u64)(typeof((o)-(o)))(o),              \
+                               (u64)(typeof((n)-(n)))(n));             \
+                       break;                                          \
+               default:                                                \
+                       __cmpxchg_called_with_bad_pointer();            \
+               }                                                       \
+               __x;                                                    \
+       })
+
 #define tas(ptr) (xchg((ptr), 1))
 
 #endif /* __ASSEMBLY__ */
index ed359aee88375f1d5257ac6d21fbebe84d7a350c..92a8bee323113520374d917155c7be3dcc358726 100644 (file)
@@ -110,16 +110,6 @@ static inline void atomic_set(atomic_t *v, int n)
        _atomic_xchg(v, n);
 }
 
-#define xchg(ptr, x) ((typeof(*(ptr))) \
-  ((sizeof(*(ptr)) == sizeof(atomic_t)) ? \
-   atomic_xchg((atomic_t *)(ptr), (long)(x)) : \
-   __xchg_called_with_bad_pointer()))
-
-#define cmpxchg(ptr, o, n) ((typeof(*(ptr))) \
-  ((sizeof(*(ptr)) == sizeof(atomic_t)) ? \
-   atomic_cmpxchg((atomic_t *)(ptr), (long)(o), (long)(n)) : \
-   __cmpxchg_called_with_bad_pointer()))
-
 /* A 64bit atomic type */
 
 typedef struct {
diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h
new file mode 100644 (file)
index 0000000..1c1e60d
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Do not include directly; use <asm/atomic.h>.
+ */
+
+#ifndef _ASM_TILE_ATOMIC_64_H
+#define _ASM_TILE_ATOMIC_64_H
+
+#ifndef __ASSEMBLY__
+
+#include <arch/spr_def.h>
+
+/* First, the 32-bit atomic ops that are "real" on our 64-bit platform. */
+
+#define atomic_set(v, i) ((v)->counter = (i))
+
+/*
+ * The smp_mb() operations throughout are to support the fact that
+ * Linux requires memory barriers before and after the operation,
+ * on any routine which updates memory and returns a value.
+ */
+
+static inline int atomic_cmpxchg(atomic_t *v, int o, int n)
+{
+       int val;
+       __insn_mtspr(SPR_CMPEXCH_VALUE, o);
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_cmpexch4((void *)&v->counter, n);
+       smp_mb();  /* barrier for proper semantics */
+       return val;
+}
+
+static inline int atomic_xchg(atomic_t *v, int n)
+{
+       int val;
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_exch4((void *)&v->counter, n);
+       smp_mb();  /* barrier for proper semantics */
+       return val;
+}
+
+static inline void atomic_add(int i, atomic_t *v)
+{
+       __insn_fetchadd4((void *)&v->counter, i);
+}
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+       int val;
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_fetchadd4((void *)&v->counter, i) + i;
+       barrier();  /* the "+ i" above will wait on memory */
+       return val;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+       int guess, oldval = v->counter;
+       do {
+               if (oldval == u)
+                       break;
+               guess = oldval;
+               oldval = atomic_cmpxchg(v, guess, guess + a);
+       } while (guess != oldval);
+       return oldval != u;
+}
+
+/* Now the true 64-bit operations. */
+
+#define ATOMIC64_INIT(i)       { (i) }
+
+#define atomic64_read(v)               ((v)->counter)
+#define atomic64_set(v, i) ((v)->counter = (i))
+
+static inline long atomic64_cmpxchg(atomic64_t *v, long o, long n)
+{
+       long val;
+       smp_mb();  /* barrier for proper semantics */
+       __insn_mtspr(SPR_CMPEXCH_VALUE, o);
+       val = __insn_cmpexch((void *)&v->counter, n);
+       smp_mb();  /* barrier for proper semantics */
+       return val;
+}
+
+static inline long atomic64_xchg(atomic64_t *v, long n)
+{
+       long val;
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_exch((void *)&v->counter, n);
+       smp_mb();  /* barrier for proper semantics */
+       return val;
+}
+
+static inline void atomic64_add(long i, atomic64_t *v)
+{
+       __insn_fetchadd((void *)&v->counter, i);
+}
+
+static inline long atomic64_add_return(long i, atomic64_t *v)
+{
+       int val;
+       smp_mb();  /* barrier for proper semantics */
+       val = __insn_fetchadd((void *)&v->counter, i) + i;
+       barrier();  /* the "+ i" above will wait on memory */
+       return val;
+}
+
+static inline long atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+       long guess, oldval = v->counter;
+       do {
+               if (oldval == u)
+                       break;
+               guess = oldval;
+               oldval = atomic64_cmpxchg(v, guess, guess + a);
+       } while (guess != oldval);
+       return oldval != u;
+}
+
+#define atomic64_sub_return(i, v)      atomic64_add_return(-(i), (v))
+#define atomic64_sub(i, v)             atomic64_add(-(i), (v))
+#define atomic64_inc_return(v)         atomic64_add_return(1, (v))
+#define atomic64_dec_return(v)         atomic64_sub_return(1, (v))
+#define atomic64_inc(v)                        atomic64_add(1, (v))
+#define atomic64_dec(v)                        atomic64_sub(1, (v))
+
+#define atomic64_inc_and_test(v)       (atomic64_inc_return(v) == 0)
+#define atomic64_dec_and_test(v)       (atomic64_dec_return(v) == 0)
+#define atomic64_sub_and_test(i, v)    (atomic64_sub_return((i), (v)) == 0)
+#define atomic64_add_negative(i, v)    (atomic64_add_return((i), (v)) < 0)
+
+#define atomic64_inc_not_zero(v)       atomic64_add_unless((v), 1, 0)
+
+/* Atomic dec and inc don't implement barrier, so provide them if needed. */
+#define smp_mb__before_atomic_dec()    smp_mb()
+#define smp_mb__after_atomic_dec()     smp_mb()
+#define smp_mb__before_atomic_inc()    smp_mb()
+#define smp_mb__after_atomic_inc()     smp_mb()
+
+/* Define this to indicate that cmpxchg is an efficient operation. */
+#define __HAVE_ARCH_CMPXCHG
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_ATOMIC_64_H */
index f18887d823999f8a7778defa2196ab10b586b81d..bd5399a69edf011bf23b4e51a9828b772f8de3cd 100644 (file)
  *   more details.
  */
 
-#ifndef _TILE_BACKTRACE_H
-#define _TILE_BACKTRACE_H
-
-
+#ifndef _ASM_TILE_BACKTRACE_H
+#define _ASM_TILE_BACKTRACE_H
 
 #include <linux/types.h>
 
-#include <arch/chip.h>
-
-#if defined(__tile__)
-typedef unsigned long VirtualAddress;
-#elif CHIP_VA_WIDTH() > 32
-typedef unsigned long long VirtualAddress;
-#else
-typedef unsigned int VirtualAddress;
-#endif
-
-
-/** Reads 'size' bytes from 'address' and writes the data to 'result'.
+/* Reads 'size' bytes from 'address' and writes the data to 'result'.
  * Returns true if successful, else false (e.g. memory not readable).
  */
 typedef bool (*BacktraceMemoryReader)(void *result,
-                                     VirtualAddress address,
+                                     unsigned long address,
                                      unsigned int size,
                                      void *extra);
 
 typedef struct {
-       /** Current PC. */
-       VirtualAddress pc;
+       /* Current PC. */
+       unsigned long pc;
 
-       /** Current stack pointer value. */
-       VirtualAddress sp;
+       /* Current stack pointer value. */
+       unsigned long sp;
 
-       /** Current frame pointer value (i.e. caller's stack pointer) */
-       VirtualAddress fp;
+       /* Current frame pointer value (i.e. caller's stack pointer) */
+       unsigned long fp;
 
-       /** Internal use only: caller's PC for first frame. */
-       VirtualAddress initial_frame_caller_pc;
+       /* Internal use only: caller's PC for first frame. */
+       unsigned long initial_frame_caller_pc;
 
-       /** Internal use only: callback to read memory. */
+       /* Internal use only: callback to read memory. */
        BacktraceMemoryReader read_memory_func;
 
-       /** Internal use only: arbitrary argument to read_memory_func. */
+       /* Internal use only: arbitrary argument to read_memory_func. */
        void *read_memory_func_extra;
 
 } BacktraceIterator;
 
 
-/** Initializes a backtracer to start from the given location.
- *
- * If the frame pointer cannot be determined it is set to -1.
- *
- * @param state The state to be filled in.
- * @param read_memory_func A callback that reads memory. If NULL, a default
- *        value is provided.
- * @param read_memory_func_extra An arbitrary argument to read_memory_func.
- * @param pc The current PC.
- * @param lr The current value of the 'lr' register.
- * @param sp The current value of the 'sp' register.
- * @param r52 The current value of the 'r52' register.
- */
-extern void backtrace_init(BacktraceIterator *state,
-                          BacktraceMemoryReader read_memory_func,
-                          void *read_memory_func_extra,
-                          VirtualAddress pc, VirtualAddress lr,
-                          VirtualAddress sp, VirtualAddress r52);
-
-
-/** Advances the backtracing state to the calling frame, returning
- * true iff successful.
- */
-extern bool backtrace_next(BacktraceIterator *state);
-
-
 typedef enum {
 
        /* We have no idea what the caller's pc is. */
@@ -138,7 +99,7 @@ enum {
 };
 
 
-/** Internal constants used to define 'info' operands. */
+/* Internal constants used to define 'info' operands. */
 enum {
        /* 0 and 1 are reserved, as are all negative numbers. */
 
@@ -147,13 +108,10 @@ enum {
        CALLER_SP_IN_R52_BASE = 4,
 
        CALLER_SP_OFFSET_BASE = 8,
-
-       /* Marks the entry point of certain functions. */
-       ENTRY_POINT_INFO_OP = 16
 };
 
 
-/** Current backtracer state describing where it thinks the caller is. */
+/* Current backtracer state describing where it thinks the caller is. */
 typedef struct {
        /*
         * Public fields
@@ -192,7 +150,13 @@ typedef struct {
 
 } CallerLocation;
 
+extern void backtrace_init(BacktraceIterator *state,
+                          BacktraceMemoryReader read_memory_func,
+                          void *read_memory_func_extra,
+                          unsigned long pc, unsigned long lr,
+                          unsigned long sp, unsigned long r52);
 
 
+extern bool backtrace_next(BacktraceIterator *state);
 
-#endif /* _TILE_BACKTRACE_H */
+#endif /* _ASM_TILE_BACKTRACE_H */
index 132e6bbd07e911e02f6abba5586db0c6d7d9456a..16f1fa51fea13de4139c5a18c2d10088b8e395c1 100644 (file)
@@ -122,6 +122,7 @@ static inline unsigned long __arch_hweight64(__u64 w)
 #include <asm-generic/bitops/lock.h>
 #include <asm-generic/bitops/find.h>
 #include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/non-atomic.h>
 #include <asm-generic/bitops/le.h>
 
 #endif /* _ASM_TILE_BITOPS_H */
index 2638be51a16438989987a20146584879bd06ae76..d31ab905cfa7105b4ba32bcc03db55c8e0a74be1 100644 (file)
@@ -126,7 +126,6 @@ static inline int test_and_change_bit(unsigned nr,
 #define smp_mb__before_clear_bit()     smp_mb()
 #define smp_mb__after_clear_bit()      do {} while (0)
 
-#include <asm-generic/bitops/non-atomic.h>
 #include <asm-generic/bitops/ext2-atomic.h>
 
 #endif /* _ASM_TILE_BITOPS_32_H */
diff --git a/arch/tile/include/asm/bitops_64.h b/arch/tile/include/asm/bitops_64.h
new file mode 100644 (file)
index 0000000..99615e8
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _ASM_TILE_BITOPS_64_H
+#define _ASM_TILE_BITOPS_64_H
+
+#include <linux/compiler.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+/* See <asm/bitops.h> for API comments. */
+
+static inline void set_bit(unsigned nr, volatile unsigned long *addr)
+{
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       __insn_fetchor((void *)(addr + nr / BITS_PER_LONG), mask);
+}
+
+static inline void clear_bit(unsigned nr, volatile unsigned long *addr)
+{
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       __insn_fetchand((void *)(addr + nr / BITS_PER_LONG), ~mask);
+}
+
+#define smp_mb__before_clear_bit()     smp_mb()
+#define smp_mb__after_clear_bit()      smp_mb()
+
+
+static inline void change_bit(unsigned nr, volatile unsigned long *addr)
+{
+       unsigned long old, mask = (1UL << (nr % BITS_PER_LONG));
+       long guess, oldval;
+       addr += nr / BITS_PER_LONG;
+       old = *addr;
+       do {
+               guess = oldval;
+               oldval = atomic64_cmpxchg((atomic64_t *)addr,
+                                         guess, guess ^ mask);
+       } while (guess != oldval);
+}
+
+
+/*
+ * The test_and_xxx_bit() routines require a memory fence before we
+ * start the operation, and after the operation completes.  We use
+ * smp_mb() before, and rely on the "!= 0" comparison, plus a compiler
+ * barrier(), to block until the atomic op is complete.
+ */
+
+static inline int test_and_set_bit(unsigned nr, volatile unsigned long *addr)
+{
+       int val;
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       smp_mb();  /* barrier for proper semantics */
+       val = (__insn_fetchor((void *)(addr + nr / BITS_PER_LONG), mask)
+              & mask) != 0;
+       barrier();
+       return val;
+}
+
+
+static inline int test_and_clear_bit(unsigned nr, volatile unsigned long *addr)
+{
+       int val;
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       smp_mb();  /* barrier for proper semantics */
+       val = (__insn_fetchand((void *)(addr + nr / BITS_PER_LONG), ~mask)
+              & mask) != 0;
+       barrier();
+       return val;
+}
+
+
+static inline int test_and_change_bit(unsigned nr,
+                                     volatile unsigned long *addr)
+{
+       unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+       long guess, oldval = *addr;
+       addr += nr / BITS_PER_LONG;
+       oldval = *addr;
+       do {
+               guess = oldval;
+               oldval = atomic64_cmpxchg((atomic64_t *)addr,
+                                         guess, guess ^ mask);
+       } while (guess != oldval);
+       return (oldval & mask) != 0;
+}
+
+#define ext2_set_bit_atomic(lock, nr, addr)                    \
+       test_and_set_bit((nr), (unsigned long *)(addr))
+#define ext2_clear_bit_atomic(lock, nr, addr)                  \
+       test_and_clear_bit((nr), (unsigned long *)(addr))
+
+#endif /* _ASM_TILE_BITOPS_64_H */
index 12fb0fb330ee95895360a5ddc4287e3efc0917d2..e925f4bb498f40f93b1ffe6a04390f9732c2ffdb 100644 (file)
@@ -116,22 +116,28 @@ static inline void __finv_buffer(void *buffer, size_t size)
 }
 
 
-/* Invalidate a VA range, then memory fence. */
+/* Invalidate a VA range and wait for it to be complete. */
 static inline void inv_buffer(void *buffer, size_t size)
 {
        __inv_buffer(buffer, size);
-       mb_incoherent();
+       mb();
 }
 
-/* Flush a VA range, then memory fence. */
-static inline void flush_buffer(void *buffer, size_t size)
+/*
+ * Flush a locally-homecached VA range and wait for the evicted
+ * cachelines to hit memory.
+ */
+static inline void flush_buffer_local(void *buffer, size_t size)
 {
        __flush_buffer(buffer, size);
        mb_incoherent();
 }
 
-/* Flush & invalidate a VA range, then memory fence. */
-static inline void finv_buffer(void *buffer, size_t size)
+/*
+ * Flush and invalidate a locally-homecached VA range and wait for the
+ * evicted cachelines to hit memory.
+ */
+static inline void finv_buffer_local(void *buffer, size_t size)
 {
        __finv_buffer(buffer, size);
        mb_incoherent();
index c3ae570c0a5d9ef209970d6d00a388a3128e550a..bf95f55b82b04e77c0e93ac8e28391c820ecaa08 100644 (file)
@@ -215,8 +215,8 @@ struct compat_sigaction;
 struct compat_siginfo;
 struct compat_sigaltstack;
 long compat_sys_execve(const char __user *path,
-                      const compat_uptr_t __user *argv,
-                      const compat_uptr_t __user *envp, struct pt_regs *);
+                      compat_uptr_t __user *argv,
+                      compat_uptr_t __user *envp, struct pt_regs *);
 long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
                             struct compat_sigaction __user *oact,
                             size_t sigsetsize);
index 15e1dceecc646186d21a95eebf372ab5cc9f42cb..eaa06d175b39d3af86d91f2761058ffb6fc1fc27 100644 (file)
@@ -65,7 +65,8 @@ extern void dma_sync_single_range_for_cpu(struct device *, dma_addr_t,
 extern void dma_sync_single_range_for_device(struct device *, dma_addr_t,
                                             unsigned long offset, size_t,
                                             enum dma_data_direction);
-extern void dma_cache_sync(void *vaddr, size_t, enum dma_data_direction);
+extern void dma_cache_sync(struct device *dev, void *vaddr, size_t,
+                          enum dma_data_direction);
 
 static inline int
 dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/arch/tile/include/asm/fb.h b/arch/tile/include/asm/fb.h
new file mode 100644 (file)
index 0000000..3a4988e
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/fb.h>
index d3cbb9b14cbe4b7950575c46b6f8b34312f42a78..c9ea1652af03c609f355ec12c456a45e0dd826f3 100644 (file)
@@ -52,6 +52,7 @@ extern void iounmap(volatile void __iomem *addr);
 #endif
 
 #define ioremap_nocache(physaddr, size)                ioremap(physaddr, size)
+#define ioremap_wc(physaddr, size)             ioremap(physaddr, size)
 #define ioremap_writethrough(physaddr, size)   ioremap(physaddr, size)
 #define ioremap_fullcache(physaddr, size)      ioremap(physaddr, size)
 
@@ -161,6 +162,15 @@ static inline void _tile_writeq(u64 val, unsigned long addr)
 #define iowrite32 writel
 #define iowrite64 writeq
 
+static inline void memset_io(void *dst, int val, size_t len)
+{
+       int x;
+       BUG_ON((unsigned long)dst & 0x3);
+       val = (val & 0xff) * 0x01010101;
+       for (x = 0; x < len; x += 4)
+               writel(val, dst + x);
+}
+
 static inline void memcpy_fromio(void *dst, const volatile void __iomem *src,
                                 size_t len)
 {
@@ -269,6 +279,11 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
        ioport_panic();
 }
 
+#define ioread16be(addr)       be16_to_cpu(ioread16(addr))
+#define ioread32be(addr)       be32_to_cpu(ioread32(addr))
+#define iowrite16be(v, addr)   iowrite16(be16_to_cpu(v), (addr))
+#define iowrite32be(v, addr)   iowrite32(be32_to_cpu(v), (addr))
+
 #define ioread8_rep(p, dst, count) \
        insb((unsigned long) (p), (dst), (count))
 #define ioread16_rep(p, dst, count) \
@@ -283,4 +298,7 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
 #define iowrite32_rep(p, src, count) \
        outsl((unsigned long) (p), (src), (count))
 
+#define virt_to_bus     virt_to_phys
+#define bus_to_virt     phys_to_virt
+
 #endif /* _ASM_TILE_IO_H */
index 572fd3ef1d7314daf51ee058376b75446649c076..94e9a511de849c925bcf28841368ce278feade0c 100644 (file)
@@ -23,6 +23,8 @@
 /* IRQ numbers used for linux IPIs. */
 #define IRQ_RESCHEDULE 1
 
+#define irq_canonicalize(irq)   (irq)
+
 void ack_bad_irq(unsigned int irq);
 
 /*
index 9bc0d0725c28da6ce73f026784dea406609adb88..15fb246411202d1ba1547a07132ff6bf2198f8fd 100644 (file)
@@ -100,8 +100,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                __get_cpu_var(current_asid) = asid;
 
                /* Clear cpu from the old mm, and set it in the new one. */
-               cpumask_clear_cpu(cpu, &prev->cpu_vm_mask);
-               cpumask_set_cpu(cpu, &next->cpu_vm_mask);
+               cpumask_clear_cpu(cpu, mm_cpumask(prev));
+               cpumask_set_cpu(cpu, mm_cpumask(next));
 
                /* Re-load page tables */
                install_page_table(next->pgd, asid);
index eda60ecbae3d5f924e42a56dea5bcbfc51ff4252..03df7b1e77bfef861fee0171c4d205bada39a414 100644 (file)
@@ -1502,5 +1502,12 @@ extern int parse_insn_tile(tile_bundle_bits bits,
                            decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
 
 
+/* Given a set of bundle bits and a specific pipe, returns which
+ * instruction the bundle contains in that pipe.
+ */
+extern const struct tile_opcode *
+find_opcode(tile_bundle_bits bits, tile_pipeline pipe);
+
+
 
 #endif /* opcode_tile_h */
index eda60ecbae3d5f924e42a56dea5bcbfc51ff4252..c0633466cd5ce49c9739c953268fea79ffcee559 100644 (file)
 #ifndef opcode_tile_h
 #define opcode_tile_h
 
-typedef unsigned long long tile_bundle_bits;
+typedef unsigned long long tilegx_bundle_bits;
 
 
 enum
 {
-  TILE_MAX_OPERANDS = 5 /* mm */
+  TILEGX_MAX_OPERANDS = 4 /* bfexts */
 };
 
 typedef enum
 {
-  TILE_OPC_BPT,
-  TILE_OPC_INFO,
-  TILE_OPC_INFOL,
-  TILE_OPC_J,
-  TILE_OPC_JAL,
-  TILE_OPC_MOVE,
-  TILE_OPC_MOVE_SN,
-  TILE_OPC_MOVEI,
-  TILE_OPC_MOVEI_SN,
-  TILE_OPC_MOVELI,
-  TILE_OPC_MOVELI_SN,
-  TILE_OPC_MOVELIS,
-  TILE_OPC_PREFETCH,
-  TILE_OPC_RAISE,
-  TILE_OPC_ADD,
-  TILE_OPC_ADD_SN,
-  TILE_OPC_ADDB,
-  TILE_OPC_ADDB_SN,
-  TILE_OPC_ADDBS_U,
-  TILE_OPC_ADDBS_U_SN,
-  TILE_OPC_ADDH,
-  TILE_OPC_ADDH_SN,
-  TILE_OPC_ADDHS,
-  TILE_OPC_ADDHS_SN,
-  TILE_OPC_ADDI,
-  TILE_OPC_ADDI_SN,
-  TILE_OPC_ADDIB,
-  TILE_OPC_ADDIB_SN,
-  TILE_OPC_ADDIH,
-  TILE_OPC_ADDIH_SN,
-  TILE_OPC_ADDLI,
-  TILE_OPC_ADDLI_SN,
-  TILE_OPC_ADDLIS,
-  TILE_OPC_ADDS,
-  TILE_OPC_ADDS_SN,
-  TILE_OPC_ADIFFB_U,
-  TILE_OPC_ADIFFB_U_SN,
-  TILE_OPC_ADIFFH,
-  TILE_OPC_ADIFFH_SN,
-  TILE_OPC_AND,
-  TILE_OPC_AND_SN,
-  TILE_OPC_ANDI,
-  TILE_OPC_ANDI_SN,
-  TILE_OPC_AULI,
-  TILE_OPC_AVGB_U,
-  TILE_OPC_AVGB_U_SN,
-  TILE_OPC_AVGH,
-  TILE_OPC_AVGH_SN,
-  TILE_OPC_BBNS,
-  TILE_OPC_BBNS_SN,
-  TILE_OPC_BBNST,
-  TILE_OPC_BBNST_SN,
-  TILE_OPC_BBS,
-  TILE_OPC_BBS_SN,
-  TILE_OPC_BBST,
-  TILE_OPC_BBST_SN,
-  TILE_OPC_BGEZ,
-  TILE_OPC_BGEZ_SN,
-  TILE_OPC_BGEZT,
-  TILE_OPC_BGEZT_SN,
-  TILE_OPC_BGZ,
-  TILE_OPC_BGZ_SN,
-  TILE_OPC_BGZT,
-  TILE_OPC_BGZT_SN,
-  TILE_OPC_BITX,
-  TILE_OPC_BITX_SN,
-  TILE_OPC_BLEZ,
-  TILE_OPC_BLEZ_SN,
-  TILE_OPC_BLEZT,
-  TILE_OPC_BLEZT_SN,
-  TILE_OPC_BLZ,
-  TILE_OPC_BLZ_SN,
-  TILE_OPC_BLZT,
-  TILE_OPC_BLZT_SN,
-  TILE_OPC_BNZ,
-  TILE_OPC_BNZ_SN,
-  TILE_OPC_BNZT,
-  TILE_OPC_BNZT_SN,
-  TILE_OPC_BYTEX,
-  TILE_OPC_BYTEX_SN,
-  TILE_OPC_BZ,
-  TILE_OPC_BZ_SN,
-  TILE_OPC_BZT,
-  TILE_OPC_BZT_SN,
-  TILE_OPC_CLZ,
-  TILE_OPC_CLZ_SN,
-  TILE_OPC_CRC32_32,
-  TILE_OPC_CRC32_32_SN,
-  TILE_OPC_CRC32_8,
-  TILE_OPC_CRC32_8_SN,
-  TILE_OPC_CTZ,
-  TILE_OPC_CTZ_SN,
-  TILE_OPC_DRAIN,
-  TILE_OPC_DTLBPR,
-  TILE_OPC_DWORD_ALIGN,
-  TILE_OPC_DWORD_ALIGN_SN,
-  TILE_OPC_FINV,
-  TILE_OPC_FLUSH,
-  TILE_OPC_FNOP,
-  TILE_OPC_ICOH,
-  TILE_OPC_ILL,
-  TILE_OPC_INTHB,
-  TILE_OPC_INTHB_SN,
-  TILE_OPC_INTHH,
-  TILE_OPC_INTHH_SN,
-  TILE_OPC_INTLB,
-  TILE_OPC_INTLB_SN,
-  TILE_OPC_INTLH,
-  TILE_OPC_INTLH_SN,
-  TILE_OPC_INV,
-  TILE_OPC_IRET,
-  TILE_OPC_JALB,
-  TILE_OPC_JALF,
-  TILE_OPC_JALR,
-  TILE_OPC_JALRP,
-  TILE_OPC_JB,
-  TILE_OPC_JF,
-  TILE_OPC_JR,
-  TILE_OPC_JRP,
-  TILE_OPC_LB,
-  TILE_OPC_LB_SN,
-  TILE_OPC_LB_U,
-  TILE_OPC_LB_U_SN,
-  TILE_OPC_LBADD,
-  TILE_OPC_LBADD_SN,
-  TILE_OPC_LBADD_U,
-  TILE_OPC_LBADD_U_SN,
-  TILE_OPC_LH,
-  TILE_OPC_LH_SN,
-  TILE_OPC_LH_U,
-  TILE_OPC_LH_U_SN,
-  TILE_OPC_LHADD,
-  TILE_OPC_LHADD_SN,
-  TILE_OPC_LHADD_U,
-  TILE_OPC_LHADD_U_SN,
-  TILE_OPC_LNK,
-  TILE_OPC_LNK_SN,
-  TILE_OPC_LW,
-  TILE_OPC_LW_SN,
-  TILE_OPC_LW_NA,
-  TILE_OPC_LW_NA_SN,
-  TILE_OPC_LWADD,
-  TILE_OPC_LWADD_SN,
-  TILE_OPC_LWADD_NA,
-  TILE_OPC_LWADD_NA_SN,
-  TILE_OPC_MAXB_U,
-  TILE_OPC_MAXB_U_SN,
-  TILE_OPC_MAXH,
-  TILE_OPC_MAXH_SN,
-  TILE_OPC_MAXIB_U,
-  TILE_OPC_MAXIB_U_SN,
-  TILE_OPC_MAXIH,
-  TILE_OPC_MAXIH_SN,
-  TILE_OPC_MF,
-  TILE_OPC_MFSPR,
-  TILE_OPC_MINB_U,
-  TILE_OPC_MINB_U_SN,
-  TILE_OPC_MINH,
-  TILE_OPC_MINH_SN,
-  TILE_OPC_MINIB_U,
-  TILE_OPC_MINIB_U_SN,
-  TILE_OPC_MINIH,
-  TILE_OPC_MINIH_SN,
-  TILE_OPC_MM,
-  TILE_OPC_MNZ,
-  TILE_OPC_MNZ_SN,
-  TILE_OPC_MNZB,
-  TILE_OPC_MNZB_SN,
-  TILE_OPC_MNZH,
-  TILE_OPC_MNZH_SN,
-  TILE_OPC_MTSPR,
-  TILE_OPC_MULHH_SS,
-  TILE_OPC_MULHH_SS_SN,
-  TILE_OPC_MULHH_SU,
-  TILE_OPC_MULHH_SU_SN,
-  TILE_OPC_MULHH_UU,
-  TILE_OPC_MULHH_UU_SN,
-  TILE_OPC_MULHHA_SS,
-  TILE_OPC_MULHHA_SS_SN,
-  TILE_OPC_MULHHA_SU,
-  TILE_OPC_MULHHA_SU_SN,
-  TILE_OPC_MULHHA_UU,
-  TILE_OPC_MULHHA_UU_SN,
-  TILE_OPC_MULHHSA_UU,
-  TILE_OPC_MULHHSA_UU_SN,
-  TILE_OPC_MULHL_SS,
-  TILE_OPC_MULHL_SS_SN,
-  TILE_OPC_MULHL_SU,
-  TILE_OPC_MULHL_SU_SN,
-  TILE_OPC_MULHL_US,
-  TILE_OPC_MULHL_US_SN,
-  TILE_OPC_MULHL_UU,
-  TILE_OPC_MULHL_UU_SN,
-  TILE_OPC_MULHLA_SS,
-  TILE_OPC_MULHLA_SS_SN,
-  TILE_OPC_MULHLA_SU,
-  TILE_OPC_MULHLA_SU_SN,
-  TILE_OPC_MULHLA_US,
-  TILE_OPC_MULHLA_US_SN,
-  TILE_OPC_MULHLA_UU,
-  TILE_OPC_MULHLA_UU_SN,
-  TILE_OPC_MULHLSA_UU,
-  TILE_OPC_MULHLSA_UU_SN,
-  TILE_OPC_MULLL_SS,
-  TILE_OPC_MULLL_SS_SN,
-  TILE_OPC_MULLL_SU,
-  TILE_OPC_MULLL_SU_SN,
-  TILE_OPC_MULLL_UU,
-  TILE_OPC_MULLL_UU_SN,
-  TILE_OPC_MULLLA_SS,
-  TILE_OPC_MULLLA_SS_SN,
-  TILE_OPC_MULLLA_SU,
-  TILE_OPC_MULLLA_SU_SN,
-  TILE_OPC_MULLLA_UU,
-  TILE_OPC_MULLLA_UU_SN,
-  TILE_OPC_MULLLSA_UU,
-  TILE_OPC_MULLLSA_UU_SN,
-  TILE_OPC_MVNZ,
-  TILE_OPC_MVNZ_SN,
-  TILE_OPC_MVZ,
-  TILE_OPC_MVZ_SN,
-  TILE_OPC_MZ,
-  TILE_OPC_MZ_SN,
-  TILE_OPC_MZB,
-  TILE_OPC_MZB_SN,
-  TILE_OPC_MZH,
-  TILE_OPC_MZH_SN,
-  TILE_OPC_NAP,
-  TILE_OPC_NOP,
-  TILE_OPC_NOR,
-  TILE_OPC_NOR_SN,
-  TILE_OPC_OR,
-  TILE_OPC_OR_SN,
-  TILE_OPC_ORI,
-  TILE_OPC_ORI_SN,
-  TILE_OPC_PACKBS_U,
-  TILE_OPC_PACKBS_U_SN,
-  TILE_OPC_PACKHB,
-  TILE_OPC_PACKHB_SN,
-  TILE_OPC_PACKHS,
-  TILE_OPC_PACKHS_SN,
-  TILE_OPC_PACKLB,
-  TILE_OPC_PACKLB_SN,
-  TILE_OPC_PCNT,
-  TILE_OPC_PCNT_SN,
-  TILE_OPC_RL,
-  TILE_OPC_RL_SN,
-  TILE_OPC_RLI,
-  TILE_OPC_RLI_SN,
-  TILE_OPC_S1A,
-  TILE_OPC_S1A_SN,
-  TILE_OPC_S2A,
-  TILE_OPC_S2A_SN,
-  TILE_OPC_S3A,
-  TILE_OPC_S3A_SN,
-  TILE_OPC_SADAB_U,
-  TILE_OPC_SADAB_U_SN,
-  TILE_OPC_SADAH,
-  TILE_OPC_SADAH_SN,
-  TILE_OPC_SADAH_U,
-  TILE_OPC_SADAH_U_SN,
-  TILE_OPC_SADB_U,
-  TILE_OPC_SADB_U_SN,
-  TILE_OPC_SADH,
-  TILE_OPC_SADH_SN,
-  TILE_OPC_SADH_U,
-  TILE_OPC_SADH_U_SN,
-  TILE_OPC_SB,
-  TILE_OPC_SBADD,
-  TILE_OPC_SEQ,
-  TILE_OPC_SEQ_SN,
-  TILE_OPC_SEQB,
-  TILE_OPC_SEQB_SN,
-  TILE_OPC_SEQH,
-  TILE_OPC_SEQH_SN,
-  TILE_OPC_SEQI,
-  TILE_OPC_SEQI_SN,
-  TILE_OPC_SEQIB,
-  TILE_OPC_SEQIB_SN,
-  TILE_OPC_SEQIH,
-  TILE_OPC_SEQIH_SN,
-  TILE_OPC_SH,
-  TILE_OPC_SHADD,
-  TILE_OPC_SHL,
-  TILE_OPC_SHL_SN,
-  TILE_OPC_SHLB,
-  TILE_OPC_SHLB_SN,
-  TILE_OPC_SHLH,
-  TILE_OPC_SHLH_SN,
-  TILE_OPC_SHLI,
-  TILE_OPC_SHLI_SN,
-  TILE_OPC_SHLIB,
-  TILE_OPC_SHLIB_SN,
-  TILE_OPC_SHLIH,
-  TILE_OPC_SHLIH_SN,
-  TILE_OPC_SHR,
-  TILE_OPC_SHR_SN,
-  TILE_OPC_SHRB,
-  TILE_OPC_SHRB_SN,
-  TILE_OPC_SHRH,
-  TILE_OPC_SHRH_SN,
-  TILE_OPC_SHRI,
-  TILE_OPC_SHRI_SN,
-  TILE_OPC_SHRIB,
-  TILE_OPC_SHRIB_SN,
-  TILE_OPC_SHRIH,
-  TILE_OPC_SHRIH_SN,
-  TILE_OPC_SLT,
-  TILE_OPC_SLT_SN,
-  TILE_OPC_SLT_U,
-  TILE_OPC_SLT_U_SN,
-  TILE_OPC_SLTB,
-  TILE_OPC_SLTB_SN,
-  TILE_OPC_SLTB_U,
-  TILE_OPC_SLTB_U_SN,
-  TILE_OPC_SLTE,
-  TILE_OPC_SLTE_SN,
-  TILE_OPC_SLTE_U,
-  TILE_OPC_SLTE_U_SN,
-  TILE_OPC_SLTEB,
-  TILE_OPC_SLTEB_SN,
-  TILE_OPC_SLTEB_U,
-  TILE_OPC_SLTEB_U_SN,
-  TILE_OPC_SLTEH,
-  TILE_OPC_SLTEH_SN,
-  TILE_OPC_SLTEH_U,
-  TILE_OPC_SLTEH_U_SN,
-  TILE_OPC_SLTH,
-  TILE_OPC_SLTH_SN,
-  TILE_OPC_SLTH_U,
-  TILE_OPC_SLTH_U_SN,
-  TILE_OPC_SLTI,
-  TILE_OPC_SLTI_SN,
-  TILE_OPC_SLTI_U,
-  TILE_OPC_SLTI_U_SN,
-  TILE_OPC_SLTIB,
-  TILE_OPC_SLTIB_SN,
-  TILE_OPC_SLTIB_U,
-  TILE_OPC_SLTIB_U_SN,
-  TILE_OPC_SLTIH,
-  TILE_OPC_SLTIH_SN,
-  TILE_OPC_SLTIH_U,
-  TILE_OPC_SLTIH_U_SN,
-  TILE_OPC_SNE,
-  TILE_OPC_SNE_SN,
-  TILE_OPC_SNEB,
-  TILE_OPC_SNEB_SN,
-  TILE_OPC_SNEH,
-  TILE_OPC_SNEH_SN,
-  TILE_OPC_SRA,
-  TILE_OPC_SRA_SN,
-  TILE_OPC_SRAB,
-  TILE_OPC_SRAB_SN,
-  TILE_OPC_SRAH,
-  TILE_OPC_SRAH_SN,
-  TILE_OPC_SRAI,
-  TILE_OPC_SRAI_SN,
-  TILE_OPC_SRAIB,
-  TILE_OPC_SRAIB_SN,
-  TILE_OPC_SRAIH,
-  TILE_OPC_SRAIH_SN,
-  TILE_OPC_SUB,
-  TILE_OPC_SUB_SN,
-  TILE_OPC_SUBB,
-  TILE_OPC_SUBB_SN,
-  TILE_OPC_SUBBS_U,
-  TILE_OPC_SUBBS_U_SN,
-  TILE_OPC_SUBH,
-  TILE_OPC_SUBH_SN,
-  TILE_OPC_SUBHS,
-  TILE_OPC_SUBHS_SN,
-  TILE_OPC_SUBS,
-  TILE_OPC_SUBS_SN,
-  TILE_OPC_SW,
-  TILE_OPC_SWADD,
-  TILE_OPC_SWINT0,
-  TILE_OPC_SWINT1,
-  TILE_OPC_SWINT2,
-  TILE_OPC_SWINT3,
-  TILE_OPC_TBLIDXB0,
-  TILE_OPC_TBLIDXB0_SN,
-  TILE_OPC_TBLIDXB1,
-  TILE_OPC_TBLIDXB1_SN,
-  TILE_OPC_TBLIDXB2,
-  TILE_OPC_TBLIDXB2_SN,
-  TILE_OPC_TBLIDXB3,
-  TILE_OPC_TBLIDXB3_SN,
-  TILE_OPC_TNS,
-  TILE_OPC_TNS_SN,
-  TILE_OPC_WH64,
-  TILE_OPC_XOR,
-  TILE_OPC_XOR_SN,
-  TILE_OPC_XORI,
-  TILE_OPC_XORI_SN,
-  TILE_OPC_NONE
-} tile_mnemonic;
+  TILEGX_OPC_BPT,
+  TILEGX_OPC_INFO,
+  TILEGX_OPC_INFOL,
+  TILEGX_OPC_MOVE,
+  TILEGX_OPC_MOVEI,
+  TILEGX_OPC_MOVELI,
+  TILEGX_OPC_PREFETCH,
+  TILEGX_OPC_PREFETCH_ADD_L1,
+  TILEGX_OPC_PREFETCH_ADD_L1_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L2,
+  TILEGX_OPC_PREFETCH_ADD_L2_FAULT,
+  TILEGX_OPC_PREFETCH_ADD_L3,
+  TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  TILEGX_OPC_PREFETCH_L1,
+  TILEGX_OPC_PREFETCH_L1_FAULT,
+  TILEGX_OPC_PREFETCH_L2,
+  TILEGX_OPC_PREFETCH_L2_FAULT,
+  TILEGX_OPC_PREFETCH_L3,
+  TILEGX_OPC_PREFETCH_L3_FAULT,
+  TILEGX_OPC_RAISE,
+  TILEGX_OPC_ADD,
+  TILEGX_OPC_ADDI,
+  TILEGX_OPC_ADDLI,
+  TILEGX_OPC_ADDX,
+  TILEGX_OPC_ADDXI,
+  TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXSC,
+  TILEGX_OPC_AND,
+  TILEGX_OPC_ANDI,
+  TILEGX_OPC_BEQZ,
+  TILEGX_OPC_BEQZT,
+  TILEGX_OPC_BFEXTS,
+  TILEGX_OPC_BFEXTU,
+  TILEGX_OPC_BFINS,
+  TILEGX_OPC_BGEZ,
+  TILEGX_OPC_BGEZT,
+  TILEGX_OPC_BGTZ,
+  TILEGX_OPC_BGTZT,
+  TILEGX_OPC_BLBC,
+  TILEGX_OPC_BLBCT,
+  TILEGX_OPC_BLBS,
+  TILEGX_OPC_BLBST,
+  TILEGX_OPC_BLEZ,
+  TILEGX_OPC_BLEZT,
+  TILEGX_OPC_BLTZ,
+  TILEGX_OPC_BLTZT,
+  TILEGX_OPC_BNEZ,
+  TILEGX_OPC_BNEZT,
+  TILEGX_OPC_CLZ,
+  TILEGX_OPC_CMOVEQZ,
+  TILEGX_OPC_CMOVNEZ,
+  TILEGX_OPC_CMPEQ,
+  TILEGX_OPC_CMPEQI,
+  TILEGX_OPC_CMPEXCH,
+  TILEGX_OPC_CMPEXCH4,
+  TILEGX_OPC_CMPLES,
+  TILEGX_OPC_CMPLEU,
+  TILEGX_OPC_CMPLTS,
+  TILEGX_OPC_CMPLTSI,
+  TILEGX_OPC_CMPLTU,
+  TILEGX_OPC_CMPLTUI,
+  TILEGX_OPC_CMPNE,
+  TILEGX_OPC_CMUL,
+  TILEGX_OPC_CMULA,
+  TILEGX_OPC_CMULAF,
+  TILEGX_OPC_CMULF,
+  TILEGX_OPC_CMULFR,
+  TILEGX_OPC_CMULH,
+  TILEGX_OPC_CMULHR,
+  TILEGX_OPC_CRC32_32,
+  TILEGX_OPC_CRC32_8,
+  TILEGX_OPC_CTZ,
+  TILEGX_OPC_DBLALIGN,
+  TILEGX_OPC_DBLALIGN2,
+  TILEGX_OPC_DBLALIGN4,
+  TILEGX_OPC_DBLALIGN6,
+  TILEGX_OPC_DRAIN,
+  TILEGX_OPC_DTLBPR,
+  TILEGX_OPC_EXCH,
+  TILEGX_OPC_EXCH4,
+  TILEGX_OPC_FDOUBLE_ADD_FLAGS,
+  TILEGX_OPC_FDOUBLE_ADDSUB,
+  TILEGX_OPC_FDOUBLE_MUL_FLAGS,
+  TILEGX_OPC_FDOUBLE_PACK1,
+  TILEGX_OPC_FDOUBLE_PACK2,
+  TILEGX_OPC_FDOUBLE_SUB_FLAGS,
+  TILEGX_OPC_FDOUBLE_UNPACK_MAX,
+  TILEGX_OPC_FDOUBLE_UNPACK_MIN,
+  TILEGX_OPC_FETCHADD,
+  TILEGX_OPC_FETCHADD4,
+  TILEGX_OPC_FETCHADDGEZ,
+  TILEGX_OPC_FETCHADDGEZ4,
+  TILEGX_OPC_FETCHAND,
+  TILEGX_OPC_FETCHAND4,
+  TILEGX_OPC_FETCHOR,
+  TILEGX_OPC_FETCHOR4,
+  TILEGX_OPC_FINV,
+  TILEGX_OPC_FLUSH,
+  TILEGX_OPC_FLUSHWB,
+  TILEGX_OPC_FNOP,
+  TILEGX_OPC_FSINGLE_ADD1,
+  TILEGX_OPC_FSINGLE_ADDSUB2,
+  TILEGX_OPC_FSINGLE_MUL1,
+  TILEGX_OPC_FSINGLE_MUL2,
+  TILEGX_OPC_FSINGLE_PACK1,
+  TILEGX_OPC_FSINGLE_PACK2,
+  TILEGX_OPC_FSINGLE_SUB1,
+  TILEGX_OPC_ICOH,
+  TILEGX_OPC_ILL,
+  TILEGX_OPC_INV,
+  TILEGX_OPC_IRET,
+  TILEGX_OPC_J,
+  TILEGX_OPC_JAL,
+  TILEGX_OPC_JALR,
+  TILEGX_OPC_JALRP,
+  TILEGX_OPC_JR,
+  TILEGX_OPC_JRP,
+  TILEGX_OPC_LD,
+  TILEGX_OPC_LD1S,
+  TILEGX_OPC_LD1S_ADD,
+  TILEGX_OPC_LD1U,
+  TILEGX_OPC_LD1U_ADD,
+  TILEGX_OPC_LD2S,
+  TILEGX_OPC_LD2S_ADD,
+  TILEGX_OPC_LD2U,
+  TILEGX_OPC_LD2U_ADD,
+  TILEGX_OPC_LD4S,
+  TILEGX_OPC_LD4S_ADD,
+  TILEGX_OPC_LD4U,
+  TILEGX_OPC_LD4U_ADD,
+  TILEGX_OPC_LD_ADD,
+  TILEGX_OPC_LDNA,
+  TILEGX_OPC_LDNA_ADD,
+  TILEGX_OPC_LDNT,
+  TILEGX_OPC_LDNT1S,
+  TILEGX_OPC_LDNT1S_ADD,
+  TILEGX_OPC_LDNT1U,
+  TILEGX_OPC_LDNT1U_ADD,
+  TILEGX_OPC_LDNT2S,
+  TILEGX_OPC_LDNT2S_ADD,
+  TILEGX_OPC_LDNT2U,
+  TILEGX_OPC_LDNT2U_ADD,
+  TILEGX_OPC_LDNT4S,
+  TILEGX_OPC_LDNT4S_ADD,
+  TILEGX_OPC_LDNT4U,
+  TILEGX_OPC_LDNT4U_ADD,
+  TILEGX_OPC_LDNT_ADD,
+  TILEGX_OPC_LNK,
+  TILEGX_OPC_MF,
+  TILEGX_OPC_MFSPR,
+  TILEGX_OPC_MM,
+  TILEGX_OPC_MNZ,
+  TILEGX_OPC_MTSPR,
+  TILEGX_OPC_MUL_HS_HS,
+  TILEGX_OPC_MUL_HS_HU,
+  TILEGX_OPC_MUL_HS_LS,
+  TILEGX_OPC_MUL_HS_LU,
+  TILEGX_OPC_MUL_HU_HU,
+  TILEGX_OPC_MUL_HU_LS,
+  TILEGX_OPC_MUL_HU_LU,
+  TILEGX_OPC_MUL_LS_LS,
+  TILEGX_OPC_MUL_LS_LU,
+  TILEGX_OPC_MUL_LU_LU,
+  TILEGX_OPC_MULA_HS_HS,
+  TILEGX_OPC_MULA_HS_HU,
+  TILEGX_OPC_MULA_HS_LS,
+  TILEGX_OPC_MULA_HS_LU,
+  TILEGX_OPC_MULA_HU_HU,
+  TILEGX_OPC_MULA_HU_LS,
+  TILEGX_OPC_MULA_HU_LU,
+  TILEGX_OPC_MULA_LS_LS,
+  TILEGX_OPC_MULA_LS_LU,
+  TILEGX_OPC_MULA_LU_LU,
+  TILEGX_OPC_MULAX,
+  TILEGX_OPC_MULX,
+  TILEGX_OPC_MZ,
+  TILEGX_OPC_NAP,
+  TILEGX_OPC_NOP,
+  TILEGX_OPC_NOR,
+  TILEGX_OPC_OR,
+  TILEGX_OPC_ORI,
+  TILEGX_OPC_PCNT,
+  TILEGX_OPC_REVBITS,
+  TILEGX_OPC_REVBYTES,
+  TILEGX_OPC_ROTL,
+  TILEGX_OPC_ROTLI,
+  TILEGX_OPC_SHL,
+  TILEGX_OPC_SHL16INSLI,
+  TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADDX,
+  TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADDX,
+  TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADDX,
+  TILEGX_OPC_SHLI,
+  TILEGX_OPC_SHLX,
+  TILEGX_OPC_SHLXI,
+  TILEGX_OPC_SHRS,
+  TILEGX_OPC_SHRSI,
+  TILEGX_OPC_SHRU,
+  TILEGX_OPC_SHRUI,
+  TILEGX_OPC_SHRUX,
+  TILEGX_OPC_SHRUXI,
+  TILEGX_OPC_SHUFFLEBYTES,
+  TILEGX_OPC_ST,
+  TILEGX_OPC_ST1,
+  TILEGX_OPC_ST1_ADD,
+  TILEGX_OPC_ST2,
+  TILEGX_OPC_ST2_ADD,
+  TILEGX_OPC_ST4,
+  TILEGX_OPC_ST4_ADD,
+  TILEGX_OPC_ST_ADD,
+  TILEGX_OPC_STNT,
+  TILEGX_OPC_STNT1,
+  TILEGX_OPC_STNT1_ADD,
+  TILEGX_OPC_STNT2,
+  TILEGX_OPC_STNT2_ADD,
+  TILEGX_OPC_STNT4,
+  TILEGX_OPC_STNT4_ADD,
+  TILEGX_OPC_STNT_ADD,
+  TILEGX_OPC_SUB,
+  TILEGX_OPC_SUBX,
+  TILEGX_OPC_SUBXSC,
+  TILEGX_OPC_SWINT0,
+  TILEGX_OPC_SWINT1,
+  TILEGX_OPC_SWINT2,
+  TILEGX_OPC_SWINT3,
+  TILEGX_OPC_TBLIDXB0,
+  TILEGX_OPC_TBLIDXB1,
+  TILEGX_OPC_TBLIDXB2,
+  TILEGX_OPC_TBLIDXB3,
+  TILEGX_OPC_V1ADD,
+  TILEGX_OPC_V1ADDI,
+  TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADIFFU,
+  TILEGX_OPC_V1AVGU,
+  TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPEQI,
+  TILEGX_OPC_V1CMPLES,
+  TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTSI,
+  TILEGX_OPC_V1CMPLTU,
+  TILEGX_OPC_V1CMPLTUI,
+  TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1DDOTPU,
+  TILEGX_OPC_V1DDOTPUA,
+  TILEGX_OPC_V1DDOTPUS,
+  TILEGX_OPC_V1DDOTPUSA,
+  TILEGX_OPC_V1DOTP,
+  TILEGX_OPC_V1DOTPA,
+  TILEGX_OPC_V1DOTPU,
+  TILEGX_OPC_V1DOTPUA,
+  TILEGX_OPC_V1DOTPUS,
+  TILEGX_OPC_V1DOTPUSA,
+  TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_L,
+  TILEGX_OPC_V1MAXU,
+  TILEGX_OPC_V1MAXUI,
+  TILEGX_OPC_V1MINU,
+  TILEGX_OPC_V1MINUI,
+  TILEGX_OPC_V1MNZ,
+  TILEGX_OPC_V1MULTU,
+  TILEGX_OPC_V1MULU,
+  TILEGX_OPC_V1MULUS,
+  TILEGX_OPC_V1MZ,
+  TILEGX_OPC_V1SADAU,
+  TILEGX_OPC_V1SADU,
+  TILEGX_OPC_V1SHL,
+  TILEGX_OPC_V1SHLI,
+  TILEGX_OPC_V1SHRS,
+  TILEGX_OPC_V1SHRSI,
+  TILEGX_OPC_V1SHRU,
+  TILEGX_OPC_V1SHRUI,
+  TILEGX_OPC_V1SUB,
+  TILEGX_OPC_V1SUBUC,
+  TILEGX_OPC_V2ADD,
+  TILEGX_OPC_V2ADDI,
+  TILEGX_OPC_V2ADDSC,
+  TILEGX_OPC_V2ADIFFS,
+  TILEGX_OPC_V2AVGS,
+  TILEGX_OPC_V2CMPEQ,
+  TILEGX_OPC_V2CMPEQI,
+  TILEGX_OPC_V2CMPLES,
+  TILEGX_OPC_V2CMPLEU,
+  TILEGX_OPC_V2CMPLTS,
+  TILEGX_OPC_V2CMPLTSI,
+  TILEGX_OPC_V2CMPLTU,
+  TILEGX_OPC_V2CMPLTUI,
+  TILEGX_OPC_V2CMPNE,
+  TILEGX_OPC_V2DOTP,
+  TILEGX_OPC_V2DOTPA,
+  TILEGX_OPC_V2INT_H,
+  TILEGX_OPC_V2INT_L,
+  TILEGX_OPC_V2MAXS,
+  TILEGX_OPC_V2MAXSI,
+  TILEGX_OPC_V2MINS,
+  TILEGX_OPC_V2MINSI,
+  TILEGX_OPC_V2MNZ,
+  TILEGX_OPC_V2MULFSC,
+  TILEGX_OPC_V2MULS,
+  TILEGX_OPC_V2MULTS,
+  TILEGX_OPC_V2MZ,
+  TILEGX_OPC_V2PACKH,
+  TILEGX_OPC_V2PACKL,
+  TILEGX_OPC_V2PACKUC,
+  TILEGX_OPC_V2SADAS,
+  TILEGX_OPC_V2SADAU,
+  TILEGX_OPC_V2SADS,
+  TILEGX_OPC_V2SADU,
+  TILEGX_OPC_V2SHL,
+  TILEGX_OPC_V2SHLI,
+  TILEGX_OPC_V2SHLSC,
+  TILEGX_OPC_V2SHRS,
+  TILEGX_OPC_V2SHRSI,
+  TILEGX_OPC_V2SHRU,
+  TILEGX_OPC_V2SHRUI,
+  TILEGX_OPC_V2SUB,
+  TILEGX_OPC_V2SUBSC,
+  TILEGX_OPC_V4ADD,
+  TILEGX_OPC_V4ADDSC,
+  TILEGX_OPC_V4INT_H,
+  TILEGX_OPC_V4INT_L,
+  TILEGX_OPC_V4PACKSC,
+  TILEGX_OPC_V4SHL,
+  TILEGX_OPC_V4SHLSC,
+  TILEGX_OPC_V4SHRS,
+  TILEGX_OPC_V4SHRU,
+  TILEGX_OPC_V4SUB,
+  TILEGX_OPC_V4SUBSC,
+  TILEGX_OPC_WH64,
+  TILEGX_OPC_XOR,
+  TILEGX_OPC_XORI,
+  TILEGX_OPC_NONE
+} tilegx_mnemonic;
 
 /* 64-bit pattern for a { bpt ; nop } bundle. */
-#define TILE_BPT_BUNDLE 0x400b3cae70166000ULL
+#define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL
 
 
-#define TILE_ELF_MACHINE_CODE EM_TILEPRO
+#define TILE_ELF_MACHINE_CODE EM_TILE64
 
-#define TILE_ELF_NAME "elf32-tilepro"
+#define TILE_ELF_NAME "elf32-tile64"
 
 
 static __inline unsigned int
-get_BrOff_SN(tile_bundle_bits num)
+get_BFEnd_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0x3ff);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_BrOff_X1(tile_bundle_bits n)
+get_BFOpcodeExtension_X0(tilegx_bundle_bits num)
 {
-  return (((unsigned int)(n >> 43)) & 0x00007fff) |
-         (((unsigned int)(n >> 20)) & 0x00018000);
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 24)) & 0xf);
 }
 
 static __inline unsigned int
-get_BrType_X1(tile_bundle_bits n)
+get_BFStart_X0(tilegx_bundle_bits num)
 {
-  return (((unsigned int)(n >> 31)) & 0xf);
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 18)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Dest_Imm8_X1(tile_bundle_bits n)
+get_BrOff_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 31)) & 0x0000003f) |
-         (((unsigned int)(n >> 43)) & 0x000000c0);
+         (((unsigned int)(n >> 37)) & 0x0001ffc0);
 }
 
 static __inline unsigned int
-get_Dest_SN(tile_bundle_bits num)
+get_BrType_X1(tilegx_bundle_bits n)
 {
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 2)) & 0x3);
+  return (((unsigned int)(n >> 54)) & 0x1f);
 }
 
 static __inline unsigned int
-get_Dest_X0(tile_bundle_bits num)
+get_Dest_Imm8_X1(tilegx_bundle_bits n)
+{
+  return (((unsigned int)(n >> 31)) & 0x0000003f) |
+         (((unsigned int)(n >> 43)) & 0x000000c0);
+}
+
+static __inline unsigned int
+get_Dest_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 0)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Dest_X1(tile_bundle_bits n)
+get_Dest_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 31)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Dest_Y0(tile_bundle_bits num)
+get_Dest_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 0)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Dest_Y1(tile_bundle_bits n)
+get_Dest_Y1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 31)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Imm16_X0(tile_bundle_bits num)
+get_Imm16_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 12)) & 0xffff);
 }
 
 static __inline unsigned int
-get_Imm16_X1(tile_bundle_bits n)
+get_Imm16_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 43)) & 0xffff);
 }
 
 static __inline unsigned int
-get_Imm8_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0xff);
-}
-
-static __inline unsigned int
-get_Imm8_X0(tile_bundle_bits num)
+get_Imm8OpcodeExtension_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0xff);
+  return (((n >> 20)) & 0xff);
 }
 
 static __inline unsigned int
-get_Imm8_X1(tile_bundle_bits n)
+get_Imm8OpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0xff);
+  return (((unsigned int)(n >> 51)) & 0xff);
 }
 
 static __inline unsigned int
-get_Imm8_Y0(tile_bundle_bits num)
+get_Imm8_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 12)) & 0xff);
 }
 
 static __inline unsigned int
-get_Imm8_Y1(tile_bundle_bits n)
+get_Imm8_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 43)) & 0xff);
 }
 
 static __inline unsigned int
-get_ImmOpcodeExtension_X0(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 20)) & 0x7f);
-}
-
-static __inline unsigned int
-get_ImmOpcodeExtension_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 51)) & 0x7f);
-}
-
-static __inline unsigned int
-get_ImmRROpcodeExtension_SN(tile_bundle_bits num)
+get_Imm8_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 8)) & 0x3);
-}
-
-static __inline unsigned int
-get_JOffLong_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 43)) & 0x00007fff) |
-         (((unsigned int)(n >> 20)) & 0x00018000) |
-         (((unsigned int)(n >> 14)) & 0x001e0000) |
-         (((unsigned int)(n >> 16)) & 0x07e00000) |
-         (((unsigned int)(n >> 31)) & 0x18000000);
-}
-
-static __inline unsigned int
-get_JOff_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 43)) & 0x00007fff) |
-         (((unsigned int)(n >> 20)) & 0x00018000) |
-         (((unsigned int)(n >> 14)) & 0x001e0000) |
-         (((unsigned int)(n >> 16)) & 0x07e00000) |
-         (((unsigned int)(n >> 31)) & 0x08000000);
-}
-
-static __inline unsigned int
-get_MF_Imm15_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 37)) & 0x00003fff) |
-         (((unsigned int)(n >> 44)) & 0x00004000);
+  return (((n >> 12)) & 0xff);
 }
 
 static __inline unsigned int
-get_MMEnd_X0(tile_bundle_bits num)
+get_Imm8_Y1(tilegx_bundle_bits n)
 {
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 18)) & 0x1f);
+  return (((unsigned int)(n >> 43)) & 0xff);
 }
 
 static __inline unsigned int
-get_MMEnd_X1(tile_bundle_bits n)
+get_JumpOff_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 49)) & 0x1f);
+  return (((unsigned int)(n >> 31)) & 0x7ffffff);
 }
 
 static __inline unsigned int
-get_MMStart_X0(tile_bundle_bits num)
+get_JumpOpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 23)) & 0x1f);
+  return (((unsigned int)(n >> 58)) & 0x1);
 }
 
 static __inline unsigned int
-get_MMStart_X1(tile_bundle_bits n)
+get_MF_Imm14_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 54)) & 0x1f);
+  return (((unsigned int)(n >> 37)) & 0x3fff);
 }
 
 static __inline unsigned int
-get_MT_Imm15_X1(tile_bundle_bits n)
+get_MT_Imm14_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 31)) & 0x0000003f) |
-         (((unsigned int)(n >> 37)) & 0x00003fc0) |
-         (((unsigned int)(n >> 44)) & 0x00004000);
+         (((unsigned int)(n >> 37)) & 0x00003fc0);
 }
 
 static __inline unsigned int
-get_Mode(tile_bundle_bits n)
+get_Mode(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 63)) & 0x1);
+  return (((unsigned int)(n >> 62)) & 0x3);
 }
 
 static __inline unsigned int
-get_NoRegOpcodeExtension_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0xf);
-}
-
-static __inline unsigned int
-get_Opcode_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 10)) & 0x3f);
-}
-
-static __inline unsigned int
-get_Opcode_X0(tile_bundle_bits num)
+get_Opcode_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 28)) & 0x7);
 }
 
 static __inline unsigned int
-get_Opcode_X1(tile_bundle_bits n)
+get_Opcode_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 59)) & 0xf);
+  return (((unsigned int)(n >> 59)) & 0x7);
 }
 
 static __inline unsigned int
-get_Opcode_Y0(tile_bundle_bits num)
+get_Opcode_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 27)) & 0xf);
 }
 
 static __inline unsigned int
-get_Opcode_Y1(tile_bundle_bits n)
+get_Opcode_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 59)) & 0xf);
+  return (((unsigned int)(n >> 58)) & 0xf);
 }
 
 static __inline unsigned int
-get_Opcode_Y2(tile_bundle_bits n)
+get_Opcode_Y2(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 56)) & 0x7);
-}
-
-static __inline unsigned int
-get_RROpcodeExtension_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 4)) & 0xf);
+  return (((n >> 26)) & 0x00000001) |
+         (((unsigned int)(n >> 56)) & 0x00000002);
 }
 
 static __inline unsigned int
-get_RRROpcodeExtension_X0(tile_bundle_bits num)
+get_RRROpcodeExtension_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 18)) & 0x1ff);
+  return (((n >> 18)) & 0x3ff);
 }
 
 static __inline unsigned int
-get_RRROpcodeExtension_X1(tile_bundle_bits n)
+get_RRROpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 49)) & 0x1ff);
+  return (((unsigned int)(n >> 49)) & 0x3ff);
 }
 
 static __inline unsigned int
-get_RRROpcodeExtension_Y0(tile_bundle_bits num)
+get_RRROpcodeExtension_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 18)) & 0x3);
 }
 
 static __inline unsigned int
-get_RRROpcodeExtension_Y1(tile_bundle_bits n)
+get_RRROpcodeExtension_Y1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 49)) & 0x3);
 }
 
 static __inline unsigned int
-get_RouteOpcodeExtension_SN(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0x3ff);
-}
-
-static __inline unsigned int
-get_S_X0(tile_bundle_bits num)
+get_ShAmt_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 27)) & 0x1);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_S_X1(tile_bundle_bits n)
+get_ShAmt_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 58)) & 0x1);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_ShAmt_X0(tile_bundle_bits num)
+get_ShAmt_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x1f);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_ShAmt_X1(tile_bundle_bits n)
+get_ShAmt_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0x1f);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_ShAmt_Y0(tile_bundle_bits num)
+get_ShiftOpcodeExtension_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x1f);
+  return (((n >> 18)) & 0x3ff);
 }
 
 static __inline unsigned int
-get_ShAmt_Y1(tile_bundle_bits n)
+get_ShiftOpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0x1f);
+  return (((unsigned int)(n >> 49)) & 0x3ff);
 }
 
 static __inline unsigned int
-get_SrcA_X0(tile_bundle_bits num)
+get_ShiftOpcodeExtension_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 6)) & 0x3f);
+  return (((n >> 18)) & 0x3);
 }
 
 static __inline unsigned int
-get_SrcA_X1(tile_bundle_bits n)
+get_ShiftOpcodeExtension_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 37)) & 0x3f);
+  return (((unsigned int)(n >> 49)) & 0x3);
 }
 
 static __inline unsigned int
-get_SrcA_Y0(tile_bundle_bits num)
+get_SrcA_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 6)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcA_Y1(tile_bundle_bits n)
+get_SrcA_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 37)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcA_Y2(tile_bundle_bits n)
+get_SrcA_Y0(tilegx_bundle_bits num)
 {
-  return (((n >> 26)) & 0x00000001) |
-         (((unsigned int)(n >> 50)) & 0x0000003e);
+  const unsigned int n = (unsigned int)num;
+  return (((n >> 6)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcBDest_Y2(tile_bundle_bits num)
+get_SrcA_Y1(tilegx_bundle_bits n)
 {
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 20)) & 0x3f);
+  return (((unsigned int)(n >> 37)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcB_X0(tile_bundle_bits num)
+get_SrcA_Y2(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x3f);
+  return (((n >> 20)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcB_X1(tile_bundle_bits n)
+get_SrcBDest_Y2(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0x3f);
+  return (((unsigned int)(n >> 51)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcB_Y0(tile_bundle_bits num)
+get_SrcB_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
   return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_SrcB_Y1(tile_bundle_bits n)
+get_SrcB_X1(tilegx_bundle_bits n)
 {
   return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_Src_SN(tile_bundle_bits num)
+get_SrcB_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 0)) & 0x3);
-}
-
-static __inline unsigned int
-get_UnOpcodeExtension_X0(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x1f);
-}
-
-static __inline unsigned int
-get_UnOpcodeExtension_X1(tile_bundle_bits n)
-{
-  return (((unsigned int)(n >> 43)) & 0x1f);
-}
-
-static __inline unsigned int
-get_UnOpcodeExtension_Y0(tile_bundle_bits num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((n >> 12)) & 0x1f);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnOpcodeExtension_Y1(tile_bundle_bits n)
+get_SrcB_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 43)) & 0x1f);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnShOpcodeExtension_X0(tile_bundle_bits num)
+get_UnaryOpcodeExtension_X0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 17)) & 0x3ff);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnShOpcodeExtension_X1(tile_bundle_bits n)
+get_UnaryOpcodeExtension_X1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 48)) & 0x3ff);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnShOpcodeExtension_Y0(tile_bundle_bits num)
+get_UnaryOpcodeExtension_Y0(tilegx_bundle_bits num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((n >> 17)) & 0x7);
+  return (((n >> 12)) & 0x3f);
 }
 
 static __inline unsigned int
-get_UnShOpcodeExtension_Y1(tile_bundle_bits n)
+get_UnaryOpcodeExtension_Y1(tilegx_bundle_bits n)
 {
-  return (((unsigned int)(n >> 48)) & 0x7);
+  return (((unsigned int)(n >> 43)) & 0x3f);
 }
 
 
@@ -874,546 +722,441 @@ sign_extend(int n, int num_bits)
 
 
 
-static __inline tile_bundle_bits
-create_BrOff_SN(int num)
+static __inline tilegx_bundle_bits
+create_BFEnd_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3ff) << 0);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_BrOff_X1(int num)
+static __inline tilegx_bundle_bits
+create_BFOpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
-         (((tile_bundle_bits)(n & 0x00018000)) << 20);
+  return ((n & 0xf) << 24);
 }
 
-static __inline tile_bundle_bits
-create_BrType_X1(int num)
+static __inline tilegx_bundle_bits
+create_BFStart_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xf)) << 31);
+  return ((n & 0x3f) << 18);
 }
 
-static __inline tile_bundle_bits
-create_Dest_Imm8_X1(int num)
+static __inline tilegx_bundle_bits
+create_BrOff_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
-         (((tile_bundle_bits)(n & 0x000000c0)) << 43);
+  return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+         (((tilegx_bundle_bits)(n & 0x0001ffc0)) << 37);
 }
 
-static __inline tile_bundle_bits
-create_Dest_SN(int num)
+static __inline tilegx_bundle_bits
+create_BrType_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x1f)) << 54);
+}
+
+static __inline tilegx_bundle_bits
+create_Dest_Imm8_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3) << 2);
+  return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+         (((tilegx_bundle_bits)(n & 0x000000c0)) << 43);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Dest_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 0);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Dest_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 31);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 31);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Dest_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 0);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Dest_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 31);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 31);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm16_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0xffff) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm16_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xffff)) << 43);
+  return (((tilegx_bundle_bits)(n & 0xffff)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_Imm8_SN(int num)
+static __inline tilegx_bundle_bits
+create_Imm8OpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0xff) << 0);
+  return ((n & 0xff) << 20);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
+create_Imm8OpcodeExtension_X1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0xff)) << 51);
+}
+
+static __inline tilegx_bundle_bits
 create_Imm8_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0xff) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm8_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xff)) << 43);
+  return (((tilegx_bundle_bits)(n & 0xff)) << 43);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm8_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0xff) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Imm8_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xff)) << 43);
-}
-
-static __inline tile_bundle_bits
-create_ImmOpcodeExtension_X0(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x7f) << 20);
-}
-
-static __inline tile_bundle_bits
-create_ImmOpcodeExtension_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x7f)) << 51);
-}
-
-static __inline tile_bundle_bits
-create_ImmRROpcodeExtension_SN(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x3) << 8);
-}
-
-static __inline tile_bundle_bits
-create_JOffLong_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
-         (((tile_bundle_bits)(n & 0x00018000)) << 20) |
-         (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
-         (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
-         (((tile_bundle_bits)(n & 0x18000000)) << 31);
-}
-
-static __inline tile_bundle_bits
-create_JOff_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
-         (((tile_bundle_bits)(n & 0x00018000)) << 20) |
-         (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
-         (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
-         (((tile_bundle_bits)(n & 0x08000000)) << 31);
-}
-
-static __inline tile_bundle_bits
-create_MF_Imm15_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x00003fff)) << 37) |
-         (((tile_bundle_bits)(n & 0x00004000)) << 44);
+  return (((tilegx_bundle_bits)(n & 0xff)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_MMEnd_X0(int num)
+static __inline tilegx_bundle_bits
+create_JumpOff_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 18);
+  return (((tilegx_bundle_bits)(n & 0x7ffffff)) << 31);
 }
 
-static __inline tile_bundle_bits
-create_MMEnd_X1(int num)
+static __inline tilegx_bundle_bits
+create_JumpOpcodeExtension_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 49);
+  return (((tilegx_bundle_bits)(n & 0x1)) << 58);
 }
 
-static __inline tile_bundle_bits
-create_MMStart_X0(int num)
+static __inline tilegx_bundle_bits
+create_MF_Imm14_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 23);
+  return (((tilegx_bundle_bits)(n & 0x3fff)) << 37);
 }
 
-static __inline tile_bundle_bits
-create_MMStart_X1(int num)
+static __inline tilegx_bundle_bits
+create_MT_Imm14_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 54);
+  return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+         (((tilegx_bundle_bits)(n & 0x00003fc0)) << 37);
 }
 
-static __inline tile_bundle_bits
-create_MT_Imm15_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
-         (((tile_bundle_bits)(n & 0x00003fc0)) << 37) |
-         (((tile_bundle_bits)(n & 0x00004000)) << 44);
-}
-
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Mode(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1)) << 63);
+  return (((tilegx_bundle_bits)(n & 0x3)) << 62);
 }
 
-static __inline tile_bundle_bits
-create_NoRegOpcodeExtension_SN(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0xf) << 0);
-}
-
-static __inline tile_bundle_bits
-create_Opcode_SN(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x3f) << 10);
-}
-
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x7) << 28);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xf)) << 59);
+  return (((tilegx_bundle_bits)(n & 0x7)) << 59);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0xf) << 27);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0xf)) << 59);
+  return (((tilegx_bundle_bits)(n & 0xf)) << 58);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_Opcode_Y2(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x7)) << 56);
-}
-
-static __inline tile_bundle_bits
-create_RROpcodeExtension_SN(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0xf) << 4);
+  return ((n & 0x00000001) << 26) |
+         (((tilegx_bundle_bits)(n & 0x00000002)) << 56);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_RRROpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1ff) << 18);
+  return ((n & 0x3ff) << 18);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_RRROpcodeExtension_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1ff)) << 49);
+  return (((tilegx_bundle_bits)(n & 0x3ff)) << 49);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_RRROpcodeExtension_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3) << 18);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_RRROpcodeExtension_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3)) << 49);
+  return (((tilegx_bundle_bits)(n & 0x3)) << 49);
 }
 
-static __inline tile_bundle_bits
-create_RouteOpcodeExtension_SN(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3ff) << 0);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_S_X0(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1) << 27);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_S_X1(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1)) << 58);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_ShAmt_X0(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 12);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_ShAmt_X1(int num)
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 43);
+  return ((n & 0x3ff) << 18);
 }
 
-static __inline tile_bundle_bits
-create_ShAmt_Y0(int num)
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 12);
+  return (((tilegx_bundle_bits)(n & 0x3ff)) << 49);
 }
 
-static __inline tile_bundle_bits
-create_ShAmt_Y1(int num)
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 43);
+  return ((n & 0x3) << 18);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_Y1(int num)
+{
+  const unsigned int n = (unsigned int)num;
+  return (((tilegx_bundle_bits)(n & 0x3)) << 49);
+}
+
+static __inline tilegx_bundle_bits
 create_SrcA_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 6);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcA_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 37);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 37);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcA_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 6);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcA_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 37);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 37);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcA_Y2(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x00000001) << 26) |
-         (((tile_bundle_bits)(n & 0x0000003e)) << 50);
+  return ((n & 0x3f) << 20);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcBDest_Y2(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3f) << 20);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 51);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcB_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcB_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 43);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcB_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
   return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
 create_SrcB_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3f)) << 43);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_Src_SN(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_X0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x3) << 0);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_X0(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 12);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_X1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 43);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_Y0(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x1f) << 12);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_Y1(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x1f)) << 43);
-}
-
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_X0(int num)
-{
-  const unsigned int n = (unsigned int)num;
-  return ((n & 0x3ff) << 17);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_X1(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_X1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x3ff)) << 48);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_Y0(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_Y0(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return ((n & 0x7) << 17);
+  return ((n & 0x3f) << 12);
 }
 
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_Y1(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_Y1(int num)
 {
   const unsigned int n = (unsigned int)num;
-  return (((tile_bundle_bits)(n & 0x7)) << 48);
+  return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
 }
 
 
-
 typedef enum
 {
-  TILE_PIPELINE_X0,
-  TILE_PIPELINE_X1,
-  TILE_PIPELINE_Y0,
-  TILE_PIPELINE_Y1,
-  TILE_PIPELINE_Y2,
-} tile_pipeline;
+  TILEGX_PIPELINE_X0,
+  TILEGX_PIPELINE_X1,
+  TILEGX_PIPELINE_Y0,
+  TILEGX_PIPELINE_Y1,
+  TILEGX_PIPELINE_Y2,
+} tilegx_pipeline;
 
-#define tile_is_x_pipeline(p) ((int)(p) <= (int)TILE_PIPELINE_X1)
+#define tilegx_is_x_pipeline(p) ((int)(p) <= (int)TILEGX_PIPELINE_X1)
 
 typedef enum
 {
-  TILE_OP_TYPE_REGISTER,
-  TILE_OP_TYPE_IMMEDIATE,
-  TILE_OP_TYPE_ADDRESS,
-  TILE_OP_TYPE_SPR
-} tile_operand_type;
+  TILEGX_OP_TYPE_REGISTER,
+  TILEGX_OP_TYPE_IMMEDIATE,
+  TILEGX_OP_TYPE_ADDRESS,
+  TILEGX_OP_TYPE_SPR
+} tilegx_operand_type;
 
-/* This is the bit that determines if a bundle is in the Y encoding. */
-#define TILE_BUNDLE_Y_ENCODING_MASK ((tile_bundle_bits)1 << 63)
+/* These are the bits that determine if a bundle is in the X encoding. */
+#define TILEGX_BUNDLE_MODE_MASK ((tilegx_bundle_bits)3 << 62)
 
 enum
 {
   /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */
-  TILE_MAX_INSTRUCTIONS_PER_BUNDLE = 3,
+  TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE = 3,
 
   /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */
-  TILE_NUM_PIPELINE_ENCODINGS = 5,
+  TILEGX_NUM_PIPELINE_ENCODINGS = 5,
 
-  /* Log base 2 of TILE_BUNDLE_SIZE_IN_BYTES. */
-  TILE_LOG2_BUNDLE_SIZE_IN_BYTES = 3,
+  /* Log base 2 of TILEGX_BUNDLE_SIZE_IN_BYTES. */
+  TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES = 3,
 
   /* Instructions take this many bytes. */
-  TILE_BUNDLE_SIZE_IN_BYTES = 1 << TILE_LOG2_BUNDLE_SIZE_IN_BYTES,
+  TILEGX_BUNDLE_SIZE_IN_BYTES = 1 << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES,
 
-  /* Log base 2 of TILE_BUNDLE_ALIGNMENT_IN_BYTES. */
-  TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3,
+  /* Log base 2 of TILEGX_BUNDLE_ALIGNMENT_IN_BYTES. */
+  TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3,
 
   /* Bundles should be aligned modulo this number of bytes. */
-  TILE_BUNDLE_ALIGNMENT_IN_BYTES =
-    (1 << TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES),
-
-  /* Log base 2 of TILE_SN_INSTRUCTION_SIZE_IN_BYTES. */
-  TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES = 1,
-
-  /* Static network instructions take this many bytes. */
-  TILE_SN_INSTRUCTION_SIZE_IN_BYTES =
-    (1 << TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES),
+  TILEGX_BUNDLE_ALIGNMENT_IN_BYTES =
+    (1 << TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES),
 
   /* Number of registers (some are magic, such as network I/O). */
-  TILE_NUM_REGISTERS = 64,
-
-  /* Number of static network registers. */
-  TILE_NUM_SN_REGISTERS = 4
+  TILEGX_NUM_REGISTERS = 64,
 };
 
 
-struct tile_operand
+struct tilegx_operand
 {
   /* Is this operand a register, immediate or address? */
-  tile_operand_type type;
+  tilegx_operand_type type;
 
   /* The default relocation type for this operand.  */
   signed int default_reloc : 16;
@@ -1437,27 +1180,27 @@ struct tile_operand
   unsigned int rightshift : 2;
 
   /* Return the bits for this operand to be ORed into an existing bundle. */
-  tile_bundle_bits (*insert) (int op);
+  tilegx_bundle_bits (*insert) (int op);
 
   /* Extract this operand and return it. */
-  unsigned int (*extract) (tile_bundle_bits bundle);
+  unsigned int (*extract) (tilegx_bundle_bits bundle);
 };
 
 
-extern const struct tile_operand tile_operands[];
+extern const struct tilegx_operand tilegx_operands[];
 
 /* One finite-state machine per pipe for rapid instruction decoding. */
 extern const unsigned short * const
-tile_bundle_decoder_fsms[TILE_NUM_PIPELINE_ENCODINGS];
+tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS];
 
 
-struct tile_opcode
+struct tilegx_opcode
 {
   /* The opcode mnemonic, e.g. "add" */
   const char *name;
 
   /* The enum value for this mnemonic. */
-  tile_mnemonic mnemonic;
+  tilegx_mnemonic mnemonic;
 
   /* A bit mask of which of the five pipes this instruction
      is compatible with:
@@ -1478,29 +1221,28 @@ struct tile_opcode
   unsigned char can_bundle;
 
   /* The description of the operands. Each of these is an
-   * index into the tile_operands[] table. */
-  unsigned char operands[TILE_NUM_PIPELINE_ENCODINGS][TILE_MAX_OPERANDS];
+   * index into the tilegx_operands[] table. */
+  unsigned char operands[TILEGX_NUM_PIPELINE_ENCODINGS][TILEGX_MAX_OPERANDS];
 
 };
 
-extern const struct tile_opcode tile_opcodes[];
-
+extern const struct tilegx_opcode tilegx_opcodes[];
 
 /* Used for non-textual disassembly into structs. */
-struct tile_decoded_instruction
+struct tilegx_decoded_instruction
 {
-  const struct tile_opcode *opcode;
-  const struct tile_operand *operands[TILE_MAX_OPERANDS];
-  int operand_values[TILE_MAX_OPERANDS];
+  const struct tilegx_opcode *opcode;
+  const struct tilegx_operand *operands[TILEGX_MAX_OPERANDS];
+  long long operand_values[TILEGX_MAX_OPERANDS];
 };
 
 
 /* Disassemble a bundle into a struct for machine processing. */
-extern int parse_insn_tile(tile_bundle_bits bits,
-                           unsigned int pc,
-                           struct tile_decoded_instruction
-                           decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
+extern int parse_insn_tilegx(tilegx_bundle_bits bits,
+                             unsigned long long pc,
+                             struct tilegx_decoded_instruction
+                             decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]);
 
 
 
-#endif /* opcode_tile_h */
+#endif /* opcode_tilegx_h */
index 227d033b180c16d04297fc17297cee0c8e4c0728..710192869476a5b1fb40fa2a61a4ce2623410d9d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU General Public License
 #define _TILE_OPCODE_CONSTANTS_H
 enum
 {
-  ADDBS_U_SPECIAL_0_OPCODE_X0 = 98,
-  ADDBS_U_SPECIAL_0_OPCODE_X1 = 68,
-  ADDB_SPECIAL_0_OPCODE_X0 = 1,
-  ADDB_SPECIAL_0_OPCODE_X1 = 1,
-  ADDHS_SPECIAL_0_OPCODE_X0 = 99,
-  ADDHS_SPECIAL_0_OPCODE_X1 = 69,
-  ADDH_SPECIAL_0_OPCODE_X0 = 2,
-  ADDH_SPECIAL_0_OPCODE_X1 = 2,
-  ADDIB_IMM_0_OPCODE_X0 = 1,
-  ADDIB_IMM_0_OPCODE_X1 = 1,
-  ADDIH_IMM_0_OPCODE_X0 = 2,
-  ADDIH_IMM_0_OPCODE_X1 = 2,
-  ADDI_IMM_0_OPCODE_X0 = 3,
-  ADDI_IMM_0_OPCODE_X1 = 3,
-  ADDI_IMM_1_OPCODE_SN = 1,
-  ADDI_OPCODE_Y0 = 9,
-  ADDI_OPCODE_Y1 = 7,
-  ADDLIS_OPCODE_X0 = 1,
-  ADDLIS_OPCODE_X1 = 2,
-  ADDLI_OPCODE_X0 = 2,
-  ADDLI_OPCODE_X1 = 3,
-  ADDS_SPECIAL_0_OPCODE_X0 = 96,
-  ADDS_SPECIAL_0_OPCODE_X1 = 66,
-  ADD_SPECIAL_0_OPCODE_X0 = 3,
-  ADD_SPECIAL_0_OPCODE_X1 = 3,
-  ADD_SPECIAL_0_OPCODE_Y0 = 0,
-  ADD_SPECIAL_0_OPCODE_Y1 = 0,
-  ADIFFB_U_SPECIAL_0_OPCODE_X0 = 4,
-  ADIFFH_SPECIAL_0_OPCODE_X0 = 5,
-  ANDI_IMM_0_OPCODE_X0 = 1,
-  ANDI_IMM_0_OPCODE_X1 = 4,
-  ANDI_OPCODE_Y0 = 10,
-  ANDI_OPCODE_Y1 = 8,
-  AND_SPECIAL_0_OPCODE_X0 = 6,
-  AND_SPECIAL_0_OPCODE_X1 = 4,
-  AND_SPECIAL_2_OPCODE_Y0 = 0,
-  AND_SPECIAL_2_OPCODE_Y1 = 0,
-  AULI_OPCODE_X0 = 3,
-  AULI_OPCODE_X1 = 4,
-  AVGB_U_SPECIAL_0_OPCODE_X0 = 7,
-  AVGH_SPECIAL_0_OPCODE_X0 = 8,
-  BBNST_BRANCH_OPCODE_X1 = 15,
-  BBNS_BRANCH_OPCODE_X1 = 14,
-  BBNS_OPCODE_SN = 63,
-  BBST_BRANCH_OPCODE_X1 = 13,
-  BBS_BRANCH_OPCODE_X1 = 12,
-  BBS_OPCODE_SN = 62,
-  BGEZT_BRANCH_OPCODE_X1 = 7,
-  BGEZ_BRANCH_OPCODE_X1 = 6,
-  BGEZ_OPCODE_SN = 61,
-  BGZT_BRANCH_OPCODE_X1 = 5,
-  BGZ_BRANCH_OPCODE_X1 = 4,
-  BGZ_OPCODE_SN = 58,
-  BITX_UN_0_SHUN_0_OPCODE_X0 = 1,
-  BITX_UN_0_SHUN_0_OPCODE_Y0 = 1,
-  BLEZT_BRANCH_OPCODE_X1 = 11,
-  BLEZ_BRANCH_OPCODE_X1 = 10,
-  BLEZ_OPCODE_SN = 59,
-  BLZT_BRANCH_OPCODE_X1 = 9,
-  BLZ_BRANCH_OPCODE_X1 = 8,
-  BLZ_OPCODE_SN = 60,
-  BNZT_BRANCH_OPCODE_X1 = 3,
-  BNZ_BRANCH_OPCODE_X1 = 2,
-  BNZ_OPCODE_SN = 57,
-  BPT_NOREG_RR_IMM_0_OPCODE_SN = 1,
-  BRANCH_OPCODE_X1 = 5,
-  BYTEX_UN_0_SHUN_0_OPCODE_X0 = 2,
-  BYTEX_UN_0_SHUN_0_OPCODE_Y0 = 2,
-  BZT_BRANCH_OPCODE_X1 = 1,
-  BZ_BRANCH_OPCODE_X1 = 0,
-  BZ_OPCODE_SN = 56,
-  CLZ_UN_0_SHUN_0_OPCODE_X0 = 3,
-  CLZ_UN_0_SHUN_0_OPCODE_Y0 = 3,
-  CRC32_32_SPECIAL_0_OPCODE_X0 = 9,
-  CRC32_8_SPECIAL_0_OPCODE_X0 = 10,
-  CTZ_UN_0_SHUN_0_OPCODE_X0 = 4,
-  CTZ_UN_0_SHUN_0_OPCODE_Y0 = 4,
-  DRAIN_UN_0_SHUN_0_OPCODE_X1 = 1,
-  DTLBPR_UN_0_SHUN_0_OPCODE_X1 = 2,
-  DWORD_ALIGN_SPECIAL_0_OPCODE_X0 = 95,
-  FINV_UN_0_SHUN_0_OPCODE_X1 = 3,
-  FLUSH_UN_0_SHUN_0_OPCODE_X1 = 4,
-  FNOP_NOREG_RR_IMM_0_OPCODE_SN = 3,
-  FNOP_UN_0_SHUN_0_OPCODE_X0 = 5,
-  FNOP_UN_0_SHUN_0_OPCODE_X1 = 5,
-  FNOP_UN_0_SHUN_0_OPCODE_Y0 = 5,
-  FNOP_UN_0_SHUN_0_OPCODE_Y1 = 1,
-  HALT_NOREG_RR_IMM_0_OPCODE_SN = 0,
-  ICOH_UN_0_SHUN_0_OPCODE_X1 = 6,
-  ILL_UN_0_SHUN_0_OPCODE_X1 = 7,
-  ILL_UN_0_SHUN_0_OPCODE_Y1 = 2,
-  IMM_0_OPCODE_SN = 0,
-  IMM_0_OPCODE_X0 = 4,
-  IMM_0_OPCODE_X1 = 6,
-  IMM_1_OPCODE_SN = 1,
-  IMM_OPCODE_0_X0 = 5,
-  INTHB_SPECIAL_0_OPCODE_X0 = 11,
-  INTHB_SPECIAL_0_OPCODE_X1 = 5,
-  INTHH_SPECIAL_0_OPCODE_X0 = 12,
-  INTHH_SPECIAL_0_OPCODE_X1 = 6,
-  INTLB_SPECIAL_0_OPCODE_X0 = 13,
-  INTLB_SPECIAL_0_OPCODE_X1 = 7,
-  INTLH_SPECIAL_0_OPCODE_X0 = 14,
-  INTLH_SPECIAL_0_OPCODE_X1 = 8,
-  INV_UN_0_SHUN_0_OPCODE_X1 = 8,
-  IRET_UN_0_SHUN_0_OPCODE_X1 = 9,
-  JALB_OPCODE_X1 = 13,
-  JALF_OPCODE_X1 = 12,
-  JALRP_SPECIAL_0_OPCODE_X1 = 9,
-  JALRR_IMM_1_OPCODE_SN = 3,
-  JALR_RR_IMM_0_OPCODE_SN = 5,
-  JALR_SPECIAL_0_OPCODE_X1 = 10,
-  JB_OPCODE_X1 = 11,
-  JF_OPCODE_X1 = 10,
-  JRP_SPECIAL_0_OPCODE_X1 = 11,
-  JRR_IMM_1_OPCODE_SN = 2,
-  JR_RR_IMM_0_OPCODE_SN = 4,
-  JR_SPECIAL_0_OPCODE_X1 = 12,
-  LBADD_IMM_0_OPCODE_X1 = 22,
-  LBADD_U_IMM_0_OPCODE_X1 = 23,
-  LB_OPCODE_Y2 = 0,
-  LB_UN_0_SHUN_0_OPCODE_X1 = 10,
-  LB_U_OPCODE_Y2 = 1,
-  LB_U_UN_0_SHUN_0_OPCODE_X1 = 11,
-  LHADD_IMM_0_OPCODE_X1 = 24,
-  LHADD_U_IMM_0_OPCODE_X1 = 25,
-  LH_OPCODE_Y2 = 2,
-  LH_UN_0_SHUN_0_OPCODE_X1 = 12,
-  LH_U_OPCODE_Y2 = 3,
-  LH_U_UN_0_SHUN_0_OPCODE_X1 = 13,
-  LNK_SPECIAL_0_OPCODE_X1 = 13,
-  LWADD_IMM_0_OPCODE_X1 = 26,
-  LWADD_NA_IMM_0_OPCODE_X1 = 27,
-  LW_NA_UN_0_SHUN_0_OPCODE_X1 = 24,
-  LW_OPCODE_Y2 = 4,
-  LW_UN_0_SHUN_0_OPCODE_X1 = 14,
-  MAXB_U_SPECIAL_0_OPCODE_X0 = 15,
-  MAXB_U_SPECIAL_0_OPCODE_X1 = 14,
-  MAXH_SPECIAL_0_OPCODE_X0 = 16,
-  MAXH_SPECIAL_0_OPCODE_X1 = 15,
-  MAXIB_U_IMM_0_OPCODE_X0 = 4,
-  MAXIB_U_IMM_0_OPCODE_X1 = 5,
-  MAXIH_IMM_0_OPCODE_X0 = 5,
-  MAXIH_IMM_0_OPCODE_X1 = 6,
-  MFSPR_IMM_0_OPCODE_X1 = 7,
-  MF_UN_0_SHUN_0_OPCODE_X1 = 15,
-  MINB_U_SPECIAL_0_OPCODE_X0 = 17,
-  MINB_U_SPECIAL_0_OPCODE_X1 = 16,
-  MINH_SPECIAL_0_OPCODE_X0 = 18,
-  MINH_SPECIAL_0_OPCODE_X1 = 17,
-  MINIB_U_IMM_0_OPCODE_X0 = 6,
-  MINIB_U_IMM_0_OPCODE_X1 = 8,
-  MINIH_IMM_0_OPCODE_X0 = 7,
-  MINIH_IMM_0_OPCODE_X1 = 9,
-  MM_OPCODE_X0 = 6,
-  MM_OPCODE_X1 = 7,
-  MNZB_SPECIAL_0_OPCODE_X0 = 19,
-  MNZB_SPECIAL_0_OPCODE_X1 = 18,
-  MNZH_SPECIAL_0_OPCODE_X0 = 20,
-  MNZH_SPECIAL_0_OPCODE_X1 = 19,
-  MNZ_SPECIAL_0_OPCODE_X0 = 21,
-  MNZ_SPECIAL_0_OPCODE_X1 = 20,
-  MNZ_SPECIAL_1_OPCODE_Y0 = 0,
-  MNZ_SPECIAL_1_OPCODE_Y1 = 1,
-  MOVEI_IMM_1_OPCODE_SN = 0,
-  MOVE_RR_IMM_0_OPCODE_SN = 8,
-  MTSPR_IMM_0_OPCODE_X1 = 10,
-  MULHHA_SS_SPECIAL_0_OPCODE_X0 = 22,
-  MULHHA_SS_SPECIAL_7_OPCODE_Y0 = 0,
-  MULHHA_SU_SPECIAL_0_OPCODE_X0 = 23,
-  MULHHA_UU_SPECIAL_0_OPCODE_X0 = 24,
-  MULHHA_UU_SPECIAL_7_OPCODE_Y0 = 1,
-  MULHHSA_UU_SPECIAL_0_OPCODE_X0 = 25,
-  MULHH_SS_SPECIAL_0_OPCODE_X0 = 26,
-  MULHH_SS_SPECIAL_6_OPCODE_Y0 = 0,
-  MULHH_SU_SPECIAL_0_OPCODE_X0 = 27,
-  MULHH_UU_SPECIAL_0_OPCODE_X0 = 28,
-  MULHH_UU_SPECIAL_6_OPCODE_Y0 = 1,
-  MULHLA_SS_SPECIAL_0_OPCODE_X0 = 29,
-  MULHLA_SU_SPECIAL_0_OPCODE_X0 = 30,
-  MULHLA_US_SPECIAL_0_OPCODE_X0 = 31,
-  MULHLA_UU_SPECIAL_0_OPCODE_X0 = 32,
-  MULHLSA_UU_SPECIAL_0_OPCODE_X0 = 33,
-  MULHLSA_UU_SPECIAL_5_OPCODE_Y0 = 0,
-  MULHL_SS_SPECIAL_0_OPCODE_X0 = 34,
-  MULHL_SU_SPECIAL_0_OPCODE_X0 = 35,
-  MULHL_US_SPECIAL_0_OPCODE_X0 = 36,
-  MULHL_UU_SPECIAL_0_OPCODE_X0 = 37,
-  MULLLA_SS_SPECIAL_0_OPCODE_X0 = 38,
-  MULLLA_SS_SPECIAL_7_OPCODE_Y0 = 2,
-  MULLLA_SU_SPECIAL_0_OPCODE_X0 = 39,
-  MULLLA_UU_SPECIAL_0_OPCODE_X0 = 40,
-  MULLLA_UU_SPECIAL_7_OPCODE_Y0 = 3,
-  MULLLSA_UU_SPECIAL_0_OPCODE_X0 = 41,
-  MULLL_SS_SPECIAL_0_OPCODE_X0 = 42,
-  MULLL_SS_SPECIAL_6_OPCODE_Y0 = 2,
-  MULLL_SU_SPECIAL_0_OPCODE_X0 = 43,
-  MULLL_UU_SPECIAL_0_OPCODE_X0 = 44,
-  MULLL_UU_SPECIAL_6_OPCODE_Y0 = 3,
-  MVNZ_SPECIAL_0_OPCODE_X0 = 45,
-  MVNZ_SPECIAL_1_OPCODE_Y0 = 1,
-  MVZ_SPECIAL_0_OPCODE_X0 = 46,
-  MVZ_SPECIAL_1_OPCODE_Y0 = 2,
-  MZB_SPECIAL_0_OPCODE_X0 = 47,
-  MZB_SPECIAL_0_OPCODE_X1 = 21,
-  MZH_SPECIAL_0_OPCODE_X0 = 48,
-  MZH_SPECIAL_0_OPCODE_X1 = 22,
-  MZ_SPECIAL_0_OPCODE_X0 = 49,
-  MZ_SPECIAL_0_OPCODE_X1 = 23,
-  MZ_SPECIAL_1_OPCODE_Y0 = 3,
-  MZ_SPECIAL_1_OPCODE_Y1 = 2,
-  NAP_UN_0_SHUN_0_OPCODE_X1 = 16,
-  NOP_NOREG_RR_IMM_0_OPCODE_SN = 2,
-  NOP_UN_0_SHUN_0_OPCODE_X0 = 6,
-  NOP_UN_0_SHUN_0_OPCODE_X1 = 17,
-  NOP_UN_0_SHUN_0_OPCODE_Y0 = 6,
-  NOP_UN_0_SHUN_0_OPCODE_Y1 = 3,
-  NOREG_RR_IMM_0_OPCODE_SN = 0,
-  NOR_SPECIAL_0_OPCODE_X0 = 50,
-  NOR_SPECIAL_0_OPCODE_X1 = 24,
-  NOR_SPECIAL_2_OPCODE_Y0 = 1,
-  NOR_SPECIAL_2_OPCODE_Y1 = 1,
-  ORI_IMM_0_OPCODE_X0 = 8,
-  ORI_IMM_0_OPCODE_X1 = 11,
-  ORI_OPCODE_Y0 = 11,
-  ORI_OPCODE_Y1 = 9,
-  OR_SPECIAL_0_OPCODE_X0 = 51,
-  OR_SPECIAL_0_OPCODE_X1 = 25,
-  OR_SPECIAL_2_OPCODE_Y0 = 2,
-  OR_SPECIAL_2_OPCODE_Y1 = 2,
-  PACKBS_U_SPECIAL_0_OPCODE_X0 = 103,
-  PACKBS_U_SPECIAL_0_OPCODE_X1 = 73,
-  PACKHB_SPECIAL_0_OPCODE_X0 = 52,
-  PACKHB_SPECIAL_0_OPCODE_X1 = 26,
-  PACKHS_SPECIAL_0_OPCODE_X0 = 102,
-  PACKHS_SPECIAL_0_OPCODE_X1 = 72,
-  PACKLB_SPECIAL_0_OPCODE_X0 = 53,
-  PACKLB_SPECIAL_0_OPCODE_X1 = 27,
-  PCNT_UN_0_SHUN_0_OPCODE_X0 = 7,
-  PCNT_UN_0_SHUN_0_OPCODE_Y0 = 7,
-  RLI_SHUN_0_OPCODE_X0 = 1,
-  RLI_SHUN_0_OPCODE_X1 = 1,
-  RLI_SHUN_0_OPCODE_Y0 = 1,
-  RLI_SHUN_0_OPCODE_Y1 = 1,
-  RL_SPECIAL_0_OPCODE_X0 = 54,
-  RL_SPECIAL_0_OPCODE_X1 = 28,
-  RL_SPECIAL_3_OPCODE_Y0 = 0,
-  RL_SPECIAL_3_OPCODE_Y1 = 0,
-  RR_IMM_0_OPCODE_SN = 0,
-  S1A_SPECIAL_0_OPCODE_X0 = 55,
-  S1A_SPECIAL_0_OPCODE_X1 = 29,
-  S1A_SPECIAL_0_OPCODE_Y0 = 1,
-  S1A_SPECIAL_0_OPCODE_Y1 = 1,
-  S2A_SPECIAL_0_OPCODE_X0 = 56,
-  S2A_SPECIAL_0_OPCODE_X1 = 30,
-  S2A_SPECIAL_0_OPCODE_Y0 = 2,
-  S2A_SPECIAL_0_OPCODE_Y1 = 2,
-  S3A_SPECIAL_0_OPCODE_X0 = 57,
-  S3A_SPECIAL_0_OPCODE_X1 = 31,
-  S3A_SPECIAL_5_OPCODE_Y0 = 1,
-  S3A_SPECIAL_5_OPCODE_Y1 = 1,
-  SADAB_U_SPECIAL_0_OPCODE_X0 = 58,
-  SADAH_SPECIAL_0_OPCODE_X0 = 59,
-  SADAH_U_SPECIAL_0_OPCODE_X0 = 60,
-  SADB_U_SPECIAL_0_OPCODE_X0 = 61,
-  SADH_SPECIAL_0_OPCODE_X0 = 62,
-  SADH_U_SPECIAL_0_OPCODE_X0 = 63,
-  SBADD_IMM_0_OPCODE_X1 = 28,
-  SB_OPCODE_Y2 = 5,
-  SB_SPECIAL_0_OPCODE_X1 = 32,
-  SEQB_SPECIAL_0_OPCODE_X0 = 64,
-  SEQB_SPECIAL_0_OPCODE_X1 = 33,
-  SEQH_SPECIAL_0_OPCODE_X0 = 65,
-  SEQH_SPECIAL_0_OPCODE_X1 = 34,
-  SEQIB_IMM_0_OPCODE_X0 = 9,
-  SEQIB_IMM_0_OPCODE_X1 = 12,
-  SEQIH_IMM_0_OPCODE_X0 = 10,
-  SEQIH_IMM_0_OPCODE_X1 = 13,
-  SEQI_IMM_0_OPCODE_X0 = 11,
-  SEQI_IMM_0_OPCODE_X1 = 14,
-  SEQI_OPCODE_Y0 = 12,
-  SEQI_OPCODE_Y1 = 10,
-  SEQ_SPECIAL_0_OPCODE_X0 = 66,
-  SEQ_SPECIAL_0_OPCODE_X1 = 35,
-  SEQ_SPECIAL_5_OPCODE_Y0 = 2,
-  SEQ_SPECIAL_5_OPCODE_Y1 = 2,
-  SHADD_IMM_0_OPCODE_X1 = 29,
-  SHL8II_IMM_0_OPCODE_SN = 3,
-  SHLB_SPECIAL_0_OPCODE_X0 = 67,
-  SHLB_SPECIAL_0_OPCODE_X1 = 36,
-  SHLH_SPECIAL_0_OPCODE_X0 = 68,
-  SHLH_SPECIAL_0_OPCODE_X1 = 37,
-  SHLIB_SHUN_0_OPCODE_X0 = 2,
-  SHLIB_SHUN_0_OPCODE_X1 = 2,
-  SHLIH_SHUN_0_OPCODE_X0 = 3,
-  SHLIH_SHUN_0_OPCODE_X1 = 3,
-  SHLI_SHUN_0_OPCODE_X0 = 4,
-  SHLI_SHUN_0_OPCODE_X1 = 4,
-  SHLI_SHUN_0_OPCODE_Y0 = 2,
-  SHLI_SHUN_0_OPCODE_Y1 = 2,
-  SHL_SPECIAL_0_OPCODE_X0 = 69,
-  SHL_SPECIAL_0_OPCODE_X1 = 38,
-  SHL_SPECIAL_3_OPCODE_Y0 = 1,
-  SHL_SPECIAL_3_OPCODE_Y1 = 1,
-  SHR1_RR_IMM_0_OPCODE_SN = 9,
-  SHRB_SPECIAL_0_OPCODE_X0 = 70,
-  SHRB_SPECIAL_0_OPCODE_X1 = 39,
-  SHRH_SPECIAL_0_OPCODE_X0 = 71,
-  SHRH_SPECIAL_0_OPCODE_X1 = 40,
-  SHRIB_SHUN_0_OPCODE_X0 = 5,
-  SHRIB_SHUN_0_OPCODE_X1 = 5,
-  SHRIH_SHUN_0_OPCODE_X0 = 6,
-  SHRIH_SHUN_0_OPCODE_X1 = 6,
-  SHRI_SHUN_0_OPCODE_X0 = 7,
-  SHRI_SHUN_0_OPCODE_X1 = 7,
-  SHRI_SHUN_0_OPCODE_Y0 = 3,
-  SHRI_SHUN_0_OPCODE_Y1 = 3,
-  SHR_SPECIAL_0_OPCODE_X0 = 72,
-  SHR_SPECIAL_0_OPCODE_X1 = 41,
-  SHR_SPECIAL_3_OPCODE_Y0 = 2,
-  SHR_SPECIAL_3_OPCODE_Y1 = 2,
-  SHUN_0_OPCODE_X0 = 7,
-  SHUN_0_OPCODE_X1 = 8,
-  SHUN_0_OPCODE_Y0 = 13,
-  SHUN_0_OPCODE_Y1 = 11,
-  SH_OPCODE_Y2 = 6,
-  SH_SPECIAL_0_OPCODE_X1 = 42,
-  SLTB_SPECIAL_0_OPCODE_X0 = 73,
-  SLTB_SPECIAL_0_OPCODE_X1 = 43,
-  SLTB_U_SPECIAL_0_OPCODE_X0 = 74,
-  SLTB_U_SPECIAL_0_OPCODE_X1 = 44,
-  SLTEB_SPECIAL_0_OPCODE_X0 = 75,
-  SLTEB_SPECIAL_0_OPCODE_X1 = 45,
-  SLTEB_U_SPECIAL_0_OPCODE_X0 = 76,
-  SLTEB_U_SPECIAL_0_OPCODE_X1 = 46,
-  SLTEH_SPECIAL_0_OPCODE_X0 = 77,
-  SLTEH_SPECIAL_0_OPCODE_X1 = 47,
-  SLTEH_U_SPECIAL_0_OPCODE_X0 = 78,
-  SLTEH_U_SPECIAL_0_OPCODE_X1 = 48,
-  SLTE_SPECIAL_0_OPCODE_X0 = 79,
-  SLTE_SPECIAL_0_OPCODE_X1 = 49,
-  SLTE_SPECIAL_4_OPCODE_Y0 = 0,
-  SLTE_SPECIAL_4_OPCODE_Y1 = 0,
-  SLTE_U_SPECIAL_0_OPCODE_X0 = 80,
-  SLTE_U_SPECIAL_0_OPCODE_X1 = 50,
-  SLTE_U_SPECIAL_4_OPCODE_Y0 = 1,
-  SLTE_U_SPECIAL_4_OPCODE_Y1 = 1,
-  SLTH_SPECIAL_0_OPCODE_X0 = 81,
-  SLTH_SPECIAL_0_OPCODE_X1 = 51,
-  SLTH_U_SPECIAL_0_OPCODE_X0 = 82,
-  SLTH_U_SPECIAL_0_OPCODE_X1 = 52,
-  SLTIB_IMM_0_OPCODE_X0 = 12,
-  SLTIB_IMM_0_OPCODE_X1 = 15,
-  SLTIB_U_IMM_0_OPCODE_X0 = 13,
-  SLTIB_U_IMM_0_OPCODE_X1 = 16,
-  SLTIH_IMM_0_OPCODE_X0 = 14,
-  SLTIH_IMM_0_OPCODE_X1 = 17,
-  SLTIH_U_IMM_0_OPCODE_X0 = 15,
-  SLTIH_U_IMM_0_OPCODE_X1 = 18,
-  SLTI_IMM_0_OPCODE_X0 = 16,
-  SLTI_IMM_0_OPCODE_X1 = 19,
-  SLTI_OPCODE_Y0 = 14,
-  SLTI_OPCODE_Y1 = 12,
-  SLTI_U_IMM_0_OPCODE_X0 = 17,
-  SLTI_U_IMM_0_OPCODE_X1 = 20,
-  SLTI_U_OPCODE_Y0 = 15,
-  SLTI_U_OPCODE_Y1 = 13,
-  SLT_SPECIAL_0_OPCODE_X0 = 83,
-  SLT_SPECIAL_0_OPCODE_X1 = 53,
-  SLT_SPECIAL_4_OPCODE_Y0 = 2,
-  SLT_SPECIAL_4_OPCODE_Y1 = 2,
-  SLT_U_SPECIAL_0_OPCODE_X0 = 84,
-  SLT_U_SPECIAL_0_OPCODE_X1 = 54,
-  SLT_U_SPECIAL_4_OPCODE_Y0 = 3,
-  SLT_U_SPECIAL_4_OPCODE_Y1 = 3,
-  SNEB_SPECIAL_0_OPCODE_X0 = 85,
-  SNEB_SPECIAL_0_OPCODE_X1 = 55,
-  SNEH_SPECIAL_0_OPCODE_X0 = 86,
-  SNEH_SPECIAL_0_OPCODE_X1 = 56,
-  SNE_SPECIAL_0_OPCODE_X0 = 87,
-  SNE_SPECIAL_0_OPCODE_X1 = 57,
-  SNE_SPECIAL_5_OPCODE_Y0 = 3,
-  SNE_SPECIAL_5_OPCODE_Y1 = 3,
-  SPECIAL_0_OPCODE_X0 = 0,
-  SPECIAL_0_OPCODE_X1 = 1,
-  SPECIAL_0_OPCODE_Y0 = 1,
-  SPECIAL_0_OPCODE_Y1 = 1,
-  SPECIAL_1_OPCODE_Y0 = 2,
-  SPECIAL_1_OPCODE_Y1 = 2,
-  SPECIAL_2_OPCODE_Y0 = 3,
-  SPECIAL_2_OPCODE_Y1 = 3,
-  SPECIAL_3_OPCODE_Y0 = 4,
-  SPECIAL_3_OPCODE_Y1 = 4,
-  SPECIAL_4_OPCODE_Y0 = 5,
-  SPECIAL_4_OPCODE_Y1 = 5,
-  SPECIAL_5_OPCODE_Y0 = 6,
-  SPECIAL_5_OPCODE_Y1 = 6,
-  SPECIAL_6_OPCODE_Y0 = 7,
-  SPECIAL_7_OPCODE_Y0 = 8,
-  SRAB_SPECIAL_0_OPCODE_X0 = 88,
-  SRAB_SPECIAL_0_OPCODE_X1 = 58,
-  SRAH_SPECIAL_0_OPCODE_X0 = 89,
-  SRAH_SPECIAL_0_OPCODE_X1 = 59,
-  SRAIB_SHUN_0_OPCODE_X0 = 8,
-  SRAIB_SHUN_0_OPCODE_X1 = 8,
-  SRAIH_SHUN_0_OPCODE_X0 = 9,
-  SRAIH_SHUN_0_OPCODE_X1 = 9,
-  SRAI_SHUN_0_OPCODE_X0 = 10,
-  SRAI_SHUN_0_OPCODE_X1 = 10,
-  SRAI_SHUN_0_OPCODE_Y0 = 4,
-  SRAI_SHUN_0_OPCODE_Y1 = 4,
-  SRA_SPECIAL_0_OPCODE_X0 = 90,
-  SRA_SPECIAL_0_OPCODE_X1 = 60,
-  SRA_SPECIAL_3_OPCODE_Y0 = 3,
-  SRA_SPECIAL_3_OPCODE_Y1 = 3,
-  SUBBS_U_SPECIAL_0_OPCODE_X0 = 100,
-  SUBBS_U_SPECIAL_0_OPCODE_X1 = 70,
-  SUBB_SPECIAL_0_OPCODE_X0 = 91,
-  SUBB_SPECIAL_0_OPCODE_X1 = 61,
-  SUBHS_SPECIAL_0_OPCODE_X0 = 101,
-  SUBHS_SPECIAL_0_OPCODE_X1 = 71,
-  SUBH_SPECIAL_0_OPCODE_X0 = 92,
-  SUBH_SPECIAL_0_OPCODE_X1 = 62,
-  SUBS_SPECIAL_0_OPCODE_X0 = 97,
-  SUBS_SPECIAL_0_OPCODE_X1 = 67,
-  SUB_SPECIAL_0_OPCODE_X0 = 93,
-  SUB_SPECIAL_0_OPCODE_X1 = 63,
-  SUB_SPECIAL_0_OPCODE_Y0 = 3,
-  SUB_SPECIAL_0_OPCODE_Y1 = 3,
-  SWADD_IMM_0_OPCODE_X1 = 30,
-  SWINT0_UN_0_SHUN_0_OPCODE_X1 = 18,
-  SWINT1_UN_0_SHUN_0_OPCODE_X1 = 19,
-  SWINT2_UN_0_SHUN_0_OPCODE_X1 = 20,
-  SWINT3_UN_0_SHUN_0_OPCODE_X1 = 21,
-  SW_OPCODE_Y2 = 7,
-  SW_SPECIAL_0_OPCODE_X1 = 64,
-  TBLIDXB0_UN_0_SHUN_0_OPCODE_X0 = 8,
-  TBLIDXB0_UN_0_SHUN_0_OPCODE_Y0 = 8,
-  TBLIDXB1_UN_0_SHUN_0_OPCODE_X0 = 9,
-  TBLIDXB1_UN_0_SHUN_0_OPCODE_Y0 = 9,
-  TBLIDXB2_UN_0_SHUN_0_OPCODE_X0 = 10,
-  TBLIDXB2_UN_0_SHUN_0_OPCODE_Y0 = 10,
-  TBLIDXB3_UN_0_SHUN_0_OPCODE_X0 = 11,
-  TBLIDXB3_UN_0_SHUN_0_OPCODE_Y0 = 11,
-  TNS_UN_0_SHUN_0_OPCODE_X1 = 22,
-  UN_0_SHUN_0_OPCODE_X0 = 11,
-  UN_0_SHUN_0_OPCODE_X1 = 11,
-  UN_0_SHUN_0_OPCODE_Y0 = 5,
-  UN_0_SHUN_0_OPCODE_Y1 = 5,
-  WH64_UN_0_SHUN_0_OPCODE_X1 = 23,
-  XORI_IMM_0_OPCODE_X0 = 2,
-  XORI_IMM_0_OPCODE_X1 = 21,
-  XOR_SPECIAL_0_OPCODE_X0 = 94,
-  XOR_SPECIAL_0_OPCODE_X1 = 65,
-  XOR_SPECIAL_2_OPCODE_Y0 = 3,
-  XOR_SPECIAL_2_OPCODE_Y1 = 3
+  ADDI_IMM8_OPCODE_X0 = 1,
+  ADDI_IMM8_OPCODE_X1 = 1,
+  ADDI_OPCODE_Y0 = 0,
+  ADDI_OPCODE_Y1 = 1,
+  ADDLI_OPCODE_X0 = 1,
+  ADDLI_OPCODE_X1 = 0,
+  ADDXI_IMM8_OPCODE_X0 = 2,
+  ADDXI_IMM8_OPCODE_X1 = 2,
+  ADDXI_OPCODE_Y0 = 1,
+  ADDXI_OPCODE_Y1 = 2,
+  ADDXLI_OPCODE_X0 = 2,
+  ADDXLI_OPCODE_X1 = 1,
+  ADDXSC_RRR_0_OPCODE_X0 = 1,
+  ADDXSC_RRR_0_OPCODE_X1 = 1,
+  ADDX_RRR_0_OPCODE_X0 = 2,
+  ADDX_RRR_0_OPCODE_X1 = 2,
+  ADDX_RRR_0_OPCODE_Y0 = 0,
+  ADDX_SPECIAL_0_OPCODE_Y1 = 0,
+  ADD_RRR_0_OPCODE_X0 = 3,
+  ADD_RRR_0_OPCODE_X1 = 3,
+  ADD_RRR_0_OPCODE_Y0 = 1,
+  ADD_SPECIAL_0_OPCODE_Y1 = 1,
+  ANDI_IMM8_OPCODE_X0 = 3,
+  ANDI_IMM8_OPCODE_X1 = 3,
+  ANDI_OPCODE_Y0 = 2,
+  ANDI_OPCODE_Y1 = 3,
+  AND_RRR_0_OPCODE_X0 = 4,
+  AND_RRR_0_OPCODE_X1 = 4,
+  AND_RRR_5_OPCODE_Y0 = 0,
+  AND_RRR_5_OPCODE_Y1 = 0,
+  BEQZT_BRANCH_OPCODE_X1 = 16,
+  BEQZ_BRANCH_OPCODE_X1 = 17,
+  BFEXTS_BF_OPCODE_X0 = 4,
+  BFEXTU_BF_OPCODE_X0 = 5,
+  BFINS_BF_OPCODE_X0 = 6,
+  BF_OPCODE_X0 = 3,
+  BGEZT_BRANCH_OPCODE_X1 = 18,
+  BGEZ_BRANCH_OPCODE_X1 = 19,
+  BGTZT_BRANCH_OPCODE_X1 = 20,
+  BGTZ_BRANCH_OPCODE_X1 = 21,
+  BLBCT_BRANCH_OPCODE_X1 = 22,
+  BLBC_BRANCH_OPCODE_X1 = 23,
+  BLBST_BRANCH_OPCODE_X1 = 24,
+  BLBS_BRANCH_OPCODE_X1 = 25,
+  BLEZT_BRANCH_OPCODE_X1 = 26,
+  BLEZ_BRANCH_OPCODE_X1 = 27,
+  BLTZT_BRANCH_OPCODE_X1 = 28,
+  BLTZ_BRANCH_OPCODE_X1 = 29,
+  BNEZT_BRANCH_OPCODE_X1 = 30,
+  BNEZ_BRANCH_OPCODE_X1 = 31,
+  BRANCH_OPCODE_X1 = 2,
+  CMOVEQZ_RRR_0_OPCODE_X0 = 5,
+  CMOVEQZ_RRR_4_OPCODE_Y0 = 0,
+  CMOVNEZ_RRR_0_OPCODE_X0 = 6,
+  CMOVNEZ_RRR_4_OPCODE_Y0 = 1,
+  CMPEQI_IMM8_OPCODE_X0 = 4,
+  CMPEQI_IMM8_OPCODE_X1 = 4,
+  CMPEQI_OPCODE_Y0 = 3,
+  CMPEQI_OPCODE_Y1 = 4,
+  CMPEQ_RRR_0_OPCODE_X0 = 7,
+  CMPEQ_RRR_0_OPCODE_X1 = 5,
+  CMPEQ_RRR_3_OPCODE_Y0 = 0,
+  CMPEQ_RRR_3_OPCODE_Y1 = 2,
+  CMPEXCH4_RRR_0_OPCODE_X1 = 6,
+  CMPEXCH_RRR_0_OPCODE_X1 = 7,
+  CMPLES_RRR_0_OPCODE_X0 = 8,
+  CMPLES_RRR_0_OPCODE_X1 = 8,
+  CMPLES_RRR_2_OPCODE_Y0 = 0,
+  CMPLES_RRR_2_OPCODE_Y1 = 0,
+  CMPLEU_RRR_0_OPCODE_X0 = 9,
+  CMPLEU_RRR_0_OPCODE_X1 = 9,
+  CMPLEU_RRR_2_OPCODE_Y0 = 1,
+  CMPLEU_RRR_2_OPCODE_Y1 = 1,
+  CMPLTSI_IMM8_OPCODE_X0 = 5,
+  CMPLTSI_IMM8_OPCODE_X1 = 5,
+  CMPLTSI_OPCODE_Y0 = 4,
+  CMPLTSI_OPCODE_Y1 = 5,
+  CMPLTS_RRR_0_OPCODE_X0 = 10,
+  CMPLTS_RRR_0_OPCODE_X1 = 10,
+  CMPLTS_RRR_2_OPCODE_Y0 = 2,
+  CMPLTS_RRR_2_OPCODE_Y1 = 2,
+  CMPLTUI_IMM8_OPCODE_X0 = 6,
+  CMPLTUI_IMM8_OPCODE_X1 = 6,
+  CMPLTU_RRR_0_OPCODE_X0 = 11,
+  CMPLTU_RRR_0_OPCODE_X1 = 11,
+  CMPLTU_RRR_2_OPCODE_Y0 = 3,
+  CMPLTU_RRR_2_OPCODE_Y1 = 3,
+  CMPNE_RRR_0_OPCODE_X0 = 12,
+  CMPNE_RRR_0_OPCODE_X1 = 12,
+  CMPNE_RRR_3_OPCODE_Y0 = 1,
+  CMPNE_RRR_3_OPCODE_Y1 = 3,
+  CMULAF_RRR_0_OPCODE_X0 = 13,
+  CMULA_RRR_0_OPCODE_X0 = 14,
+  CMULFR_RRR_0_OPCODE_X0 = 15,
+  CMULF_RRR_0_OPCODE_X0 = 16,
+  CMULHR_RRR_0_OPCODE_X0 = 17,
+  CMULH_RRR_0_OPCODE_X0 = 18,
+  CMUL_RRR_0_OPCODE_X0 = 19,
+  CNTLZ_UNARY_OPCODE_X0 = 1,
+  CNTLZ_UNARY_OPCODE_Y0 = 1,
+  CNTTZ_UNARY_OPCODE_X0 = 2,
+  CNTTZ_UNARY_OPCODE_Y0 = 2,
+  CRC32_32_RRR_0_OPCODE_X0 = 20,
+  CRC32_8_RRR_0_OPCODE_X0 = 21,
+  DBLALIGN2_RRR_0_OPCODE_X0 = 22,
+  DBLALIGN2_RRR_0_OPCODE_X1 = 13,
+  DBLALIGN4_RRR_0_OPCODE_X0 = 23,
+  DBLALIGN4_RRR_0_OPCODE_X1 = 14,
+  DBLALIGN6_RRR_0_OPCODE_X0 = 24,
+  DBLALIGN6_RRR_0_OPCODE_X1 = 15,
+  DBLALIGN_RRR_0_OPCODE_X0 = 25,
+  DRAIN_UNARY_OPCODE_X1 = 1,
+  DTLBPR_UNARY_OPCODE_X1 = 2,
+  EXCH4_RRR_0_OPCODE_X1 = 16,
+  EXCH_RRR_0_OPCODE_X1 = 17,
+  FDOUBLE_ADDSUB_RRR_0_OPCODE_X0 = 26,
+  FDOUBLE_ADD_FLAGS_RRR_0_OPCODE_X0 = 27,
+  FDOUBLE_MUL_FLAGS_RRR_0_OPCODE_X0 = 28,
+  FDOUBLE_PACK1_RRR_0_OPCODE_X0 = 29,
+  FDOUBLE_PACK2_RRR_0_OPCODE_X0 = 30,
+  FDOUBLE_SUB_FLAGS_RRR_0_OPCODE_X0 = 31,
+  FDOUBLE_UNPACK_MAX_RRR_0_OPCODE_X0 = 32,
+  FDOUBLE_UNPACK_MIN_RRR_0_OPCODE_X0 = 33,
+  FETCHADD4_RRR_0_OPCODE_X1 = 18,
+  FETCHADDGEZ4_RRR_0_OPCODE_X1 = 19,
+  FETCHADDGEZ_RRR_0_OPCODE_X1 = 20,
+  FETCHADD_RRR_0_OPCODE_X1 = 21,
+  FETCHAND4_RRR_0_OPCODE_X1 = 22,
+  FETCHAND_RRR_0_OPCODE_X1 = 23,
+  FETCHOR4_RRR_0_OPCODE_X1 = 24,
+  FETCHOR_RRR_0_OPCODE_X1 = 25,
+  FINV_UNARY_OPCODE_X1 = 3,
+  FLUSHWB_UNARY_OPCODE_X1 = 4,
+  FLUSH_UNARY_OPCODE_X1 = 5,
+  FNOP_UNARY_OPCODE_X0 = 3,
+  FNOP_UNARY_OPCODE_X1 = 6,
+  FNOP_UNARY_OPCODE_Y0 = 3,
+  FNOP_UNARY_OPCODE_Y1 = 8,
+  FSINGLE_ADD1_RRR_0_OPCODE_X0 = 34,
+  FSINGLE_ADDSUB2_RRR_0_OPCODE_X0 = 35,
+  FSINGLE_MUL1_RRR_0_OPCODE_X0 = 36,
+  FSINGLE_MUL2_RRR_0_OPCODE_X0 = 37,
+  FSINGLE_PACK1_UNARY_OPCODE_X0 = 4,
+  FSINGLE_PACK1_UNARY_OPCODE_Y0 = 4,
+  FSINGLE_PACK2_RRR_0_OPCODE_X0 = 38,
+  FSINGLE_SUB1_RRR_0_OPCODE_X0 = 39,
+  ICOH_UNARY_OPCODE_X1 = 7,
+  ILL_UNARY_OPCODE_X1 = 8,
+  ILL_UNARY_OPCODE_Y1 = 9,
+  IMM8_OPCODE_X0 = 4,
+  IMM8_OPCODE_X1 = 3,
+  INV_UNARY_OPCODE_X1 = 9,
+  IRET_UNARY_OPCODE_X1 = 10,
+  JALRP_UNARY_OPCODE_X1 = 11,
+  JALRP_UNARY_OPCODE_Y1 = 10,
+  JALR_UNARY_OPCODE_X1 = 12,
+  JALR_UNARY_OPCODE_Y1 = 11,
+  JAL_JUMP_OPCODE_X1 = 0,
+  JRP_UNARY_OPCODE_X1 = 13,
+  JRP_UNARY_OPCODE_Y1 = 12,
+  JR_UNARY_OPCODE_X1 = 14,
+  JR_UNARY_OPCODE_Y1 = 13,
+  JUMP_OPCODE_X1 = 4,
+  J_JUMP_OPCODE_X1 = 1,
+  LD1S_ADD_IMM8_OPCODE_X1 = 7,
+  LD1S_OPCODE_Y2 = 0,
+  LD1S_UNARY_OPCODE_X1 = 15,
+  LD1U_ADD_IMM8_OPCODE_X1 = 8,
+  LD1U_OPCODE_Y2 = 1,
+  LD1U_UNARY_OPCODE_X1 = 16,
+  LD2S_ADD_IMM8_OPCODE_X1 = 9,
+  LD2S_OPCODE_Y2 = 2,
+  LD2S_UNARY_OPCODE_X1 = 17,
+  LD2U_ADD_IMM8_OPCODE_X1 = 10,
+  LD2U_OPCODE_Y2 = 3,
+  LD2U_UNARY_OPCODE_X1 = 18,
+  LD4S_ADD_IMM8_OPCODE_X1 = 11,
+  LD4S_OPCODE_Y2 = 1,
+  LD4S_UNARY_OPCODE_X1 = 19,
+  LD4U_ADD_IMM8_OPCODE_X1 = 12,
+  LD4U_OPCODE_Y2 = 2,
+  LD4U_UNARY_OPCODE_X1 = 20,
+  LDNA_UNARY_OPCODE_X1 = 21,
+  LDNT1S_ADD_IMM8_OPCODE_X1 = 13,
+  LDNT1S_UNARY_OPCODE_X1 = 22,
+  LDNT1U_ADD_IMM8_OPCODE_X1 = 14,
+  LDNT1U_UNARY_OPCODE_X1 = 23,
+  LDNT2S_ADD_IMM8_OPCODE_X1 = 15,
+  LDNT2S_UNARY_OPCODE_X1 = 24,
+  LDNT2U_ADD_IMM8_OPCODE_X1 = 16,
+  LDNT2U_UNARY_OPCODE_X1 = 25,
+  LDNT4S_ADD_IMM8_OPCODE_X1 = 17,
+  LDNT4S_UNARY_OPCODE_X1 = 26,
+  LDNT4U_ADD_IMM8_OPCODE_X1 = 18,
+  LDNT4U_UNARY_OPCODE_X1 = 27,
+  LDNT_ADD_IMM8_OPCODE_X1 = 19,
+  LDNT_UNARY_OPCODE_X1 = 28,
+  LD_ADD_IMM8_OPCODE_X1 = 20,
+  LD_OPCODE_Y2 = 3,
+  LD_UNARY_OPCODE_X1 = 29,
+  LNK_UNARY_OPCODE_X1 = 30,
+  LNK_UNARY_OPCODE_Y1 = 14,
+  LWNA_ADD_IMM8_OPCODE_X1 = 21,
+  MFSPR_IMM8_OPCODE_X1 = 22,
+  MF_UNARY_OPCODE_X1 = 31,
+  MM_BF_OPCODE_X0 = 7,
+  MNZ_RRR_0_OPCODE_X0 = 40,
+  MNZ_RRR_0_OPCODE_X1 = 26,
+  MNZ_RRR_4_OPCODE_Y0 = 2,
+  MNZ_RRR_4_OPCODE_Y1 = 2,
+  MODE_OPCODE_YA2 = 1,
+  MODE_OPCODE_YB2 = 2,
+  MODE_OPCODE_YC2 = 3,
+  MTSPR_IMM8_OPCODE_X1 = 23,
+  MULAX_RRR_0_OPCODE_X0 = 41,
+  MULAX_RRR_3_OPCODE_Y0 = 2,
+  MULA_HS_HS_RRR_0_OPCODE_X0 = 42,
+  MULA_HS_HS_RRR_9_OPCODE_Y0 = 0,
+  MULA_HS_HU_RRR_0_OPCODE_X0 = 43,
+  MULA_HS_LS_RRR_0_OPCODE_X0 = 44,
+  MULA_HS_LU_RRR_0_OPCODE_X0 = 45,
+  MULA_HU_HU_RRR_0_OPCODE_X0 = 46,
+  MULA_HU_HU_RRR_9_OPCODE_Y0 = 1,
+  MULA_HU_LS_RRR_0_OPCODE_X0 = 47,
+  MULA_HU_LU_RRR_0_OPCODE_X0 = 48,
+  MULA_LS_LS_RRR_0_OPCODE_X0 = 49,
+  MULA_LS_LS_RRR_9_OPCODE_Y0 = 2,
+  MULA_LS_LU_RRR_0_OPCODE_X0 = 50,
+  MULA_LU_LU_RRR_0_OPCODE_X0 = 51,
+  MULA_LU_LU_RRR_9_OPCODE_Y0 = 3,
+  MULX_RRR_0_OPCODE_X0 = 52,
+  MULX_RRR_3_OPCODE_Y0 = 3,
+  MUL_HS_HS_RRR_0_OPCODE_X0 = 53,
+  MUL_HS_HS_RRR_8_OPCODE_Y0 = 0,
+  MUL_HS_HU_RRR_0_OPCODE_X0 = 54,
+  MUL_HS_LS_RRR_0_OPCODE_X0 = 55,
+  MUL_HS_LU_RRR_0_OPCODE_X0 = 56,
+  MUL_HU_HU_RRR_0_OPCODE_X0 = 57,
+  MUL_HU_HU_RRR_8_OPCODE_Y0 = 1,
+  MUL_HU_LS_RRR_0_OPCODE_X0 = 58,
+  MUL_HU_LU_RRR_0_OPCODE_X0 = 59,
+  MUL_LS_LS_RRR_0_OPCODE_X0 = 60,
+  MUL_LS_LS_RRR_8_OPCODE_Y0 = 2,
+  MUL_LS_LU_RRR_0_OPCODE_X0 = 61,
+  MUL_LU_LU_RRR_0_OPCODE_X0 = 62,
+  MUL_LU_LU_RRR_8_OPCODE_Y0 = 3,
+  MZ_RRR_0_OPCODE_X0 = 63,
+  MZ_RRR_0_OPCODE_X1 = 27,
+  MZ_RRR_4_OPCODE_Y0 = 3,
+  MZ_RRR_4_OPCODE_Y1 = 3,
+  NAP_UNARY_OPCODE_X1 = 32,
+  NOP_UNARY_OPCODE_X0 = 5,
+  NOP_UNARY_OPCODE_X1 = 33,
+  NOP_UNARY_OPCODE_Y0 = 5,
+  NOP_UNARY_OPCODE_Y1 = 15,
+  NOR_RRR_0_OPCODE_X0 = 64,
+  NOR_RRR_0_OPCODE_X1 = 28,
+  NOR_RRR_5_OPCODE_Y0 = 1,
+  NOR_RRR_5_OPCODE_Y1 = 1,
+  ORI_IMM8_OPCODE_X0 = 7,
+  ORI_IMM8_OPCODE_X1 = 24,
+  OR_RRR_0_OPCODE_X0 = 65,
+  OR_RRR_0_OPCODE_X1 = 29,
+  OR_RRR_5_OPCODE_Y0 = 2,
+  OR_RRR_5_OPCODE_Y1 = 2,
+  PCNT_UNARY_OPCODE_X0 = 6,
+  PCNT_UNARY_OPCODE_Y0 = 6,
+  REVBITS_UNARY_OPCODE_X0 = 7,
+  REVBITS_UNARY_OPCODE_Y0 = 7,
+  REVBYTES_UNARY_OPCODE_X0 = 8,
+  REVBYTES_UNARY_OPCODE_Y0 = 8,
+  ROTLI_SHIFT_OPCODE_X0 = 1,
+  ROTLI_SHIFT_OPCODE_X1 = 1,
+  ROTLI_SHIFT_OPCODE_Y0 = 0,
+  ROTLI_SHIFT_OPCODE_Y1 = 0,
+  ROTL_RRR_0_OPCODE_X0 = 66,
+  ROTL_RRR_0_OPCODE_X1 = 30,
+  ROTL_RRR_6_OPCODE_Y0 = 0,
+  ROTL_RRR_6_OPCODE_Y1 = 0,
+  RRR_0_OPCODE_X0 = 5,
+  RRR_0_OPCODE_X1 = 5,
+  RRR_0_OPCODE_Y0 = 5,
+  RRR_0_OPCODE_Y1 = 6,
+  RRR_1_OPCODE_Y0 = 6,
+  RRR_1_OPCODE_Y1 = 7,
+  RRR_2_OPCODE_Y0 = 7,
+  RRR_2_OPCODE_Y1 = 8,
+  RRR_3_OPCODE_Y0 = 8,
+  RRR_3_OPCODE_Y1 = 9,
+  RRR_4_OPCODE_Y0 = 9,
+  RRR_4_OPCODE_Y1 = 10,
+  RRR_5_OPCODE_Y0 = 10,
+  RRR_5_OPCODE_Y1 = 11,
+  RRR_6_OPCODE_Y0 = 11,
+  RRR_6_OPCODE_Y1 = 12,
+  RRR_7_OPCODE_Y0 = 12,
+  RRR_7_OPCODE_Y1 = 13,
+  RRR_8_OPCODE_Y0 = 13,
+  RRR_9_OPCODE_Y0 = 14,
+  SHIFT_OPCODE_X0 = 6,
+  SHIFT_OPCODE_X1 = 6,
+  SHIFT_OPCODE_Y0 = 15,
+  SHIFT_OPCODE_Y1 = 14,
+  SHL16INSLI_OPCODE_X0 = 7,
+  SHL16INSLI_OPCODE_X1 = 7,
+  SHL1ADDX_RRR_0_OPCODE_X0 = 67,
+  SHL1ADDX_RRR_0_OPCODE_X1 = 31,
+  SHL1ADDX_RRR_7_OPCODE_Y0 = 1,
+  SHL1ADDX_RRR_7_OPCODE_Y1 = 1,
+  SHL1ADD_RRR_0_OPCODE_X0 = 68,
+  SHL1ADD_RRR_0_OPCODE_X1 = 32,
+  SHL1ADD_RRR_1_OPCODE_Y0 = 0,
+  SHL1ADD_RRR_1_OPCODE_Y1 = 0,
+  SHL2ADDX_RRR_0_OPCODE_X0 = 69,
+  SHL2ADDX_RRR_0_OPCODE_X1 = 33,
+  SHL2ADDX_RRR_7_OPCODE_Y0 = 2,
+  SHL2ADDX_RRR_7_OPCODE_Y1 = 2,
+  SHL2ADD_RRR_0_OPCODE_X0 = 70,
+  SHL2ADD_RRR_0_OPCODE_X1 = 34,
+  SHL2ADD_RRR_1_OPCODE_Y0 = 1,
+  SHL2ADD_RRR_1_OPCODE_Y1 = 1,
+  SHL3ADDX_RRR_0_OPCODE_X0 = 71,
+  SHL3ADDX_RRR_0_OPCODE_X1 = 35,
+  SHL3ADDX_RRR_7_OPCODE_Y0 = 3,
+  SHL3ADDX_RRR_7_OPCODE_Y1 = 3,
+  SHL3ADD_RRR_0_OPCODE_X0 = 72,
+  SHL3ADD_RRR_0_OPCODE_X1 = 36,
+  SHL3ADD_RRR_1_OPCODE_Y0 = 2,
+  SHL3ADD_RRR_1_OPCODE_Y1 = 2,
+  SHLI_SHIFT_OPCODE_X0 = 2,
+  SHLI_SHIFT_OPCODE_X1 = 2,
+  SHLI_SHIFT_OPCODE_Y0 = 1,
+  SHLI_SHIFT_OPCODE_Y1 = 1,
+  SHLXI_SHIFT_OPCODE_X0 = 3,
+  SHLXI_SHIFT_OPCODE_X1 = 3,
+  SHLX_RRR_0_OPCODE_X0 = 73,
+  SHLX_RRR_0_OPCODE_X1 = 37,
+  SHL_RRR_0_OPCODE_X0 = 74,
+  SHL_RRR_0_OPCODE_X1 = 38,
+  SHL_RRR_6_OPCODE_Y0 = 1,
+  SHL_RRR_6_OPCODE_Y1 = 1,
+  SHRSI_SHIFT_OPCODE_X0 = 4,
+  SHRSI_SHIFT_OPCODE_X1 = 4,
+  SHRSI_SHIFT_OPCODE_Y0 = 2,
+  SHRSI_SHIFT_OPCODE_Y1 = 2,
+  SHRS_RRR_0_OPCODE_X0 = 75,
+  SHRS_RRR_0_OPCODE_X1 = 39,
+  SHRS_RRR_6_OPCODE_Y0 = 2,
+  SHRS_RRR_6_OPCODE_Y1 = 2,
+  SHRUI_SHIFT_OPCODE_X0 = 5,
+  SHRUI_SHIFT_OPCODE_X1 = 5,
+  SHRUI_SHIFT_OPCODE_Y0 = 3,
+  SHRUI_SHIFT_OPCODE_Y1 = 3,
+  SHRUXI_SHIFT_OPCODE_X0 = 6,
+  SHRUXI_SHIFT_OPCODE_X1 = 6,
+  SHRUX_RRR_0_OPCODE_X0 = 76,
+  SHRUX_RRR_0_OPCODE_X1 = 40,
+  SHRU_RRR_0_OPCODE_X0 = 77,
+  SHRU_RRR_0_OPCODE_X1 = 41,
+  SHRU_RRR_6_OPCODE_Y0 = 3,
+  SHRU_RRR_6_OPCODE_Y1 = 3,
+  SHUFFLEBYTES_RRR_0_OPCODE_X0 = 78,
+  ST1_ADD_IMM8_OPCODE_X1 = 25,
+  ST1_OPCODE_Y2 = 0,
+  ST1_RRR_0_OPCODE_X1 = 42,
+  ST2_ADD_IMM8_OPCODE_X1 = 26,
+  ST2_OPCODE_Y2 = 1,
+  ST2_RRR_0_OPCODE_X1 = 43,
+  ST4_ADD_IMM8_OPCODE_X1 = 27,
+  ST4_OPCODE_Y2 = 2,
+  ST4_RRR_0_OPCODE_X1 = 44,
+  STNT1_ADD_IMM8_OPCODE_X1 = 28,
+  STNT1_RRR_0_OPCODE_X1 = 45,
+  STNT2_ADD_IMM8_OPCODE_X1 = 29,
+  STNT2_RRR_0_OPCODE_X1 = 46,
+  STNT4_ADD_IMM8_OPCODE_X1 = 30,
+  STNT4_RRR_0_OPCODE_X1 = 47,
+  STNT_ADD_IMM8_OPCODE_X1 = 31,
+  STNT_RRR_0_OPCODE_X1 = 48,
+  ST_ADD_IMM8_OPCODE_X1 = 32,
+  ST_OPCODE_Y2 = 3,
+  ST_RRR_0_OPCODE_X1 = 49,
+  SUBXSC_RRR_0_OPCODE_X0 = 79,
+  SUBXSC_RRR_0_OPCODE_X1 = 50,
+  SUBX_RRR_0_OPCODE_X0 = 80,
+  SUBX_RRR_0_OPCODE_X1 = 51,
+  SUBX_RRR_0_OPCODE_Y0 = 2,
+  SUBX_RRR_0_OPCODE_Y1 = 2,
+  SUB_RRR_0_OPCODE_X0 = 81,
+  SUB_RRR_0_OPCODE_X1 = 52,
+  SUB_RRR_0_OPCODE_Y0 = 3,
+  SUB_RRR_0_OPCODE_Y1 = 3,
+  SWINT0_UNARY_OPCODE_X1 = 34,
+  SWINT1_UNARY_OPCODE_X1 = 35,
+  SWINT2_UNARY_OPCODE_X1 = 36,
+  SWINT3_UNARY_OPCODE_X1 = 37,
+  TBLIDXB0_UNARY_OPCODE_X0 = 9,
+  TBLIDXB0_UNARY_OPCODE_Y0 = 9,
+  TBLIDXB1_UNARY_OPCODE_X0 = 10,
+  TBLIDXB1_UNARY_OPCODE_Y0 = 10,
+  TBLIDXB2_UNARY_OPCODE_X0 = 11,
+  TBLIDXB2_UNARY_OPCODE_Y0 = 11,
+  TBLIDXB3_UNARY_OPCODE_X0 = 12,
+  TBLIDXB3_UNARY_OPCODE_Y0 = 12,
+  UNARY_RRR_0_OPCODE_X0 = 82,
+  UNARY_RRR_0_OPCODE_X1 = 53,
+  UNARY_RRR_1_OPCODE_Y0 = 3,
+  UNARY_RRR_1_OPCODE_Y1 = 3,
+  V1ADDI_IMM8_OPCODE_X0 = 8,
+  V1ADDI_IMM8_OPCODE_X1 = 33,
+  V1ADDUC_RRR_0_OPCODE_X0 = 83,
+  V1ADDUC_RRR_0_OPCODE_X1 = 54,
+  V1ADD_RRR_0_OPCODE_X0 = 84,
+  V1ADD_RRR_0_OPCODE_X1 = 55,
+  V1ADIFFU_RRR_0_OPCODE_X0 = 85,
+  V1AVGU_RRR_0_OPCODE_X0 = 86,
+  V1CMPEQI_IMM8_OPCODE_X0 = 9,
+  V1CMPEQI_IMM8_OPCODE_X1 = 34,
+  V1CMPEQ_RRR_0_OPCODE_X0 = 87,
+  V1CMPEQ_RRR_0_OPCODE_X1 = 56,
+  V1CMPLES_RRR_0_OPCODE_X0 = 88,
+  V1CMPLES_RRR_0_OPCODE_X1 = 57,
+  V1CMPLEU_RRR_0_OPCODE_X0 = 89,
+  V1CMPLEU_RRR_0_OPCODE_X1 = 58,
+  V1CMPLTSI_IMM8_OPCODE_X0 = 10,
+  V1CMPLTSI_IMM8_OPCODE_X1 = 35,
+  V1CMPLTS_RRR_0_OPCODE_X0 = 90,
+  V1CMPLTS_RRR_0_OPCODE_X1 = 59,
+  V1CMPLTUI_IMM8_OPCODE_X0 = 11,
+  V1CMPLTUI_IMM8_OPCODE_X1 = 36,
+  V1CMPLTU_RRR_0_OPCODE_X0 = 91,
+  V1CMPLTU_RRR_0_OPCODE_X1 = 60,
+  V1CMPNE_RRR_0_OPCODE_X0 = 92,
+  V1CMPNE_RRR_0_OPCODE_X1 = 61,
+  V1DDOTPUA_RRR_0_OPCODE_X0 = 161,
+  V1DDOTPUSA_RRR_0_OPCODE_X0 = 93,
+  V1DDOTPUS_RRR_0_OPCODE_X0 = 94,
+  V1DDOTPU_RRR_0_OPCODE_X0 = 162,
+  V1DOTPA_RRR_0_OPCODE_X0 = 95,
+  V1DOTPUA_RRR_0_OPCODE_X0 = 163,
+  V1DOTPUSA_RRR_0_OPCODE_X0 = 96,
+  V1DOTPUS_RRR_0_OPCODE_X0 = 97,
+  V1DOTPU_RRR_0_OPCODE_X0 = 164,
+  V1DOTP_RRR_0_OPCODE_X0 = 98,
+  V1INT_H_RRR_0_OPCODE_X0 = 99,
+  V1INT_H_RRR_0_OPCODE_X1 = 62,
+  V1INT_L_RRR_0_OPCODE_X0 = 100,
+  V1INT_L_RRR_0_OPCODE_X1 = 63,
+  V1MAXUI_IMM8_OPCODE_X0 = 12,
+  V1MAXUI_IMM8_OPCODE_X1 = 37,
+  V1MAXU_RRR_0_OPCODE_X0 = 101,
+  V1MAXU_RRR_0_OPCODE_X1 = 64,
+  V1MINUI_IMM8_OPCODE_X0 = 13,
+  V1MINUI_IMM8_OPCODE_X1 = 38,
+  V1MINU_RRR_0_OPCODE_X0 = 102,
+  V1MINU_RRR_0_OPCODE_X1 = 65,
+  V1MNZ_RRR_0_OPCODE_X0 = 103,
+  V1MNZ_RRR_0_OPCODE_X1 = 66,
+  V1MULTU_RRR_0_OPCODE_X0 = 104,
+  V1MULUS_RRR_0_OPCODE_X0 = 105,
+  V1MULU_RRR_0_OPCODE_X0 = 106,
+  V1MZ_RRR_0_OPCODE_X0 = 107,
+  V1MZ_RRR_0_OPCODE_X1 = 67,
+  V1SADAU_RRR_0_OPCODE_X0 = 108,
+  V1SADU_RRR_0_OPCODE_X0 = 109,
+  V1SHLI_SHIFT_OPCODE_X0 = 7,
+  V1SHLI_SHIFT_OPCODE_X1 = 7,
+  V1SHL_RRR_0_OPCODE_X0 = 110,
+  V1SHL_RRR_0_OPCODE_X1 = 68,
+  V1SHRSI_SHIFT_OPCODE_X0 = 8,
+  V1SHRSI_SHIFT_OPCODE_X1 = 8,
+  V1SHRS_RRR_0_OPCODE_X0 = 111,
+  V1SHRS_RRR_0_OPCODE_X1 = 69,
+  V1SHRUI_SHIFT_OPCODE_X0 = 9,
+  V1SHRUI_SHIFT_OPCODE_X1 = 9,
+  V1SHRU_RRR_0_OPCODE_X0 = 112,
+  V1SHRU_RRR_0_OPCODE_X1 = 70,
+  V1SUBUC_RRR_0_OPCODE_X0 = 113,
+  V1SUBUC_RRR_0_OPCODE_X1 = 71,
+  V1SUB_RRR_0_OPCODE_X0 = 114,
+  V1SUB_RRR_0_OPCODE_X1 = 72,
+  V2ADDI_IMM8_OPCODE_X0 = 14,
+  V2ADDI_IMM8_OPCODE_X1 = 39,
+  V2ADDSC_RRR_0_OPCODE_X0 = 115,
+  V2ADDSC_RRR_0_OPCODE_X1 = 73,
+  V2ADD_RRR_0_OPCODE_X0 = 116,
+  V2ADD_RRR_0_OPCODE_X1 = 74,
+  V2ADIFFS_RRR_0_OPCODE_X0 = 117,
+  V2AVGS_RRR_0_OPCODE_X0 = 118,
+  V2CMPEQI_IMM8_OPCODE_X0 = 15,
+  V2CMPEQI_IMM8_OPCODE_X1 = 40,
+  V2CMPEQ_RRR_0_OPCODE_X0 = 119,
+  V2CMPEQ_RRR_0_OPCODE_X1 = 75,
+  V2CMPLES_RRR_0_OPCODE_X0 = 120,
+  V2CMPLES_RRR_0_OPCODE_X1 = 76,
+  V2CMPLEU_RRR_0_OPCODE_X0 = 121,
+  V2CMPLEU_RRR_0_OPCODE_X1 = 77,
+  V2CMPLTSI_IMM8_OPCODE_X0 = 16,
+  V2CMPLTSI_IMM8_OPCODE_X1 = 41,
+  V2CMPLTS_RRR_0_OPCODE_X0 = 122,
+  V2CMPLTS_RRR_0_OPCODE_X1 = 78,
+  V2CMPLTUI_IMM8_OPCODE_X0 = 17,
+  V2CMPLTUI_IMM8_OPCODE_X1 = 42,
+  V2CMPLTU_RRR_0_OPCODE_X0 = 123,
+  V2CMPLTU_RRR_0_OPCODE_X1 = 79,
+  V2CMPNE_RRR_0_OPCODE_X0 = 124,
+  V2CMPNE_RRR_0_OPCODE_X1 = 80,
+  V2DOTPA_RRR_0_OPCODE_X0 = 125,
+  V2DOTP_RRR_0_OPCODE_X0 = 126,
+  V2INT_H_RRR_0_OPCODE_X0 = 127,
+  V2INT_H_RRR_0_OPCODE_X1 = 81,
+  V2INT_L_RRR_0_OPCODE_X0 = 128,
+  V2INT_L_RRR_0_OPCODE_X1 = 82,
+  V2MAXSI_IMM8_OPCODE_X0 = 18,
+  V2MAXSI_IMM8_OPCODE_X1 = 43,
+  V2MAXS_RRR_0_OPCODE_X0 = 129,
+  V2MAXS_RRR_0_OPCODE_X1 = 83,
+  V2MINSI_IMM8_OPCODE_X0 = 19,
+  V2MINSI_IMM8_OPCODE_X1 = 44,
+  V2MINS_RRR_0_OPCODE_X0 = 130,
+  V2MINS_RRR_0_OPCODE_X1 = 84,
+  V2MNZ_RRR_0_OPCODE_X0 = 131,
+  V2MNZ_RRR_0_OPCODE_X1 = 85,
+  V2MULFSC_RRR_0_OPCODE_X0 = 132,
+  V2MULS_RRR_0_OPCODE_X0 = 133,
+  V2MULTS_RRR_0_OPCODE_X0 = 134,
+  V2MZ_RRR_0_OPCODE_X0 = 135,
+  V2MZ_RRR_0_OPCODE_X1 = 86,
+  V2PACKH_RRR_0_OPCODE_X0 = 136,
+  V2PACKH_RRR_0_OPCODE_X1 = 87,
+  V2PACKL_RRR_0_OPCODE_X0 = 137,
+  V2PACKL_RRR_0_OPCODE_X1 = 88,
+  V2PACKUC_RRR_0_OPCODE_X0 = 138,
+  V2PACKUC_RRR_0_OPCODE_X1 = 89,
+  V2SADAS_RRR_0_OPCODE_X0 = 139,
+  V2SADAU_RRR_0_OPCODE_X0 = 140,
+  V2SADS_RRR_0_OPCODE_X0 = 141,
+  V2SADU_RRR_0_OPCODE_X0 = 142,
+  V2SHLI_SHIFT_OPCODE_X0 = 10,
+  V2SHLI_SHIFT_OPCODE_X1 = 10,
+  V2SHLSC_RRR_0_OPCODE_X0 = 143,
+  V2SHLSC_RRR_0_OPCODE_X1 = 90,
+  V2SHL_RRR_0_OPCODE_X0 = 144,
+  V2SHL_RRR_0_OPCODE_X1 = 91,
+  V2SHRSI_SHIFT_OPCODE_X0 = 11,
+  V2SHRSI_SHIFT_OPCODE_X1 = 11,
+  V2SHRS_RRR_0_OPCODE_X0 = 145,
+  V2SHRS_RRR_0_OPCODE_X1 = 92,
+  V2SHRUI_SHIFT_OPCODE_X0 = 12,
+  V2SHRUI_SHIFT_OPCODE_X1 = 12,
+  V2SHRU_RRR_0_OPCODE_X0 = 146,
+  V2SHRU_RRR_0_OPCODE_X1 = 93,
+  V2SUBSC_RRR_0_OPCODE_X0 = 147,
+  V2SUBSC_RRR_0_OPCODE_X1 = 94,
+  V2SUB_RRR_0_OPCODE_X0 = 148,
+  V2SUB_RRR_0_OPCODE_X1 = 95,
+  V4ADDSC_RRR_0_OPCODE_X0 = 149,
+  V4ADDSC_RRR_0_OPCODE_X1 = 96,
+  V4ADD_RRR_0_OPCODE_X0 = 150,
+  V4ADD_RRR_0_OPCODE_X1 = 97,
+  V4INT_H_RRR_0_OPCODE_X0 = 151,
+  V4INT_H_RRR_0_OPCODE_X1 = 98,
+  V4INT_L_RRR_0_OPCODE_X0 = 152,
+  V4INT_L_RRR_0_OPCODE_X1 = 99,
+  V4PACKSC_RRR_0_OPCODE_X0 = 153,
+  V4PACKSC_RRR_0_OPCODE_X1 = 100,
+  V4SHLSC_RRR_0_OPCODE_X0 = 154,
+  V4SHLSC_RRR_0_OPCODE_X1 = 101,
+  V4SHL_RRR_0_OPCODE_X0 = 155,
+  V4SHL_RRR_0_OPCODE_X1 = 102,
+  V4SHRS_RRR_0_OPCODE_X0 = 156,
+  V4SHRS_RRR_0_OPCODE_X1 = 103,
+  V4SHRU_RRR_0_OPCODE_X0 = 157,
+  V4SHRU_RRR_0_OPCODE_X1 = 104,
+  V4SUBSC_RRR_0_OPCODE_X0 = 158,
+  V4SUBSC_RRR_0_OPCODE_X1 = 105,
+  V4SUB_RRR_0_OPCODE_X0 = 159,
+  V4SUB_RRR_0_OPCODE_X1 = 106,
+  WH64_UNARY_OPCODE_X1 = 38,
+  XORI_IMM8_OPCODE_X0 = 20,
+  XORI_IMM8_OPCODE_X1 = 45,
+  XOR_RRR_0_OPCODE_X0 = 160,
+  XOR_RRR_0_OPCODE_X1 = 107,
+  XOR_RRR_5_OPCODE_Y0 = 3,
+  XOR_RRR_5_OPCODE_Y1 = 3
 };
 
 #endif /* !_TILE_OPCODE_CONSTANTS_H */
index 3eb53525bf9d380d8b4d54db5c063abe694b527e..db93518fac033ff373671549ed7c7da23688ce80 100644 (file)
@@ -16,7 +16,8 @@
 #define _ASM_TILE_PAGE_H
 
 #include <linux/const.h>
-#include <hv/pagesize.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
 
 /* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
 #define PAGE_SHIFT     HV_LOG2_PAGE_SIZE_SMALL
@@ -28,8 +29,6 @@
 #define PAGE_MASK      (~(PAGE_SIZE - 1))
 #define HPAGE_MASK     (~(HPAGE_SIZE - 1))
 
-#ifdef __KERNEL__
-
 /*
  * If the Kconfig doesn't specify, set a maximum zone order that
  * is enough so that we can create huge pages from small pages given
@@ -39,9 +38,6 @@
 #define CONFIG_FORCE_MAX_ZONEORDER (HPAGE_SHIFT - PAGE_SHIFT + 1)
 #endif
 
-#include <hv/hypervisor.h>
-#include <arch/chip.h>
-
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
@@ -91,6 +87,10 @@ typedef struct page *pgtable_t;
 /* Must be a macro since it is used to create constants. */
 #define __pgprot(val) hv_pte(val)
 
+/* Rarely-used initializers, typically with a "zero" value. */
+#define __pte(x) hv_pte(x)
+#define __pgd(x) hv_pte(x)
+
 static inline u64 pgprot_val(pgprot_t pgprot)
 {
        return hv_pte_val(pgprot);
@@ -110,6 +110,8 @@ static inline u64 pgd_val(pgd_t pgd)
 
 typedef HV_PTE pmd_t;
 
+#define __pmd(x) hv_pte(x)
+
 static inline u64 pmd_val(pmd_t pmd)
 {
        return hv_pte_val(pmd);
@@ -318,7 +320,7 @@ static inline int pfn_valid(unsigned long pfn)
 
 /* Provide as macros since these require some other headers included. */
 #define page_to_pa(page) ((phys_addr_t)(page_to_pfn(page)) << PAGE_SHIFT)
-#define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn(kaddr))
+#define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn((void *)(kaddr)))
 #define page_to_virt(page) pfn_to_kaddr(page_to_pfn(page))
 
 struct mm_struct;
@@ -331,6 +333,4 @@ extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
 
 #include <asm-generic/memory_model.h>
 
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_TILE_PAGE_H */
diff --git a/arch/tile/include/asm/parport.h b/arch/tile/include/asm/parport.h
new file mode 100644 (file)
index 0000000..cf252af
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/parport.h>
index c3fc458a0d323485557c1b6a97db662534fd9c3f..7f03cefed1b92079687a2ca838cd9d700a600a58 100644 (file)
@@ -46,7 +46,8 @@ struct pci_controller {
  */
 #define PCI_DMA_BUS_IS_PHYS     1
 
-int __init tile_pci_init(void);
+int __devinit tile_pci_init(void);
+int __devinit pcibios_init(void);
 
 void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {}
diff --git a/arch/tile/include/asm/pgtable_64.h b/arch/tile/include/asm/pgtable_64.h
new file mode 100644 (file)
index 0000000..fd80328
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ */
+
+#ifndef _ASM_TILE_PGTABLE_64_H
+#define _ASM_TILE_PGTABLE_64_H
+
+/* The level-0 page table breaks the address space into 32-bit chunks. */
+#define PGDIR_SHIFT    HV_LOG2_L1_SPAN
+#define PGDIR_SIZE     HV_L1_SPAN
+#define PGDIR_MASK     (~(PGDIR_SIZE-1))
+#define PTRS_PER_PGD   HV_L0_ENTRIES
+#define SIZEOF_PGD     (PTRS_PER_PGD * sizeof(pgd_t))
+
+/*
+ * The level-1 index is defined by the huge page size.  A PMD is composed
+ * of PTRS_PER_PMD pgd_t's and is the middle level of the page table.
+ */
+#define PMD_SHIFT      HV_LOG2_PAGE_SIZE_LARGE
+#define PMD_SIZE       HV_PAGE_SIZE_LARGE
+#define PMD_MASK       (~(PMD_SIZE-1))
+#define PTRS_PER_PMD   (1 << (PGDIR_SHIFT - PMD_SHIFT))
+#define SIZEOF_PMD     (PTRS_PER_PMD * sizeof(pmd_t))
+
+/*
+ * The level-2 index is defined by the difference between the huge
+ * page size and the normal page size.  A PTE is composed of
+ * PTRS_PER_PTE pte_t's and is the bottom level of the page table.
+ * Note that the hypervisor docs use PTE for what we call pte_t, so
+ * this nomenclature is somewhat confusing.
+ */
+#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
+#define SIZEOF_PTE     (PTRS_PER_PTE * sizeof(pte_t))
+
+/*
+ * Align the vmalloc area to an L2 page table, and leave a guard page
+ * at the beginning and end.  The vmalloc code also puts in an internal
+ * guard page between each allocation.
+ */
+#define _VMALLOC_END   HUGE_VMAP_BASE
+#define VMALLOC_END    (_VMALLOC_END - PAGE_SIZE)
+#define VMALLOC_START  (_VMALLOC_START + PAGE_SIZE)
+
+#define HUGE_VMAP_END  (HUGE_VMAP_BASE + PGDIR_SIZE)
+
+#ifndef __ASSEMBLY__
+
+/* We have no pud since we are a three-level page table. */
+#include <asm-generic/pgtable-nopud.h>
+
+static inline int pud_none(pud_t pud)
+{
+       return pud_val(pud) == 0;
+}
+
+static inline int pud_present(pud_t pud)
+{
+       return pud_val(pud) & _PAGE_PRESENT;
+}
+
+#define pmd_ERROR(e) \
+       pr_err("%s:%d: bad pmd 0x%016llx.\n", __FILE__, __LINE__, pmd_val(e))
+
+static inline void pud_clear(pud_t *pudp)
+{
+       __pte_clear(&pudp->pgd);
+}
+
+static inline int pud_bad(pud_t pud)
+{
+       return ((pud_val(pud) & _PAGE_ALL) != _PAGE_TABLE);
+}
+
+/* Return the page-table frame number (ptfn) that a pud_t points at. */
+#define pud_ptfn(pud) hv_pte_get_ptfn((pud).pgd)
+
+/*
+ * A given kernel pud_t maps to a kernel pmd_t table at a specific
+ * virtual address.  Since kernel pmd_t tables can be aligned at
+ * sub-page granularity, this macro can return non-page-aligned
+ * pointers, despite its name.
+ */
+#define pud_page_vaddr(pud) \
+       (__va((phys_addr_t)pud_ptfn(pud) << HV_LOG2_PAGE_TABLE_ALIGN))
+
+/*
+ * A pud_t points to a pmd_t array.  Since we can have multiple per
+ * page, we don't have a one-to-one mapping of pud_t's to pages.
+ */
+#define pud_page(pud) pfn_to_page(HV_PTFN_TO_PFN(pud_ptfn(pud)))
+
+static inline unsigned long pud_index(unsigned long address)
+{
+       return (address >> PUD_SHIFT) & (PTRS_PER_PUD - 1);
+}
+
+#define pmd_offset(pud, address) \
+       ((pmd_t *)pud_page_vaddr(*(pud)) + pmd_index(address))
+
+static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+       set_pte(pmdp, pmdval);
+}
+
+/* Create a pmd from a PTFN and pgprot. */
+static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot)
+{
+       return hv_pte_set_ptfn(prot, ptfn);
+}
+
+/* Return the page-table frame number (ptfn) that a pmd_t points at. */
+static inline unsigned long pmd_ptfn(pmd_t pmd)
+{
+       return hv_pte_get_ptfn(pmd);
+}
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+       __pte_clear(pmdp);
+}
+
+/* Normalize an address to having the correct high bits set. */
+#define pgd_addr_normalize pgd_addr_normalize
+static inline unsigned long pgd_addr_normalize(unsigned long addr)
+{
+       return ((long)addr << (CHIP_WORD_SIZE() - CHIP_VA_WIDTH())) >>
+               (CHIP_WORD_SIZE() - CHIP_VA_WIDTH());
+}
+
+/* We don't define any pgds for these addresses. */
+static inline int pgd_addr_invalid(unsigned long addr)
+{
+       return addr >= MEM_HV_START ||
+               (addr > MEM_LOW_END && addr < MEM_HIGH_START);
+}
+
+/*
+ * Use atomic instructions to provide atomicity against the hypervisor.
+ */
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
+                                           unsigned long addr, pte_t *ptep)
+{
+       return (__insn_fetchand(&ptep->val, ~HV_PTE_ACCESSED) >>
+               HV_PTE_INDEX_ACCESSED) & 0x1;
+}
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm,
+                                     unsigned long addr, pte_t *ptep)
+{
+       __insn_fetchand(&ptep->val, ~HV_PTE_WRITABLE);
+}
+
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+                                      unsigned long addr, pte_t *ptep)
+{
+       return hv_pte(__insn_exch(&ptep->val, 0UL));
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_TILE_PGTABLE_64_H */
index e6889474038a056e43ba19c5928b334ddca5a741..34c1e01ffb5e24648c4171fccedcd3257ef5e0da 100644 (file)
@@ -215,6 +215,8 @@ static inline void release_thread(struct task_struct *dead_task)
 
 extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
+extern int do_work_pending(struct pt_regs *regs, u32 flags);
+
 
 /*
  * Return saved (kernel) PC of a blocked thread.
@@ -255,10 +257,6 @@ static inline void cpu_relax(void)
        barrier();
 }
 
-struct siginfo;
-extern void arch_coredump_signal(struct siginfo *, struct pt_regs *);
-#define arch_coredump_signal arch_coredump_signal
-
 /* Info on this processor (see fs/proc/cpuinfo.c) */
 struct seq_operations;
 extern const struct seq_operations cpuinfo_op;
@@ -269,9 +267,6 @@ extern char chip_model[64];
 /* Data on which physical memory controller corresponds to which NUMA node. */
 extern int node_controller[];
 
-/* Do we dump information to the console when a user application crashes? */
-extern int show_crashinfo;
-
 #if CHIP_HAS_CBOX_HOME_MAP()
 /* Does the heap allocator return hash-for-home pages by default? */
 extern int hash_default;
diff --git a/arch/tile/include/asm/serial.h b/arch/tile/include/asm/serial.h
new file mode 100644 (file)
index 0000000..a0cb0ca
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/serial.h>
index 81d92a45cd4b613e2c18add9afe153e43a5d703e..1e1e616783ebfdd50ba937df77391816026ecaff 100644 (file)
@@ -28,6 +28,10 @@ struct pt_regs;
 int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
 int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
 void do_signal(struct pt_regs *regs);
+void signal_fault(const char *type, struct pt_regs *,
+                 void __user *frame, int sig);
+void trace_unhandled_signal(const char *type, struct pt_regs *regs,
+                           unsigned long address, int signo);
 #endif
 
 #endif /* _ASM_TILE_SIGNAL_H */
diff --git a/arch/tile/include/asm/spinlock_64.h b/arch/tile/include/asm/spinlock_64.h
new file mode 100644 (file)
index 0000000..72be590
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * 64-bit SMP ticket spinlocks, allowing only a single CPU anywhere
+ * (the type definitions are in asm/spinlock_types.h)
+ */
+
+#ifndef _ASM_TILE_SPINLOCK_64_H
+#define _ASM_TILE_SPINLOCK_64_H
+
+/* Shifts and masks for the various fields in "lock". */
+#define __ARCH_SPIN_CURRENT_SHIFT      17
+#define __ARCH_SPIN_NEXT_MASK          0x7fff
+#define __ARCH_SPIN_NEXT_OVERFLOW      0x8000
+
+/*
+ * Return the "current" portion of a ticket lock value,
+ * i.e. the number that currently owns the lock.
+ */
+static inline int arch_spin_current(u32 val)
+{
+       return val >> __ARCH_SPIN_CURRENT_SHIFT;
+}
+
+/*
+ * Return the "next" portion of a ticket lock value,
+ * i.e. the number that the next task to try to acquire the lock will get.
+ */
+static inline int arch_spin_next(u32 val)
+{
+       return val & __ARCH_SPIN_NEXT_MASK;
+}
+
+/* The lock is locked if a task would have to wait to get it. */
+static inline int arch_spin_is_locked(arch_spinlock_t *lock)
+{
+       u32 val = lock->lock;
+       return arch_spin_current(val) != arch_spin_next(val);
+}
+
+/* Bump the current ticket so the next task owns the lock. */
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+       wmb();  /* guarantee anything modified under the lock is visible */
+       __insn_fetchadd4(&lock->lock, 1U << __ARCH_SPIN_CURRENT_SHIFT);
+}
+
+void arch_spin_unlock_wait(arch_spinlock_t *lock);
+
+void arch_spin_lock_slow(arch_spinlock_t *lock, u32 val);
+
+/* Grab the "next" ticket number and bump it atomically.
+ * If the current ticket is not ours, go to the slow path.
+ * We also take the slow path if the "next" value overflows.
+ */
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+       u32 val = __insn_fetchadd4(&lock->lock, 1);
+       u32 ticket = val & (__ARCH_SPIN_NEXT_MASK | __ARCH_SPIN_NEXT_OVERFLOW);
+       if (unlikely(arch_spin_current(val) != ticket))
+               arch_spin_lock_slow(lock, ticket);
+}
+
+/* Try to get the lock, and return whether we succeeded. */
+int arch_spin_trylock(arch_spinlock_t *lock);
+
+/* We cannot take an interrupt after getting a ticket, so don't enable them. */
+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * We use fetchadd() for readers, and fetchor() with the sign bit
+ * for writers.
+ */
+
+#define __WRITE_LOCK_BIT (1 << 31)
+
+static inline int arch_write_val_locked(int val)
+{
+       return val < 0;  /* Optimize "val & __WRITE_LOCK_BIT". */
+}
+
+/**
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static inline int arch_read_can_lock(arch_rwlock_t *rw)
+{
+       return !arch_write_val_locked(rw->lock);
+}
+
+/**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static inline int arch_write_can_lock(arch_rwlock_t *rw)
+{
+       return rw->lock == 0;
+}
+
+extern void __read_lock_failed(arch_rwlock_t *rw);
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+       u32 val = __insn_fetchaddgez4(&rw->lock, 1);
+       if (unlikely(arch_write_val_locked(val)))
+               __read_lock_failed(rw);
+}
+
+extern void __write_lock_failed(arch_rwlock_t *rw, u32 val);
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+       u32 val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT);
+       if (unlikely(val != 0))
+               __write_lock_failed(rw, val);
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+       __insn_mf();
+       __insn_fetchadd4(&rw->lock, -1);
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+       __insn_mf();
+       rw->lock = 0;
+}
+
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+       return !arch_write_val_locked(__insn_fetchaddgez4(&rw->lock, 1));
+}
+
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+       u32 val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT);
+       if (likely(val == 0))
+               return 1;
+       if (!arch_write_val_locked(val))
+               __insn_fetchand4(&rw->lock, ~__WRITE_LOCK_BIT);
+       return 0;
+}
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#endif /* _ASM_TILE_SPINLOCK_64_H */
index b16e5db8f0e7225f9e8789a747f9295d341d947d..c0db34d56be367f24a29b9e4249a98d9ad356961 100644 (file)
@@ -1,4 +1,4 @@
-#ifdef CONFIG_COMPAT
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 #define __ARCH_WANT_STAT64     /* Used for compat_sys_stat64() etc. */
 #endif
 #include <asm-generic/stat.h>
index 25c686a00f1d2ed460e4c14330e414a10e587d4a..7c37b38f6c8d78f36c2215e6387e71c25c0e29ab 100644 (file)
 /* Tile gcc is always >= 4.3.0, so we use __builtin_bswap. */
 #define __arch_swab32(x) __builtin_bswap32(x)
 #define __arch_swab64(x) __builtin_bswap64(x)
-
-/* Use the variant that is natural for the wordsize. */
-#ifdef CONFIG_64BIT
-#define __arch_swab16(x) (__builtin_bswap64(x) >> 48)
-#else
 #define __arch_swab16(x) (__builtin_bswap32(x) >> 16)
-#endif
 
 #endif /* _ASM_TILE_SWAB_H */
index 3405b52853b869ba7bae0fcd7e091051fdaa30a7..bc4f562bd4594762a04dc7a845be8b0fcfa6b763 100644 (file)
@@ -125,6 +125,7 @@ extern void cpu_idle_on_new_stack(struct thread_info *old_ti,
 #define TIF_SYSCALL_AUDIT      5       /* syscall auditing active */
 #define TIF_SECCOMP            6       /* secure computing */
 #define TIF_MEMDIE             7       /* OOM killer at work */
+#define TIF_NOTIFY_RESUME      8       /* callback before returning to user */
 
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
@@ -134,10 +135,12 @@ extern void cpu_idle_on_new_stack(struct thread_info *old_ti,
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_MEMDIE            (1<<TIF_MEMDIE)
+#define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 
 /* Work to do on any return to user space. */
 #define _TIF_ALLWORK_MASK \
-  (_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|_TIF_ASYNC_TLB)
+  (_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|\
+   _TIF_ASYNC_TLB|_TIF_NOTIFY_RESUME)
 
 /*
  * Thread-synchronous status.
index 343172d422a95fe3652de7038bf42a9b36b7a0e5..6fdd0c860193a9b3b3279d881a4d368706de7f9a 100644 (file)
@@ -44,25 +44,64 @@ static inline const struct cpumask *cpumask_of_node(int node)
 /* For now, use numa node -1 for global allocation. */
 #define pcibus_to_node(bus)            ((void)(bus), -1)
 
+/*
+ * TILE architecture has many cores integrated in one processor, so we need
+ * setup bigger balance_interval for both CPU/NODE scheduling domains to
+ * reduce process scheduling costs.
+ */
+
+/* sched_domains SD_CPU_INIT for TILE architecture */
+#define SD_CPU_INIT (struct sched_domain) {                            \
+       .min_interval           = 4,                                    \
+       .max_interval           = 128,                                  \
+       .busy_factor            = 64,                                   \
+       .imbalance_pct          = 125,                                  \
+       .cache_nice_tries       = 1,                                    \
+       .busy_idx               = 2,                                    \
+       .idle_idx               = 1,                                    \
+       .newidle_idx            = 0,                                    \
+       .wake_idx               = 0,                                    \
+       .forkexec_idx           = 0,                                    \
+                                                                       \
+       .flags                  = 1*SD_LOAD_BALANCE                     \
+                               | 1*SD_BALANCE_NEWIDLE                  \
+                               | 1*SD_BALANCE_EXEC                     \
+                               | 1*SD_BALANCE_FORK                     \
+                               | 0*SD_BALANCE_WAKE                     \
+                               | 0*SD_WAKE_AFFINE                      \
+                               | 0*SD_PREFER_LOCAL                     \
+                               | 0*SD_SHARE_CPUPOWER                   \
+                               | 0*SD_SHARE_PKG_RESOURCES              \
+                               | 0*SD_SERIALIZE                        \
+                               ,                                       \
+       .last_balance           = jiffies,                              \
+       .balance_interval       = 32,                                   \
+}
+
 /* sched_domains SD_NODE_INIT for TILE architecture */
-#define SD_NODE_INIT (struct sched_domain) {           \
-       .min_interval           = 8,                    \
-       .max_interval           = 32,                   \
-       .busy_factor            = 32,                   \
-       .imbalance_pct          = 125,                  \
-       .cache_nice_tries       = 1,                    \
-       .busy_idx               = 3,                    \
-       .idle_idx               = 1,                    \
-       .newidle_idx            = 2,                    \
-       .wake_idx               = 1,                    \
-       .flags                  = SD_LOAD_BALANCE       \
-                               | SD_BALANCE_NEWIDLE    \
-                               | SD_BALANCE_EXEC       \
-                               | SD_BALANCE_FORK       \
-                               | SD_WAKE_AFFINE        \
-                               | SD_SERIALIZE,         \
-       .last_balance           = jiffies,              \
-       .balance_interval       = 1,                    \
+#define SD_NODE_INIT (struct sched_domain) {                           \
+       .min_interval           = 16,                                   \
+       .max_interval           = 512,                                  \
+       .busy_factor            = 32,                                   \
+       .imbalance_pct          = 125,                                  \
+       .cache_nice_tries       = 1,                                    \
+       .busy_idx               = 3,                                    \
+       .idle_idx               = 1,                                    \
+       .newidle_idx            = 2,                                    \
+       .wake_idx               = 1,                                    \
+       .flags                  = 1*SD_LOAD_BALANCE                     \
+                               | 1*SD_BALANCE_NEWIDLE                  \
+                               | 1*SD_BALANCE_EXEC                     \
+                               | 1*SD_BALANCE_FORK                     \
+                               | 0*SD_BALANCE_WAKE                     \
+                               | 0*SD_WAKE_AFFINE                      \
+                               | 0*SD_PREFER_LOCAL                     \
+                               | 0*SD_SHARE_CPUPOWER                   \
+                               | 0*SD_SHARE_PKG_RESOURCES              \
+                               | 1*SD_SERIALIZE                        \
+                               ,                                       \
+       .last_balance           = jiffies,                              \
+       .balance_interval       = 128,                                  \
 }
 
 /* By definition, we create nodes based on online memory. */
index d06e35f572010cc1a5f4de4e78740039b785f89d..5f20f920f932b6c38e0a8971d1cedfb012dd729c 100644 (file)
 #ifndef _ASM_TILE_TRAPS_H
 #define _ASM_TILE_TRAPS_H
 
+#include <arch/chip.h>
+
 /* mm/fault.c */
 void do_page_fault(struct pt_regs *, int fault_num,
                   unsigned long address, unsigned long write);
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
 void do_async_page_fault(struct pt_regs *);
+#endif
 
 #ifndef __tilegx__
 /*
index b35c2db71199ae3d70fc2b1e29687dc350514a77..f70bf1c541f1e2b8f4572223c1b1ee34893269f1 100644 (file)
@@ -15,7 +15,7 @@
 #if !defined(_ASM_TILE_UNISTD_H) || defined(__SYSCALL)
 #define _ASM_TILE_UNISTD_H
 
-#ifndef __LP64__
+#if !defined(__LP64__) || defined(__SYSCALL_COMPAT)
 /* Use the flavor of this syscall that matches the 32-bit API better. */
 #define __ARCH_WANT_SYNC_FILE_RANGE2
 #endif
similarity index 52%
rename from arch/tile/include/hv/pagesize.h
rename to arch/tile/include/asm/vga.h
index 58bed114fedd7212f3a9793fe41a8e6b52c49b36..7b46e754d611c8852b03a920ad7531f65bab6a58 100644 (file)
  *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  *   NON INFRINGEMENT.  See the GNU General Public License for
  *   more details.
+ *
+ * Access to VGA videoram.
  */
 
-/**
- * @file pagesize.h
- */
+#ifndef _ASM_TILE_VGA_H
+#define _ASM_TILE_VGA_H
 
-#ifndef _HV_PAGESIZE_H
-#define _HV_PAGESIZE_H
+#include <asm/io.h>
 
-/** The log2 of the size of small pages, in bytes. This value should
- * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
- */
-#define HV_LOG2_PAGE_SIZE_SMALL 16
+#define VT_BUF_HAVE_RW
 
-/** The log2 of the size of large pages, in bytes. This value should be
- * verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
- */
-#define HV_LOG2_PAGE_SIZE_LARGE 24
+static inline void scr_writew(u16 val, volatile u16 *addr)
+{
+       __raw_writew(val, (volatile u16 __iomem *) addr);
+}
+
+static inline u16 scr_readw(volatile const u16 *addr)
+{
+       return __raw_readw((volatile const u16 __iomem *) addr);
+}
+
+#define vga_readb(a)   readb((u8 __iomem *)(a))
+#define vga_writeb(v,a)        writeb(v, (u8 __iomem *)(a))
+
+#define VGA_MAP_MEM(x,s)       ((unsigned long) ioremap(x, s))
 
-#endif /* _HV_PAGESIZE_H */
+#endif
index ee41bca4c8c40f8b4f34bf574a188b0ab838f0d3..72ec1e972f15afb84746da32594e8d3b8bccdf6e 100644 (file)
@@ -22,8 +22,6 @@
 
 #include <arch/chip.h>
 
-#include <hv/pagesize.h>
-
 /* Linux builds want unsigned long constants, but assembler wants numbers */
 #ifdef __ASSEMBLER__
 /** One, for assembler */
  */
 #define HV_L1_SPAN (__HV_SIZE_ONE << HV_LOG2_L1_SPAN)
 
+/** The log2 of the size of small pages, in bytes. This value should
+ * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
+ */
+#define HV_LOG2_PAGE_SIZE_SMALL 16
+
 /** The size of small pages, in bytes. This value should be verified
  * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
  */
 #define HV_PAGE_SIZE_SMALL (__HV_SIZE_ONE << HV_LOG2_PAGE_SIZE_SMALL)
 
+/** The log2 of the size of large pages, in bytes. This value should be
+ * verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
+ */
+#define HV_LOG2_PAGE_SIZE_LARGE 24
+
 /** The size of large pages, in bytes. This value should be verified
  * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
  */
index 55a6a74974b4dad8c973484bcf2dc1934c34b309..1dc71eabfc5ad8aa49c9fceb6d4fb9423233fd2c 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/string.h>
-
 #include <asm/backtrace.h>
-
-#include <arch/chip.h>
-
 #include <asm/opcode-tile.h>
+#include <arch/abi.h>
 
-
-#define TREG_SP 54
-#define TREG_LR 55
-
-
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
 #define tile_bundle_bits tilegx_bundle_bits
 #define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
 #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
@@ -47,7 +39,7 @@ typedef long long bt_int_reg_t;
 typedef int bt_int_reg_t;
 #endif
 
-/** A decoded bundle used for backtracer analysis. */
+/* A decoded bundle used for backtracer analysis. */
 struct BacktraceBundle {
        tile_bundle_bits bits;
        int num_insns;
@@ -56,23 +48,7 @@ struct BacktraceBundle {
 };
 
 
-/* This implementation only makes sense for native tools. */
-/** Default function to read memory. */
-static bool bt_read_memory(void *result, VirtualAddress addr,
-                          unsigned int size, void *extra)
-{
-       /* FIXME: this should do some horrible signal stuff to catch
-        * SEGV cleanly and fail.
-        *
-        * Or else the caller should do the setjmp for efficiency.
-        */
-
-       memcpy(result, (const void *)addr, size);
-       return true;
-}
-
-
-/** Locates an instruction inside the given bundle that
+/* Locates an instruction inside the given bundle that
  * has the specified mnemonic, and whose first 'num_operands_to_match'
  * operands exactly match those in 'operand_values'.
  */
@@ -107,13 +83,13 @@ static const struct tile_decoded_instruction *find_matching_insn(
        return NULL;
 }
 
-/** Does this bundle contain an 'iret' instruction? */
+/* Does this bundle contain an 'iret' instruction? */
 static inline bool bt_has_iret(const struct BacktraceBundle *bundle)
 {
        return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL;
 }
 
-/** Does this bundle contain an 'addi sp, sp, OFFSET' or
+/* Does this bundle contain an 'addi sp, sp, OFFSET' or
  * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET?
  */
 static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
@@ -124,7 +100,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
                find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2);
        if (insn == NULL)
                insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2);
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
        if (insn == NULL)
                insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2);
        if (insn == NULL)
@@ -137,7 +113,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
        return true;
 }
 
-/** Does this bundle contain any 'info OP' or 'infol OP'
+/* Does this bundle contain any 'info OP' or 'infol OP'
  * instruction, and if so, what are their OP?  Note that OP is interpreted
  * as an unsigned value by this code since that's what the caller wants.
  * Returns the number of info ops found.
@@ -161,7 +137,7 @@ static int bt_get_info_ops(const struct BacktraceBundle *bundle,
        return num_ops;
 }
 
-/** Does this bundle contain a jrp instruction, and if so, to which
+/* Does this bundle contain a jrp instruction, and if so, to which
  * register is it jumping?
  */
 static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
@@ -175,7 +151,7 @@ static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
        return true;
 }
 
-/** Does this bundle modify the specified register in any way? */
+/* Does this bundle modify the specified register in any way? */
 static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
 {
        int i, j;
@@ -195,34 +171,34 @@ static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
        return false;
 }
 
-/** Does this bundle modify sp? */
+/* Does this bundle modify sp? */
 static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle)
 {
        return bt_modifies_reg(bundle, TREG_SP);
 }
 
-/** Does this bundle modify lr? */
+/* Does this bundle modify lr? */
 static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle)
 {
        return bt_modifies_reg(bundle, TREG_LR);
 }
 
-/** Does this bundle contain the instruction 'move fp, sp'? */
+/* Does this bundle contain the instruction 'move fp, sp'? */
 static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle)
 {
        static const int vals[2] = { 52, TREG_SP };
        return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL;
 }
 
-/** Does this bundle contain a store of lr to sp? */
+/* Does this bundle contain a store of lr to sp? */
 static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle)
 {
        static const int vals[2] = { TREG_SP, TREG_LR };
        return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL;
 }
 
-#if TILE_CHIP >= 10
-/** Track moveli values placed into registers. */
+#ifdef __tilegx__
+/* Track moveli values placed into registers. */
 static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
                                    int moveli_args[])
 {
@@ -238,7 +214,7 @@ static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
        }
 }
 
-/** Does this bundle contain an 'add sp, sp, reg' instruction
+/* Does this bundle contain an 'add sp, sp, reg' instruction
  * from a register that we saw a moveli into, and if so, what
  * is the value in the register?
  */
@@ -260,11 +236,11 @@ static bool bt_has_add_sp(const struct BacktraceBundle *bundle, int *adjust,
 }
 #endif
 
-/** Locates the caller's PC and SP for a program starting at the
+/* Locates the caller's PC and SP for a program starting at the
  * given address.
  */
 static void find_caller_pc_and_caller_sp(CallerLocation *location,
-                                        const VirtualAddress start_pc,
+                                        const unsigned long start_pc,
                                         BacktraceMemoryReader read_memory_func,
                                         void *read_memory_func_extra)
 {
@@ -288,9 +264,9 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
        tile_bundle_bits prefetched_bundles[32];
        int num_bundles_prefetched = 0;
        int next_bundle = 0;
-       VirtualAddress pc;
+       unsigned long pc;
 
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
        /* Naively try to track moveli values to support addx for -m32. */
        int moveli_args[TILEGX_NUM_REGISTERS] = { 0 };
 #endif
@@ -369,10 +345,6 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
                                        /* Weird; reserved value, ignore it. */
                                        continue;
                                }
-                               if (info_operand & ENTRY_POINT_INFO_OP) {
-                                       /* This info op is ignored by the backtracer. */
-                                       continue;
-                               }
 
                                /* Skip info ops which are not in the
                                 * "one_ago" mode we want right now.
@@ -453,7 +425,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
                if (!sp_determined) {
                        int adjust;
                        if (bt_has_addi_sp(&bundle, &adjust)
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
                            || bt_has_add_sp(&bundle, &adjust, moveli_args)
 #endif
                                ) {
@@ -504,7 +476,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
                                }
                        }
 
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
                        /* Track moveli arguments for -m32 mode. */
                        bt_update_moveli(&bundle, moveli_args);
 #endif
@@ -546,18 +518,26 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
        }
 }
 
+/* Initializes a backtracer to start from the given location.
+ *
+ * If the frame pointer cannot be determined it is set to -1.
+ *
+ * state: The state to be filled in.
+ * read_memory_func: A callback that reads memory.
+ * read_memory_func_extra: An arbitrary argument to read_memory_func.
+ * pc: The current PC.
+ * lr: The current value of the 'lr' register.
+ * sp: The current value of the 'sp' register.
+ * r52: The current value of the 'r52' register.
+ */
 void backtrace_init(BacktraceIterator *state,
                    BacktraceMemoryReader read_memory_func,
                    void *read_memory_func_extra,
-                   VirtualAddress pc, VirtualAddress lr,
-                   VirtualAddress sp, VirtualAddress r52)
+                   unsigned long pc, unsigned long lr,
+                   unsigned long sp, unsigned long r52)
 {
        CallerLocation location;
-       VirtualAddress fp, initial_frame_caller_pc;
-
-       if (read_memory_func == NULL) {
-               read_memory_func = bt_read_memory;
-       }
+       unsigned long fp, initial_frame_caller_pc;
 
        /* Find out where we are in the initial frame. */
        find_caller_pc_and_caller_sp(&location, pc,
@@ -630,12 +610,15 @@ void backtrace_init(BacktraceIterator *state,
 /* Handle the case where the register holds more bits than the VA. */
 static bool valid_addr_reg(bt_int_reg_t reg)
 {
-       return ((VirtualAddress)reg == reg);
+       return ((unsigned long)reg == reg);
 }
 
+/* Advances the backtracing state to the calling frame, returning
+ * true iff successful.
+ */
 bool backtrace_next(BacktraceIterator *state)
 {
-       VirtualAddress next_fp, next_pc;
+       unsigned long next_fp, next_pc;
        bt_int_reg_t next_frame[2];
 
        if (state->fp == -1) {
index dbc213adf5e1dac8557e38647266c730ecb7e6eb..bf5e9d70266c72fe9ef45e30cdade23ef0f2e374 100644 (file)
@@ -135,26 +135,15 @@ long tile_compat_sys_msgrcv(int msqid,
 
 /* Provide the compat syscall number to call mapping. */
 #undef __SYSCALL
-#define __SYSCALL(nr, call) [nr] = (compat_##call),
+#define __SYSCALL(nr, call) [nr] = (call),
 
 /* The generic versions of these don't work for Tile. */
 #define compat_sys_msgrcv tile_compat_sys_msgrcv
 #define compat_sys_msgsnd tile_compat_sys_msgsnd
 
 /* See comments in sys.c */
-#define compat_sys_fadvise64 sys32_fadvise64
 #define compat_sys_fadvise64_64 sys32_fadvise64_64
 #define compat_sys_readahead sys32_readahead
-#define compat_sys_sync_file_range compat_sys_sync_file_range2
-
-/* We leverage the "struct stat64" type for 32-bit time_t/nsec. */
-#define compat_sys_stat64 sys_stat64
-#define compat_sys_lstat64 sys_lstat64
-#define compat_sys_fstat64 sys_fstat64
-#define compat_sys_fstatat64 sys_fstatat64
-
-/* The native sys_ptrace dynamically handles compat binaries. */
-#define compat_sys_ptrace sys_ptrace
 
 /* Call the trampolines to manage pt_regs where necessary. */
 #define compat_sys_execve _compat_sys_execve
index dbb0dfc7beceb10eaa25fd4b73579cdc620334c5..a7869ad627760e1315ca1fd3096233910ab56df3 100644 (file)
@@ -317,7 +317,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs)
        return 0;
 
 badframe:
-       force_sig(SIGSEGV, current);
+       signal_fault("bad sigreturn frame", regs, frame, 0);
        return 0;
 }
 
@@ -431,6 +431,6 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        return 0;
 
 give_sigsegv:
-       force_sigsegv(sig, current);
+       signal_fault("bad setup frame", regs, frame, sig);
        return -EFAULT;
 }
diff --git a/arch/tile/kernel/futex_64.S b/arch/tile/kernel/futex_64.S
new file mode 100644 (file)
index 0000000..f465d1e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Atomically access user memory, but use MMU to avoid propagating
+ * kernel exceptions.
+ */
+
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/futex.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+
+/*
+ * Provide a set of atomic memory operations supporting <asm/futex.h>.
+ *
+ * r0: user address to manipulate
+ * r1: new value to write, or for cmpxchg, old value to compare against
+ * r2: (cmpxchg only) new value to write
+ *
+ * Return __get_user struct, r0 with value, r1 with error.
+ */
+#define FUTEX_OP(name, ...) \
+STD_ENTRY(futex_##name)                        \
+       __VA_ARGS__;                    \
+       {                               \
+        move   r1, zero;               \
+        jrp    lr                      \
+       };                              \
+       STD_ENDPROC(futex_##name);      \
+       .pushsection __ex_table,"a";    \
+       .quad 1b, get_user_fault;       \
+       .popsection
+
+       .pushsection .fixup,"ax"
+get_user_fault:
+       { movei r1, -EFAULT; jrp lr }
+       ENDPROC(get_user_fault)
+       .popsection
+
+FUTEX_OP(cmpxchg, mtspr CMPEXCH_VALUE, r1; 1: cmpexch4 r0, r0, r2)
+FUTEX_OP(set, 1: exch4 r0, r0, r1)
+FUTEX_OP(add, 1: fetchadd4 r0, r0, r1)
+FUTEX_OP(or, 1: fetchor4 r0, r0, r1)
+FUTEX_OP(andn, nor r1, r1, zero; 1: fetchand4 r0, r0, r1)
index e910530436e64a4079ba65e22bdca13e6ad01bfa..3bddef710de432b089d03d9ff52e928ea487d938 100644 (file)
@@ -268,12 +268,10 @@ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num)
        found_processes = 0;
        list_for_each_entry(p, &rect->task_head, thread.hardwall_list) {
                BUG_ON(p->thread.hardwall != rect);
-               if (p->sighand) {
+               if (!(p->flags & PF_EXITING)) {
                        found_processes = 1;
                        pr_notice("hardwall: killing %d\n", p->pid);
-                       spin_lock(&p->sighand->siglock);
-                       __group_send_sig_info(info.si_signo, &info, p);
-                       spin_unlock(&p->sighand->siglock);
+                       do_send_sig_info(info.si_signo, &info, p, false);
                }
        }
        if (!found_processes)
diff --git a/arch/tile/kernel/head_64.S b/arch/tile/kernel/head_64.S
new file mode 100644 (file)
index 0000000..6bc3a93
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * TILE startup code.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/thread_info.h>
+#include <asm/processor.h>
+#include <asm/asm-offsets.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
+#include <arch/spr_def.h>
+
+/*
+ * This module contains the entry code for kernel images. It performs the
+ * minimal setup needed to call the generic C routines.
+ */
+
+       __HEAD
+ENTRY(_start)
+       /* Notify the hypervisor of what version of the API we want */
+       {
+         movei r1, TILE_CHIP
+         movei r2, TILE_CHIP_REV
+       }
+       {
+         moveli r0, _HV_VERSION
+         jal hv_init
+       }
+       /* Get a reasonable default ASID in r0 */
+       {
+         move r0, zero
+         jal hv_inquire_asid
+       }
+
+       /*
+        * Install the default page table.  The relocation required to
+        * statically define the table is a bit too complex, so we have
+        * to plug in the pointer from the L0 to the L1 table by hand.
+        * We only do this on the first cpu to boot, though, since the
+        * other CPUs should see a properly-constructed page table.
+        */
+       {
+         v4int_l r2, zero, r0    /* ASID for hv_install_context */
+         moveli r4, hw1_last(swapper_pgprot - PAGE_OFFSET)
+       }
+       {
+         shl16insli r4, r4, hw0(swapper_pgprot - PAGE_OFFSET)
+       }
+       {
+         ld r1, r4               /* access_pte for hv_install_context */
+       }
+       {
+         moveli r0, hw1_last(.Lsv_data_pmd - PAGE_OFFSET)
+         moveli r6, hw1_last(temp_data_pmd - PAGE_OFFSET)
+       }
+       {
+         /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */
+         bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL
+         inv r4
+       }
+       bnez r7, .Lno_write
+       {
+         shl16insli r0, r0, hw0(.Lsv_data_pmd - PAGE_OFFSET)
+         shl16insli r6, r6, hw0(temp_data_pmd - PAGE_OFFSET)
+       }
+       {
+         /* Cut off the low bits of the PT address. */
+         shrui r6, r6, HV_LOG2_PAGE_TABLE_ALIGN
+         /* Start with our access pte. */
+         move r5, r1
+       }
+       {
+         /* Stuff the address into the page table pointer slot of the PTE. */
+         bfins r5, r6, HV_PTE_INDEX_PTFN, \
+                       HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
+       }
+       {
+         /* Store the L0 data PTE. */
+         st r0, r5
+         addli r6, r6, (temp_code_pmd - temp_data_pmd) >> \
+                       HV_LOG2_PAGE_TABLE_ALIGN
+       }
+       {
+         addli r0, r0, .Lsv_code_pmd - .Lsv_data_pmd
+         bfins r5, r6, HV_PTE_INDEX_PTFN, \
+                       HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
+       }
+       /* Store the L0 code PTE. */
+       st r0, r5
+
+.Lno_write:
+       moveli lr, hw2_last(1f)
+       {
+         shl16insli lr, lr, hw1(1f)
+         moveli r0, hw1_last(swapper_pg_dir - PAGE_OFFSET)
+       }
+       {
+         shl16insli lr, lr, hw0(1f)
+         shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET)
+       }
+       {
+         move r3, zero
+         j hv_install_context
+       }
+1:
+
+       /* Install the interrupt base. */
+       moveli r0, hw2_last(MEM_SV_START)
+       shl16insli r0, r0, hw1(MEM_SV_START)
+       shl16insli r0, r0, hw0(MEM_SV_START)
+       mtspr SPR_INTERRUPT_VECTOR_BASE_K, r0
+
+       /*
+        * Get our processor number and save it away in SAVE_K_0.
+        * Extract stuff from the topology structure: r4 = y, r6 = x,
+        * r5 = width.  FIXME: consider whether we want to just make these
+        * 64-bit values (and if so fix smp_topology write below, too).
+        */
+       jal hv_inquire_topology
+       {
+         v4int_l r5, zero, r1    /* r5 = width */
+         shrui r4, r0, 32        /* r4 = y */
+       }
+       {
+         v4int_l r6, zero, r0    /* r6 = x */
+         mul_lu_lu r4, r4, r5
+       }
+       {
+         add r4, r4, r6          /* r4 == cpu == y*width + x */
+       }
+
+#ifdef CONFIG_SMP
+       /*
+        * Load up our per-cpu offset.  When the first (master) tile
+        * boots, this value is still zero, so we will load boot_pc
+        * with start_kernel, and boot_sp with init_stack + THREAD_SIZE.
+        * The master tile initializes the per-cpu offset array, so that
+        * when subsequent (secondary) tiles boot, they will instead load
+        * from their per-cpu versions of boot_sp and boot_pc.
+        */
+       moveli r5, hw2_last(__per_cpu_offset)
+       shl16insli r5, r5, hw1(__per_cpu_offset)
+       shl16insli r5, r5, hw0(__per_cpu_offset)
+       shl3add r5, r4, r5
+       ld r5, r5
+       bnez r5, 1f
+
+       /*
+        * Save the width and height to the smp_topology variable
+        * for later use.
+        */
+       moveli r0, hw2_last(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+       shl16insli r0, r0, hw1(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+       shl16insli r0, r0, hw0(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+       st r0, r1
+1:
+#else
+       move r5, zero
+#endif
+
+       /* Load and go with the correct pc and sp. */
+       {
+         moveli r1, hw2_last(boot_sp)
+         moveli r0, hw2_last(boot_pc)
+       }
+       {
+         shl16insli r1, r1, hw1(boot_sp)
+         shl16insli r0, r0, hw1(boot_pc)
+       }
+       {
+         shl16insli r1, r1, hw0(boot_sp)
+         shl16insli r0, r0, hw0(boot_pc)
+       }
+       {
+         add r1, r1, r5
+         add r0, r0, r5
+       }
+       ld r0, r0
+       ld sp, r1
+       or r4, sp, r4
+       mtspr SPR_SYSTEM_SAVE_K_0, r4  /* save ksp0 + cpu */
+       addi sp, sp, -STACK_TOP_DELTA
+       {
+         move lr, zero   /* stop backtraces in the called function */
+         jr r0
+       }
+       ENDPROC(_start)
+
+__PAGE_ALIGNED_BSS
+       .align PAGE_SIZE
+ENTRY(empty_zero_page)
+       .fill PAGE_SIZE,1,0
+       END(empty_zero_page)
+
+       .macro PTE cpa, bits1
+       .quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\
+             HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) |\
+             (\bits1) | (HV_CPA_TO_PFN(\cpa) << HV_PTE_INDEX_PFN)
+       .endm
+
+__PAGE_ALIGNED_DATA
+       .align PAGE_SIZE
+ENTRY(swapper_pg_dir)
+       .org swapper_pg_dir + HV_L0_INDEX(PAGE_OFFSET) * HV_PTE_SIZE
+.Lsv_data_pmd:
+       .quad 0  /* PTE temp_data_pmd - PAGE_OFFSET, 0 */
+       .org swapper_pg_dir + HV_L0_INDEX(MEM_SV_START) * HV_PTE_SIZE
+.Lsv_code_pmd:
+       .quad 0  /* PTE temp_code_pmd - PAGE_OFFSET, 0 */
+       .org swapper_pg_dir + HV_L0_SIZE
+       END(swapper_pg_dir)
+
+       .align HV_PAGE_TABLE_ALIGN
+ENTRY(temp_data_pmd)
+       /*
+        * We fill the PAGE_OFFSET pmd with huge pages with
+        * VA = PA + PAGE_OFFSET.  We remap things with more precise access
+        * permissions later.
+        */
+       .set addr, 0
+       .rept HV_L1_ENTRIES
+       PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE
+       .set addr, addr + HV_PAGE_SIZE_LARGE
+       .endr
+       .org temp_data_pmd + HV_L1_SIZE
+       END(temp_data_pmd)
+
+       .align HV_PAGE_TABLE_ALIGN
+ENTRY(temp_code_pmd)
+       /*
+        * We fill the MEM_SV_START pmd with huge pages with
+        * VA = PA + PAGE_OFFSET.  We remap things with more precise access
+        * permissions later.
+        */
+       .set addr, 0
+       .rept HV_L1_ENTRIES
+       PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE
+       .set addr, addr + HV_PAGE_SIZE_LARGE
+       .endr
+       .org temp_code_pmd + HV_L1_SIZE
+       END(temp_code_pmd)
+
+       /*
+        * Isolate swapper_pgprot to its own cache line, since each cpu
+        * starting up will read it using VA-is-PA and local homing.
+        * This would otherwise likely conflict with other data on the cache
+        * line, once we have set its permanent home in the page tables.
+        */
+       __INITDATA
+       .align CHIP_L2_LINE_SIZE()
+ENTRY(swapper_pgprot)
+       .quad HV_PTE_PRESENT | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE)
+       .align CHIP_L2_LINE_SIZE()
+       END(swapper_pgprot)
index fffcfa6b3a62e11c2d4a34590b5ba8d57798ca9e..72ade79b621bcd8b23ec44650e3d4af4fdbf0b66 100644 (file)
@@ -851,14 +851,27 @@ STD_ENTRY(interrupt_return)
        /* Check to see if there is any work to do before returning to user. */
        {
         addi   r29, r32, THREAD_INFO_FLAGS_OFFSET
-        moveli r28, lo16(_TIF_ALLWORK_MASK)
+        moveli r1, lo16(_TIF_ALLWORK_MASK)
        }
        {
         lw     r29, r29
-        auli   r28, r28, ha16(_TIF_ALLWORK_MASK)
+        auli   r1, r1, ha16(_TIF_ALLWORK_MASK)
        }
-       and     r28, r29, r28
-       bnz     r28, .Lwork_pending
+       and     r1, r29, r1
+       bzt     r1, .Lrestore_all
+
+       /*
+        * Make sure we have all the registers saved for signal
+        * handling or single-step.  Call out to C code to figure out
+        * exactly what we need to do for each flag bit, then if
+        * necessary, reload the flags and recheck.
+        */
+       push_extra_callee_saves r0
+       {
+        PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+        jal    do_work_pending
+       }
+       bnz     r0, .Lresume_userspace
 
        /*
         * In the NMI case we
@@ -1099,99 +1112,6 @@ STD_ENTRY(interrupt_return)
        pop_reg r50
        pop_reg r51, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(51)
        j .Lcontinue_restore_regs
-
-.Lwork_pending:
-       /* Mask the reschedule flag */
-       andi    r28, r29, _TIF_NEED_RESCHED
-
-       {
-        /*
-         * If the NEED_RESCHED flag is called, we call schedule(), which
-         * may drop this context right here and go do something else.
-         * On return, jump back to .Lresume_userspace and recheck.
-         */
-        bz     r28, .Lasync_tlb
-
-        /* Mask the async-tlb flag */
-        andi   r28, r29, _TIF_ASYNC_TLB
-       }
-
-       jal     schedule
-       FEEDBACK_REENTER(interrupt_return)
-
-       /* Reload the flags and check again */
-       j       .Lresume_userspace
-
-.Lasync_tlb:
-       {
-        bz     r28, .Lneed_sigpending
-
-        /* Mask the sigpending flag */
-        andi   r28, r29, _TIF_SIGPENDING
-       }
-
-       PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
-       jal     do_async_page_fault
-       FEEDBACK_REENTER(interrupt_return)
-
-       /*
-        * Go restart the "resume userspace" process.  We may have
-        * fired a signal, and we need to disable interrupts again.
-        */
-       j       .Lresume_userspace
-
-.Lneed_sigpending:
-       /*
-        * At this point we are either doing signal handling or single-step,
-        * so either way make sure we have all the registers saved.
-        */
-       push_extra_callee_saves r0
-
-       {
-        /* If no signal pending, skip to singlestep check */
-        bz     r28, .Lneed_singlestep
-
-        /* Mask the singlestep flag */
-        andi   r28, r29, _TIF_SINGLESTEP
-       }
-
-       jal     do_signal
-       FEEDBACK_REENTER(interrupt_return)
-
-       /* Reload the flags and check again */
-       j       .Lresume_userspace
-
-.Lneed_singlestep:
-       {
-        /* Get a pointer to the EX1 field */
-        PTREGS_PTR(r29, PTREGS_OFFSET_EX1)
-
-        /* If we get here, our bit must be set. */
-        bz     r28, .Lwork_confusion
-       }
-       /* If we are in priv mode, don't single step */
-       lw      r28, r29
-       andi    r28, r28, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
-       bnz     r28, .Lrestore_all
-
-       /* Allow interrupts within the single step code */
-       TRACE_IRQS_ON  /* Note: clobbers registers r0-r29 */
-       IRQ_ENABLE(r20, r21)
-
-       /* try to single-step the current instruction */
-       PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
-       jal     single_step_once
-       FEEDBACK_REENTER(interrupt_return)
-
-       /* Re-disable interrupts.  TRACE_IRQS_OFF in .Lrestore_all. */
-       IRQ_DISABLE(r20,r21)
-
-       j       .Lrestore_all
-
-.Lwork_confusion:
-       move    r0, r28
-       panic   "thread_info allwork flags unhandled on userspace resume: %#x"
-
        STD_ENDPROC(interrupt_return)
 
        /*
@@ -1550,7 +1470,10 @@ STD_ENTRY(_sys_clone)
  * We place it in the __HEAD section to ensure it is relatively
  * near to the intvec_SWINT_1 code (reachable by a conditional branch).
  *
- * Must match register usage in do_page_fault().
+ * Our use of ATOMIC_LOCK_REG here must match do_page_fault_ics().
+ *
+ * As we do in lib/atomic_asm_32.S, we bypass a store if the value we
+ * would store is the same as the value we just loaded.
  */
        __HEAD
        .align 64
@@ -1611,17 +1534,7 @@ ENTRY(sys_cmpxchg)
        {
         shri   r20, r25, 32 - ATOMIC_HASH_L1_SHIFT
         slt_u  r23, r0, r23
-
-        /*
-         * Ensure that the TLB is loaded before we take out the lock.
-         * On TILEPro, this will start fetching the value all the way
-         * into our L1 as well (and if it gets modified before we
-         * grab the lock, it will be invalidated from our cache
-         * before we reload it).  On tile64, we'll start fetching it
-         * into our L1 if we're the home, and if we're not, we'll
-         * still at least start fetching it into the home's L2.
-         */
-        lw     r26, r0
+        lw     r26, r0  /* see comment in the "#else" for the "lw r26". */
        }
        {
         s2a    r21, r20, r21
@@ -1637,18 +1550,9 @@ ENTRY(sys_cmpxchg)
         bbs    r23, .Lcmpxchg64
         andi   r23, r0, 7       /* Precompute alignment for cmpxchg64. */
        }
-
        {
-        /*
-         * We very carefully align the code that actually runs with
-         * the lock held (nine bundles) so that we know it is all in
-         * the icache when we start.  This instruction (the jump) is
-         * at the start of the first cache line, address zero mod 64;
-         * we jump to somewhere in the second cache line to issue the
-         * tns, then jump back to finish up.
-         */
         s2a    ATOMIC_LOCK_REG_NAME, r25, r21
-        j      .Lcmpxchg32_tns
+        j      .Lcmpxchg32_tns   /* see comment in the #else for the jump. */
        }
 
 #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
@@ -1713,24 +1617,25 @@ ENTRY(sys_cmpxchg)
        {
         /*
          * We very carefully align the code that actually runs with
-         * the lock held (nine bundles) so that we know it is all in
+         * the lock held (twelve bundles) so that we know it is all in
          * the icache when we start.  This instruction (the jump) is
          * at the start of the first cache line, address zero mod 64;
-         * we jump to somewhere in the second cache line to issue the
-         * tns, then jump back to finish up.
+         * we jump to the very end of the second cache line to get that
+         * line loaded in the icache, then fall through to issue the tns
+         * in the third cache line, at which point it's all cached.
+         * Note that is for performance, not correctness.
          */
         j      .Lcmpxchg32_tns
        }
 
 #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
 
-       ENTRY(__sys_cmpxchg_grab_lock)
+/* Symbol for do_page_fault_ics() to use to compare against the PC. */
+.global __sys_cmpxchg_grab_lock
+__sys_cmpxchg_grab_lock:
 
        /*
         * Perform the actual cmpxchg or atomic_update.
-        * Note that the system <arch/atomic.h> header relies on
-        * atomic_update() to always perform an "mf", so don't make
-        * it optional or conditional without modifying that code.
         */
 .Ldo_cmpxchg32:
        {
@@ -1748,10 +1653,13 @@ ENTRY(sys_cmpxchg)
        }
        {
         mvnz   r24, r23, r25    /* Use atomic_update value if appropriate. */
-        bbns   r22, .Lcmpxchg32_mismatch
+        bbns   r22, .Lcmpxchg32_nostore
        }
+       seq     r22, r24, r21    /* Are we storing the value we loaded? */
+       bbs     r22, .Lcmpxchg32_nostore
        sw      r0, r24
 
+       /* The following instruction is the start of the second cache line. */
        /* Do slow mtspr here so the following "mf" waits less. */
        {
         move   sp, r27
@@ -1759,7 +1667,6 @@ ENTRY(sys_cmpxchg)
        }
        mf
 
-       /* The following instruction is the start of the second cache line. */
        {
         move   r0, r21
         sw     ATOMIC_LOCK_REG_NAME, zero
@@ -1767,7 +1674,7 @@ ENTRY(sys_cmpxchg)
        iret
 
        /* Duplicated code here in the case where we don't overlap "mf" */
-.Lcmpxchg32_mismatch:
+.Lcmpxchg32_nostore:
        {
         move   r0, r21
         sw     ATOMIC_LOCK_REG_NAME, zero
@@ -1783,8 +1690,6 @@ ENTRY(sys_cmpxchg)
         * and for 64-bit cmpxchg.  We provide it as a macro and put
         * it into both versions.  We can't share the code literally
         * since it depends on having the right branch-back address.
-        * Note that the first few instructions should share the cache
-        * line with the second half of the actual locked code.
         */
        .macro  cmpxchg_lock, bitwidth
 
@@ -1810,7 +1715,7 @@ ENTRY(sys_cmpxchg)
        }
        /*
         * The preceding instruction is the last thing that must be
-        * on the second cache line.
+        * hot in the icache before we do the "tns" above.
         */
 
 #ifdef CONFIG_SMP
@@ -1841,6 +1746,12 @@ ENTRY(sys_cmpxchg)
        .endm
 
 .Lcmpxchg32_tns:
+       /*
+        * This is the last instruction on the second cache line.
+        * The nop here loads the second line, then we fall through
+        * to the tns to load the third line before we take the lock.
+        */
+       nop
        cmpxchg_lock 32
 
        /*
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
new file mode 100644 (file)
index 0000000..79c93e1
--- /dev/null
@@ -0,0 +1,1231 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Linux interrupt vectors.
+ */
+
+#include <linux/linkage.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/irqflags.h>
+#include <asm/asm-offsets.h>
+#include <asm/types.h>
+#include <hv/hypervisor.h>
+#include <arch/abi.h>
+#include <arch/interrupts.h>
+#include <arch/spr_def.h>
+
+#ifdef CONFIG_PREEMPT
+# error "No support for kernel preemption currently"
+#endif
+
+#define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg)
+
+#define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR)
+
+
+       .macro  push_reg reg, ptr=sp, delta=-8
+       {
+        st     \ptr, \reg
+        addli  \ptr, \ptr, \delta
+       }
+       .endm
+
+       .macro  pop_reg reg, ptr=sp, delta=8
+       {
+        ld     \reg, \ptr
+        addli  \ptr, \ptr, \delta
+       }
+       .endm
+
+       .macro  pop_reg_zero reg, zreg, ptr=sp, delta=8
+       {
+        move   \zreg, zero
+        ld     \reg, \ptr
+        addi   \ptr, \ptr, \delta
+       }
+       .endm
+
+       .macro  push_extra_callee_saves reg
+       PTREGS_PTR(\reg, PTREGS_OFFSET_REG(51))
+       push_reg r51, \reg
+       push_reg r50, \reg
+       push_reg r49, \reg
+       push_reg r48, \reg
+       push_reg r47, \reg
+       push_reg r46, \reg
+       push_reg r45, \reg
+       push_reg r44, \reg
+       push_reg r43, \reg
+       push_reg r42, \reg
+       push_reg r41, \reg
+       push_reg r40, \reg
+       push_reg r39, \reg
+       push_reg r38, \reg
+       push_reg r37, \reg
+       push_reg r36, \reg
+       push_reg r35, \reg
+       push_reg r34, \reg, PTREGS_OFFSET_BASE - PTREGS_OFFSET_REG(34)
+       .endm
+
+       .macro  panic str
+       .pushsection .rodata, "a"
+1:
+       .asciz  "\str"
+       .popsection
+       {
+        moveli r0, hw2_last(1b)
+       }
+       {
+        shl16insli r0, r0, hw1(1b)
+       }
+       {
+        shl16insli r0, r0, hw0(1b)
+        jal    panic
+       }
+       .endm
+
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+       .pushsection .text.intvec_feedback,"ax"
+intvec_feedback:
+       .popsection
+#endif
+
+       /*
+        * Default interrupt handler.
+        *
+        * vecnum is where we'll put this code.
+        * c_routine is the C routine we'll call.
+        *
+        * The C routine is passed two arguments:
+        * - A pointer to the pt_regs state.
+        * - The interrupt vector number.
+        *
+        * The "processing" argument specifies the code for processing
+        * the interrupt. Defaults to "handle_interrupt".
+        */
+       .macro  int_hand vecnum, vecname, c_routine, processing=handle_interrupt
+       .org    (\vecnum << 8)
+intvec_\vecname:
+       /* Temporarily save a register so we have somewhere to work. */
+
+       mtspr   SPR_SYSTEM_SAVE_K_1, r0
+       mfspr   r0, SPR_EX_CONTEXT_K_1
+
+       andi    r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
+
+       .ifc    \vecnum, INT_DOUBLE_FAULT
+       /*
+        * For double-faults from user-space, fall through to the normal
+        * register save and stack setup path.  Otherwise, it's the
+        * hypervisor giving us one last chance to dump diagnostics, and we
+        * branch to the kernel_double_fault routine to do so.
+        */
+       beqz    r0, 1f
+       j       _kernel_double_fault
+1:
+       .else
+       /*
+        * If we're coming from user-space, then set sp to the top of
+        * the kernel stack.  Otherwise, assume sp is already valid.
+        */
+       {
+        bnez   r0, 0f
+        move   r0, sp
+       }
+       .endif
+
+       .ifc    \c_routine, do_page_fault
+       /*
+        * The page_fault handler may be downcalled directly by the
+        * hypervisor even when Linux is running and has ICS set.
+        *
+        * In this case the contents of EX_CONTEXT_K_1 reflect the
+        * previous fault and can't be relied on to choose whether or
+        * not to reinitialize the stack pointer.  So we add a test
+        * to see whether SYSTEM_SAVE_K_2 has the high bit set,
+        * and if so we don't reinitialize sp, since we must be coming
+        * from Linux.  (In fact the precise case is !(val & ~1),
+        * but any Linux PC has to have the high bit set.)
+        *
+        * Note that the hypervisor *always* sets SYSTEM_SAVE_K_2 for
+        * any path that turns into a downcall to one of our TLB handlers.
+        *
+        * FIXME: if we end up never using this path, perhaps we should
+        * prevent the hypervisor from generating downcalls in this case.
+        * The advantage of getting a downcall is we can panic in Linux.
+        */
+       mfspr   r0, SPR_SYSTEM_SAVE_K_2
+       {
+        bltz   r0, 0f    /* high bit in S_S_1_2 is for a PC to use */
+        move   r0, sp
+       }
+       .endif
+
+
+       /*
+        * SYSTEM_SAVE_K_0 holds the cpu number in the low bits, and
+        * the current stack top in the higher bits.  So we recover
+        * our stack top by just masking off the low bits, then
+        * point sp at the top aligned address on the actual stack page.
+        */
+       mfspr   r0, SPR_SYSTEM_SAVE_K_0
+       mm      r0, zero, LOG2_THREAD_SIZE, 63
+
+0:
+       /*
+        * Align the stack mod 64 so we can properly predict what
+        * cache lines we need to write-hint to reduce memory fetch
+        * latency as we enter the kernel.  The layout of memory is
+        * as follows, with cache line 0 at the lowest VA, and cache
+        * line 8 just below the r0 value this "andi" computes.
+        * Note that we never write to cache line 8, and we skip
+        * cache lines 1-3 for syscalls.
+        *
+        *    cache line 8: ptregs padding (two words)
+        *    cache line 7: sp, lr, pc, ex1, faultnum, orig_r0, flags, cmpexch
+        *    cache line 6: r46...r53 (tp)
+        *    cache line 5: r38...r45
+        *    cache line 4: r30...r37
+        *    cache line 3: r22...r29
+        *    cache line 2: r14...r21
+        *    cache line 1: r6...r13
+        *    cache line 0: 2 x frame, r0..r5
+        */
+       andi    r0, r0, -64
+
+       /*
+        * Push the first four registers on the stack, so that we can set
+        * them to vector-unique values before we jump to the common code.
+        *
+        * Registers are pushed on the stack as a struct pt_regs,
+        * with the sp initially just above the struct, and when we're
+        * done, sp points to the base of the struct, minus
+        * C_ABI_SAVE_AREA_SIZE, so we can directly jal to C code.
+        *
+        * This routine saves just the first four registers, plus the
+        * stack context so we can do proper backtracing right away,
+        * and defers to handle_interrupt to save the rest.
+        * The backtracer needs pc, ex1, lr, sp, r52, and faultnum.
+        */
+       addli   r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP)
+       wh64    r0   /* cache line 7 */
+       {
+        st     r0, lr
+        addli  r0, r0, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR
+       }
+       {
+        st     r0, sp
+        addli  sp, r0, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_SP
+       }
+       wh64    sp   /* cache line 6 */
+       {
+        st     sp, r52
+        addli  sp, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(52)
+       }
+       wh64    sp   /* cache line 0 */
+       {
+        st     sp, r1
+        addli  sp, sp, PTREGS_OFFSET_REG(2) - PTREGS_OFFSET_REG(1)
+       }
+       {
+        st     sp, r2
+        addli  sp, sp, PTREGS_OFFSET_REG(3) - PTREGS_OFFSET_REG(2)
+       }
+       {
+        st     sp, r3
+        addli  sp, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(3)
+       }
+       mfspr   r0, SPR_EX_CONTEXT_K_0
+       .ifc \processing,handle_syscall
+       /*
+        * Bump the saved PC by one bundle so that when we return, we won't
+        * execute the same swint instruction again.  We need to do this while
+        * we're in the critical section.
+        */
+       addi    r0, r0, 8
+       .endif
+       {
+        st     sp, r0
+        addli  sp, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
+       }
+       mfspr   r0, SPR_EX_CONTEXT_K_1
+       {
+        st     sp, r0
+        addi   sp, sp, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
+       /*
+        * Use r0 for syscalls so it's a temporary; use r1 for interrupts
+        * so that it gets passed through unchanged to the handler routine.
+        * Note that the .if conditional confusingly spans bundles.
+        */
+        .ifc \processing,handle_syscall
+        movei  r0, \vecnum
+       }
+       {
+        st     sp, r0
+        .else
+        movei  r1, \vecnum
+       }
+       {
+        st     sp, r1
+        .endif
+        addli  sp, sp, PTREGS_OFFSET_REG(0) - PTREGS_OFFSET_FAULTNUM
+       }
+       mfspr   r0, SPR_SYSTEM_SAVE_K_1    /* Original r0 */
+       {
+        st     sp, r0
+        addi   sp, sp, -PTREGS_OFFSET_REG(0) - 8
+       }
+       {
+        st     sp, zero        /* write zero into "Next SP" frame pointer */
+        addi   sp, sp, -8      /* leave SP pointing at bottom of frame */
+       }
+       .ifc \processing,handle_syscall
+       j       handle_syscall
+       .else
+       /* Capture per-interrupt SPR context to registers. */
+       .ifc \c_routine, do_page_fault
+       mfspr   r2, SPR_SYSTEM_SAVE_K_3   /* address of page fault */
+       mfspr   r3, SPR_SYSTEM_SAVE_K_2   /* info about page fault */
+       .else
+       .ifc \vecnum, INT_ILL_TRANS
+       mfspr   r2, ILL_TRANS_REASON
+       .else
+       .ifc \vecnum, INT_DOUBLE_FAULT
+       mfspr   r2, SPR_SYSTEM_SAVE_K_2   /* double fault info from HV */
+       .else
+       .ifc \c_routine, do_trap
+       mfspr   r2, GPV_REASON
+       .else
+       .ifc \c_routine, op_handle_perf_interrupt
+       mfspr   r2, PERF_COUNT_STS
+#if CHIP_HAS_AUX_PERF_COUNTERS()
+       .else
+       .ifc \c_routine, op_handle_aux_perf_interrupt
+       mfspr   r2, AUX_PERF_COUNT_STS
+       .endif
+#endif
+       .endif
+       .endif
+       .endif
+       .endif
+       .endif
+       /* Put function pointer in r0 */
+       moveli  r0, hw2_last(\c_routine)
+       shl16insli r0, r0, hw1(\c_routine)
+       {
+        shl16insli r0, r0, hw0(\c_routine)
+        j       \processing
+       }
+       .endif
+       ENDPROC(intvec_\vecname)
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+       .pushsection .text.intvec_feedback,"ax"
+       .org    (\vecnum << 5)
+       FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt1, 1 << 8)
+       jrp     lr
+       .popsection
+#endif
+
+       .endm
+
+
+       /*
+        * Save the rest of the registers that we didn't save in the actual
+        * vector itself.  We can't use r0-r10 inclusive here.
+        */
+       .macro  finish_interrupt_save, function
+
+       /* If it's a syscall, save a proper orig_r0, otherwise just zero. */
+       PTREGS_PTR(r52, PTREGS_OFFSET_ORIG_R0)
+       {
+        .ifc \function,handle_syscall
+        st     r52, r0
+        .else
+        st     r52, zero
+        .endif
+        PTREGS_PTR(r52, PTREGS_OFFSET_TP)
+       }
+       st      r52, tp
+       {
+        mfspr  tp, CMPEXCH_VALUE
+        PTREGS_PTR(r52, PTREGS_OFFSET_CMPEXCH)
+       }
+
+       /*
+        * For ordinary syscalls, we save neither caller- nor callee-
+        * save registers, since the syscall invoker doesn't expect the
+        * caller-saves to be saved, and the called kernel functions will
+        * take care of saving the callee-saves for us.
+        *
+        * For interrupts we save just the caller-save registers.  Saving
+        * them is required (since the "caller" can't save them).  Again,
+        * the called kernel functions will restore the callee-save
+        * registers for us appropriately.
+        *
+        * On return, we normally restore nothing special for syscalls,
+        * and just the caller-save registers for interrupts.
+        *
+        * However, there are some important caveats to all this:
+        *
+        * - We always save a few callee-save registers to give us
+        *   some scratchpad registers to carry across function calls.
+        *
+        * - fork/vfork/etc require us to save all the callee-save
+        *   registers, which we do in PTREGS_SYSCALL_ALL_REGS, below.
+        *
+        * - We always save r0..r5 and r10 for syscalls, since we need
+        *   to reload them a bit later for the actual kernel call, and
+        *   since we might need them for -ERESTARTNOINTR, etc.
+        *
+        * - Before invoking a signal handler, we save the unsaved
+        *   callee-save registers so they are visible to the
+        *   signal handler or any ptracer.
+        *
+        * - If the unsaved callee-save registers are modified, we set
+        *   a bit in pt_regs so we know to reload them from pt_regs
+        *   and not just rely on the kernel function unwinding.
+        *   (Done for ptrace register writes and SA_SIGINFO handler.)
+        */
+       {
+        st     r52, tp
+        PTREGS_PTR(r52, PTREGS_OFFSET_REG(33))
+       }
+       wh64    r52    /* cache line 4 */
+       push_reg r33, r52
+       push_reg r32, r52
+       push_reg r31, r52
+       .ifc \function,handle_syscall
+       push_reg r30, r52, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(30)
+       push_reg TREG_SYSCALL_NR_NAME, r52, \
+         PTREGS_OFFSET_REG(5) - PTREGS_OFFSET_SYSCALL
+       .else
+
+       push_reg r30, r52, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(30)
+       wh64    r52   /* cache line 3 */
+       push_reg r29, r52
+       push_reg r28, r52
+       push_reg r27, r52
+       push_reg r26, r52
+       push_reg r25, r52
+       push_reg r24, r52
+       push_reg r23, r52
+       push_reg r22, r52
+       wh64    r52   /* cache line 2 */
+       push_reg r21, r52
+       push_reg r20, r52
+       push_reg r19, r52
+       push_reg r18, r52
+       push_reg r17, r52
+       push_reg r16, r52
+       push_reg r15, r52
+       push_reg r14, r52
+       wh64    r52   /* cache line 1 */
+       push_reg r13, r52
+       push_reg r12, r52
+       push_reg r11, r52
+       push_reg r10, r52
+       push_reg r9, r52
+       push_reg r8, r52
+       push_reg r7, r52
+       push_reg r6, r52
+
+       .endif
+
+       push_reg r5, r52
+       st      r52, r4
+
+       /* Load tp with our per-cpu offset. */
+#ifdef CONFIG_SMP
+       {
+        mfspr  r20, SPR_SYSTEM_SAVE_K_0
+        moveli r21, hw2_last(__per_cpu_offset)
+       }
+       {
+        shl16insli r21, r21, hw1(__per_cpu_offset)
+        bfextu r20, r20, 0, LOG2_THREAD_SIZE-1
+       }
+       shl16insli r21, r21, hw0(__per_cpu_offset)
+       shl3add r20, r20, r21
+       ld      tp, r20
+#else
+       move    tp, zero
+#endif
+
+       /*
+        * If we will be returning to the kernel, we will need to
+        * reset the interrupt masks to the state they had before.
+        * Set DISABLE_IRQ in flags iff we came from PL1 with irqs disabled.
+        */
+       mfspr   r32, SPR_EX_CONTEXT_K_1
+       {
+        andi   r32, r32, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
+        PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS)
+       }
+       beqzt   r32, 1f       /* zero if from user space */
+       IRQS_DISABLED(r32)    /* zero if irqs enabled */
+#if PT_FLAGS_DISABLE_IRQ != 1
+# error Value of IRQS_DISABLED used to set PT_FLAGS_DISABLE_IRQ; fix
+#endif
+1:
+       .ifnc \function,handle_syscall
+       /* Record the fact that we saved the caller-save registers above. */
+       ori     r32, r32, PT_FLAGS_CALLER_SAVES
+       .endif
+       st      r21, r32
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+       /*
+        * Notify the feedback routines that we were in the
+        * appropriate fixed interrupt vector area.  Note that we
+        * still have ICS set at this point, so we can't invoke any
+        * atomic operations or we will panic.  The feedback
+        * routines internally preserve r0..r10 and r30 up.
+        */
+       .ifnc \function,handle_syscall
+       shli    r20, r1, 5
+       .else
+       moveli  r20, INT_SWINT_1 << 5
+       .endif
+       moveli  r21, hw2_last(intvec_feedback)
+       shl16insli r21, r21, hw1(intvec_feedback)
+       shl16insli r21, r21, hw0(intvec_feedback)
+       add     r20, r20, r21
+       jalr    r20
+
+       /* And now notify the feedback routines that we are here. */
+       FEEDBACK_ENTER(\function)
+#endif
+
+       /*
+        * we've captured enough state to the stack (including in
+        * particular our EX_CONTEXT state) that we can now release
+        * the interrupt critical section and replace it with our
+        * standard "interrupts disabled" mask value.  This allows
+        * synchronous interrupts (and profile interrupts) to punch
+        * through from this point onwards.
+        */
+       .ifc \function,handle_nmi
+       IRQ_DISABLE_ALL(r20)
+       .else
+       IRQ_DISABLE(r20, r21)
+       .endif
+       mtspr   INTERRUPT_CRITICAL_SECTION, zero
+
+       /*
+        * Prepare the first 256 stack bytes to be rapidly accessible
+        * without having to fetch the background data.
+        */
+       addi    r52, sp, -64
+       {
+        wh64   r52
+        addi   r52, r52, -64
+       }
+       {
+        wh64   r52
+        addi   r52, r52, -64
+       }
+       {
+        wh64   r52
+        addi   r52, r52, -64
+       }
+       wh64    r52
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+       .ifnc \function,handle_nmi
+       /*
+        * We finally have enough state set up to notify the irq
+        * tracing code that irqs were disabled on entry to the handler.
+        * The TRACE_IRQS_OFF call clobbers registers r0-r29.
+        * For syscalls, we already have the register state saved away
+        * on the stack, so we don't bother to do any register saves here,
+        * and later we pop the registers back off the kernel stack.
+        * For interrupt handlers, save r0-r3 in callee-saved registers.
+        */
+       .ifnc \function,handle_syscall
+       { move r30, r0; move r31, r1 }
+       { move r32, r2; move r33, r3 }
+       .endif
+       TRACE_IRQS_OFF
+       .ifnc \function,handle_syscall
+       { move r0, r30; move r1, r31 }
+       { move r2, r32; move r3, r33 }
+       .endif
+       .endif
+#endif
+
+       .endm
+
+       /*
+        * Redispatch a downcall.
+        */
+       .macro  dc_dispatch vecnum, vecname
+       .org    (\vecnum << 8)
+intvec_\vecname:
+       j       hv_downcall_dispatch
+       ENDPROC(intvec_\vecname)
+       .endm
+
+       /*
+        * Common code for most interrupts.  The C function we're eventually
+        * going to is in r0, and the faultnum is in r1; the original
+        * values for those registers are on the stack.
+        */
+       .pushsection .text.handle_interrupt,"ax"
+handle_interrupt:
+       finish_interrupt_save handle_interrupt
+
+       /* Jump to the C routine; it should enable irqs as soon as possible. */
+       {
+        jalr   r0
+        PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+       }
+       FEEDBACK_REENTER(handle_interrupt)
+       {
+        movei  r30, 0   /* not an NMI */
+        j      interrupt_return
+       }
+       STD_ENDPROC(handle_interrupt)
+
+/*
+ * This routine takes a boolean in r30 indicating if this is an NMI.
+ * If so, we also expect a boolean in r31 indicating whether to
+ * re-enable the oprofile interrupts.
+ */
+STD_ENTRY(interrupt_return)
+       /* If we're resuming to kernel space, don't check thread flags. */
+       {
+        bnez   r30, .Lrestore_all  /* NMIs don't special-case user-space */
+        PTREGS_PTR(r29, PTREGS_OFFSET_EX1)
+       }
+       ld      r29, r29
+       andi    r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
+       {
+        beqzt  r29, .Lresume_userspace
+        PTREGS_PTR(r29, PTREGS_OFFSET_PC)
+       }
+
+       /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */
+       moveli  r27, hw2_last(_cpu_idle_nap)
+       {
+        ld     r28, r29
+        shl16insli r27, r27, hw1(_cpu_idle_nap)
+       }
+       {
+        shl16insli r27, r27, hw0(_cpu_idle_nap)
+       }
+       {
+        cmpeq  r27, r27, r28
+       }
+       {
+        blbc   r27, .Lrestore_all
+        addi   r28, r28, 8
+       }
+       st      r29, r28
+       j       .Lrestore_all
+
+.Lresume_userspace:
+       FEEDBACK_REENTER(interrupt_return)
+
+       /*
+        * Disable interrupts so as to make sure we don't
+        * miss an interrupt that sets any of the thread flags (like
+        * need_resched or sigpending) between sampling and the iret.
+        * Routines like schedule() or do_signal() may re-enable
+        * interrupts before returning.
+        */
+       IRQ_DISABLE(r20, r21)
+       TRACE_IRQS_OFF  /* Note: clobbers registers r0-r29 */
+
+       /* Get base of stack in r32; note r30/31 are used as arguments here. */
+       GET_THREAD_INFO(r32)
+
+
+       /* Check to see if there is any work to do before returning to user. */
+       {
+        addi   r29, r32, THREAD_INFO_FLAGS_OFFSET
+        moveli r1, hw1_last(_TIF_ALLWORK_MASK)
+       }
+       {
+        ld     r29, r29
+        shl16insli r1, r1, hw0(_TIF_ALLWORK_MASK)
+       }
+       and     r1, r29, r1
+       beqzt   r1, .Lrestore_all
+
+       /*
+        * Make sure we have all the registers saved for signal
+        * handling or single-step.  Call out to C code to figure out
+        * exactly what we need to do for each flag bit, then if
+        * necessary, reload the flags and recheck.
+        */
+       push_extra_callee_saves r0
+       {
+        PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+        jal    do_work_pending
+       }
+       bnez    r0, .Lresume_userspace
+
+       /*
+        * In the NMI case we
+        * omit the call to single_process_check_nohz, which normally checks
+        * to see if we should start or stop the scheduler tick, because
+        * we can't call arbitrary Linux code from an NMI context.
+        * We always call the homecache TLB deferral code to re-trigger
+        * the deferral mechanism.
+        *
+        * The other chunk of responsibility this code has is to reset the
+        * interrupt masks appropriately to reset irqs and NMIs.  We have
+        * to call TRACE_IRQS_OFF and TRACE_IRQS_ON to support all the
+        * lockdep-type stuff, but we can't set ICS until afterwards, since
+        * ICS can only be used in very tight chunks of code to avoid
+        * tripping over various assertions that it is off.
+        */
+.Lrestore_all:
+       PTREGS_PTR(r0, PTREGS_OFFSET_EX1)
+       {
+        ld      r0, r0
+        PTREGS_PTR(r32, PTREGS_OFFSET_FLAGS)
+       }
+       {
+        andi   r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK
+        ld     r32, r32
+       }
+       bnez    r0, 1f
+       j       2f
+#if PT_FLAGS_DISABLE_IRQ != 1
+# error Assuming PT_FLAGS_DISABLE_IRQ == 1 so we can use blbct below
+#endif
+1:     blbct   r32, 2f
+       IRQ_DISABLE(r20,r21)
+       TRACE_IRQS_OFF
+       movei   r0, 1
+       mtspr   INTERRUPT_CRITICAL_SECTION, r0
+       beqzt   r30, .Lrestore_regs
+       j       3f
+2:     TRACE_IRQS_ON
+       movei   r0, 1
+       mtspr   INTERRUPT_CRITICAL_SECTION, r0
+       IRQ_ENABLE(r20, r21)
+       beqzt   r30, .Lrestore_regs
+3:
+
+
+       /*
+        * We now commit to returning from this interrupt, since we will be
+        * doing things like setting EX_CONTEXT SPRs and unwinding the stack
+        * frame.  No calls should be made to any other code after this point.
+        * This code should only be entered with ICS set.
+        * r32 must still be set to ptregs.flags.
+        * We launch loads to each cache line separately first, so we can
+        * get some parallelism out of the memory subsystem.
+        * We start zeroing caller-saved registers throughout, since
+        * that will save some cycles if this turns out to be a syscall.
+        */
+.Lrestore_regs:
+       FEEDBACK_REENTER(interrupt_return)   /* called from elsewhere */
+
+       /*
+        * Rotate so we have one high bit and one low bit to test.
+        * - low bit says whether to restore all the callee-saved registers,
+        *   or just r30-r33, and r52 up.
+        * - high bit (i.e. sign bit) says whether to restore all the
+        *   caller-saved registers, or just r0.
+        */
+#if PT_FLAGS_CALLER_SAVES != 2 || PT_FLAGS_RESTORE_REGS != 4
+# error Rotate trick does not work :-)
+#endif
+       {
+        rotli  r20, r32, 62
+        PTREGS_PTR(sp, PTREGS_OFFSET_REG(0))
+       }
+
+       /*
+        * Load cache lines 0, 4, 6 and 7, in that order, then use
+        * the last loaded value, which makes it likely that the other
+        * cache lines have also loaded, at which point we should be
+        * able to safely read all the remaining words on those cache
+        * lines without waiting for the memory subsystem.
+        */
+       pop_reg r0, sp, PTREGS_OFFSET_REG(30) - PTREGS_OFFSET_REG(0)
+       pop_reg r30, sp, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_REG(30)
+       pop_reg_zero r52, r3, sp, PTREGS_OFFSET_CMPEXCH - PTREGS_OFFSET_REG(52)
+       pop_reg_zero r21, r27, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_CMPEXCH
+       pop_reg_zero lr, r2, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_EX1
+       {
+        mtspr  CMPEXCH_VALUE, r21
+        move   r4, zero
+       }
+       pop_reg r21, sp, PTREGS_OFFSET_REG(31) - PTREGS_OFFSET_PC
+       {
+        mtspr  SPR_EX_CONTEXT_K_1, lr
+        andi   lr, lr, SPR_EX_CONTEXT_1_1__PL_MASK  /* mask off ICS */
+       }
+       {
+        mtspr  SPR_EX_CONTEXT_K_0, r21
+        move   r5, zero
+       }
+
+       /* Restore callee-saveds that we actually use. */
+       pop_reg_zero r31, r6
+       pop_reg_zero r32, r7
+       pop_reg_zero r33, r8, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(33)
+
+       /*
+        * If we modified other callee-saveds, restore them now.
+        * This is rare, but could be via ptrace or signal handler.
+        */
+       {
+        move   r9, zero
+        blbs   r20, .Lrestore_callees
+       }
+.Lcontinue_restore_regs:
+
+       /* Check if we're returning from a syscall. */
+       {
+        move   r10, zero
+        bltzt  r20, 1f  /* no, so go restore callee-save registers */
+       }
+
+       /*
+        * Check if we're returning to userspace.
+        * Note that if we're not, we don't worry about zeroing everything.
+        */
+       {
+        addli  sp, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(29)
+        bnez   lr, .Lkernel_return
+       }
+
+       /*
+        * On return from syscall, we've restored r0 from pt_regs, but we
+        * clear the remainder of the caller-saved registers.  We could
+        * restore the syscall arguments, but there's not much point,
+        * and it ensures user programs aren't trying to use the
+        * caller-saves if we clear them, as well as avoiding leaking
+        * kernel pointers into userspace.
+        */
+       pop_reg_zero lr, r11, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR
+       pop_reg_zero tp, r12, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP
+       {
+        ld     sp, sp
+        move   r13, zero
+        move   r14, zero
+       }
+       { move r15, zero; move r16, zero }
+       { move r17, zero; move r18, zero }
+       { move r19, zero; move r20, zero }
+       { move r21, zero; move r22, zero }
+       { move r23, zero; move r24, zero }
+       { move r25, zero; move r26, zero }
+
+       /* Set r1 to errno if we are returning an error, otherwise zero. */
+       {
+        moveli r29, 4096
+        sub    r1, zero, r0
+       }
+       {
+        move   r28, zero
+        cmpltu r29, r1, r29
+       }
+       {
+        mnz    r1, r29, r1
+        move   r29, zero
+       }
+       iret
+
+       /*
+        * Not a syscall, so restore caller-saved registers.
+        * First kick off loads for cache lines 1-3, which we're touching
+        * for the first time here.
+        */
+       .align 64
+1:     pop_reg r29, sp, PTREGS_OFFSET_REG(21) - PTREGS_OFFSET_REG(29)
+       pop_reg r21, sp, PTREGS_OFFSET_REG(13) - PTREGS_OFFSET_REG(21)
+       pop_reg r13, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(13)
+       pop_reg r1
+       pop_reg r2
+       pop_reg r3
+       pop_reg r4
+       pop_reg r5
+       pop_reg r6
+       pop_reg r7
+       pop_reg r8
+       pop_reg r9
+       pop_reg r10
+       pop_reg r11
+       pop_reg r12, sp, 16
+       /* r13 already restored above */
+       pop_reg r14
+       pop_reg r15
+       pop_reg r16
+       pop_reg r17
+       pop_reg r18
+       pop_reg r19
+       pop_reg r20, sp, 16
+       /* r21 already restored above */
+       pop_reg r22
+       pop_reg r23
+       pop_reg r24
+       pop_reg r25
+       pop_reg r26
+       pop_reg r27
+       pop_reg r28, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(28)
+       /* r29 already restored above */
+       bnez    lr, .Lkernel_return
+       pop_reg lr, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR
+       pop_reg tp, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP
+       ld      sp, sp
+       iret
+
+       /*
+        * We can't restore tp when in kernel mode, since a thread might
+        * have migrated from another cpu and brought a stale tp value.
+        */
+.Lkernel_return:
+       pop_reg lr, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR
+       ld      sp, sp
+       iret
+
+       /* Restore callee-saved registers from r34 to r51. */
+.Lrestore_callees:
+       addli  sp, sp, PTREGS_OFFSET_REG(34) - PTREGS_OFFSET_REG(29)
+       pop_reg r34
+       pop_reg r35
+       pop_reg r36
+       pop_reg r37
+       pop_reg r38
+       pop_reg r39
+       pop_reg r40
+       pop_reg r41
+       pop_reg r42
+       pop_reg r43
+       pop_reg r44
+       pop_reg r45
+       pop_reg r46
+       pop_reg r47
+       pop_reg r48
+       pop_reg r49
+       pop_reg r50
+       pop_reg r51, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(51)
+       j .Lcontinue_restore_regs
+       STD_ENDPROC(interrupt_return)
+
+       /*
+        * "NMI" interrupts mask ALL interrupts before calling the
+        * handler, and don't check thread flags, etc., on the way
+        * back out.  In general, the only things we do here for NMIs
+        * are register save/restore and dataplane kernel-TLB management.
+        * We don't (for example) deal with start/stop of the sched tick.
+        */
+       .pushsection .text.handle_nmi,"ax"
+handle_nmi:
+       finish_interrupt_save handle_nmi
+       {
+        jalr   r0
+        PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+       }
+       FEEDBACK_REENTER(handle_nmi)
+       {
+        movei  r30, 1
+        move   r31, r0
+       }
+       j       interrupt_return
+       STD_ENDPROC(handle_nmi)
+
+       /*
+        * Parallel code for syscalls to handle_interrupt.
+        */
+       .pushsection .text.handle_syscall,"ax"
+handle_syscall:
+       finish_interrupt_save handle_syscall
+
+       /* Enable irqs. */
+       TRACE_IRQS_ON
+       IRQ_ENABLE(r20, r21)
+
+       /* Bump the counter for syscalls made on this tile. */
+       moveli r20, hw2_last(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+       shl16insli r20, r20, hw1(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+       shl16insli r20, r20, hw0(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+       add     r20, r20, tp
+       ld4s    r21, r20
+       addi    r21, r21, 1
+       st4     r20, r21
+
+       /* Trace syscalls, if requested. */
+       GET_THREAD_INFO(r31)
+       addi    r31, r31, THREAD_INFO_FLAGS_OFFSET
+       ld      r30, r31
+       andi    r30, r30, _TIF_SYSCALL_TRACE
+       {
+        addi   r30, r31, THREAD_INFO_STATUS_OFFSET - THREAD_INFO_FLAGS_OFFSET
+        beqzt  r30, .Lrestore_syscall_regs
+       }
+       jal     do_syscall_trace
+       FEEDBACK_REENTER(handle_syscall)
+
+       /*
+        * We always reload our registers from the stack at this
+        * point.  They might be valid, if we didn't build with
+        * TRACE_IRQFLAGS, and this isn't a dataplane tile, and we're not
+        * doing syscall tracing, but there are enough cases now that it
+        * seems simplest just to do the reload unconditionally.
+        */
+.Lrestore_syscall_regs:
+       {
+        ld     r30, r30
+        PTREGS_PTR(r11, PTREGS_OFFSET_REG(0))
+       }
+       pop_reg r0,  r11
+       pop_reg r1,  r11
+       pop_reg r2,  r11
+       pop_reg r3,  r11
+       pop_reg r4,  r11
+       pop_reg r5,  r11, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(5)
+       {
+        ld     TREG_SYSCALL_NR_NAME, r11
+        moveli r21, __NR_syscalls
+       }
+
+       /* Ensure that the syscall number is within the legal range. */
+       {
+        moveli r20, hw2(sys_call_table)
+        blbs   r30, .Lcompat_syscall
+       }
+       {
+        cmpltu r21, TREG_SYSCALL_NR_NAME, r21
+        shl16insli r20, r20, hw1(sys_call_table)
+       }
+       {
+        blbc   r21, .Linvalid_syscall
+        shl16insli r20, r20, hw0(sys_call_table)
+       }
+.Lload_syscall_pointer:
+       shl3add r20, TREG_SYSCALL_NR_NAME, r20
+       ld      r20, r20
+
+       /* Jump to syscall handler. */
+       jalr    r20
+.Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */
+
+       /*
+        * Write our r0 onto the stack so it gets restored instead
+        * of whatever the user had there before.
+        * In compat mode, sign-extend r0 before storing it.
+        */
+       {
+        PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
+        blbct  r30, 1f
+       }
+       addxi   r0, r0, 0
+1:     st      r29, r0
+
+.Lsyscall_sigreturn_skip:
+       FEEDBACK_REENTER(handle_syscall)
+
+       /* Do syscall trace again, if requested. */
+       ld      r30, r31
+       andi    r30, r30, _TIF_SYSCALL_TRACE
+       beqzt   r30, 1f
+       jal     do_syscall_trace
+       FEEDBACK_REENTER(handle_syscall)
+1:     j       .Lresume_userspace   /* jump into middle of interrupt_return */
+
+.Lcompat_syscall:
+       /*
+        * Load the base of the compat syscall table in r20, and
+        * range-check the syscall number (duplicated from 64-bit path).
+        * Sign-extend all the user's passed arguments to make them consistent.
+        * Also save the original "r(n)" values away in "r(11+n)" in
+        * case the syscall table entry wants to validate them.
+        */
+       moveli  r20, hw2(compat_sys_call_table)
+       {
+        cmpltu r21, TREG_SYSCALL_NR_NAME, r21
+        shl16insli r20, r20, hw1(compat_sys_call_table)
+       }
+       {
+        blbc   r21, .Linvalid_syscall
+        shl16insli r20, r20, hw0(compat_sys_call_table)
+       }
+       { move r11, r0; addxi r0, r0, 0 }
+       { move r12, r1; addxi r1, r1, 0 }
+       { move r13, r2; addxi r2, r2, 0 }
+       { move r14, r3; addxi r3, r3, 0 }
+       { move r15, r4; addxi r4, r4, 0 }
+       { move r16, r5; addxi r5, r5, 0 }
+       j .Lload_syscall_pointer
+
+.Linvalid_syscall:
+       /* Report an invalid syscall back to the user program */
+       {
+        PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
+        movei  r28, -ENOSYS
+       }
+       st      r29, r28
+       j       .Lresume_userspace   /* jump into middle of interrupt_return */
+       STD_ENDPROC(handle_syscall)
+
+       /* Return the address for oprofile to suppress in backtraces. */
+STD_ENTRY_SECTION(handle_syscall_link_address, .text.handle_syscall)
+       lnk     r0
+       {
+        addli  r0, r0, .Lhandle_syscall_link - .
+        jrp    lr
+       }
+       STD_ENDPROC(handle_syscall_link_address)
+
+STD_ENTRY(ret_from_fork)
+       jal     sim_notify_fork
+       jal     schedule_tail
+       FEEDBACK_REENTER(ret_from_fork)
+       j       .Lresume_userspace
+       STD_ENDPROC(ret_from_fork)
+
+/* Various stub interrupt handlers and syscall handlers */
+
+STD_ENTRY_LOCAL(_kernel_double_fault)
+       mfspr   r1, SPR_EX_CONTEXT_K_0
+       move    r2, lr
+       move    r3, sp
+       move    r4, r52
+       addi    sp, sp, -C_ABI_SAVE_AREA_SIZE
+       j       kernel_double_fault
+       STD_ENDPROC(_kernel_double_fault)
+
+STD_ENTRY_LOCAL(bad_intr)
+       mfspr   r2, SPR_EX_CONTEXT_K_0
+       panic   "Unhandled interrupt %#x: PC %#lx"
+       STD_ENDPROC(bad_intr)
+
+/* Put address of pt_regs in reg and jump. */
+#define PTREGS_SYSCALL(x, reg)                          \
+       STD_ENTRY(_##x);                                \
+       {                                               \
+        PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
+        j      x                                       \
+       };                                              \
+       STD_ENDPROC(_##x)
+
+/*
+ * Special-case sigreturn to not write r0 to the stack on return.
+ * This is technically more efficient, but it also avoids difficulties
+ * in the 64-bit OS when handling 32-bit compat code, since we must not
+ * sign-extend r0 for the sigreturn return-value case.
+ */
+#define PTREGS_SYSCALL_SIGRETURN(x, reg)                \
+       STD_ENTRY(_##x);                                \
+       addli   lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \
+       {                                               \
+        PTREGS_PTR(reg, PTREGS_OFFSET_BASE);           \
+        j      x                                       \
+       };                                              \
+       STD_ENDPROC(_##x)
+
+PTREGS_SYSCALL(sys_execve, r3)
+PTREGS_SYSCALL(sys_sigaltstack, r2)
+PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
+#ifdef CONFIG_COMPAT
+PTREGS_SYSCALL(compat_sys_execve, r3)
+PTREGS_SYSCALL(compat_sys_sigaltstack, r2)
+PTREGS_SYSCALL_SIGRETURN(compat_sys_rt_sigreturn, r0)
+#endif
+
+/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+STD_ENTRY(_sys_clone)
+       push_extra_callee_saves r4
+       j       sys_clone
+       STD_ENDPROC(_sys_clone)
+
+/* The single-step support may need to read all the registers. */
+int_unalign:
+       push_extra_callee_saves r0
+       j       do_trap
+
+/* Include .intrpt1 array of interrupt vectors */
+       .section ".intrpt1", "ax"
+
+#define op_handle_perf_interrupt bad_intr
+#define op_handle_aux_perf_interrupt bad_intr
+
+#ifndef CONFIG_HARDWALL
+#define do_hardwall_trap bad_intr
+#endif
+
+       int_hand     INT_MEM_ERROR, MEM_ERROR, bad_intr
+       int_hand     INT_SINGLE_STEP_3, SINGLE_STEP_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+       int_hand     INT_SINGLE_STEP_2, SINGLE_STEP_2, gx_singlestep_handle
+       int_hand     INT_SINGLE_STEP_1, SINGLE_STEP_1, bad_intr
+#else
+       int_hand     INT_SINGLE_STEP_2, SINGLE_STEP_2, bad_intr
+       int_hand     INT_SINGLE_STEP_1, SINGLE_STEP_1, gx_singlestep_handle
+#endif
+       int_hand     INT_SINGLE_STEP_0, SINGLE_STEP_0, bad_intr
+       int_hand     INT_IDN_COMPLETE, IDN_COMPLETE, bad_intr
+       int_hand     INT_UDN_COMPLETE, UDN_COMPLETE, bad_intr
+       int_hand     INT_ITLB_MISS, ITLB_MISS, do_page_fault
+       int_hand     INT_ILL, ILL, do_trap
+       int_hand     INT_GPV, GPV, do_trap
+       int_hand     INT_IDN_ACCESS, IDN_ACCESS, do_trap
+       int_hand     INT_UDN_ACCESS, UDN_ACCESS, do_trap
+       int_hand     INT_SWINT_3, SWINT_3, do_trap
+       int_hand     INT_SWINT_2, SWINT_2, do_trap
+       int_hand     INT_SWINT_1, SWINT_1, SYSCALL, handle_syscall
+       int_hand     INT_SWINT_0, SWINT_0, do_trap
+       int_hand     INT_ILL_TRANS, ILL_TRANS, do_trap
+       int_hand     INT_UNALIGN_DATA, UNALIGN_DATA, int_unalign
+       int_hand     INT_DTLB_MISS, DTLB_MISS, do_page_fault
+       int_hand     INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault
+       int_hand     INT_IDN_FIREWALL, IDN_FIREWALL, bad_intr
+       int_hand     INT_UDN_FIREWALL, UDN_FIREWALL, do_hardwall_trap
+       int_hand     INT_TILE_TIMER, TILE_TIMER, do_timer_interrupt
+       int_hand     INT_IDN_TIMER, IDN_TIMER, bad_intr
+       int_hand     INT_UDN_TIMER, UDN_TIMER, bad_intr
+       int_hand     INT_IDN_AVAIL, IDN_AVAIL, bad_intr
+       int_hand     INT_UDN_AVAIL, UDN_AVAIL, bad_intr
+       int_hand     INT_IPI_3, IPI_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+       int_hand     INT_IPI_2, IPI_2, tile_dev_intr
+       int_hand     INT_IPI_1, IPI_1, bad_intr
+#else
+       int_hand     INT_IPI_2, IPI_2, bad_intr
+       int_hand     INT_IPI_1, IPI_1, tile_dev_intr
+#endif
+       int_hand     INT_IPI_0, IPI_0, bad_intr
+       int_hand     INT_PERF_COUNT, PERF_COUNT, \
+                    op_handle_perf_interrupt, handle_nmi
+       int_hand     INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \
+                    op_handle_perf_interrupt, handle_nmi
+       int_hand     INT_INTCTRL_3, INTCTRL_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+       dc_dispatch  INT_INTCTRL_2, INTCTRL_2
+       int_hand     INT_INTCTRL_1, INTCTRL_1, bad_intr
+#else
+       int_hand     INT_INTCTRL_2, INTCTRL_2, bad_intr
+       dc_dispatch  INT_INTCTRL_1, INTCTRL_1
+#endif
+       int_hand     INT_INTCTRL_0, INTCTRL_0, bad_intr
+       int_hand     INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \
+                    hv_message_intr
+       int_hand     INT_DEV_INTR_DWNCL, DEV_INTR_DWNCL, bad_intr
+       int_hand     INT_I_ASID, I_ASID, bad_intr
+       int_hand     INT_D_ASID, D_ASID, bad_intr
+       int_hand     INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap
+
+       /* Synthetic interrupt delivered only by the simulator */
+       int_hand     INT_BREAKPOINT, BREAKPOINT, do_breakpoint
index e2ab82b7c7e7122fcc2c8d48cd1ac0f2f7fa61c3..f68df69f1f67bcc20ab6e90708014240887a7c50 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/kernel.h>
 #include <asm/opcode-tile.h>
 #include <asm/pgtable.h>
+#include <asm/homecache.h>
 
 #ifdef __tilegx__
 # define Elf_Rela Elf64_Rela
@@ -86,8 +87,13 @@ error:
 void module_free(struct module *mod, void *module_region)
 {
        vfree(module_region);
+
+       /* Globally flush the L1 icache. */
+       flush_remote(0, HV_FLUSH_EVICT_L1I, cpu_online_mask,
+                    0, 0, 0, NULL, NULL, 0);
+
        /*
-        * FIXME: If module_region == mod->init_region, trim exception
+        * FIXME: If module_region == mod->module_init, trim exception
         * table entries.
         */
 }
index 658752b2835e37fa7472f2ef52e93045d1674645..658f2ce426a44ef5fefab5852cfbe05dc796953b 100644 (file)
@@ -244,7 +244,7 @@ EXPORT_SYMBOL(dma_sync_single_range_for_device);
  * dma_alloc_noncoherent() returns non-cacheable memory, so there's no
  * need to do any flushing here.
  */
-void dma_cache_sync(void *vaddr, size_t size,
+void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
                    enum dma_data_direction direction)
 {
 }
index ea38f0c9ec7cc776f4bdeddfd7e8371e224166e4..6d4cb5d7a9fd0da47f0f78235c44072c310e57ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU General Public License
@@ -59,6 +59,7 @@ int __write_once tile_plx_gen1;
 
 static struct pci_controller controllers[TILE_NUM_PCIE];
 static int num_controllers;
+static int pci_scan_flags[TILE_NUM_PCIE];
 
 static struct pci_ops tile_cfg_ops;
 
@@ -79,7 +80,7 @@ EXPORT_SYMBOL(pcibios_align_resource);
  * controller_id is the controller number, config type is 0 or 1 for
  * config0 or config1 operations.
  */
-static int __init tile_pcie_open(int controller_id, int config_type)
+static int __devinit tile_pcie_open(int controller_id, int config_type)
 {
        char filename[32];
        int fd;
@@ -95,7 +96,7 @@ static int __init tile_pcie_open(int controller_id, int config_type)
 /*
  * Get the IRQ numbers from the HV and set up the handlers for them.
  */
-static int __init tile_init_irqs(int controller_id,
+static int __devinit tile_init_irqs(int controller_id,
                                 struct pci_controller *controller)
 {
        char filename[32];
@@ -139,71 +140,74 @@ static int __init tile_init_irqs(int controller_id,
  *
  * Returns the number of controllers discovered.
  */
-int __init tile_pci_init(void)
+int __devinit tile_pci_init(void)
 {
        int i;
 
        pr_info("PCI: Searching for controllers...\n");
 
+       /* Re-init number of PCIe controllers to support hot-plug feature. */
+       num_controllers = 0;
+
        /* Do any configuration we need before using the PCIe */
 
        for (i = 0; i < TILE_NUM_PCIE; i++) {
-               int hv_cfg_fd0 = -1;
-               int hv_cfg_fd1 = -1;
-               int hv_mem_fd = -1;
-               char name[32];
-               struct pci_controller *controller;
-
                /*
-                * Open the fd to the HV.  If it fails then this
-                * device doesn't exist.
+                * To see whether we need a real config op based on
+                * the results of pcibios_init(), to support PCIe hot-plug.
                 */
-               hv_cfg_fd0 = tile_pcie_open(i, 0);
-               if (hv_cfg_fd0 < 0)
-                       continue;
-               hv_cfg_fd1 = tile_pcie_open(i, 1);
-               if (hv_cfg_fd1 < 0) {
-                       pr_err("PCI: Couldn't open config fd to HV "
-                           "for controller %d\n", i);
-                       goto err_cont;
-               }
-
-               sprintf(name, "pcie/%d/mem", i);
-               hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0);
-               if (hv_mem_fd < 0) {
-                       pr_err("PCI: Could not open mem fd to HV!\n");
-                       goto err_cont;
-               }
+               if (pci_scan_flags[i] == 0) {
+                       int hv_cfg_fd0 = -1;
+                       int hv_cfg_fd1 = -1;
+                       int hv_mem_fd = -1;
+                       char name[32];
+                       struct pci_controller *controller;
+
+                       /*
+                        * Open the fd to the HV.  If it fails then this
+                        * device doesn't exist.
+                        */
+                       hv_cfg_fd0 = tile_pcie_open(i, 0);
+                       if (hv_cfg_fd0 < 0)
+                               continue;
+                       hv_cfg_fd1 = tile_pcie_open(i, 1);
+                       if (hv_cfg_fd1 < 0) {
+                               pr_err("PCI: Couldn't open config fd to HV "
+                                   "for controller %d\n", i);
+                               goto err_cont;
+                       }
 
-               pr_info("PCI: Found PCI controller #%d\n", i);
+                       sprintf(name, "pcie/%d/mem", i);
+                       hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0);
+                       if (hv_mem_fd < 0) {
+                               pr_err("PCI: Could not open mem fd to HV!\n");
+                               goto err_cont;
+                       }
 
-               controller = &controllers[num_controllers];
+                       pr_info("PCI: Found PCI controller #%d\n", i);
 
-               if (tile_init_irqs(i, controller)) {
-                       pr_err("PCI: Could not initialize "
-                              "IRQs, aborting.\n");
-                       goto err_cont;
-               }
+                       controller = &controllers[i];
 
-               controller->index = num_controllers;
-               controller->hv_cfg_fd[0] = hv_cfg_fd0;
-               controller->hv_cfg_fd[1] = hv_cfg_fd1;
-               controller->hv_mem_fd = hv_mem_fd;
-               controller->first_busno = 0;
-               controller->last_busno = 0xff;
-               controller->ops = &tile_cfg_ops;
+                       controller->index = i;
+                       controller->hv_cfg_fd[0] = hv_cfg_fd0;
+                       controller->hv_cfg_fd[1] = hv_cfg_fd1;
+                       controller->hv_mem_fd = hv_mem_fd;
+                       controller->first_busno = 0;
+                       controller->last_busno = 0xff;
+                       controller->ops = &tile_cfg_ops;
 
-               num_controllers++;
-               continue;
+                       num_controllers++;
+                       continue;
 
 err_cont:
-               if (hv_cfg_fd0 >= 0)
-                       hv_dev_close(hv_cfg_fd0);
-               if (hv_cfg_fd1 >= 0)
-                       hv_dev_close(hv_cfg_fd1);
-               if (hv_mem_fd >= 0)
-                       hv_dev_close(hv_mem_fd);
-               continue;
+                       if (hv_cfg_fd0 >= 0)
+                               hv_dev_close(hv_cfg_fd0);
+                       if (hv_cfg_fd1 >= 0)
+                               hv_dev_close(hv_cfg_fd1);
+                       if (hv_mem_fd >= 0)
+                               hv_dev_close(hv_mem_fd);
+                       continue;
+               }
        }
 
        /*
@@ -232,7 +236,7 @@ static int tile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 }
 
 
-static void __init fixup_read_and_payload_sizes(void)
+static void __devinit fixup_read_and_payload_sizes(void)
 {
        struct pci_dev *dev = NULL;
        int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */
@@ -282,7 +286,7 @@ static void __init fixup_read_and_payload_sizes(void)
  * The controllers have been set up by the time we get here, by a call to
  * tile_pci_init.
  */
-static int __init pcibios_init(void)
+int __devinit pcibios_init(void)
 {
        int i;
 
@@ -296,25 +300,36 @@ static int __init pcibios_init(void)
        mdelay(250);
 
        /* Scan all of the recorded PCI controllers.  */
-       for (i = 0; i < num_controllers; i++) {
-               struct pci_controller *controller = &controllers[i];
-               struct pci_bus *bus;
-
-               pr_info("PCI: initializing controller #%d\n", i);
-
+       for (i = 0; i < TILE_NUM_PCIE; i++) {
                /*
-                * This comes from the generic Linux PCI driver.
-                *
-                * It reads the PCI tree for this bus into the Linux
-                * data structures.
-                *
-                * This is inlined in linux/pci.h and calls into
-                * pci_scan_bus_parented() in probe.c.
+                * Do real pcibios init ops if the controller is initialized
+                * by tile_pci_init() successfully and not initialized by
+                * pcibios_init() yet to support PCIe hot-plug.
                 */
-               bus = pci_scan_bus(0, controller->ops, controller);
-               controller->root_bus = bus;
-               controller->last_busno = bus->subordinate;
+               if (pci_scan_flags[i] == 0 && controllers[i].ops != NULL) {
+                       struct pci_controller *controller = &controllers[i];
+                       struct pci_bus *bus;
 
+                       if (tile_init_irqs(i, controller)) {
+                               pr_err("PCI: Could not initialize IRQs\n");
+                               continue;
+                       }
+
+                       pr_info("PCI: initializing controller #%d\n", i);
+
+                       /*
+                        * This comes from the generic Linux PCI driver.
+                        *
+                        * It reads the PCI tree for this bus into the Linux
+                        * data structures.
+                        *
+                        * This is inlined in linux/pci.h and calls into
+                        * pci_scan_bus_parented() in probe.c.
+                        */
+                       bus = pci_scan_bus(0, controller->ops, controller);
+                       controller->root_bus = bus;
+                       controller->last_busno = bus->subordinate;
+               }
        }
 
        /* Do machine dependent PCI interrupt routing */
@@ -326,34 +341,45 @@ static int __init pcibios_init(void)
         * It allocates all of the resources (I/O memory, etc)
         * associated with the devices read in above.
         */
-
        pci_assign_unassigned_resources();
 
        /* Configure the max_read_size and max_payload_size values. */
        fixup_read_and_payload_sizes();
 
        /* Record the I/O resources in the PCI controller structure. */
-       for (i = 0; i < num_controllers; i++) {
-               struct pci_bus *root_bus = controllers[i].root_bus;
-               struct pci_bus *next_bus;
-               struct pci_dev *dev;
-
-               list_for_each_entry(dev, &root_bus->devices, bus_list) {
-                       /* Find the PCI host controller, ie. the 1st bridge. */
-                       if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
-                               (PCI_SLOT(dev->devfn) == 0)) {
-                               next_bus = dev->subordinate;
-                               controllers[i].mem_resources[0] =
-                                       *next_bus->resource[0];
-                               controllers[i].mem_resources[1] =
-                                        *next_bus->resource[1];
-                               controllers[i].mem_resources[2] =
-                                        *next_bus->resource[2];
-
-                               break;
+       for (i = 0; i < TILE_NUM_PCIE; i++) {
+               /*
+                * Do real pcibios init ops if the controller is initialized
+                * by tile_pci_init() successfully and not initialized by
+                * pcibios_init() yet to support PCIe hot-plug.
+                */
+               if (pci_scan_flags[i] == 0 && controllers[i].ops != NULL) {
+                       struct pci_bus *root_bus = controllers[i].root_bus;
+                       struct pci_bus *next_bus;
+                       struct pci_dev *dev;
+
+                       list_for_each_entry(dev, &root_bus->devices, bus_list) {
+                               /*
+                                * Find the PCI host controller, ie. the 1st
+                                * bridge.
+                                */
+                               if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+                                       (PCI_SLOT(dev->devfn) == 0)) {
+                                       next_bus = dev->subordinate;
+                                       controllers[i].mem_resources[0] =
+                                               *next_bus->resource[0];
+                                       controllers[i].mem_resources[1] =
+                                                *next_bus->resource[1];
+                                       controllers[i].mem_resources[2] =
+                                                *next_bus->resource[2];
+
+                                       /* Setup flags. */
+                                       pci_scan_flags[i] = 1;
+
+                                       break;
+                               }
                        }
                }
-
        }
 
        return 0;
@@ -381,7 +407,7 @@ char __devinit *pcibios_setup(char *str)
 /*
  * This is called from the generic Linux layer.
  */
-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
 {
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
index d0065103eb7bd48e98003e2d594c7c8b2572f0c4..9c45d8bbdf57a7d6b7e9b8eb99da20138e16116e 100644 (file)
 #include <linux/hardirq.h>
 #include <linux/syscalls.h>
 #include <linux/kernel.h>
+#include <linux/tracehook.h>
+#include <linux/signal.h>
 #include <asm/system.h>
 #include <asm/stack.h>
 #include <asm/homecache.h>
 #include <asm/syscalls.h>
+#include <asm/traps.h>
 #ifdef CONFIG_HARDWALL
 #include <asm/hardwall.h>
 #endif
@@ -546,6 +549,51 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
        return __switch_to(prev, next, next_current_ksp0(next));
 }
 
+/*
+ * This routine is called on return from interrupt if any of the
+ * TIF_WORK_MASK flags are set in thread_info->flags.  It is
+ * entered with interrupts disabled so we don't miss an event
+ * that modified the thread_info flags.  If any flag is set, we
+ * handle it and return, and the calling assembly code will
+ * re-disable interrupts, reload the thread flags, and call back
+ * if more flags need to be handled.
+ *
+ * We return whether we need to check the thread_info flags again
+ * or not.  Note that we don't clear TIF_SINGLESTEP here, so it's
+ * important that it be tested last, and then claim that we don't
+ * need to recheck the flags.
+ */
+int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
+{
+       if (thread_info_flags & _TIF_NEED_RESCHED) {
+               schedule();
+               return 1;
+       }
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
+       if (thread_info_flags & _TIF_ASYNC_TLB) {
+               do_async_page_fault(regs);
+               return 1;
+       }
+#endif
+       if (thread_info_flags & _TIF_SIGPENDING) {
+               do_signal(regs);
+               return 1;
+       }
+       if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+               clear_thread_flag(TIF_NOTIFY_RESUME);
+               tracehook_notify_resume(regs);
+               if (current->replacement_session_keyring)
+                       key_replace_session_keyring();
+               return 1;
+       }
+       if (thread_info_flags & _TIF_SINGLESTEP) {
+               if ((regs->ex1 & SPR_EX_CONTEXT_1_1__PL_MASK) == 0)
+                       single_step_once(regs);
+               return 0;
+       }
+       panic("work_pending: bad flags %#x\n", thread_info_flags);
+}
+
 /* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
 SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
                void __user *, parent_tidptr, void __user *, child_tidptr,
@@ -582,8 +630,8 @@ out:
 
 #ifdef CONFIG_COMPAT
 long compat_sys_execve(const char __user *path,
-                      const compat_uptr_t __user *argv,
-                      const compat_uptr_t __user *envp,
+                      compat_uptr_t __user *argv,
+                      compat_uptr_t __user *envp,
                       struct pt_regs *regs)
 {
        long error;
diff --git a/arch/tile/kernel/regs_64.S b/arch/tile/kernel/regs_64.S
new file mode 100644 (file)
index 0000000..f748c1e
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/asm-offsets.h>
+#include <arch/spr_def.h>
+#include <asm/processor.h>
+
+/*
+ * See <asm/system.h>; called with prev and next task_struct pointers.
+ * "prev" is returned in r0 for _switch_to and also for ret_from_fork.
+ *
+ * We want to save pc/sp in "prev", and get the new pc/sp from "next".
+ * We also need to save all the callee-saved registers on the stack.
+ *
+ * Intel enables/disables access to the hardware cycle counter in
+ * seccomp (secure computing) environments if necessary, based on
+ * has_secure_computing().  We might want to do this at some point,
+ * though it would require virtualizing the other SPRs under WORLD_ACCESS.
+ *
+ * Since we're saving to the stack, we omit sp from this list.
+ * And for parallels with other architectures, we save lr separately,
+ * in the thread_struct itself (as the "pc" field).
+ *
+ * This code also needs to be aligned with process.c copy_thread()
+ */
+
+#if CALLEE_SAVED_REGS_COUNT != 24
+# error Mismatch between <asm/system.h> and kernel/entry.S
+#endif
+#define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 8)
+
+#define SAVE_REG(r) { st r12, r; addi r12, r12, 8 }
+#define LOAD_REG(r) { ld r, r12; addi r12, r12, 8 }
+#define FOR_EACH_CALLEE_SAVED_REG(f)                                   \
+                                                       f(r30); f(r31); \
+       f(r32); f(r33); f(r34); f(r35); f(r36); f(r37); f(r38); f(r39); \
+       f(r40); f(r41); f(r42); f(r43); f(r44); f(r45); f(r46); f(r47); \
+       f(r48); f(r49); f(r50); f(r51); f(r52);
+
+STD_ENTRY_SECTION(__switch_to, .sched.text)
+       {
+         move r10, sp
+         st sp, lr
+       }
+       {
+         addli r11, sp, -FRAME_SIZE + 8
+         addli sp, sp, -FRAME_SIZE
+       }
+       {
+         st r11, r10
+         addli r4, r1, TASK_STRUCT_THREAD_KSP_OFFSET
+       }
+       {
+         ld r13, r4   /* Load new sp to a temp register early. */
+         addi r12, sp, 16
+       }
+       FOR_EACH_CALLEE_SAVED_REG(SAVE_REG)
+       addli r3, r0, TASK_STRUCT_THREAD_KSP_OFFSET
+       {
+         st r3, sp
+         addli r3, r0, TASK_STRUCT_THREAD_PC_OFFSET
+       }
+       {
+         st r3, lr
+         addli r4, r1, TASK_STRUCT_THREAD_PC_OFFSET
+       }
+       {
+         ld lr, r4
+         addi r12, r13, 16
+       }
+       {
+         /* Update sp and ksp0 simultaneously to avoid backtracer warnings. */
+         move sp, r13
+         mtspr SPR_SYSTEM_SAVE_K_0, r2
+       }
+       FOR_EACH_CALLEE_SAVED_REG(LOAD_REG)
+.L__switch_to_pc:
+       {
+         addli sp, sp, FRAME_SIZE
+         jrp lr   /* r0 is still valid here, so return it */
+       }
+       STD_ENDPROC(__switch_to)
+
+/* Return a suitable address for the backtracer for suspended threads */
+STD_ENTRY_SECTION(get_switch_to_pc, .sched.text)
+       lnk r0
+       {
+         addli r0, r0, .L__switch_to_pc - .
+         jrp lr
+       }
+       STD_ENDPROC(get_switch_to_pc)
+
+STD_ENTRY(get_pt_regs)
+       .irp reg, r0, r1, r2, r3, r4, r5, r6, r7, \
+                r8, r9, r10, r11, r12, r13, r14, r15, \
+                r16, r17, r18, r19, r20, r21, r22, r23, \
+                r24, r25, r26, r27, r28, r29, r30, r31, \
+                r32, r33, r34, r35, r36, r37, r38, r39, \
+                r40, r41, r42, r43, r44, r45, r46, r47, \
+                r48, r49, r50, r51, r52, tp, sp
+       {
+        st r0, \reg
+        addi r0, r0, 8
+       }
+       .endr
+       {
+        st r0, lr
+        addi r0, r0, PTREGS_OFFSET_PC - PTREGS_OFFSET_LR
+       }
+       lnk r1
+       {
+        st r0, r1
+        addi r0, r0, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
+       }
+       mfspr r1, INTERRUPT_CRITICAL_SECTION
+       shli r1, r1, SPR_EX_CONTEXT_1_1__ICS_SHIFT
+       ori r1, r1, KERNEL_PL
+       {
+        st r0, r1
+        addi r0, r0, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
+       }
+       {
+        st r0, zero       /* clear faultnum */
+        addi r0, r0, PTREGS_OFFSET_ORIG_R0 - PTREGS_OFFSET_FAULTNUM
+       }
+       {
+        st r0, zero       /* clear orig_r0 */
+        addli r0, r0, -PTREGS_OFFSET_ORIG_R0    /* restore r0 to base */
+       }
+       jrp lr
+       STD_ENDPROC(get_pt_regs)
index 3696b18325665784156689aac1325e725a200b74..6cdc9ba55fe0443dd8906fd60056d1ad9e6e783f 100644 (file)
@@ -912,6 +912,8 @@ void __cpuinit setup_cpu(int boot)
 #endif
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+
 static int __initdata set_initramfs_file;
 static char __initdata initramfs_file[128] = "initramfs.cpio.gz";
 
@@ -969,6 +971,10 @@ void __init free_initrd_mem(unsigned long begin, unsigned long end)
        free_bootmem(__pa(begin), end - begin);
 }
 
+#else
+static inline void load_hv_initrd(void) {}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
 static void __init validate_hv(void)
 {
        /*
index 1260321155f1d591b85131f44d9c72ad31122626..bedaf4e9f3a77ff57ee62b3ccc3bc70bb0e202c2 100644 (file)
@@ -39,7 +39,6 @@
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-
 SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
                stack_t __user *, uoss, struct pt_regs *, regs)
 {
@@ -78,6 +77,13 @@ int restore_sigcontext(struct pt_regs *regs,
        return err;
 }
 
+void signal_fault(const char *type, struct pt_regs *regs,
+                 void __user *frame, int sig)
+{
+       trace_unhandled_signal(type, regs, (unsigned long)frame, SIGSEGV);
+       force_sigsegv(sig, current);
+}
+
 /* The assembly shim for this function arranges to ignore the return value. */
 SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
 {
@@ -105,7 +111,7 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
        return 0;
 
 badframe:
-       force_sig(SIGSEGV, current);
+       signal_fault("bad sigreturn frame", regs, frame, 0);
        return 0;
 }
 
@@ -231,7 +237,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        return 0;
 
 give_sigsegv:
-       force_sigsegv(sig, current);
+       signal_fault("bad setup frame", regs, frame, sig);
        return -EFAULT;
 }
 
@@ -245,7 +251,6 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
 {
        int ret;
 
-
        /* Are we from a system call? */
        if (regs->faultnum == INT_SWINT_1) {
                /* If so, check system call restarting.. */
@@ -363,3 +368,118 @@ done:
        /* Avoid double syscall restart if there are nested signals. */
        regs->faultnum = INT_SWINT_1_SIGRETURN;
 }
+
+int show_unhandled_signals = 1;
+
+static int __init crashinfo(char *str)
+{
+       unsigned long val;
+       const char *word;
+
+       if (*str == '\0')
+               val = 2;
+       else if (*str != '=' || strict_strtoul(++str, 0, &val) != 0)
+               return 0;
+       show_unhandled_signals = val;
+       switch (show_unhandled_signals) {
+       case 0:
+               word = "No";
+               break;
+       case 1:
+               word = "One-line";
+               break;
+       default:
+               word = "Detailed";
+               break;
+       }
+       pr_info("%s crash reports will be generated on the console\n", word);
+       return 1;
+}
+__setup("crashinfo", crashinfo);
+
+static void dump_mem(void __user *address)
+{
+       void __user *addr;
+       enum { region_size = 256, bytes_per_line = 16 };
+       int i, j, k;
+       int found_readable_mem = 0;
+
+       pr_err("\n");
+       if (!access_ok(VERIFY_READ, address, 1)) {
+               pr_err("Not dumping at address 0x%lx (kernel address)\n",
+                      (unsigned long)address);
+               return;
+       }
+
+       addr = (void __user *)
+               (((unsigned long)address & -bytes_per_line) - region_size/2);
+       if (addr > address)
+               addr = NULL;
+       for (i = 0; i < region_size;
+            addr += bytes_per_line, i += bytes_per_line) {
+               unsigned char buf[bytes_per_line];
+               char line[100];
+               if (copy_from_user(buf, addr, bytes_per_line))
+                       continue;
+               if (!found_readable_mem) {
+                       pr_err("Dumping memory around address 0x%lx:\n",
+                              (unsigned long)address);
+                       found_readable_mem = 1;
+               }
+               j = sprintf(line, REGFMT":", (unsigned long)addr);
+               for (k = 0; k < bytes_per_line; ++k)
+                       j += sprintf(&line[j], " %02x", buf[k]);
+               pr_err("%s\n", line);
+       }
+       if (!found_readable_mem)
+               pr_err("No readable memory around address 0x%lx\n",
+                      (unsigned long)address);
+}
+
+void trace_unhandled_signal(const char *type, struct pt_regs *regs,
+                           unsigned long address, int sig)
+{
+       struct task_struct *tsk = current;
+
+       if (show_unhandled_signals == 0)
+               return;
+
+       /* If the signal is handled, don't show it here. */
+       if (!is_global_init(tsk)) {
+               void __user *handler =
+                       tsk->sighand->action[sig-1].sa.sa_handler;
+               if (handler != SIG_IGN && handler != SIG_DFL)
+                       return;
+       }
+
+       /* Rate-limit the one-line output, not the detailed output. */
+       if (show_unhandled_signals <= 1 && !printk_ratelimit())
+               return;
+
+       printk("%s%s[%d]: %s at %lx pc "REGFMT" signal %d",
+              task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
+              tsk->comm, task_pid_nr(tsk), type, address, regs->pc, sig);
+
+       print_vma_addr(KERN_CONT " in ", regs->pc);
+
+       printk(KERN_CONT "\n");
+
+       if (show_unhandled_signals > 1) {
+               switch (sig) {
+               case SIGILL:
+               case SIGFPE:
+               case SIGSEGV:
+               case SIGBUS:
+                       pr_err("User crash: signal %d,"
+                              " trap %ld, address 0x%lx\n",
+                              sig, regs->faultnum, address);
+                       show_regs(regs);
+                       dump_mem((void __user *)address);
+                       break;
+               default:
+                       pr_err("User crash: signal %d, trap %ld\n",
+                              sig, regs->faultnum);
+                       break;
+               }
+       }
+}
index 84a729e06ec44b448110ddf78cef5852ef87fa23..4032ca8e51b613b894bee171f1afa8468ffddb1d 100644 (file)
@@ -186,6 +186,8 @@ static tile_bundle_bits rewrite_load_store_unaligned(
                        .si_code = SEGV_MAPERR,
                        .si_addr = addr
                };
+               trace_unhandled_signal("segfault", regs,
+                                      (unsigned long)addr, SIGSEGV);
                force_sig_info(info.si_signo, &info, current);
                return (tile_bundle_bits) 0;
        }
@@ -196,6 +198,8 @@ static tile_bundle_bits rewrite_load_store_unaligned(
                        .si_code = BUS_ADRALN,
                        .si_addr = addr
                };
+               trace_unhandled_signal("unaligned trap", regs,
+                                      (unsigned long)addr, SIGBUS);
                force_sig_info(info.si_signo, &info, current);
                return (tile_bundle_bits) 0;
        }
@@ -318,6 +322,14 @@ void single_step_once(struct pt_regs *regs)
 "    .popsection\n"
        );
 
+       /*
+        * Enable interrupts here to allow touching userspace and the like.
+        * The callers expect this: do_trap() already has interrupts
+        * enabled, and do_work_pending() handles functions that enable
+        * interrupts internally.
+        */
+       local_irq_enable();
+
        if (state == NULL) {
                /* allocate a page of writable, executable memory */
                state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL);
index dd81713a90dc5991a077fbfde30c3d65cb91489c..37ee4d037e0bae6788762e23e28fd3f518f38175 100644 (file)
@@ -36,7 +36,7 @@
 #define KBT_LOOP       3  /* Backtrace entered a loop */
 
 /* Is address on the specified kernel stack? */
-static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
+static int in_kernel_stack(struct KBacktraceIterator *kbt, unsigned long sp)
 {
        ulong kstack_base = (ulong) kbt->task->stack;
        if (kstack_base == 0)  /* corrupt task pointer; just follow stack... */
@@ -45,7 +45,7 @@ static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
 }
 
 /* Is address valid for reading? */
-static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
+static int valid_address(struct KBacktraceIterator *kbt, unsigned long address)
 {
        HV_PTE *l1_pgtable = kbt->pgtable;
        HV_PTE *l2_pgtable;
@@ -97,7 +97,7 @@ static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
 }
 
 /* Callback for backtracer; basically a glorified memcpy */
-static bool read_memory_func(void *result, VirtualAddress address,
+static bool read_memory_func(void *result, unsigned long address,
                             unsigned int size, void *vkbt)
 {
        int retval;
@@ -124,7 +124,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
 {
        const char *fault = NULL;  /* happy compiler */
        char fault_buf[64];
-       VirtualAddress sp = kbt->it.sp;
+       unsigned long sp = kbt->it.sp;
        struct pt_regs *p;
 
        if (!in_kernel_stack(kbt, sp))
@@ -163,7 +163,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
 }
 
 /* Is the pc pointing to a sigreturn trampoline? */
-static int is_sigreturn(VirtualAddress pc)
+static int is_sigreturn(unsigned long pc)
 {
        return (pc == VDSO_BASE);
 }
@@ -260,7 +260,7 @@ static void validate_stack(struct pt_regs *regs)
 void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
                             struct task_struct *t, struct pt_regs *regs)
 {
-       VirtualAddress pc, lr, sp, r52;
+       unsigned long pc, lr, sp, r52;
        int is_current;
 
        /*
@@ -331,7 +331,7 @@ EXPORT_SYMBOL(KBacktraceIterator_end);
 
 void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
 {
-       VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp;
+       unsigned long old_pc = kbt->it.pc, old_sp = kbt->it.sp;
        kbt->new_context = 0;
        if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
                kbt->end = KBT_DONE;
index e2187d24a9b41d8ad765f1a383347525dc728a5f..cb44ba7ccd2d1e61622a761c90259c3b257a9c1f 100644 (file)
@@ -56,13 +56,6 @@ ssize_t sys32_readahead(int fd, u32 offset_lo, u32 offset_hi, u32 count)
        return sys_readahead(fd, ((loff_t)offset_hi << 32) | offset_lo, count);
 }
 
-long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi,
-                    u32 len, int advice)
-{
-       return sys_fadvise64_64(fd, ((loff_t)offset_hi << 32) | offset_lo,
-                               len, advice);
-}
-
 int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
                       u32 len_lo, u32 len_hi, int advice)
 {
@@ -103,10 +96,8 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
 
 #ifndef __tilegx__
 /* See comments at the top of the file. */
-#define sys_fadvise64 sys32_fadvise64
 #define sys_fadvise64_64 sys32_fadvise64_64
 #define sys_readahead sys32_readahead
-#define sys_sync_file_range sys_sync_file_range2
 #endif
 
 /* Call the trampolines to manage pt_regs where necessary. */
index 69af0e150f785b974fbcbbbc0aa532f3685c5de6..7e31a12857885c13affbcbd53ad916b2006bf15c 100644 (file)
@@ -2413,12 +2413,13 @@ const struct tile_operand tile_operands[43] =
 
 
 
-/* Given a set of bundle bits and the lookup FSM for a specific pipe,
- * returns which instruction the bundle contains in that pipe.
+/* Given a set of bundle bits and a specific pipe, returns which
+ * instruction the bundle contains in that pipe.
  */
-static const struct tile_opcode *
-find_opcode(tile_bundle_bits bits, const unsigned short *table)
+const struct tile_opcode *
+find_opcode(tile_bundle_bits bits, tile_pipeline pipe)
 {
+  const unsigned short *table = tile_bundle_decoder_fsms[pipe];
   int index = 0;
 
   while (1)
@@ -2465,7 +2466,7 @@ parse_insn_tile(tile_bundle_bits bits,
     int i;
 
     d = &decoded[num_instructions++];
-    opc = find_opcode (bits, tile_bundle_decoder_fsms[pipe]);
+    opc = find_opcode (bits, (tile_pipeline)pipe);
     d->opcode = opc;
 
     /* Decode each operand, sign extending, etc. as appropriate. */
diff --git a/arch/tile/kernel/tile-desc_64.c b/arch/tile/kernel/tile-desc_64.c
new file mode 100644 (file)
index 0000000..d57007b
--- /dev/null
@@ -0,0 +1,2200 @@
+/* This define is BFD_RELOC_##x for real bfd, or -1 for everyone else. */
+#define BFD_RELOC(x) -1
+
+/* Special registers. */
+#define TREG_LR 55
+#define TREG_SN 56
+#define TREG_ZERO 63
+
+/* FIXME: Rename this. */
+#include <asm/opcode-tile_64.h>
+
+#include <linux/stddef.h>
+
+const struct tilegx_opcode tilegx_opcodes[334] =
+{
+ { "bpt", TILEGX_OPC_BPT, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "info", TILEGX_OPC_INFO, 0xf, 1, TREG_ZERO, 1,
+    { { 0 }, { 1 }, { 2 }, { 3 }, { 0, } },
+  },
+  { "infol", TILEGX_OPC_INFOL, 0x3, 1, TREG_ZERO, 1,
+    { { 4 }, { 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "move", TILEGX_OPC_MOVE, 0xf, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 8, 9 }, { 10, 11 }, { 12, 13 }, { 0, } },
+  },
+  { "movei", TILEGX_OPC_MOVEI, 0xf, 2, TREG_ZERO, 1,
+    { { 6, 0 }, { 8, 1 }, { 10, 2 }, { 12, 3 }, { 0, } },
+  },
+  { "moveli", TILEGX_OPC_MOVELI, 0x3, 2, TREG_ZERO, 1,
+    { { 6, 4 }, { 8, 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch", TILEGX_OPC_PREFETCH, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_add_l1", TILEGX_OPC_PREFETCH_ADD_L1, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l1_fault", TILEGX_OPC_PREFETCH_ADD_L1_FAULT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l2", TILEGX_OPC_PREFETCH_ADD_L2, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l2_fault", TILEGX_OPC_PREFETCH_ADD_L2_FAULT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l3", TILEGX_OPC_PREFETCH_ADD_L3, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_add_l3_fault", TILEGX_OPC_PREFETCH_ADD_L3_FAULT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "prefetch_l1", TILEGX_OPC_PREFETCH_L1, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l1_fault", TILEGX_OPC_PREFETCH_L1_FAULT, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l2", TILEGX_OPC_PREFETCH_L2, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l2_fault", TILEGX_OPC_PREFETCH_L2_FAULT, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l3", TILEGX_OPC_PREFETCH_L3, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "prefetch_l3_fault", TILEGX_OPC_PREFETCH_L3_FAULT, 0x12, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+  },
+  { "raise", TILEGX_OPC_RAISE, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "add", TILEGX_OPC_ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "addi", TILEGX_OPC_ADDI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "addli", TILEGX_OPC_ADDLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "addx", TILEGX_OPC_ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "addxi", TILEGX_OPC_ADDXI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "addxli", TILEGX_OPC_ADDXLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "addxsc", TILEGX_OPC_ADDXSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "and", TILEGX_OPC_AND, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "andi", TILEGX_OPC_ANDI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "beqz", TILEGX_OPC_BEQZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "beqzt", TILEGX_OPC_BEQZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bfexts", TILEGX_OPC_BFEXTS, 0x1, 4, TREG_ZERO, 1,
+    { { 6, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bfextu", TILEGX_OPC_BFEXTU, 0x1, 4, TREG_ZERO, 1,
+    { { 6, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bfins", TILEGX_OPC_BFINS, 0x1, 4, TREG_ZERO, 1,
+    { { 23, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bgez", TILEGX_OPC_BGEZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bgezt", TILEGX_OPC_BGEZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bgtz", TILEGX_OPC_BGTZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bgtzt", TILEGX_OPC_BGTZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blbc", TILEGX_OPC_BLBC, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blbct", TILEGX_OPC_BLBCT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blbs", TILEGX_OPC_BLBS, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blbst", TILEGX_OPC_BLBST, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blez", TILEGX_OPC_BLEZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "blezt", TILEGX_OPC_BLEZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bltz", TILEGX_OPC_BLTZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bltzt", TILEGX_OPC_BLTZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bnez", TILEGX_OPC_BNEZ, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "bnezt", TILEGX_OPC_BNEZT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "clz", TILEGX_OPC_CLZ, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "cmoveqz", TILEGX_OPC_CMOVEQZ, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "cmovnez", TILEGX_OPC_CMOVNEZ, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "cmpeq", TILEGX_OPC_CMPEQ, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmpeqi", TILEGX_OPC_CMPEQI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "cmpexch", TILEGX_OPC_CMPEXCH, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmpexch4", TILEGX_OPC_CMPEXCH4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmples", TILEGX_OPC_CMPLES, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmpleu", TILEGX_OPC_CMPLEU, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmplts", TILEGX_OPC_CMPLTS, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmpltsi", TILEGX_OPC_CMPLTSI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+  },
+  { "cmpltu", TILEGX_OPC_CMPLTU, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmpltui", TILEGX_OPC_CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmpne", TILEGX_OPC_CMPNE, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "cmul", TILEGX_OPC_CMUL, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmula", TILEGX_OPC_CMULA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulaf", TILEGX_OPC_CMULAF, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulf", TILEGX_OPC_CMULF, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulfr", TILEGX_OPC_CMULFR, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulh", TILEGX_OPC_CMULH, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "cmulhr", TILEGX_OPC_CMULHR, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "crc32_32", TILEGX_OPC_CRC32_32, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "crc32_8", TILEGX_OPC_CRC32_8, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ctz", TILEGX_OPC_CTZ, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "dblalign", TILEGX_OPC_DBLALIGN, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "dblalign2", TILEGX_OPC_DBLALIGN2, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "dblalign4", TILEGX_OPC_DBLALIGN4, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "dblalign6", TILEGX_OPC_DBLALIGN6, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "drain", TILEGX_OPC_DRAIN, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "dtlbpr", TILEGX_OPC_DTLBPR, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "exch", TILEGX_OPC_EXCH, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "exch4", TILEGX_OPC_EXCH4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_add_flags", TILEGX_OPC_FDOUBLE_ADD_FLAGS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_addsub", TILEGX_OPC_FDOUBLE_ADDSUB, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_mul_flags", TILEGX_OPC_FDOUBLE_MUL_FLAGS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_pack1", TILEGX_OPC_FDOUBLE_PACK1, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_pack2", TILEGX_OPC_FDOUBLE_PACK2, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_sub_flags", TILEGX_OPC_FDOUBLE_SUB_FLAGS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_unpack_max", TILEGX_OPC_FDOUBLE_UNPACK_MAX, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fdouble_unpack_min", TILEGX_OPC_FDOUBLE_UNPACK_MIN, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchadd", TILEGX_OPC_FETCHADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchadd4", TILEGX_OPC_FETCHADD4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchaddgez", TILEGX_OPC_FETCHADDGEZ, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchaddgez4", TILEGX_OPC_FETCHADDGEZ4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchand", TILEGX_OPC_FETCHAND, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchand4", TILEGX_OPC_FETCHAND4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchor", TILEGX_OPC_FETCHOR, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fetchor4", TILEGX_OPC_FETCHOR4, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "finv", TILEGX_OPC_FINV, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "flush", TILEGX_OPC_FLUSH, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "flushwb", TILEGX_OPC_FLUSHWB, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fnop", TILEGX_OPC_FNOP, 0xf, 0, TREG_ZERO, 1,
+    { {  }, {  }, {  }, {  }, { 0, } },
+  },
+  { "fsingle_add1", TILEGX_OPC_FSINGLE_ADD1, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_addsub2", TILEGX_OPC_FSINGLE_ADDSUB2, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_mul1", TILEGX_OPC_FSINGLE_MUL1, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_mul2", TILEGX_OPC_FSINGLE_MUL2, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_pack1", TILEGX_OPC_FSINGLE_PACK1, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "fsingle_pack2", TILEGX_OPC_FSINGLE_PACK2, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "fsingle_sub1", TILEGX_OPC_FSINGLE_SUB1, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "icoh", TILEGX_OPC_ICOH, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ill", TILEGX_OPC_ILL, 0xa, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, {  }, { 0, } },
+  },
+  { "inv", TILEGX_OPC_INV, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "iret", TILEGX_OPC_IRET, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "j", TILEGX_OPC_J, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "jal", TILEGX_OPC_JAL, 0x2, 1, TREG_LR, 1,
+    { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "jalr", TILEGX_OPC_JALR, 0xa, 1, TREG_LR, 1,
+    { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+  },
+  { "jalrp", TILEGX_OPC_JALRP, 0xa, 1, TREG_LR, 1,
+    { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+  },
+  { "jr", TILEGX_OPC_JR, 0xa, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+  },
+  { "jrp", TILEGX_OPC_JRP, 0xa, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+  },
+  { "ld", TILEGX_OPC_LD, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld1s", TILEGX_OPC_LD1S, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld1s_add", TILEGX_OPC_LD1S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld1u", TILEGX_OPC_LD1U, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld1u_add", TILEGX_OPC_LD1U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld2s", TILEGX_OPC_LD2S, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld2s_add", TILEGX_OPC_LD2S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld2u", TILEGX_OPC_LD2U, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld2u_add", TILEGX_OPC_LD2U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld4s", TILEGX_OPC_LD4S, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld4s_add", TILEGX_OPC_LD4S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld4u", TILEGX_OPC_LD4U, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+  },
+  { "ld4u_add", TILEGX_OPC_LD4U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ld_add", TILEGX_OPC_LD_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldna", TILEGX_OPC_LDNA, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldna_add", TILEGX_OPC_LDNA_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt", TILEGX_OPC_LDNT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt1s", TILEGX_OPC_LDNT1S, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt1s_add", TILEGX_OPC_LDNT1S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt1u", TILEGX_OPC_LDNT1U, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt1u_add", TILEGX_OPC_LDNT1U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt2s", TILEGX_OPC_LDNT2S, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt2s_add", TILEGX_OPC_LDNT2S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt2u", TILEGX_OPC_LDNT2U, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt2u_add", TILEGX_OPC_LDNT2U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt4s", TILEGX_OPC_LDNT4S, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt4s_add", TILEGX_OPC_LDNT4S_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt4u", TILEGX_OPC_LDNT4U, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt4u_add", TILEGX_OPC_LDNT4U_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "ldnt_add", TILEGX_OPC_LDNT_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "lnk", TILEGX_OPC_LNK, 0xa, 1, TREG_ZERO, 1,
+    { { 0, }, { 8 }, { 0, }, { 12 }, { 0, } },
+  },
+  { "mf", TILEGX_OPC_MF, 0x2, 0, TREG_ZERO, 1,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mfspr", TILEGX_OPC_MFSPR, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 8, 27 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mm", TILEGX_OPC_MM, 0x1, 4, TREG_ZERO, 1,
+    { { 23, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mnz", TILEGX_OPC_MNZ, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "mtspr", TILEGX_OPC_MTSPR, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 28, 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hs_hs", TILEGX_OPC_MUL_HS_HS, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mul_hs_hu", TILEGX_OPC_MUL_HS_HU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hs_ls", TILEGX_OPC_MUL_HS_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hs_lu", TILEGX_OPC_MUL_HS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hu_hu", TILEGX_OPC_MUL_HU_HU, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mul_hu_ls", TILEGX_OPC_MUL_HU_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_hu_lu", TILEGX_OPC_MUL_HU_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_ls_ls", TILEGX_OPC_MUL_LS_LS, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mul_ls_lu", TILEGX_OPC_MUL_LS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mul_lu_lu", TILEGX_OPC_MUL_LU_LU, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mula_hs_hs", TILEGX_OPC_MULA_HS_HS, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mula_hs_hu", TILEGX_OPC_MULA_HS_HU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_hs_ls", TILEGX_OPC_MULA_HS_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_hs_lu", TILEGX_OPC_MULA_HS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_hu_hu", TILEGX_OPC_MULA_HU_HU, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mula_hu_ls", TILEGX_OPC_MULA_HU_LS, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_hu_lu", TILEGX_OPC_MULA_HU_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_ls_ls", TILEGX_OPC_MULA_LS_LS, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mula_ls_lu", TILEGX_OPC_MULA_LS_LU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "mula_lu_lu", TILEGX_OPC_MULA_LU_LU, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mulax", TILEGX_OPC_MULAX, 0x5, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mulx", TILEGX_OPC_MULX, 0x5, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+  },
+  { "mz", TILEGX_OPC_MZ, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "nap", TILEGX_OPC_NAP, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "nop", TILEGX_OPC_NOP, 0xf, 0, TREG_ZERO, 1,
+    { {  }, {  }, {  }, {  }, { 0, } },
+  },
+  { "nor", TILEGX_OPC_NOR, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "or", TILEGX_OPC_OR, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "ori", TILEGX_OPC_ORI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "pcnt", TILEGX_OPC_PCNT, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "revbits", TILEGX_OPC_REVBITS, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "revbytes", TILEGX_OPC_REVBYTES, 0x5, 2, TREG_ZERO, 1,
+    { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+  },
+  { "rotl", TILEGX_OPC_ROTL, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "rotli", TILEGX_OPC_ROTLI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+  },
+  { "shl", TILEGX_OPC_SHL, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl16insli", TILEGX_OPC_SHL16INSLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shl1add", TILEGX_OPC_SHL1ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl1addx", TILEGX_OPC_SHL1ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl2add", TILEGX_OPC_SHL2ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl2addx", TILEGX_OPC_SHL2ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl3add", TILEGX_OPC_SHL3ADD, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shl3addx", TILEGX_OPC_SHL3ADDX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shli", TILEGX_OPC_SHLI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+  },
+  { "shlx", TILEGX_OPC_SHLX, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shlxi", TILEGX_OPC_SHLXI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shrs", TILEGX_OPC_SHRS, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shrsi", TILEGX_OPC_SHRSI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+  },
+  { "shru", TILEGX_OPC_SHRU, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "shrui", TILEGX_OPC_SHRUI, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+  },
+  { "shrux", TILEGX_OPC_SHRUX, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shruxi", TILEGX_OPC_SHRUXI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "shufflebytes", TILEGX_OPC_SHUFFLEBYTES, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "st", TILEGX_OPC_ST, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+  },
+  { "st1", TILEGX_OPC_ST1, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+  },
+  { "st1_add", TILEGX_OPC_ST1_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "st2", TILEGX_OPC_ST2, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+  },
+  { "st2_add", TILEGX_OPC_ST2_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "st4", TILEGX_OPC_ST4, 0x12, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+  },
+  { "st4_add", TILEGX_OPC_ST4_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "st_add", TILEGX_OPC_ST_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt", TILEGX_OPC_STNT, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt1", TILEGX_OPC_STNT1, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt1_add", TILEGX_OPC_STNT1_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt2", TILEGX_OPC_STNT2, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt2_add", TILEGX_OPC_STNT2_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt4", TILEGX_OPC_STNT4, 0x2, 2, TREG_ZERO, 1,
+    { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt4_add", TILEGX_OPC_STNT4_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "stnt_add", TILEGX_OPC_STNT_ADD, 0x2, 3, TREG_ZERO, 1,
+    { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "sub", TILEGX_OPC_SUB, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "subx", TILEGX_OPC_SUBX, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "subxsc", TILEGX_OPC_SUBXSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "swint0", TILEGX_OPC_SWINT0, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "swint1", TILEGX_OPC_SWINT1, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "swint2", TILEGX_OPC_SWINT2, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "swint3", TILEGX_OPC_SWINT3, 0x2, 0, TREG_ZERO, 0,
+    { { 0, }, {  }, { 0, }, { 0, }, { 0, } },
+  },
+  { "tblidxb0", TILEGX_OPC_TBLIDXB0, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+  },
+  { "tblidxb1", TILEGX_OPC_TBLIDXB1, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+  },
+  { "tblidxb2", TILEGX_OPC_TBLIDXB2, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+  },
+  { "tblidxb3", TILEGX_OPC_TBLIDXB3, 0x5, 2, TREG_ZERO, 1,
+    { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+  },
+  { "v1add", TILEGX_OPC_V1ADD, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1addi", TILEGX_OPC_V1ADDI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1adduc", TILEGX_OPC_V1ADDUC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1adiffu", TILEGX_OPC_V1ADIFFU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1avgu", TILEGX_OPC_V1AVGU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpeq", TILEGX_OPC_V1CMPEQ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpeqi", TILEGX_OPC_V1CMPEQI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmples", TILEGX_OPC_V1CMPLES, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpleu", TILEGX_OPC_V1CMPLEU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmplts", TILEGX_OPC_V1CMPLTS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpltsi", TILEGX_OPC_V1CMPLTSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpltu", TILEGX_OPC_V1CMPLTU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpltui", TILEGX_OPC_V1CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1cmpne", TILEGX_OPC_V1CMPNE, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1ddotpu", TILEGX_OPC_V1DDOTPU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1ddotpua", TILEGX_OPC_V1DDOTPUA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1ddotpus", TILEGX_OPC_V1DDOTPUS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1ddotpusa", TILEGX_OPC_V1DDOTPUSA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotp", TILEGX_OPC_V1DOTP, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpa", TILEGX_OPC_V1DOTPA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpu", TILEGX_OPC_V1DOTPU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpua", TILEGX_OPC_V1DOTPUA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpus", TILEGX_OPC_V1DOTPUS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1dotpusa", TILEGX_OPC_V1DOTPUSA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1int_h", TILEGX_OPC_V1INT_H, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1int_l", TILEGX_OPC_V1INT_L, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1maxu", TILEGX_OPC_V1MAXU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1maxui", TILEGX_OPC_V1MAXUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1minu", TILEGX_OPC_V1MINU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1minui", TILEGX_OPC_V1MINUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1mnz", TILEGX_OPC_V1MNZ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1multu", TILEGX_OPC_V1MULTU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1mulu", TILEGX_OPC_V1MULU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1mulus", TILEGX_OPC_V1MULUS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1mz", TILEGX_OPC_V1MZ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1sadau", TILEGX_OPC_V1SADAU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1sadu", TILEGX_OPC_V1SADU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shl", TILEGX_OPC_V1SHL, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shli", TILEGX_OPC_V1SHLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shrs", TILEGX_OPC_V1SHRS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shrsi", TILEGX_OPC_V1SHRSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shru", TILEGX_OPC_V1SHRU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1shrui", TILEGX_OPC_V1SHRUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1sub", TILEGX_OPC_V1SUB, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v1subuc", TILEGX_OPC_V1SUBUC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2add", TILEGX_OPC_V2ADD, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2addi", TILEGX_OPC_V2ADDI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2addsc", TILEGX_OPC_V2ADDSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2adiffs", TILEGX_OPC_V2ADIFFS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2avgs", TILEGX_OPC_V2AVGS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpeq", TILEGX_OPC_V2CMPEQ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpeqi", TILEGX_OPC_V2CMPEQI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmples", TILEGX_OPC_V2CMPLES, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpleu", TILEGX_OPC_V2CMPLEU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmplts", TILEGX_OPC_V2CMPLTS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpltsi", TILEGX_OPC_V2CMPLTSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpltu", TILEGX_OPC_V2CMPLTU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpltui", TILEGX_OPC_V2CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2cmpne", TILEGX_OPC_V2CMPNE, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2dotp", TILEGX_OPC_V2DOTP, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2dotpa", TILEGX_OPC_V2DOTPA, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2int_h", TILEGX_OPC_V2INT_H, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2int_l", TILEGX_OPC_V2INT_L, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2maxs", TILEGX_OPC_V2MAXS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2maxsi", TILEGX_OPC_V2MAXSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mins", TILEGX_OPC_V2MINS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2minsi", TILEGX_OPC_V2MINSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mnz", TILEGX_OPC_V2MNZ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mulfsc", TILEGX_OPC_V2MULFSC, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2muls", TILEGX_OPC_V2MULS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mults", TILEGX_OPC_V2MULTS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2mz", TILEGX_OPC_V2MZ, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2packh", TILEGX_OPC_V2PACKH, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2packl", TILEGX_OPC_V2PACKL, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2packuc", TILEGX_OPC_V2PACKUC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sadas", TILEGX_OPC_V2SADAS, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sadau", TILEGX_OPC_V2SADAU, 0x1, 3, TREG_ZERO, 1,
+    { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sads", TILEGX_OPC_V2SADS, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sadu", TILEGX_OPC_V2SADU, 0x1, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shl", TILEGX_OPC_V2SHL, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shli", TILEGX_OPC_V2SHLI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shlsc", TILEGX_OPC_V2SHLSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shrs", TILEGX_OPC_V2SHRS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shrsi", TILEGX_OPC_V2SHRSI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shru", TILEGX_OPC_V2SHRU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2shrui", TILEGX_OPC_V2SHRUI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2sub", TILEGX_OPC_V2SUB, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v2subsc", TILEGX_OPC_V2SUBSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4add", TILEGX_OPC_V4ADD, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4addsc", TILEGX_OPC_V4ADDSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4int_h", TILEGX_OPC_V4INT_H, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4int_l", TILEGX_OPC_V4INT_L, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4packsc", TILEGX_OPC_V4PACKSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4shl", TILEGX_OPC_V4SHL, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4shlsc", TILEGX_OPC_V4SHLSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4shrs", TILEGX_OPC_V4SHRS, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4shru", TILEGX_OPC_V4SHRU, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4sub", TILEGX_OPC_V4SUB, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "v4subsc", TILEGX_OPC_V4SUBSC, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "wh64", TILEGX_OPC_WH64, 0x2, 1, TREG_ZERO, 1,
+    { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+  },
+  { "xor", TILEGX_OPC_XOR, 0xf, 3, TREG_ZERO, 1,
+    { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+  },
+  { "xori", TILEGX_OPC_XORI, 0x3, 3, TREG_ZERO, 1,
+    { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+  },
+  { NULL, TILEGX_OPC_NONE, 0, 0, TREG_ZERO, 0, { { 0, } },
+  }
+};
+#define BITFIELD(start, size) ((start) | (((1 << (size)) - 1) << 6))
+#define CHILD(array_index) (TILEGX_OPC_NONE + (array_index))
+
+static const unsigned short decode_X0_fsm[936] =
+{
+  BITFIELD(22, 9) /* index 0 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BFEXTS,
+  TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTU,
+  TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFINS,
+  TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_MM,
+  TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(528), CHILD(578),
+  CHILD(583), CHILD(588), CHILD(593), CHILD(598), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, CHILD(603), CHILD(620), CHILD(637), CHILD(654), CHILD(671),
+  CHILD(703), CHILD(797), CHILD(814), CHILD(831), CHILD(848), CHILD(865),
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, CHILD(889), TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+  BITFIELD(6, 2) /* index 513 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518),
+  BITFIELD(8, 2) /* index 518 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523),
+  BITFIELD(10, 2) /* index 523 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI,
+  BITFIELD(20, 2) /* index 528 */,
+  TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548),
+  BITFIELD(6, 2) /* index 533 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538),
+  BITFIELD(8, 2) /* index 538 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543),
+  BITFIELD(10, 2) /* index 543 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(0, 2) /* index 548 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553),
+  BITFIELD(2, 2) /* index 553 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558),
+  BITFIELD(4, 2) /* index 558 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563),
+  BITFIELD(6, 2) /* index 563 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568),
+  BITFIELD(8, 2) /* index 568 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573),
+  BITFIELD(10, 2) /* index 573 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(20, 2) /* index 578 */,
+  TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, TILEGX_OPC_ORI,
+  BITFIELD(20, 2) /* index 583 */,
+  TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI, TILEGX_OPC_V1CMPLTSI,
+  TILEGX_OPC_V1CMPLTUI,
+  BITFIELD(20, 2) /* index 588 */,
+  TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI, TILEGX_OPC_V2ADDI,
+  TILEGX_OPC_V2CMPEQI,
+  BITFIELD(20, 2) /* index 593 */,
+  TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI, TILEGX_OPC_V2MAXSI,
+  TILEGX_OPC_V2MINSI,
+  BITFIELD(20, 2) /* index 598 */,
+  TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(18, 4) /* index 603 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD,
+  TILEGX_OPC_AND, TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_CMPEQ,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  TILEGX_OPC_CMPNE, TILEGX_OPC_CMULAF, TILEGX_OPC_CMULA, TILEGX_OPC_CMULFR,
+  BITFIELD(18, 4) /* index 620 */,
+  TILEGX_OPC_CMULF, TILEGX_OPC_CMULHR, TILEGX_OPC_CMULH, TILEGX_OPC_CMUL,
+  TILEGX_OPC_CRC32_32, TILEGX_OPC_CRC32_8, TILEGX_OPC_DBLALIGN2,
+  TILEGX_OPC_DBLALIGN4, TILEGX_OPC_DBLALIGN6, TILEGX_OPC_DBLALIGN,
+  TILEGX_OPC_FDOUBLE_ADDSUB, TILEGX_OPC_FDOUBLE_ADD_FLAGS,
+  TILEGX_OPC_FDOUBLE_MUL_FLAGS, TILEGX_OPC_FDOUBLE_PACK1,
+  TILEGX_OPC_FDOUBLE_PACK2, TILEGX_OPC_FDOUBLE_SUB_FLAGS,
+  BITFIELD(18, 4) /* index 637 */,
+  TILEGX_OPC_FDOUBLE_UNPACK_MAX, TILEGX_OPC_FDOUBLE_UNPACK_MIN,
+  TILEGX_OPC_FSINGLE_ADD1, TILEGX_OPC_FSINGLE_ADDSUB2,
+  TILEGX_OPC_FSINGLE_MUL1, TILEGX_OPC_FSINGLE_MUL2, TILEGX_OPC_FSINGLE_PACK2,
+  TILEGX_OPC_FSINGLE_SUB1, TILEGX_OPC_MNZ, TILEGX_OPC_MULAX,
+  TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HS_HU, TILEGX_OPC_MULA_HS_LS,
+  TILEGX_OPC_MULA_HS_LU, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_HU_LS,
+  BITFIELD(18, 4) /* index 654 */,
+  TILEGX_OPC_MULA_HU_LU, TILEGX_OPC_MULA_LS_LS, TILEGX_OPC_MULA_LS_LU,
+  TILEGX_OPC_MULA_LU_LU, TILEGX_OPC_MULX, TILEGX_OPC_MUL_HS_HS,
+  TILEGX_OPC_MUL_HS_HU, TILEGX_OPC_MUL_HS_LS, TILEGX_OPC_MUL_HS_LU,
+  TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_HU_LS, TILEGX_OPC_MUL_HU_LU,
+  TILEGX_OPC_MUL_LS_LS, TILEGX_OPC_MUL_LS_LU, TILEGX_OPC_MUL_LU_LU,
+  TILEGX_OPC_MZ,
+  BITFIELD(18, 4) /* index 671 */,
+  TILEGX_OPC_NOR, CHILD(688), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL,
+  TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_SHUFFLEBYTES,
+  TILEGX_OPC_SUBXSC,
+  BITFIELD(12, 2) /* index 688 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(693),
+  BITFIELD(14, 2) /* index 693 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(698),
+  BITFIELD(16, 2) /* index 698 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(18, 4) /* index 703 */,
+  TILEGX_OPC_SUBX, TILEGX_OPC_SUB, CHILD(720), TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADIFFU, TILEGX_OPC_V1AVGU,
+  TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1DDOTPUSA, TILEGX_OPC_V1DDOTPUS, TILEGX_OPC_V1DOTPA,
+  BITFIELD(12, 4) /* index 720 */,
+  TILEGX_OPC_NONE, CHILD(737), CHILD(742), CHILD(747), CHILD(752), CHILD(757),
+  CHILD(762), CHILD(767), CHILD(772), CHILD(777), CHILD(782), CHILD(787),
+  CHILD(792), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 737 */,
+  TILEGX_OPC_CLZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 742 */,
+  TILEGX_OPC_CTZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 747 */,
+  TILEGX_OPC_FNOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 752 */,
+  TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 757 */,
+  TILEGX_OPC_NOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 762 */,
+  TILEGX_OPC_PCNT, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 767 */,
+  TILEGX_OPC_REVBITS, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 772 */,
+  TILEGX_OPC_REVBYTES, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 777 */,
+  TILEGX_OPC_TBLIDXB0, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 782 */,
+  TILEGX_OPC_TBLIDXB1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 787 */,
+  TILEGX_OPC_TBLIDXB2, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(16, 2) /* index 792 */,
+  TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(18, 4) /* index 797 */,
+  TILEGX_OPC_V1DOTPUSA, TILEGX_OPC_V1DOTPUS, TILEGX_OPC_V1DOTP,
+  TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1MAXU,
+  TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MULTU, TILEGX_OPC_V1MULUS,
+  TILEGX_OPC_V1MULU, TILEGX_OPC_V1MZ, TILEGX_OPC_V1SADAU, TILEGX_OPC_V1SADU,
+  TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS,
+  BITFIELD(18, 4) /* index 814 */,
+  TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC, TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC,
+  TILEGX_OPC_V2ADD, TILEGX_OPC_V2ADIFFS, TILEGX_OPC_V2AVGS,
+  TILEGX_OPC_V2CMPEQ, TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU,
+  TILEGX_OPC_V2CMPLTS, TILEGX_OPC_V2CMPLTU, TILEGX_OPC_V2CMPNE,
+  TILEGX_OPC_V2DOTPA, TILEGX_OPC_V2DOTP, TILEGX_OPC_V2INT_H,
+  BITFIELD(18, 4) /* index 831 */,
+  TILEGX_OPC_V2INT_L, TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ,
+  TILEGX_OPC_V2MULFSC, TILEGX_OPC_V2MULS, TILEGX_OPC_V2MULTS, TILEGX_OPC_V2MZ,
+  TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC,
+  TILEGX_OPC_V2SADAS, TILEGX_OPC_V2SADAU, TILEGX_OPC_V2SADS,
+  TILEGX_OPC_V2SADU, TILEGX_OPC_V2SHLSC,
+  BITFIELD(18, 4) /* index 848 */,
+  TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU, TILEGX_OPC_V2SUBSC,
+  TILEGX_OPC_V2SUB, TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H,
+  TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC,
+  TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC,
+  TILEGX_OPC_V4SUB,
+  BITFIELD(18, 3) /* index 865 */,
+  CHILD(874), CHILD(877), CHILD(880), CHILD(883), CHILD(886), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 874 */,
+  TILEGX_OPC_XOR, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 877 */,
+  TILEGX_OPC_V1DDOTPUA, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 880 */,
+  TILEGX_OPC_V1DDOTPU, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 883 */,
+  TILEGX_OPC_V1DOTPUA, TILEGX_OPC_NONE,
+  BITFIELD(21, 1) /* index 886 */,
+  TILEGX_OPC_V1DOTPU, TILEGX_OPC_NONE,
+  BITFIELD(18, 4) /* index 889 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI,
+  TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI,
+  TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI,
+  TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE,
+  BITFIELD(0, 2) /* index 906 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(911),
+  BITFIELD(2, 2) /* index 911 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(916),
+  BITFIELD(4, 2) /* index 916 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(921),
+  BITFIELD(6, 2) /* index 921 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(926),
+  BITFIELD(8, 2) /* index 926 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(931),
+  BITFIELD(10, 2) /* index 931 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  TILEGX_OPC_INFOL,
+};
+
+static const unsigned short decode_X1_fsm[1206] =
+{
+  BITFIELD(53, 9) /* index 0 */,
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+  CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+  TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BEQZT,
+  TILEGX_OPC_BEQZT, TILEGX_OPC_BEQZ, TILEGX_OPC_BEQZ, TILEGX_OPC_BGEZT,
+  TILEGX_OPC_BGEZT, TILEGX_OPC_BGEZ, TILEGX_OPC_BGEZ, TILEGX_OPC_BGTZT,
+  TILEGX_OPC_BGTZT, TILEGX_OPC_BGTZ, TILEGX_OPC_BGTZ, TILEGX_OPC_BLBCT,
+  TILEGX_OPC_BLBCT, TILEGX_OPC_BLBC, TILEGX_OPC_BLBC, TILEGX_OPC_BLBST,
+  TILEGX_OPC_BLBST, TILEGX_OPC_BLBS, TILEGX_OPC_BLBS, TILEGX_OPC_BLEZT,
+  TILEGX_OPC_BLEZT, TILEGX_OPC_BLEZ, TILEGX_OPC_BLEZ, TILEGX_OPC_BLTZT,
+  TILEGX_OPC_BLTZT, TILEGX_OPC_BLTZ, TILEGX_OPC_BLTZ, TILEGX_OPC_BNEZT,
+  TILEGX_OPC_BNEZT, TILEGX_OPC_BNEZ, TILEGX_OPC_BNEZ, CHILD(528), CHILD(578),
+  CHILD(598), CHILD(663), CHILD(683), CHILD(688), CHILD(693), CHILD(698),
+  CHILD(703), CHILD(708), CHILD(713), CHILD(718), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+  TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+  CHILD(723), CHILD(740), CHILD(772), CHILD(789), CHILD(1108), CHILD(1125),
+  CHILD(1142), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1159), TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+  CHILD(1176),
+  BITFIELD(37, 2) /* index 513 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518),
+  BITFIELD(39, 2) /* index 518 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523),
+  BITFIELD(41, 2) /* index 523 */,
+  TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI,
+  BITFIELD(51, 2) /* index 528 */,
+  TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548),
+  BITFIELD(37, 2) /* index 533 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538),
+  BITFIELD(39, 2) /* index 538 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543),
+  BITFIELD(41, 2) /* index 543 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(31, 2) /* index 548 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553),
+  BITFIELD(33, 2) /* index 553 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558),
+  BITFIELD(35, 2) /* index 558 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563),
+  BITFIELD(37, 2) /* index 563 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568),
+  BITFIELD(39, 2) /* index 568 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573),
+  BITFIELD(41, 2) /* index 573 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(51, 2) /* index 578 */,
+  TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, CHILD(583),
+  BITFIELD(31, 2) /* index 583 */,
+  TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(588),
+  BITFIELD(33, 2) /* index 588 */,
+  TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(593),
+  BITFIELD(35, 2) /* index 593 */,
+  TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L1_FAULT,
+  BITFIELD(51, 2) /* index 598 */,
+  CHILD(603), CHILD(618), CHILD(633), CHILD(648),
+  BITFIELD(31, 2) /* index 603 */,
+  TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(608),
+  BITFIELD(33, 2) /* index 608 */,
+  TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(613),
+  BITFIELD(35, 2) /* index 613 */,
+  TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L1,
+  BITFIELD(31, 2) /* index 618 */,
+  TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(623),
+  BITFIELD(33, 2) /* index 623 */,
+  TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(628),
+  BITFIELD(35, 2) /* index 628 */,
+  TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L2_FAULT,
+  BITFIELD(31, 2) /* index 633 */,
+  TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(638),
+  BITFIELD(33, 2) /* index 638 */,
+  TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(643),
+  BITFIELD(35, 2) /* index 643 */,
+  TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L2,
+  BITFIELD(31, 2) /* index 648 */,
+  TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, CHILD(653),
+  BITFIELD(33, 2) /* index 653 */,
+  TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, CHILD(658),
+  BITFIELD(35, 2) /* index 658 */,
+  TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+  BITFIELD(51, 2) /* index 663 */,
+  CHILD(668), TILEGX_OPC_LDNT1S_ADD, TILEGX_OPC_LDNT1U_ADD,
+  TILEGX_OPC_LDNT2S_ADD,
+  BITFIELD(31, 2) /* index 668 */,
+  TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(673),
+  BITFIELD(33, 2) /* index 673 */,
+  TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(678),
+  BITFIELD(35, 2) /* index 678 */,
+  TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD,
+  TILEGX_OPC_PREFETCH_ADD_L3,
+  BITFIELD(51, 2) /* index 683 */,
+  TILEGX_OPC_LDNT2U_ADD, TILEGX_OPC_LDNT4S_ADD, TILEGX_OPC_LDNT4U_ADD,
+  TILEGX_OPC_LDNT_ADD,
+  BITFIELD(51, 2) /* index 688 */,
+  TILEGX_OPC_LD_ADD, TILEGX_OPC_LDNA_ADD, TILEGX_OPC_MFSPR, TILEGX_OPC_MTSPR,
+  BITFIELD(51, 2) /* index 693 */,
+  TILEGX_OPC_ORI, TILEGX_OPC_ST1_ADD, TILEGX_OPC_ST2_ADD, TILEGX_OPC_ST4_ADD,
+  BITFIELD(51, 2) /* index 698 */,
+  TILEGX_OPC_STNT1_ADD, TILEGX_OPC_STNT2_ADD, TILEGX_OPC_STNT4_ADD,
+  TILEGX_OPC_STNT_ADD,
+  BITFIELD(51, 2) /* index 703 */,
+  TILEGX_OPC_ST_ADD, TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI,
+  TILEGX_OPC_V1CMPLTSI,
+  BITFIELD(51, 2) /* index 708 */,
+  TILEGX_OPC_V1CMPLTUI, TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI,
+  TILEGX_OPC_V2ADDI,
+  BITFIELD(51, 2) /* index 713 */,
+  TILEGX_OPC_V2CMPEQI, TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI,
+  TILEGX_OPC_V2MAXSI,
+  BITFIELD(51, 2) /* index 718 */,
+  TILEGX_OPC_V2MINSI, TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(49, 4) /* index 723 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD,
+  TILEGX_OPC_AND, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPEXCH4, TILEGX_OPC_CMPEXCH,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  TILEGX_OPC_CMPNE, TILEGX_OPC_DBLALIGN2, TILEGX_OPC_DBLALIGN4,
+  TILEGX_OPC_DBLALIGN6,
+  BITFIELD(49, 4) /* index 740 */,
+  TILEGX_OPC_EXCH4, TILEGX_OPC_EXCH, TILEGX_OPC_FETCHADD4,
+  TILEGX_OPC_FETCHADDGEZ4, TILEGX_OPC_FETCHADDGEZ, TILEGX_OPC_FETCHADD,
+  TILEGX_OPC_FETCHAND4, TILEGX_OPC_FETCHAND, TILEGX_OPC_FETCHOR4,
+  TILEGX_OPC_FETCHOR, TILEGX_OPC_MNZ, TILEGX_OPC_MZ, TILEGX_OPC_NOR,
+  CHILD(757), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX,
+  BITFIELD(43, 2) /* index 757 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(762),
+  BITFIELD(45, 2) /* index 762 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(767),
+  BITFIELD(47, 2) /* index 767 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(49, 4) /* index 772 */,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL,
+  TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_ST1,
+  TILEGX_OPC_ST2, TILEGX_OPC_ST4, TILEGX_OPC_STNT1, TILEGX_OPC_STNT2,
+  TILEGX_OPC_STNT4,
+  BITFIELD(46, 7) /* index 789 */,
+  TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT,
+  TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT,
+  TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST,
+  TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_SUBXSC,
+  TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC,
+  TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBX,
+  TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX,
+  TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+  TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB,
+  TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, CHILD(918), CHILD(927),
+  CHILD(1006), CHILD(1090), CHILD(1099), TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC,
+  TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD,
+  TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD,
+  TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+  TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES,
+  TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES,
+  TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU,
+  TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+  TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU,
+  TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU,
+  TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE,
+  TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+  TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+  TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+  TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+  BITFIELD(43, 3) /* index 918 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_DRAIN, TILEGX_OPC_DTLBPR, TILEGX_OPC_FINV,
+  TILEGX_OPC_FLUSHWB, TILEGX_OPC_FLUSH, TILEGX_OPC_FNOP, TILEGX_OPC_ICOH,
+  BITFIELD(43, 3) /* index 927 */,
+  CHILD(936), TILEGX_OPC_INV, TILEGX_OPC_IRET, TILEGX_OPC_JALRP,
+  TILEGX_OPC_JALR, TILEGX_OPC_JRP, TILEGX_OPC_JR, CHILD(991),
+  BITFIELD(31, 2) /* index 936 */,
+  CHILD(941), CHILD(966), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(33, 2) /* index 941 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(946),
+  BITFIELD(35, 2) /* index 946 */,
+  TILEGX_OPC_ILL, CHILD(951), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(37, 2) /* index 951 */,
+  TILEGX_OPC_ILL, CHILD(956), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(39, 2) /* index 956 */,
+  TILEGX_OPC_ILL, CHILD(961), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(41, 2) /* index 961 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_BPT, TILEGX_OPC_ILL,
+  BITFIELD(33, 2) /* index 966 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(971),
+  BITFIELD(35, 2) /* index 971 */,
+  TILEGX_OPC_ILL, CHILD(976), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(37, 2) /* index 976 */,
+  TILEGX_OPC_ILL, CHILD(981), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(39, 2) /* index 981 */,
+  TILEGX_OPC_ILL, CHILD(986), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+  BITFIELD(41, 2) /* index 986 */,
+  TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_RAISE, TILEGX_OPC_ILL,
+  BITFIELD(31, 2) /* index 991 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(996),
+  BITFIELD(33, 2) /* index 996 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(1001),
+  BITFIELD(35, 2) /* index 1001 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S,
+  TILEGX_OPC_PREFETCH_L1_FAULT,
+  BITFIELD(43, 3) /* index 1006 */,
+  CHILD(1015), CHILD(1030), CHILD(1045), CHILD(1060), CHILD(1075),
+  TILEGX_OPC_LDNA, TILEGX_OPC_LDNT1S, TILEGX_OPC_LDNT1U,
+  BITFIELD(31, 2) /* index 1015 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1020),
+  BITFIELD(33, 2) /* index 1020 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1025),
+  BITFIELD(35, 2) /* index 1025 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH,
+  BITFIELD(31, 2) /* index 1030 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1035),
+  BITFIELD(33, 2) /* index 1035 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1040),
+  BITFIELD(35, 2) /* index 1040 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S,
+  TILEGX_OPC_PREFETCH_L2_FAULT,
+  BITFIELD(31, 2) /* index 1045 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1050),
+  BITFIELD(33, 2) /* index 1050 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1055),
+  BITFIELD(35, 2) /* index 1055 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2,
+  BITFIELD(31, 2) /* index 1060 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1065),
+  BITFIELD(33, 2) /* index 1065 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1070),
+  BITFIELD(35, 2) /* index 1070 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S,
+  TILEGX_OPC_PREFETCH_L3_FAULT,
+  BITFIELD(31, 2) /* index 1075 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1080),
+  BITFIELD(33, 2) /* index 1080 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1085),
+  BITFIELD(35, 2) /* index 1085 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3,
+  BITFIELD(43, 3) /* index 1090 */,
+  TILEGX_OPC_LDNT2S, TILEGX_OPC_LDNT2U, TILEGX_OPC_LDNT4S, TILEGX_OPC_LDNT4U,
+  TILEGX_OPC_LDNT, TILEGX_OPC_LD, TILEGX_OPC_LNK, TILEGX_OPC_MF,
+  BITFIELD(43, 3) /* index 1099 */,
+  TILEGX_OPC_NAP, TILEGX_OPC_NOP, TILEGX_OPC_SWINT0, TILEGX_OPC_SWINT1,
+  TILEGX_OPC_SWINT2, TILEGX_OPC_SWINT3, TILEGX_OPC_WH64, TILEGX_OPC_NONE,
+  BITFIELD(49, 4) /* index 1108 */,
+  TILEGX_OPC_V1MAXU, TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MZ,
+  TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS, TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC,
+  TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC, TILEGX_OPC_V2ADD, TILEGX_OPC_V2CMPEQ,
+  TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU, TILEGX_OPC_V2CMPLTS,
+  TILEGX_OPC_V2CMPLTU,
+  BITFIELD(49, 4) /* index 1125 */,
+  TILEGX_OPC_V2CMPNE, TILEGX_OPC_V2INT_H, TILEGX_OPC_V2INT_L,
+  TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ, TILEGX_OPC_V2MZ,
+  TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC,
+  TILEGX_OPC_V2SHLSC, TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU,
+  TILEGX_OPC_V2SUBSC, TILEGX_OPC_V2SUB,
+  BITFIELD(49, 4) /* index 1142 */,
+  TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H,
+  TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC,
+  TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC,
+  TILEGX_OPC_V4SUB, TILEGX_OPC_XOR, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(49, 4) /* index 1159 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI,
+  TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI,
+  TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI,
+  TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE,
+  BITFIELD(31, 2) /* index 1176 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1181),
+  BITFIELD(33, 2) /* index 1181 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1186),
+  BITFIELD(35, 2) /* index 1186 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1191),
+  BITFIELD(37, 2) /* index 1191 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1196),
+  BITFIELD(39, 2) /* index 1196 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  CHILD(1201),
+  BITFIELD(41, 2) /* index 1201 */,
+  TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+  TILEGX_OPC_INFOL,
+};
+
+static const unsigned short decode_Y0_fsm[178] =
+{
+  BITFIELD(27, 4) /* index 0 */,
+  CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI,
+  TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(118), CHILD(123),
+  CHILD(128), CHILD(133), CHILD(153), CHILD(158), CHILD(163), CHILD(168),
+  CHILD(173),
+  BITFIELD(6, 2) /* index 17 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22),
+  BITFIELD(8, 2) /* index 22 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27),
+  BITFIELD(10, 2) /* index 27 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(0, 2) /* index 32 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37),
+  BITFIELD(2, 2) /* index 37 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42),
+  BITFIELD(4, 2) /* index 42 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47),
+  BITFIELD(6, 2) /* index 47 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52),
+  BITFIELD(8, 2) /* index 52 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57),
+  BITFIELD(10, 2) /* index 57 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(18, 2) /* index 62 */,
+  TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+  BITFIELD(15, 5) /* index 67 */,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(100),
+  CHILD(109), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(12, 3) /* index 100 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_CLZ, TILEGX_OPC_CTZ, TILEGX_OPC_FNOP,
+  TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NOP, TILEGX_OPC_PCNT,
+  TILEGX_OPC_REVBITS,
+  BITFIELD(12, 3) /* index 109 */,
+  TILEGX_OPC_REVBYTES, TILEGX_OPC_TBLIDXB0, TILEGX_OPC_TBLIDXB1,
+  TILEGX_OPC_TBLIDXB2, TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  TILEGX_OPC_NONE,
+  BITFIELD(18, 2) /* index 118 */,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  BITFIELD(18, 2) /* index 123 */,
+  TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE, TILEGX_OPC_MULAX, TILEGX_OPC_MULX,
+  BITFIELD(18, 2) /* index 128 */,
+  TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_MNZ, TILEGX_OPC_MZ,
+  BITFIELD(18, 2) /* index 133 */,
+  TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(138), TILEGX_OPC_XOR,
+  BITFIELD(12, 2) /* index 138 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(143),
+  BITFIELD(14, 2) /* index 143 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(148),
+  BITFIELD(16, 2) /* index 148 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(18, 2) /* index 153 */,
+  TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU,
+  BITFIELD(18, 2) /* index 158 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX,
+  TILEGX_OPC_SHL3ADDX,
+  BITFIELD(18, 2) /* index 163 */,
+  TILEGX_OPC_MUL_HS_HS, TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_LS_LS,
+  TILEGX_OPC_MUL_LU_LU,
+  BITFIELD(18, 2) /* index 168 */,
+  TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_LS_LS,
+  TILEGX_OPC_MULA_LU_LU,
+  BITFIELD(18, 2) /* index 173 */,
+  TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI,
+};
+
+static const unsigned short decode_Y1_fsm[167] =
+{
+  BITFIELD(58, 4) /* index 0 */,
+  TILEGX_OPC_NONE, CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI,
+  TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(117), CHILD(122),
+  CHILD(127), CHILD(132), CHILD(152), CHILD(157), CHILD(162), TILEGX_OPC_NONE,
+  BITFIELD(37, 2) /* index 17 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22),
+  BITFIELD(39, 2) /* index 22 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27),
+  BITFIELD(41, 2) /* index 27 */,
+  TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+  BITFIELD(31, 2) /* index 32 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37),
+  BITFIELD(33, 2) /* index 37 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42),
+  BITFIELD(35, 2) /* index 42 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47),
+  BITFIELD(37, 2) /* index 47 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52),
+  BITFIELD(39, 2) /* index 52 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57),
+  BITFIELD(41, 2) /* index 57 */,
+  TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+  BITFIELD(49, 2) /* index 62 */,
+  TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+  BITFIELD(47, 4) /* index 67 */,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+  TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+  TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD,
+  TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(84),
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+  BITFIELD(43, 3) /* index 84 */,
+  CHILD(93), CHILD(96), CHILD(99), CHILD(102), CHILD(105), CHILD(108),
+  CHILD(111), CHILD(114),
+  BITFIELD(46, 1) /* index 93 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_FNOP,
+  BITFIELD(46, 1) /* index 96 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_ILL,
+  BITFIELD(46, 1) /* index 99 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JALRP,
+  BITFIELD(46, 1) /* index 102 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JALR,
+  BITFIELD(46, 1) /* index 105 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JRP,
+  BITFIELD(46, 1) /* index 108 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_JR,
+  BITFIELD(46, 1) /* index 111 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_LNK,
+  BITFIELD(46, 1) /* index 114 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NOP,
+  BITFIELD(49, 2) /* index 117 */,
+  TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+  BITFIELD(49, 2) /* index 122 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE,
+  BITFIELD(49, 2) /* index 127 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_MNZ, TILEGX_OPC_MZ,
+  BITFIELD(49, 2) /* index 132 */,
+  TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(137), TILEGX_OPC_XOR,
+  BITFIELD(43, 2) /* index 137 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(142),
+  BITFIELD(45, 2) /* index 142 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(147),
+  BITFIELD(47, 2) /* index 147 */,
+  TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+  BITFIELD(49, 2) /* index 152 */,
+  TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU,
+  BITFIELD(49, 2) /* index 157 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX,
+  TILEGX_OPC_SHL3ADDX,
+  BITFIELD(49, 2) /* index 162 */,
+  TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI,
+};
+
+static const unsigned short decode_Y2_fsm[118] =
+{
+  BITFIELD(62, 2) /* index 0 */,
+  TILEGX_OPC_NONE, CHILD(5), CHILD(66), CHILD(109),
+  BITFIELD(55, 3) /* index 5 */,
+  CHILD(14), CHILD(14), CHILD(14), CHILD(17), CHILD(40), CHILD(40), CHILD(40),
+  CHILD(43),
+  BITFIELD(26, 1) /* index 14 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1U,
+  BITFIELD(26, 1) /* index 17 */,
+  CHILD(20), CHILD(30),
+  BITFIELD(51, 2) /* index 20 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(25),
+  BITFIELD(53, 2) /* index 25 */,
+  TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S,
+  TILEGX_OPC_PREFETCH_L1_FAULT,
+  BITFIELD(51, 2) /* index 30 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(35),
+  BITFIELD(53, 2) /* index 35 */,
+  TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH,
+  BITFIELD(26, 1) /* index 40 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2U,
+  BITFIELD(26, 1) /* index 43 */,
+  CHILD(46), CHILD(56),
+  BITFIELD(51, 2) /* index 46 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(51),
+  BITFIELD(53, 2) /* index 51 */,
+  TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S,
+  TILEGX_OPC_PREFETCH_L2_FAULT,
+  BITFIELD(51, 2) /* index 56 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(61),
+  BITFIELD(53, 2) /* index 61 */,
+  TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2,
+  BITFIELD(56, 2) /* index 66 */,
+  CHILD(71), CHILD(74), CHILD(90), CHILD(93),
+  BITFIELD(26, 1) /* index 71 */,
+  TILEGX_OPC_NONE, TILEGX_OPC_LD4S,
+  BITFIELD(26, 1) /* index 74 */,
+  TILEGX_OPC_NONE, CHILD(77),
+  BITFIELD(51, 2) /* index 77 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(82),
+  BITFIELD(53, 2) /* index 82 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(87),
+  BITFIELD(55, 1) /* index 87 */,
+  TILEGX_OPC_LD4S, TILEGX_OPC_PREFETCH_L3_FAULT,
+  BITFIELD(26, 1) /* index 90 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD,
+  BITFIELD(26, 1) /* index 93 */,
+  CHILD(96), TILEGX_OPC_LD,
+  BITFIELD(51, 2) /* index 96 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(101),
+  BITFIELD(53, 2) /* index 101 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(106),
+  BITFIELD(55, 1) /* index 106 */,
+  TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3,
+  BITFIELD(26, 1) /* index 109 */,
+  CHILD(112), CHILD(115),
+  BITFIELD(57, 1) /* index 112 */,
+  TILEGX_OPC_ST1, TILEGX_OPC_ST4,
+  BITFIELD(57, 1) /* index 115 */,
+  TILEGX_OPC_ST2, TILEGX_OPC_ST,
+};
+
+#undef BITFIELD
+#undef CHILD
+const unsigned short * const
+tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS] =
+{
+  decode_X0_fsm,
+  decode_X1_fsm,
+  decode_Y0_fsm,
+  decode_Y1_fsm,
+  decode_Y2_fsm
+};
+const struct tilegx_operand tilegx_operands[35] =
+{
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X0),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_X0, get_Imm8_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X1),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_X1, get_Imm8_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y0),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_Y0, get_Imm8_Y0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y1),
+    8, 1, 0, 0, 0, 0,
+    create_Imm8_Y1, get_Imm8_Y1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X0_HW0_LAST),
+    16, 1, 0, 0, 0, 0,
+    create_Imm16_X0, get_Imm16_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X1_HW0_LAST),
+    16, 1, 0, 0, 0, 0,
+    create_Imm16_X1, get_Imm16_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_X0, get_Dest_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_X0, get_SrcA_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_X1, get_Dest_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_X1, get_SrcA_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_Y0, get_Dest_Y0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_Y0, get_SrcA_Y0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_Dest_Y1, get_Dest_Y1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_Y1, get_SrcA_Y1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcA_Y2, get_SrcA_Y2
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 1, 0, 0,
+    create_SrcA_X1, get_SrcA_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_X0, get_SrcB_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_X1, get_SrcB_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_Y0, get_SrcB_Y0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcB_Y1, get_SrcB_Y1
+  },
+  {
+    TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_BROFF_X1),
+    17, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES,
+    create_BrOff_X1, get_BrOff_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE),
+    6, 0, 0, 0, 0, 0,
+    create_BFStart_X0, get_BFStart_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE),
+    6, 0, 0, 0, 0, 0,
+    create_BFEnd_X0, get_BFEnd_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 1, 0, 0,
+    create_Dest_X0, get_Dest_X0
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 1, 0, 0,
+    create_Dest_Y0, get_Dest_Y0
+  },
+  {
+    TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_JUMPOFF_X1),
+    27, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES,
+    create_JumpOff_X1, get_JumpOff_X1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 0, 1, 0, 0,
+    create_SrcBDest_Y2, get_SrcBDest_Y2
+  },
+  {
+    TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MF_IMM14_X1),
+    14, 0, 0, 0, 0, 0,
+    create_MF_Imm14_X1, get_MF_Imm14_X1
+  },
+  {
+    TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MT_IMM14_X1),
+    14, 0, 0, 0, 0, 0,
+    create_MT_Imm14_X1, get_MT_Imm14_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X0),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_X0, get_ShAmt_X0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X1),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_X1, get_ShAmt_X1
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y0),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_Y0, get_ShAmt_Y0
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y1),
+    6, 0, 0, 0, 0, 0,
+    create_ShAmt_Y1, get_ShAmt_Y1
+  },
+  {
+    TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+    6, 0, 1, 0, 0, 0,
+    create_SrcBDest_Y2, get_SrcBDest_Y2
+  },
+  {
+    TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_DEST_IMM8_X1),
+    8, 1, 0, 0, 0, 0,
+    create_Dest_Imm8_X1, get_Dest_Imm8_X1
+  }
+};
+
+
+
+
+/* Given a set of bundle bits and the lookup FSM for a specific pipe,
+ * returns which instruction the bundle contains in that pipe.
+ */
+static const struct tilegx_opcode *
+find_opcode(tilegx_bundle_bits bits, const unsigned short *table)
+{
+  int index = 0;
+
+  while (1)
+  {
+    unsigned short bitspec = table[index];
+    unsigned int bitfield =
+      ((unsigned int)(bits >> (bitspec & 63))) & (bitspec >> 6);
+
+    unsigned short next = table[index + 1 + bitfield];
+    if (next <= TILEGX_OPC_NONE)
+      return &tilegx_opcodes[next];
+
+    index = next - TILEGX_OPC_NONE;
+  }
+}
+
+
+int
+parse_insn_tilegx(tilegx_bundle_bits bits,
+                  unsigned long long pc,
+                  struct tilegx_decoded_instruction
+                  decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE])
+{
+  int num_instructions = 0;
+  int pipe;
+
+  int min_pipe, max_pipe;
+  if ((bits & TILEGX_BUNDLE_MODE_MASK) == 0)
+  {
+    min_pipe = TILEGX_PIPELINE_X0;
+    max_pipe = TILEGX_PIPELINE_X1;
+  }
+  else
+  {
+    min_pipe = TILEGX_PIPELINE_Y0;
+    max_pipe = TILEGX_PIPELINE_Y2;
+  }
+
+  /* For each pipe, find an instruction that fits. */
+  for (pipe = min_pipe; pipe <= max_pipe; pipe++)
+  {
+    const struct tilegx_opcode *opc;
+    struct tilegx_decoded_instruction *d;
+    int i;
+
+    d = &decoded[num_instructions++];
+    opc = find_opcode (bits, tilegx_bundle_decoder_fsms[pipe]);
+    d->opcode = opc;
+
+    /* Decode each operand, sign extending, etc. as appropriate. */
+    for (i = 0; i < opc->num_operands; i++)
+    {
+      const struct tilegx_operand *op =
+        &tilegx_operands[opc->operands[pipe][i]];
+      int raw_opval = op->extract (bits);
+      long long opval;
+
+      if (op->is_signed)
+      {
+        /* Sign-extend the operand. */
+        int shift = (int)((sizeof(int) * 8) - op->num_bits);
+        raw_opval = (raw_opval << shift) >> shift;
+      }
+
+      /* Adjust PC-relative scaled branch offsets. */
+      if (op->type == TILEGX_OP_TYPE_ADDRESS)
+        opval = (raw_opval * TILEGX_BUNDLE_SIZE_IN_BYTES) + pc;
+      else
+        opval = raw_opval;
+
+      /* Record the final value. */
+      d->operands[i] = op;
+      d->operand_values[i] = opval;
+    }
+  }
+
+  return num_instructions;
+}
index 49a605be94c56bb3712dabfa988969261eb446bb..c4be58cc5d5083fe213c9994b236c272f13c992a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 #include <asm/irq_regs.h>
 #include <asm/traps.h>
 #include <hv/hypervisor.h>
@@ -56,6 +57,7 @@ cycles_t get_cycles(void)
 
        return (((cycles_t)high) << 32) | low;
 }
+EXPORT_SYMBOL(get_cycles);
 #endif
 
 /*
index 2dffc1044d8314041a6566a2d93634f979e1775e..a5f241c24cac9ec3cdc6fc6d5e8099fe152921d6 100644 (file)
@@ -34,13 +34,13 @@ void flush_tlb_mm(struct mm_struct *mm)
 {
        HV_Remote_ASID asids[NR_CPUS];
        int i = 0, cpu;
-       for_each_cpu(cpu, &mm->cpu_vm_mask) {
+       for_each_cpu(cpu, mm_cpumask(mm)) {
                HV_Remote_ASID *asid = &asids[i++];
                asid->y = cpu / smp_topology.width;
                asid->x = cpu % smp_topology.width;
                asid->asid = per_cpu(current_asid, cpu);
        }
-       flush_remote(0, HV_FLUSH_EVICT_L1I, &mm->cpu_vm_mask,
+       flush_remote(0, HV_FLUSH_EVICT_L1I, mm_cpumask(mm),
                     0, 0, 0, NULL, asids, i);
 }
 
@@ -54,8 +54,8 @@ void flush_tlb_page_mm(const struct vm_area_struct *vma, struct mm_struct *mm,
 {
        unsigned long size = hv_page_size(vma);
        int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
-       flush_remote(0, cache, &mm->cpu_vm_mask,
-                    va, size, size, &mm->cpu_vm_mask, NULL, 0);
+       flush_remote(0, cache, mm_cpumask(mm),
+                    va, size, size, mm_cpumask(mm), NULL, 0);
 }
 
 void flush_tlb_page(const struct vm_area_struct *vma, unsigned long va)
@@ -70,8 +70,8 @@ void flush_tlb_range(const struct vm_area_struct *vma,
        unsigned long size = hv_page_size(vma);
        struct mm_struct *mm = vma->vm_mm;
        int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
-       flush_remote(0, cache, &mm->cpu_vm_mask, start, end - start, size,
-                    &mm->cpu_vm_mask, NULL, 0);
+       flush_remote(0, cache, mm_cpumask(mm), start, end - start, size,
+                    mm_cpumask(mm), NULL, 0);
 }
 
 void flush_tlb_all(void)
index 5474fc2e77e8456b3d6e745b8defc3129e08eb85..f9803dfa73573deed9f98349c212aeb45bc8dc6a 100644 (file)
@@ -308,6 +308,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
        info.si_addr = (void __user *)address;
        if (signo == SIGILL)
                info.si_trapno = fault_num;
+       trace_unhandled_signal("trap", regs, address, signo);
        force_sig_info(signo, &info, current);
 }
 
index 82f64cc636589ed9c1ae1ec9aaf743949edeb2da..24448734f6f17c3f70f95f4252afbf98c5dcce00 100644 (file)
@@ -59,7 +59,7 @@
  * bad kernel addresses).
  *
  * Note that if the value we would store is the same as what we
- * loaded, we bypass the load.  Other platforms with true atomics can
+ * loaded, we bypass the store.  Other platforms with true atomics can
  * make the guarantee that a non-atomic __clear_bit(), for example,
  * can safely race with an atomic test_and_set_bit(); this example is
  * from bit_spinlock.h in slub_lock() / slub_unlock().  We can't do
index 35c1d8ca5f38132e9428db0297f22062dbbb68e4..8928aace7a641d8a2b7be866f88deefb4f5f9a1e 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 #include <arch/icache.h>
+#include <arch/spr_def.h>
 
 
 void __flush_icache_range(unsigned long start, unsigned long end)
@@ -39,6 +40,18 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
        char *p, *base;
        size_t step_size, load_count;
        const unsigned long STRIPE_WIDTH = 8192;
+#ifdef __tilegx__
+       /*
+        * On TILE-Gx, we must disable the dstream prefetcher before doing
+        * a cache flush; otherwise, we could end up with data in the cache
+        * that we don't want there.  Note that normally we'd do an mf
+        * after the SPR write to disabling the prefetcher, but we do one
+        * below, before any further loads, so there's no need to do it
+        * here.
+        */
+       uint_reg_t old_dstream_pf = __insn_mfspr(SPR_DSTREAM_PF);
+       __insn_mtspr(SPR_DSTREAM_PF, 0);
+#endif
 
        /*
         * Flush and invalidate the buffer out of the local L1/L2
@@ -122,4 +135,9 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
 
        /* Wait for the load+inv's (and thus finvs) to have completed. */
        __insn_mf();
+
+#ifdef __tilegx__
+       /* Reenable the prefetcher. */
+       __insn_mtspr(SPR_DSTREAM_PF, old_dstream_pf);
+#endif
 }
diff --git a/arch/tile/lib/memchr_64.c b/arch/tile/lib/memchr_64.c
new file mode 100644 (file)
index 0000000..84fdc8d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+void *memchr(const void *s, int c, size_t n)
+{
+       const uint64_t *last_word_ptr;
+       const uint64_t *p;
+       const char *last_byte_ptr;
+       uintptr_t s_int;
+       uint64_t goal, before_mask, v, bits;
+       char *ret;
+
+       if (__builtin_expect(n == 0, 0)) {
+               /* Don't dereference any memory if the array is empty. */
+               return NULL;
+       }
+
+       /* Get an aligned pointer. */
+       s_int = (uintptr_t) s;
+       p = (const uint64_t *)(s_int & -8);
+
+       /* Create eight copies of the byte for which we are looking. */
+       goal = 0x0101010101010101ULL * (uint8_t) c;
+
+       /* Read the first word, but munge it so that bytes before the array
+        * will not match goal.
+        *
+        * Note that this shift count expression works because we know
+        * shift counts are taken mod 64.
+        */
+       before_mask = (1ULL << (s_int << 3)) - 1;
+       v = (*p | before_mask) ^ (goal & before_mask);
+
+       /* Compute the address of the last byte. */
+       last_byte_ptr = (const char *)s + n - 1;
+
+       /* Compute the address of the word containing the last byte. */
+       last_word_ptr = (const uint64_t *)((uintptr_t) last_byte_ptr & -8);
+
+       while ((bits = __insn_v1cmpeq(v, goal)) == 0) {
+               if (__builtin_expect(p == last_word_ptr, 0)) {
+                       /* We already read the last word in the array,
+                        * so give up.
+                        */
+                       return NULL;
+               }
+               v = *++p;
+       }
+
+       /* We found a match, but it might be in a byte past the end
+        * of the array.
+        */
+       ret = ((char *)p) + (__insn_ctz(bits) >> 3);
+       return (ret <= last_byte_ptr) ? ret : NULL;
+}
+EXPORT_SYMBOL(memchr);
diff --git a/arch/tile/lib/memcpy_64.c b/arch/tile/lib/memcpy_64.c
new file mode 100644 (file)
index 0000000..3fab9a6
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#define __memcpy memcpy
+/* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */
+
+/* Must be 8 bytes in size. */
+#define word_t uint64_t
+
+#if CHIP_L2_LINE_SIZE() != 64 && CHIP_L2_LINE_SIZE() != 128
+#error "Assumes 64 or 128 byte line size"
+#endif
+
+/* How many cache lines ahead should we prefetch? */
+#define PREFETCH_LINES_AHEAD 3
+
+/*
+ * Provide "base versions" of load and store for the normal code path.
+ * The kernel provides other versions for userspace copies.
+ */
+#define ST(p, v) (*(p) = (v))
+#define LD(p) (*(p))
+
+#ifndef USERCOPY_FUNC
+#define ST1 ST
+#define ST2 ST
+#define ST4 ST
+#define ST8 ST
+#define LD1 LD
+#define LD2 LD
+#define LD4 LD
+#define LD8 LD
+#define RETVAL dstv
+void *memcpy(void *__restrict dstv, const void *__restrict srcv, size_t n)
+#else
+/*
+ * Special kernel version will provide implementation of the LDn/STn
+ * macros to return a count of uncopied bytes due to mm fault.
+ */
+#define RETVAL 0
+int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n)
+#endif
+{
+       char *__restrict dst1 = (char *)dstv;
+       const char *__restrict src1 = (const char *)srcv;
+       const char *__restrict src1_end;
+       const char *__restrict prefetch;
+       word_t *__restrict dst8;    /* 8-byte pointer to destination memory. */
+       word_t final; /* Final bytes to write to trailing word, if any */
+       long i;
+
+       if (n < 16) {
+               for (; n; n--)
+                       ST1(dst1++, LD1(src1++));
+               return RETVAL;
+       }
+
+       /*
+        * Locate the end of source memory we will copy.  Don't
+        * prefetch past this.
+        */
+       src1_end = src1 + n - 1;
+
+       /* Prefetch ahead a few cache lines, but not past the end. */
+       prefetch = src1;
+       for (i = 0; i < PREFETCH_LINES_AHEAD; i++) {
+               __insn_prefetch(prefetch);
+               prefetch += CHIP_L2_LINE_SIZE();
+               prefetch = (prefetch > src1_end) ? prefetch : src1;
+       }
+
+       /* Copy bytes until dst is word-aligned. */
+       for (; (uintptr_t)dst1 & (sizeof(word_t) - 1); n--)
+               ST1(dst1++, LD1(src1++));
+
+       /* 8-byte pointer to destination memory. */
+       dst8 = (word_t *)dst1;
+
+       if (__builtin_expect((uintptr_t)src1 & (sizeof(word_t) - 1), 0)) {
+               /*
+                * Misaligned copy.  Copy 8 bytes at a time, but don't
+                * bother with other fanciness.
+                *
+                * TODO: Consider prefetching and using wh64 as well.
+                */
+
+               /* Create an aligned src8. */
+               const word_t *__restrict src8 =
+                       (const word_t *)((uintptr_t)src1 & -sizeof(word_t));
+               word_t b;
+
+               word_t a = LD8(src8++);
+               for (; n >= sizeof(word_t); n -= sizeof(word_t)) {
+                       b = LD8(src8++);
+                       a = __insn_dblalign(a, b, src1);
+                       ST8(dst8++, a);
+                       a = b;
+               }
+
+               if (n == 0)
+                       return RETVAL;
+
+               b = ((const char *)src8 <= src1_end) ? *src8 : 0;
+
+               /*
+                * Final source bytes to write to trailing partial
+                * word, if any.
+                */
+               final = __insn_dblalign(a, b, src1);
+       } else {
+               /* Aligned copy. */
+
+               const word_t* __restrict src8 = (const word_t *)src1;
+
+               /* src8 and dst8 are both word-aligned. */
+               if (n >= CHIP_L2_LINE_SIZE()) {
+                       /* Copy until 'dst' is cache-line-aligned. */
+                       for (; (uintptr_t)dst8 & (CHIP_L2_LINE_SIZE() - 1);
+                            n -= sizeof(word_t))
+                               ST8(dst8++, LD8(src8++));
+
+                       for (; n >= CHIP_L2_LINE_SIZE(); ) {
+                               __insn_wh64(dst8);
+
+                               /*
+                                * Prefetch and advance to next line
+                                * to prefetch, but don't go past the end
+                                */
+                               __insn_prefetch(prefetch);
+                               prefetch += CHIP_L2_LINE_SIZE();
+                               prefetch = (prefetch > src1_end) ? prefetch :
+                                       (const char *)src8;
+
+                               /*
+                                * Copy an entire cache line.  Manually
+                                * unrolled to avoid idiosyncracies of
+                                * compiler unrolling.
+                                */
+#define COPY_WORD(offset) ({ ST8(dst8+offset, LD8(src8+offset)); n -= 8; })
+                               COPY_WORD(0);
+                               COPY_WORD(1);
+                               COPY_WORD(2);
+                               COPY_WORD(3);
+                               COPY_WORD(4);
+                               COPY_WORD(5);
+                               COPY_WORD(6);
+                               COPY_WORD(7);
+#if CHIP_L2_LINE_SIZE() == 128
+                               COPY_WORD(8);
+                               COPY_WORD(9);
+                               COPY_WORD(10);
+                               COPY_WORD(11);
+                               COPY_WORD(12);
+                               COPY_WORD(13);
+                               COPY_WORD(14);
+                               COPY_WORD(15);
+#elif CHIP_L2_LINE_SIZE() != 64
+# error Fix code that assumes particular L2 cache line sizes
+#endif
+
+                               dst8 += CHIP_L2_LINE_SIZE() / sizeof(word_t);
+                               src8 += CHIP_L2_LINE_SIZE() / sizeof(word_t);
+                       }
+               }
+
+               for (; n >= sizeof(word_t); n -= sizeof(word_t))
+                       ST8(dst8++, LD8(src8++));
+
+               if (__builtin_expect(n == 0, 1))
+                       return RETVAL;
+
+               final = LD8(src8);
+       }
+
+       /* n != 0 if we get here.  Write out any trailing bytes. */
+       dst1 = (char *)dst8;
+       if (n & 4) {
+               ST4((uint32_t *)dst1, final);
+               dst1 += 4;
+               final >>= 32;
+               n &= 3;
+       }
+       if (n & 2) {
+               ST2((uint16_t *)dst1, final);
+               dst1 += 2;
+               final >>= 16;
+               n &= 1;
+       }
+       if (n)
+               ST1((uint8_t *)dst1, final);
+
+       return RETVAL;
+}
+
+
+#ifdef USERCOPY_FUNC
+#undef ST1
+#undef ST2
+#undef ST4
+#undef ST8
+#undef LD1
+#undef LD2
+#undef LD4
+#undef LD8
+#undef USERCOPY_FUNC
+#endif
diff --git a/arch/tile/lib/memcpy_user_64.c b/arch/tile/lib/memcpy_user_64.c
new file mode 100644 (file)
index 0000000..4763b3a
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Do memcpy(), but trap and return "n" when a load or store faults.
+ *
+ * Note: this idiom only works when memcpy() compiles to a leaf function.
+ * If "sp" is updated during memcpy, the "jrp lr" will be incorrect.
+ *
+ * Also note that we are capturing "n" from the containing scope here.
+ */
+
+#define _ST(p, inst, v)                                                \
+       ({                                                      \
+               asm("1: " #inst " %0, %1;"                      \
+                   ".pushsection .coldtext.memcpy,\"ax\";"     \
+                   "2: { move r0, %2; jrp lr };"               \
+                   ".section __ex_table,\"a\";"                \
+                   ".quad 1b, 2b;"                             \
+                   ".popsection"                               \
+                   : "=m" (*(p)) : "r" (v), "r" (n));          \
+       })
+
+#define _LD(p, inst)                                           \
+       ({                                                      \
+               unsigned long __v;                              \
+               asm("1: " #inst " %0, %1;"                      \
+                   ".pushsection .coldtext.memcpy,\"ax\";"     \
+                   "2: { move r0, %2; jrp lr };"               \
+                   ".section __ex_table,\"a\";"                \
+                   ".quad 1b, 2b;"                             \
+                   ".popsection"                               \
+                   : "=r" (__v) : "m" (*(p)), "r" (n));        \
+               __v;                                            \
+       })
+
+#define USERCOPY_FUNC __copy_to_user_inatomic
+#define ST1(p, v) _ST((p), st1, (v))
+#define ST2(p, v) _ST((p), st2, (v))
+#define ST4(p, v) _ST((p), st4, (v))
+#define ST8(p, v) _ST((p), st, (v))
+#define LD1 LD
+#define LD2 LD
+#define LD4 LD
+#define LD8 LD
+#include "memcpy_64.c"
+
+#define USERCOPY_FUNC __copy_from_user_inatomic
+#define ST1 ST
+#define ST2 ST
+#define ST4 ST
+#define ST8 ST
+#define LD1(p) _LD((p), ld1u)
+#define LD2(p) _LD((p), ld2u)
+#define LD4(p) _LD((p), ld4u)
+#define LD8(p) _LD((p), ld)
+#include "memcpy_64.c"
+
+#define USERCOPY_FUNC __copy_in_user_inatomic
+#define ST1(p, v) _ST((p), st1, (v))
+#define ST2(p, v) _ST((p), st2, (v))
+#define ST4(p, v) _ST((p), st4, (v))
+#define ST8(p, v) _ST((p), st, (v))
+#define LD1(p) _LD((p), ld1u)
+#define LD2(p) _LD((p), ld2u)
+#define LD4(p) _LD((p), ld4u)
+#define LD8(p) _LD((p), ld)
+#include "memcpy_64.c"
+
+unsigned long __copy_from_user_zeroing(void *to, const void __user *from,
+                                      unsigned long n)
+{
+       unsigned long rc = __copy_from_user_inatomic(to, from, n);
+       if (unlikely(rc))
+               memset(to + n - rc, 0, rc);
+       return rc;
+}
diff --git a/arch/tile/lib/memset_64.c b/arch/tile/lib/memset_64.c
new file mode 100644 (file)
index 0000000..3873085
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <arch/chip.h>
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef memset
+
+void *memset(void *s, int c, size_t n)
+{
+       uint64_t *out64;
+       int n64, to_align64;
+       uint64_t v64;
+       uint8_t *out8 = s;
+
+       /* Experimentation shows that a trivial tight loop is a win up until
+        * around a size of 20, where writing a word at a time starts to win.
+        */
+#define BYTE_CUTOFF 20
+
+#if BYTE_CUTOFF < 7
+       /* This must be at least at least this big, or some code later
+        * on doesn't work.
+        */
+#error "BYTE_CUTOFF is too small"
+#endif
+
+       if (n < BYTE_CUTOFF) {
+               /* Strangely, this turns out to be the tightest way to
+                * write this loop.
+                */
+               if (n != 0) {
+                       do {
+                               /* Strangely, combining these into one line
+                                * performs worse.
+                                */
+                               *out8 = c;
+                               out8++;
+                       } while (--n != 0);
+               }
+
+               return s;
+       }
+
+       /* Align 'out8'. We know n >= 7 so this won't write past the end. */
+       while (((uintptr_t) out8 & 7) != 0) {
+               *out8++ = c;
+               --n;
+       }
+
+       /* Align 'n'. */
+       while (n & 7)
+               out8[--n] = c;
+
+       out64 = (uint64_t *) out8;
+       n64 = n >> 3;
+
+       /* Tile input byte out to 64 bits. */
+       /* KLUDGE */
+       v64 = 0x0101010101010101ULL * (uint8_t)c;
+
+       /* This must be at least 8 or the following loop doesn't work. */
+#define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8)
+
+       /* Determine how many words we need to emit before the 'out32'
+        * pointer becomes aligned modulo the cache line size.
+        */
+       to_align64 = (-((uintptr_t)out64 >> 3)) &
+               (CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1);
+
+       /* Only bother aligning and using wh64 if there is at least
+        * one full cache line to process.  This check also prevents
+        * overrunning the end of the buffer with alignment words.
+        */
+       if (to_align64 <= n64 - CACHE_LINE_SIZE_IN_DOUBLEWORDS) {
+               int lines_left;
+
+               /* Align out64 mod the cache line size so we can use wh64. */
+               n64 -= to_align64;
+               for (; to_align64 != 0; to_align64--) {
+                       *out64 = v64;
+                       out64++;
+               }
+
+               /* Use unsigned divide to turn this into a right shift. */
+               lines_left = (unsigned)n64 / CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+
+               do {
+                       /* Only wh64 a few lines at a time, so we don't
+                        * exceed the maximum number of victim lines.
+                        */
+                       int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS())
+                                 ? lines_left
+                                 : CHIP_MAX_OUTSTANDING_VICTIMS());
+                       uint64_t *wh = out64;
+                       int i = x;
+                       int j;
+
+                       lines_left -= x;
+
+                       do {
+                               __insn_wh64(wh);
+                               wh += CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+                       } while (--i);
+
+                       for (j = x * (CACHE_LINE_SIZE_IN_DOUBLEWORDS / 4);
+                            j != 0; j--) {
+                               *out64++ = v64;
+                               *out64++ = v64;
+                               *out64++ = v64;
+                               *out64++ = v64;
+                       }
+               } while (lines_left != 0);
+
+               /* We processed all full lines above, so only this many
+                * words remain to be processed.
+                */
+               n64 &= CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1;
+       }
+
+       /* Now handle any leftover values. */
+       if (n64 != 0) {
+               do {
+                       *out64 = v64;
+                       out64++;
+               } while (--n64 != 0);
+       }
+
+       return s;
+}
+EXPORT_SYMBOL(memset);
diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c
new file mode 100644 (file)
index 0000000..d6fb958
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+
+#include "spinlock_common.h"
+
+/*
+ * Read the spinlock value without allocating in our cache and without
+ * causing an invalidation to another cpu with a copy of the cacheline.
+ * This is important when we are spinning waiting for the lock.
+ */
+static inline u32 arch_spin_read_noalloc(void *lock)
+{
+       return atomic_cmpxchg((atomic_t *)lock, -1, -1);
+}
+
+/*
+ * Wait until the high bits (current) match my ticket.
+ * If we notice the overflow bit set on entry, we clear it.
+ */
+void arch_spin_lock_slow(arch_spinlock_t *lock, u32 my_ticket)
+{
+       if (unlikely(my_ticket & __ARCH_SPIN_NEXT_OVERFLOW)) {
+               __insn_fetchand4(&lock->lock, ~__ARCH_SPIN_NEXT_OVERFLOW);
+               my_ticket &= ~__ARCH_SPIN_NEXT_OVERFLOW;
+       }
+
+       for (;;) {
+               u32 val = arch_spin_read_noalloc(lock);
+               u32 delta = my_ticket - arch_spin_current(val);
+               if (delta == 0)
+                       return;
+               relax((128 / CYCLES_PER_RELAX_LOOP) * delta);
+       }
+}
+EXPORT_SYMBOL(arch_spin_lock_slow);
+
+/*
+ * Check the lock to see if it is plausible, and try to get it with cmpxchg().
+ */
+int arch_spin_trylock(arch_spinlock_t *lock)
+{
+       u32 val = arch_spin_read_noalloc(lock);
+       if (unlikely(arch_spin_current(val) != arch_spin_next(val)))
+               return 0;
+       return cmpxchg(&lock->lock, val, (val + 1) & ~__ARCH_SPIN_NEXT_OVERFLOW)
+               == val;
+}
+EXPORT_SYMBOL(arch_spin_trylock);
+
+void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+       u32 iterations = 0;
+       while (arch_spin_is_locked(lock))
+               delay_backoff(iterations++);
+}
+EXPORT_SYMBOL(arch_spin_unlock_wait);
+
+/*
+ * If the read lock fails due to a writer, we retry periodically
+ * until the value is positive and we write our incremented reader count.
+ */
+void __read_lock_failed(arch_rwlock_t *rw)
+{
+       u32 val;
+       int iterations = 0;
+       do {
+               delay_backoff(iterations++);
+               val = __insn_fetchaddgez4(&rw->lock, 1);
+       } while (unlikely(arch_write_val_locked(val)));
+}
+EXPORT_SYMBOL(__read_lock_failed);
+
+/*
+ * If we failed because there were readers, clear the "writer" bit
+ * so we don't block additional readers.  Otherwise, there was another
+ * writer anyway, so our "fetchor" made no difference.  Then wait,
+ * issuing periodic fetchor instructions, till we get the lock.
+ */
+void __write_lock_failed(arch_rwlock_t *rw, u32 val)
+{
+       int iterations = 0;
+       do {
+               if (!arch_write_val_locked(val))
+                       val = __insn_fetchand4(&rw->lock, ~__WRITE_LOCK_BIT);
+               delay_backoff(iterations++);
+               val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT);
+       } while (val != 0);
+}
+EXPORT_SYMBOL(__write_lock_failed);
diff --git a/arch/tile/lib/strchr_64.c b/arch/tile/lib/strchr_64.c
new file mode 100644 (file)
index 0000000..617a927
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef strchr
+
+char *strchr(const char *s, int c)
+{
+       int z, g;
+
+       /* Get an aligned pointer. */
+       const uintptr_t s_int = (uintptr_t) s;
+       const uint64_t *p = (const uint64_t *)(s_int & -8);
+
+       /* Create eight copies of the byte for which we are looking. */
+       const uint64_t goal = 0x0101010101010101ULL * (uint8_t) c;
+
+       /* Read the first aligned word, but force bytes before the string to
+        * match neither zero nor goal (we make sure the high bit of each
+        * byte is 1, and the low 7 bits are all the opposite of the goal
+        * byte).
+        *
+        * Note that this shift count expression works because we know shift
+        * counts are taken mod 64.
+        */
+       const uint64_t before_mask = (1ULL << (s_int << 3)) - 1;
+       uint64_t v = (*p | before_mask) ^
+               (goal & __insn_v1shrsi(before_mask, 1));
+
+       uint64_t zero_matches, goal_matches;
+       while (1) {
+               /* Look for a terminating '\0'. */
+               zero_matches = __insn_v1cmpeqi(v, 0);
+
+               /* Look for the goal byte. */
+               goal_matches = __insn_v1cmpeq(v, goal);
+
+               if (__builtin_expect((zero_matches | goal_matches) != 0, 0))
+                       break;
+
+               v = *++p;
+       }
+
+       z = __insn_ctz(zero_matches);
+       g = __insn_ctz(goal_matches);
+
+       /* If we found c before '\0' we got a match. Note that if c == '\0'
+        * then g == z, and we correctly return the address of the '\0'
+        * rather than NULL.
+        */
+       return (g <= z) ? ((char *)p) + (g >> 3) : NULL;
+}
+EXPORT_SYMBOL(strchr);
diff --git a/arch/tile/lib/strlen_64.c b/arch/tile/lib/strlen_64.c
new file mode 100644 (file)
index 0000000..1c92d46
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef strlen
+
+size_t strlen(const char *s)
+{
+       /* Get an aligned pointer. */
+       const uintptr_t s_int = (uintptr_t) s;
+       const uint64_t *p = (const uint64_t *)(s_int & -8);
+
+       /* Read the first word, but force bytes before the string to be nonzero.
+        * This expression works because we know shift counts are taken mod 64.
+        */
+       uint64_t v = *p | ((1ULL << (s_int << 3)) - 1);
+
+       uint64_t bits;
+       while ((bits = __insn_v1cmpeqi(v, 0)) == 0)
+               v = *++p;
+
+       return ((const char *)p) + (__insn_ctz(bits) >> 3) - s;
+}
+EXPORT_SYMBOL(strlen);
diff --git a/arch/tile/lib/usercopy_64.S b/arch/tile/lib/usercopy_64.S
new file mode 100644 (file)
index 0000000..2ff44f8
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/cache.h>
+#include <arch/chip.h>
+
+/* Access user memory, but use MMU to avoid propagating kernel exceptions. */
+
+       .pushsection .fixup,"ax"
+
+get_user_fault:
+       { movei r1, -EFAULT; move r0, zero }
+       jrp lr
+       ENDPROC(get_user_fault)
+
+put_user_fault:
+       { movei r0, -EFAULT; jrp lr }
+       ENDPROC(put_user_fault)
+
+       .popsection
+
+/*
+ * __get_user_N functions take a pointer in r0, and return 0 in r1
+ * on success, with the value in r0; or else -EFAULT in r1.
+ */
+#define __get_user_N(bytes, LOAD) \
+       STD_ENTRY(__get_user_##bytes); \
+1:     { LOAD r0, r0; move r1, zero }; \
+       jrp lr; \
+       STD_ENDPROC(__get_user_##bytes); \
+       .pushsection __ex_table,"a"; \
+       .quad 1b, get_user_fault; \
+       .popsection
+
+__get_user_N(1, ld1u)
+__get_user_N(2, ld2u)
+__get_user_N(4, ld4u)
+__get_user_N(8, ld)
+
+/*
+ * __put_user_N functions take a value in r0 and a pointer in r1,
+ * and return 0 in r0 on success or -EFAULT on failure.
+ */
+#define __put_user_N(bytes, STORE) \
+       STD_ENTRY(__put_user_##bytes); \
+1:     { STORE r1, r0; move r0, zero }; \
+       jrp lr; \
+       STD_ENDPROC(__put_user_##bytes); \
+       .pushsection __ex_table,"a"; \
+       .quad 1b, put_user_fault; \
+       .popsection
+
+__put_user_N(1, st1)
+__put_user_N(2, st2)
+__put_user_N(4, st4)
+__put_user_N(8, st)
+
+/*
+ * strnlen_user_asm takes the pointer in r0, and the length bound in r1.
+ * It returns the length, including the terminating NUL, or zero on exception.
+ * If length is greater than the bound, returns one plus the bound.
+ */
+STD_ENTRY(strnlen_user_asm)
+       { beqz r1, 2f; addi r3, r0, -1 }  /* bias down to include NUL */
+1:      { ld1u r4, r0; addi r1, r1, -1 }
+       beqz r4, 2f
+       { bnezt r1, 1b; addi r0, r0, 1 }
+2:      { sub r0, r0, r3; jrp lr }
+       STD_ENDPROC(strnlen_user_asm)
+       .pushsection .fixup,"ax"
+strnlen_user_fault:
+       { move r0, zero; jrp lr }
+       ENDPROC(strnlen_user_fault)
+       .section __ex_table,"a"
+       .quad 1b, strnlen_user_fault
+       .popsection
+
+/*
+ * strncpy_from_user_asm takes the kernel target pointer in r0,
+ * the userspace source pointer in r1, and the length bound (including
+ * the trailing NUL) in r2.  On success, it returns the string length
+ * (not including the trailing NUL), or -EFAULT on failure.
+ */
+STD_ENTRY(strncpy_from_user_asm)
+       { beqz r2, 2f; move r3, r0 }
+1:      { ld1u r4, r1; addi r1, r1, 1; addi r2, r2, -1 }
+       { st1 r0, r4; addi r0, r0, 1 }
+       beqz r2, 2f
+       bnezt r4, 1b
+       addi r0, r0, -1   /* don't count the trailing NUL */
+2:      { sub r0, r0, r3; jrp lr }
+       STD_ENDPROC(strncpy_from_user_asm)
+       .pushsection .fixup,"ax"
+strncpy_from_user_fault:
+       { movei r0, -EFAULT; jrp lr }
+       ENDPROC(strncpy_from_user_fault)
+       .section __ex_table,"a"
+       .quad 1b, strncpy_from_user_fault
+       .popsection
+
+/*
+ * clear_user_asm takes the user target address in r0 and the
+ * number of bytes to zero in r1.
+ * It returns the number of uncopiable bytes (hopefully zero) in r0.
+ * Note that we don't use a separate .fixup section here since we fall
+ * through into the "fixup" code as the last straight-line bundle anyway.
+ */
+STD_ENTRY(clear_user_asm)
+       { beqz r1, 2f; or r2, r0, r1 }
+       andi r2, r2, 7
+       beqzt r2, .Lclear_aligned_user_asm
+1:      { st1 r0, zero; addi r0, r0, 1; addi r1, r1, -1 }
+       bnezt r1, 1b
+2:      { move r0, r1; jrp lr }
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
+
+.Lclear_aligned_user_asm:
+1:      { st r0, zero; addi r0, r0, 8; addi r1, r1, -8 }
+       bnezt r1, 1b
+2:      { move r0, r1; jrp lr }
+       STD_ENDPROC(clear_user_asm)
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
+
+/*
+ * flush_user_asm takes the user target address in r0 and the
+ * number of bytes to flush in r1.
+ * It returns the number of unflushable bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(flush_user_asm)
+       beqz r1, 2f
+       { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+       { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+       { and r0, r0, r2; and r1, r1, r2 }
+       { sub r1, r1, r0 }
+1:      { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() }
+       { addi r0, r0, CHIP_FLUSH_STRIDE(); bnezt r1, 1b }
+2:      { move r0, r1; jrp lr }
+       STD_ENDPROC(flush_user_asm)
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
+
+/*
+ * inv_user_asm takes the user target address in r0 and the
+ * number of bytes to invalidate in r1.
+ * It returns the number of not inv'able bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(inv_user_asm)
+       beqz r1, 2f
+       { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+       { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+       { and r0, r0, r2; and r1, r1, r2 }
+       { sub r1, r1, r0 }
+1:      { inv r0; addi r1, r1, -CHIP_INV_STRIDE() }
+       { addi r0, r0, CHIP_INV_STRIDE(); bnezt r1, 1b }
+2:      { move r0, r1; jrp lr }
+       STD_ENDPROC(inv_user_asm)
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
+
+/*
+ * finv_user_asm takes the user target address in r0 and the
+ * number of bytes to flush-invalidate in r1.
+ * It returns the number of not finv'able bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(finv_user_asm)
+       beqz r1, 2f
+       { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+       { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+       { and r0, r0, r2; and r1, r1, r2 }
+       { sub r1, r1, r0 }
+1:      { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() }
+       { addi r0, r0, CHIP_FINV_STRIDE(); bnezt r1, 1b }
+2:      { move r0, r1; jrp lr }
+       STD_ENDPROC(finv_user_asm)
+       .pushsection __ex_table,"a"
+       .quad 1b, 2b
+       .popsection
index 51f8663bf0743e57765041fbedf3c6f1927e8a86..25b7b90fd62064b46cf6faf0204a7cbc78b28cc1 100644 (file)
 
 #include <arch/interrupts.h>
 
-static noinline void force_sig_info_fault(int si_signo, int si_code,
-       unsigned long address, int fault_num, struct task_struct *tsk)
+static noinline void force_sig_info_fault(const char *type, int si_signo,
+                                         int si_code, unsigned long address,
+                                         int fault_num,
+                                         struct task_struct *tsk,
+                                         struct pt_regs *regs)
 {
        siginfo_t info;
 
@@ -59,6 +62,7 @@ static noinline void force_sig_info_fault(int si_signo, int si_code,
        info.si_code = si_code;
        info.si_addr = (void __user *)address;
        info.si_trapno = fault_num;
+       trace_unhandled_signal(type, regs, address, si_signo);
        force_sig_info(si_signo, &info, tsk);
 }
 
@@ -71,11 +75,12 @@ SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address,
                struct pt_regs *, regs)
 {
        if (address >= PAGE_OFFSET)
-               force_sig_info_fault(SIGSEGV, SEGV_MAPERR, address,
-                                    INT_DTLB_MISS, current);
+               force_sig_info_fault("atomic segfault", SIGSEGV, SEGV_MAPERR,
+                                    address, INT_DTLB_MISS, current, regs);
        else
-               force_sig_info_fault(SIGBUS, BUS_ADRALN, address,
-                                    INT_UNALIGN_DATA, current);
+               force_sig_info_fault("atomic alignment fault", SIGBUS,
+                                    BUS_ADRALN, address,
+                                    INT_UNALIGN_DATA, current, regs);
 
        /*
         * Adjust pc to point at the actual instruction, which is unusual
@@ -471,8 +476,8 @@ bad_area_nosemaphore:
                 */
                local_irq_enable();
 
-               force_sig_info_fault(SIGSEGV, si_code, address,
-                                    fault_num, tsk);
+               force_sig_info_fault("segfault", SIGSEGV, si_code, address,
+                                    fault_num, tsk, regs);
                return 0;
        }
 
@@ -547,7 +552,8 @@ do_sigbus:
        if (is_kernel_mode)
                goto no_context;
 
-       force_sig_info_fault(SIGBUS, BUS_ADRERR, address, fault_num, tsk);
+       force_sig_info_fault("bus error", SIGBUS, BUS_ADRERR, address,
+                            fault_num, tsk, regs);
        return 0;
 }
 
@@ -732,6 +738,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
                panic("Bad fault number %d in do_page_fault", fault_num);
        }
 
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
        if (EX1_PL(regs->ex1) != USER_PL) {
                struct async_tlb *async;
                switch (fault_num) {
@@ -775,6 +782,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
                        return;
                }
        }
+#endif
 
        handle_page_fault(regs, fault_num, is_page_fault, address, write);
 }
@@ -801,8 +809,6 @@ static void handle_async_page_fault(struct pt_regs *regs,
                                  async->address, async->is_write);
        }
 }
-#endif /* CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() */
-
 
 /*
  * This routine effectively re-issues asynchronous page faults
@@ -824,6 +830,8 @@ void do_async_page_fault(struct pt_regs *regs)
        handle_async_page_fault(regs, &current->thread.sn_async_tlb);
 #endif
 }
+#endif /* CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() */
+
 
 void vmalloc_sync_all(void)
 {
index d6e87fda2fb25d65449553253522f611a41d86bf..4e10c4023028181f9700143ab29738b8e0a10a84 100644 (file)
@@ -60,8 +60,6 @@ unsigned long VMALLOC_RESERVE = CONFIG_VMALLOC_RESERVE;
 EXPORT_SYMBOL(VMALLOC_RESERVE);
 #endif
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /* Create an L2 page table */
 static pte_t * __init alloc_pte(void)
 {
diff --git a/arch/tile/mm/migrate_64.S b/arch/tile/mm/migrate_64.S
new file mode 100644 (file)
index 0000000..e76fea6
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * This routine is a helper for migrating the home of a set of pages to
+ * a new cpu.  See the documentation in homecache.c for more information.
+ */
+
+#include <linux/linkage.h>
+#include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+#include <asm/types.h>
+#include <asm/asm-offsets.h>
+#include <hv/hypervisor.h>
+
+       .text
+
+/*
+ * First, some definitions that apply to all the code in the file.
+ */
+
+/* Locals (caller-save) */
+#define r_tmp          r10
+#define r_save_sp      r11
+
+/* What we save where in the stack frame; must include all callee-saves. */
+#define FRAME_SP       8
+#define FRAME_R30      16
+#define FRAME_R31      24
+#define FRAME_R32      32
+#define FRAME_R33      40
+#define FRAME_SIZE     48
+
+
+
+
+/*
+ * On entry:
+ *
+ *   r0 the new context PA to install (moved to r_context)
+ *   r1 PTE to use for context access (moved to r_access)
+ *   r2 ASID to use for new context (moved to r_asid)
+ *   r3 pointer to cpumask with just this cpu set in it (r_my_cpumask)
+ */
+
+/* Arguments (caller-save) */
+#define r_context_in   r0
+#define r_access_in    r1
+#define r_asid_in      r2
+#define r_my_cpumask   r3
+
+/* Locals (callee-save); must not be more than FRAME_xxx above. */
+#define r_save_ics     r30
+#define r_context      r31
+#define r_access       r32
+#define r_asid         r33
+
+/*
+ * Caller-save locals and frame constants are the same as
+ * for homecache_migrate_stack_and_flush.
+ */
+
+STD_ENTRY(flush_and_install_context)
+       /*
+        * Create a stack frame; we can't touch it once we flush the
+        * cache until we install the new page table and flush the TLB.
+        */
+       {
+        move r_save_sp, sp
+        st sp, lr
+        addi sp, sp, -FRAME_SIZE
+       }
+       addi r_tmp, sp, FRAME_SP
+       {
+        st r_tmp, r_save_sp
+        addi r_tmp, sp, FRAME_R30
+       }
+       {
+        st r_tmp, r30
+        addi r_tmp, sp, FRAME_R31
+       }
+       {
+        st r_tmp, r31
+        addi r_tmp, sp, FRAME_R32
+       }
+       {
+        st r_tmp, r32
+        addi r_tmp, sp, FRAME_R33
+       }
+       st r_tmp, r33
+
+       /* Move some arguments to callee-save registers. */
+       {
+        move r_context, r_context_in
+        move r_access, r_access_in
+       }
+       move r_asid, r_asid_in
+
+       /* Disable interrupts, since we can't use our stack. */
+       {
+        mfspr r_save_ics, INTERRUPT_CRITICAL_SECTION
+        movei r_tmp, 1
+       }
+       mtspr INTERRUPT_CRITICAL_SECTION, r_tmp
+
+       /* First, flush our L2 cache. */
+       {
+        move r0, zero  /* cache_pa */
+        moveli r1, hw2_last(HV_FLUSH_EVICT_L2)  /* cache_control */
+       }
+       {
+        shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2)
+        move r2, r_my_cpumask  /* cache_cpumask */
+       }
+       {
+        shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2)
+        move r3, zero  /* tlb_va */
+       }
+       {
+        move r4, zero  /* tlb_length */
+        move r5, zero  /* tlb_pgsize */
+       }
+       {
+        move r6, zero  /* tlb_cpumask */
+        move r7, zero  /* asids */
+       }
+       {
+        move r8, zero  /* asidcount */
+        jal hv_flush_remote
+       }
+       bnez r0, 1f
+
+       /* Now install the new page table. */
+       {
+        move r0, r_context
+        move r1, r_access
+       }
+       {
+        move r2, r_asid
+        movei r3, HV_CTX_DIRECTIO
+       }
+       jal hv_install_context
+       bnez r0, 1f
+
+       /* Finally, flush the TLB. */
+       {
+        movei r0, 0   /* preserve_global */
+        jal hv_flush_all
+       }
+
+1:      /* Reset interrupts back how they were before. */
+       mtspr INTERRUPT_CRITICAL_SECTION, r_save_ics
+
+       /* Restore the callee-saved registers and return. */
+       addli lr, sp, FRAME_SIZE
+       {
+        ld lr, lr
+        addli r_tmp, sp, FRAME_R30
+       }
+       {
+        ld r30, r_tmp
+        addli r_tmp, sp, FRAME_R31
+       }
+       {
+        ld r31, r_tmp
+        addli r_tmp, sp, FRAME_R32
+       }
+       {
+        ld r32, r_tmp
+        addli r_tmp, sp, FRAME_R33
+       }
+       {
+        ld r33, r_tmp
+        addi sp, sp, FRAME_SIZE
+       }
+       jrp lr
+       STD_ENDPROC(flush_and_install_context)
index 8fce5e536b0fa7a268fb59657c7ddc3f99e5d568..68205fd3b08c844e0db9d182c54f9e718032780f 100644 (file)
@@ -28,13 +28,13 @@ config GCOV
          If you're involved in UML kernel development and want to use gcov,
          say Y.  If you're unsure, say N.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       default N
-       help
-         Track the maximum kernel stack usage - this will look at each
-         kernel stack at process exit and log it if it's the deepest
-         stack seen so far.
+config EARLY_PRINTK
+       bool "Early printk"
+       default y
+       ---help---
+         Write kernel log output directly to stdout.
+
+         This is useful for kernel debugging when your machine crashes very
+         early before the console code is initialized.
 
-         This option will slow down process creation and destruction somewhat.
 endmenu
index 1d9b6ae967b089c780afd713932af0bf42900468..e7582e1d248cc91796d94e2fcaa9a6f7b4ef62fc 100644 (file)
@@ -9,7 +9,7 @@
 slip-objs := slip_kern.o slip_user.o
 slirp-objs := slirp_kern.o slirp_user.o
 daemon-objs := daemon_kern.o daemon_user.o
-mcast-objs := mcast_kern.o mcast_user.o
+umcast-objs := umcast_kern.o umcast_user.o
 net-objs := net_kern.o net_user.o
 mconsole-objs := mconsole_kern.o mconsole_user.o
 hostaudio-objs := hostaudio_kern.o
@@ -44,7 +44,7 @@ obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o
 obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
 obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
 obj-$(CONFIG_UML_NET_VDE) += vde.o
-obj-$(CONFIG_UML_NET_MCAST) += mcast.o 
+obj-$(CONFIG_UML_NET_MCAST) += umcast.o
 obj-$(CONFIG_UML_NET_PCAP) += pcap.o
 obj-$(CONFIG_UML_NET) += net.o 
 obj-$(CONFIG_MCONSOLE) += mconsole.o
diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h
deleted file mode 100644 (file)
index 6fa282e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* 
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#ifndef __DRIVERS_MCAST_H
-#define __DRIVERS_MCAST_H
-
-#include "net_user.h"
-
-struct mcast_data {
-       char *addr;
-       unsigned short port;
-       void *mcast_addr;
-       int ttl;
-       void *dev;
-};
-
-extern const struct net_user_info mcast_user_info;
-
-extern int mcast_user_write(int fd, void *buf, int len, 
-                           struct mcast_data *pri);
-
-#endif
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
deleted file mode 100644 (file)
index ffc6416..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * user-mode-linux networking multicast transport
- * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- *
- * based on the existing uml-networking code, which is
- * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
- * James Leu (jleu@mindspring.net).
- * Copyright (C) 2001 by various other people who didn't put their name here.
- *
- * Licensed under the GPL.
- */
-
-#include "linux/init.h"
-#include <linux/netdevice.h>
-#include "mcast.h"
-#include "net_kern.h"
-
-struct mcast_init {
-       char *addr;
-       int port;
-       int ttl;
-};
-
-static void mcast_init(struct net_device *dev, void *data)
-{
-       struct uml_net_private *pri;
-       struct mcast_data *dpri;
-       struct mcast_init *init = data;
-
-       pri = netdev_priv(dev);
-       dpri = (struct mcast_data *) pri->user;
-       dpri->addr = init->addr;
-       dpri->port = init->port;
-       dpri->ttl = init->ttl;
-       dpri->dev = dev;
-
-       printk("mcast backend multicast address: %s:%u, TTL:%u\n",
-              dpri->addr, dpri->port, dpri->ttl);
-}
-
-static int mcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
-{
-       return net_recvfrom(fd, skb_mac_header(skb),
-                           skb->dev->mtu + ETH_HEADER_OTHER);
-}
-
-static int mcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
-{
-       return mcast_user_write(fd, skb->data, skb->len,
-                               (struct mcast_data *) &lp->user);
-}
-
-static const struct net_kern_info mcast_kern_info = {
-       .init                   = mcast_init,
-       .protocol               = eth_protocol,
-       .read                   = mcast_read,
-       .write                  = mcast_write,
-};
-
-static int mcast_setup(char *str, char **mac_out, void *data)
-{
-       struct mcast_init *init = data;
-       char *port_str = NULL, *ttl_str = NULL, *remain;
-       char *last;
-
-       *init = ((struct mcast_init)
-               { .addr         = "239.192.168.1",
-                 .port         = 1102,
-                 .ttl          = 1 });
-
-       remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
-                              NULL);
-       if (remain != NULL) {
-               printk(KERN_ERR "mcast_setup - Extra garbage on "
-                      "specification : '%s'\n", remain);
-               return 0;
-       }
-
-       if (port_str != NULL) {
-               init->port = simple_strtoul(port_str, &last, 10);
-               if ((*last != '\0') || (last == port_str)) {
-                       printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
-                              port_str);
-                       return 0;
-               }
-       }
-
-       if (ttl_str != NULL) {
-               init->ttl = simple_strtoul(ttl_str, &last, 10);
-               if ((*last != '\0') || (last == ttl_str)) {
-                       printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
-                              ttl_str);
-                       return 0;
-               }
-       }
-
-       printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
-              init->port, init->ttl);
-
-       return 1;
-}
-
-static struct transport mcast_transport = {
-       .list           = LIST_HEAD_INIT(mcast_transport.list),
-       .name           = "mcast",
-       .setup          = mcast_setup,
-       .user           = &mcast_user_info,
-       .kern           = &mcast_kern_info,
-       .private_size   = sizeof(struct mcast_data),
-       .setup_size     = sizeof(struct mcast_init),
-};
-
-static int register_mcast(void)
-{
-       register_transport(&mcast_transport);
-       return 0;
-}
-
-late_initcall(register_mcast);
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
deleted file mode 100644 (file)
index ee19e91..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * user-mode-linux networking multicast transport
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
- *
- * based on the existing uml-networking code, which is
- * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
- * James Leu (jleu@mindspring.net).
- * Copyright (C) 2001 by various other people who didn't put their name here.
- *
- * Licensed under the GPL.
- *
- */
-
-#include <unistd.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include "kern_constants.h"
-#include "mcast.h"
-#include "net_user.h"
-#include "um_malloc.h"
-#include "user.h"
-
-static struct sockaddr_in *new_addr(char *addr, unsigned short port)
-{
-       struct sockaddr_in *sin;
-
-       sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
-       if (sin == NULL) {
-               printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in "
-                      "failed\n");
-               return NULL;
-       }
-       sin->sin_family = AF_INET;
-       sin->sin_addr.s_addr = in_aton(addr);
-       sin->sin_port = htons(port);
-       return sin;
-}
-
-static int mcast_user_init(void *data, void *dev)
-{
-       struct mcast_data *pri = data;
-
-       pri->mcast_addr = new_addr(pri->addr, pri->port);
-       pri->dev = dev;
-       return 0;
-}
-
-static void mcast_remove(void *data)
-{
-       struct mcast_data *pri = data;
-
-       kfree(pri->mcast_addr);
-       pri->mcast_addr = NULL;
-}
-
-static int mcast_open(void *data)
-{
-       struct mcast_data *pri = data;
-       struct sockaddr_in *sin = pri->mcast_addr;
-       struct ip_mreq mreq;
-       int fd, yes = 1, err = -EINVAL;
-
-
-       if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
-               goto out;
-
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-       if (fd < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open : data socket failed, "
-                      "errno = %d\n", errno);
-               goto out;
-       }
-
-       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open: SO_REUSEADDR failed, "
-                      "errno = %d\n", errno);
-               goto out_close;
-       }
-
-       /* set ttl according to config */
-       if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
-                      sizeof(pri->ttl)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_TTL failed, "
-                      "error = %d\n", errno);
-               goto out_close;
-       }
-
-       /* set LOOP, so data does get fed back to local sockets */
-       if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_LOOP failed, "
-                      "error = %d\n", errno);
-               goto out_close;
-       }
-
-       /* bind socket to mcast address */
-       if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open : data bind failed, "
-                      "errno = %d\n", errno);
-               goto out_close;
-       }
-
-       /* subscribe to the multicast group */
-       mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
-       mreq.imr_interface.s_addr = 0;
-       if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
-                      &mreq, sizeof(mreq)) < 0) {
-               err = -errno;
-               printk(UM_KERN_ERR "mcast_open: IP_ADD_MEMBERSHIP failed, "
-                      "error = %d\n", errno);
-               printk(UM_KERN_ERR "There appears not to be a multicast-"
-                      "capable network interface on the host.\n");
-               printk(UM_KERN_ERR "eth0 should be configured in order to use "
-                      "the multicast transport.\n");
-               goto out_close;
-       }
-
-       return fd;
-
- out_close:
-       close(fd);
- out:
-       return err;
-}
-
-static void mcast_close(int fd, void *data)
-{
-       struct ip_mreq mreq;
-       struct mcast_data *pri = data;
-       struct sockaddr_in *sin = pri->mcast_addr;
-
-       mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
-       mreq.imr_interface.s_addr = 0;
-       if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
-                      &mreq, sizeof(mreq)) < 0) {
-               printk(UM_KERN_ERR "mcast_open: IP_DROP_MEMBERSHIP failed, "
-                      "error = %d\n", errno);
-       }
-
-       close(fd);
-}
-
-int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
-{
-       struct sockaddr_in *data_addr = pri->mcast_addr;
-
-       return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
-}
-
-const struct net_user_info mcast_user_info = {
-       .init           = mcast_user_init,
-       .open           = mcast_open,
-       .close          = mcast_close,
-       .remove         = mcast_remove,
-       .add_address    = NULL,
-       .delete_address = NULL,
-       .mtu            = ETH_MAX_PACKET,
-       .max_packet     = ETH_MAX_PACKET + ETH_HEADER_OTHER,
-};
diff --git a/arch/um/drivers/umcast.h b/arch/um/drivers/umcast.h
new file mode 100644 (file)
index 0000000..6f8c0fe
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __DRIVERS_UMCAST_H
+#define __DRIVERS_UMCAST_H
+
+#include "net_user.h"
+
+struct umcast_data {
+       char *addr;
+       unsigned short lport;
+       unsigned short rport;
+       void *listen_addr;
+       void *remote_addr;
+       int ttl;
+       int unicast;
+       void *dev;
+};
+
+extern const struct net_user_info umcast_user_info;
+
+extern int umcast_user_write(int fd, void *buf, int len,
+                            struct umcast_data *pri);
+
+#endif
diff --git a/arch/um/drivers/umcast_kern.c b/arch/um/drivers/umcast_kern.c
new file mode 100644 (file)
index 0000000..42dab11
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ */
+
+#include "linux/init.h"
+#include <linux/netdevice.h>
+#include "umcast.h"
+#include "net_kern.h"
+
+struct umcast_init {
+       char *addr;
+       int lport;
+       int rport;
+       int ttl;
+       bool unicast;
+};
+
+static void umcast_init(struct net_device *dev, void *data)
+{
+       struct uml_net_private *pri;
+       struct umcast_data *dpri;
+       struct umcast_init *init = data;
+
+       pri = netdev_priv(dev);
+       dpri = (struct umcast_data *) pri->user;
+       dpri->addr = init->addr;
+       dpri->lport = init->lport;
+       dpri->rport = init->rport;
+       dpri->unicast = init->unicast;
+       dpri->ttl = init->ttl;
+       dpri->dev = dev;
+
+       if (dpri->unicast) {
+               printk(KERN_INFO "ucast backend address: %s:%u listen port: "
+                      "%u\n", dpri->addr, dpri->rport, dpri->lport);
+       } else {
+               printk(KERN_INFO "mcast backend multicast address: %s:%u, "
+                      "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl);
+       }
+}
+
+static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
+{
+       return net_recvfrom(fd, skb_mac_header(skb),
+                           skb->dev->mtu + ETH_HEADER_OTHER);
+}
+
+static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
+{
+       return umcast_user_write(fd, skb->data, skb->len,
+                               (struct umcast_data *) &lp->user);
+}
+
+static const struct net_kern_info umcast_kern_info = {
+       .init                   = umcast_init,
+       .protocol               = eth_protocol,
+       .read                   = umcast_read,
+       .write                  = umcast_write,
+};
+
+static int mcast_setup(char *str, char **mac_out, void *data)
+{
+       struct umcast_init *init = data;
+       char *port_str = NULL, *ttl_str = NULL, *remain;
+       char *last;
+
+       *init = ((struct umcast_init)
+               { .addr = "239.192.168.1",
+                 .lport        = 1102,
+                 .ttl  = 1 });
+
+       remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
+                              NULL);
+       if (remain != NULL) {
+               printk(KERN_ERR "mcast_setup - Extra garbage on "
+                      "specification : '%s'\n", remain);
+               return 0;
+       }
+
+       if (port_str != NULL) {
+               init->lport = simple_strtoul(port_str, &last, 10);
+               if ((*last != '\0') || (last == port_str)) {
+                       printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
+                              port_str);
+                       return 0;
+               }
+       }
+
+       if (ttl_str != NULL) {
+               init->ttl = simple_strtoul(ttl_str, &last, 10);
+               if ((*last != '\0') || (last == ttl_str)) {
+                       printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
+                              ttl_str);
+                       return 0;
+               }
+       }
+
+       init->unicast = false;
+       init->rport = init->lport;
+
+       printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
+              init->lport, init->ttl);
+
+       return 1;
+}
+
+static int ucast_setup(char *str, char **mac_out, void *data)
+{
+       struct umcast_init *init = data;
+       char *lport_str = NULL, *rport_str = NULL, *remain;
+       char *last;
+
+       *init = ((struct umcast_init)
+               { .addr         = "",
+                 .lport        = 1102,
+                 .rport        = 1102 });
+
+       remain = split_if_spec(str, mac_out, &init->addr,
+                              &lport_str, &rport_str, NULL);
+       if (remain != NULL) {
+               printk(KERN_ERR "ucast_setup - Extra garbage on "
+                      "specification : '%s'\n", remain);
+               return 0;
+       }
+
+       if (lport_str != NULL) {
+               init->lport = simple_strtoul(lport_str, &last, 10);
+               if ((*last != '\0') || (last == lport_str)) {
+                       printk(KERN_ERR "ucast_setup - Bad listen port : "
+                              "'%s'\n", lport_str);
+                       return 0;
+               }
+       }
+
+       if (rport_str != NULL) {
+               init->rport = simple_strtoul(rport_str, &last, 10);
+               if ((*last != '\0') || (last == rport_str)) {
+                       printk(KERN_ERR "ucast_setup - Bad remote port : "
+                              "'%s'\n", rport_str);
+                       return 0;
+               }
+       }
+
+       init->unicast = true;
+
+       printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n",
+              init->lport, init->addr, init->rport);
+
+       return 1;
+}
+
+static struct transport mcast_transport = {
+       .list   = LIST_HEAD_INIT(mcast_transport.list),
+       .name   = "mcast",
+       .setup  = mcast_setup,
+       .user   = &umcast_user_info,
+       .kern   = &umcast_kern_info,
+       .private_size   = sizeof(struct umcast_data),
+       .setup_size     = sizeof(struct umcast_init),
+};
+
+static struct transport ucast_transport = {
+       .list   = LIST_HEAD_INIT(ucast_transport.list),
+       .name   = "ucast",
+       .setup  = ucast_setup,
+       .user   = &umcast_user_info,
+       .kern   = &umcast_kern_info,
+       .private_size   = sizeof(struct umcast_data),
+       .setup_size     = sizeof(struct umcast_init),
+};
+
+static int register_umcast(void)
+{
+       register_transport(&mcast_transport);
+       register_transport(&ucast_transport);
+       return 0;
+}
+
+late_initcall(register_umcast);
diff --git a/arch/um/drivers/umcast_user.c b/arch/um/drivers/umcast_user.c
new file mode 100644 (file)
index 0000000..59c56fd
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ *
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include "kern_constants.h"
+#include "umcast.h"
+#include "net_user.h"
+#include "um_malloc.h"
+#include "user.h"
+
+static struct sockaddr_in *new_addr(char *addr, unsigned short port)
+{
+       struct sockaddr_in *sin;
+
+       sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
+       if (sin == NULL) {
+               printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in "
+                      "failed\n");
+               return NULL;
+       }
+       sin->sin_family = AF_INET;
+       if (addr)
+               sin->sin_addr.s_addr = in_aton(addr);
+       else
+               sin->sin_addr.s_addr = INADDR_ANY;
+       sin->sin_port = htons(port);
+       return sin;
+}
+
+static int umcast_user_init(void *data, void *dev)
+{
+       struct umcast_data *pri = data;
+
+       pri->remote_addr = new_addr(pri->addr, pri->rport);
+       if (pri->unicast)
+               pri->listen_addr = new_addr(NULL, pri->lport);
+       else
+               pri->listen_addr = pri->remote_addr;
+       pri->dev = dev;
+       return 0;
+}
+
+static void umcast_remove(void *data)
+{
+       struct umcast_data *pri = data;
+
+       kfree(pri->listen_addr);
+       if (pri->unicast)
+               kfree(pri->remote_addr);
+       pri->listen_addr = pri->remote_addr = NULL;
+}
+
+static int umcast_open(void *data)
+{
+       struct umcast_data *pri = data;
+       struct sockaddr_in *lsin = pri->listen_addr;
+       struct sockaddr_in *rsin = pri->remote_addr;
+       struct ip_mreq mreq;
+       int fd, yes = 1, err = -EINVAL;
+
+
+       if ((!pri->unicast && lsin->sin_addr.s_addr == 0) ||
+           (rsin->sin_addr.s_addr == 0) ||
+           (lsin->sin_port == 0) || (rsin->sin_port == 0))
+               goto out;
+
+       fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+       if (fd < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "umcast_open : data socket failed, "
+                      "errno = %d\n", errno);
+               goto out;
+       }
+
+       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "umcast_open: SO_REUSEADDR failed, "
+                      "errno = %d\n", errno);
+               goto out_close;
+       }
+
+       if (!pri->unicast) {
+               /* set ttl according to config */
+               if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
+                              sizeof(pri->ttl)) < 0) {
+                       err = -errno;
+                       printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_TTL "
+                              "failed, error = %d\n", errno);
+                       goto out_close;
+               }
+
+               /* set LOOP, so data does get fed back to local sockets */
+               if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP,
+                              &yes, sizeof(yes)) < 0) {
+                       err = -errno;
+                       printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_LOOP "
+                              "failed, error = %d\n", errno);
+                       goto out_close;
+               }
+       }
+
+       /* bind socket to the address */
+       if (bind(fd, (struct sockaddr *) lsin, sizeof(*lsin)) < 0) {
+               err = -errno;
+               printk(UM_KERN_ERR "umcast_open : data bind failed, "
+                      "errno = %d\n", errno);
+               goto out_close;
+       }
+
+       if (!pri->unicast) {
+               /* subscribe to the multicast group */
+               mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
+               mreq.imr_interface.s_addr = 0;
+               if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
+                              &mreq, sizeof(mreq)) < 0) {
+                       err = -errno;
+                       printk(UM_KERN_ERR "umcast_open: IP_ADD_MEMBERSHIP "
+                              "failed, error = %d\n", errno);
+                       printk(UM_KERN_ERR "There appears not to be a "
+                              "multicast-capable network interface on the "
+                              "host.\n");
+                       printk(UM_KERN_ERR "eth0 should be configured in order "
+                              "to use the multicast transport.\n");
+                       goto out_close;
+               }
+       }
+
+       return fd;
+
+ out_close:
+       close(fd);
+ out:
+       return err;
+}
+
+static void umcast_close(int fd, void *data)
+{
+       struct umcast_data *pri = data;
+
+       if (!pri->unicast) {
+               struct ip_mreq mreq;
+               struct sockaddr_in *lsin = pri->listen_addr;
+
+               mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
+               mreq.imr_interface.s_addr = 0;
+               if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
+                              &mreq, sizeof(mreq)) < 0) {
+                       printk(UM_KERN_ERR "umcast_close: IP_DROP_MEMBERSHIP "
+                              "failed, error = %d\n", errno);
+               }
+       }
+
+       close(fd);
+}
+
+int umcast_user_write(int fd, void *buf, int len, struct umcast_data *pri)
+{
+       struct sockaddr_in *data_addr = pri->remote_addr;
+
+       return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
+}
+
+const struct net_user_info umcast_user_info = {
+       .init   = umcast_user_init,
+       .open   = umcast_open,
+       .close  = umcast_close,
+       .remove = umcast_remove,
+       .add_address    = NULL,
+       .delete_address = NULL,
+       .mtu    = ETH_MAX_PACKET,
+       .max_packet     = ETH_MAX_PACKET + ETH_HEADER_OTHER,
+};
index da2caa5a21efa91333ffd44c9c7743b467ec3f26..8ac7146c237f69ae9052397767c23140055512f3 100644 (file)
@@ -90,7 +90,7 @@ static int xterm_open(int input, int output, int primary, void *d,
        int pid, fd, new, err;
        char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
        char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
-                        "/usr/lib/uml/port-helper", "-uml-socket",
+                        OS_LIB_PATH "/uml/port-helper", "-uml-socket",
                         file, NULL };
 
        if (access(argv[4], X_OK) < 0)
index d1d1b0d8a0cd9c66d754243f636425e4c942ee46..98d01bc4fa92f1267062645e31c9b632f74e2339 100644 (file)
@@ -14,6 +14,8 @@ struct task_struct;
 #include "registers.h"
 #include "sysdep/archsetjmp.h"
 
+#include <linux/prefetch.h>
+
 struct mm_struct;
 
 struct thread_struct {
index f27a963131741ba935f80ec424c9b4c413ae63d4..4a4b09d4f36648c0bf85724aa9533d9890403a07 100644 (file)
@@ -11,7 +11,6 @@
 
 #define cpu_logical_map(n) (n)
 #define cpu_number_map(n) (n)
-#define PROC_CHANGE_PENALTY    15 /* Pick a number, any number */
 extern int hard_smp_processor_id(void);
 #define NO_PROC_ID -1
 
index 660caedac9eb70bb3314beb5b1e87a3d3e876bef..4febacd1a8a1a3dee2c24e3b3447081e7ca94ebb 100644 (file)
@@ -22,9 +22,6 @@ struct mmu_gather {
        unsigned int            fullmm; /* non-zero means full mm flush */
 };
 
-/* Users of the generic TLB shootdown code must declare this storage space. */
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
                                          unsigned long address)
 {
@@ -47,27 +44,20 @@ static inline void init_tlb_gather(struct mmu_gather *tlb)
        }
 }
 
-/* tlb_gather_mmu
- *     Return a pointer to an initialized struct mmu_gather.
- */
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
 {
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
        tlb->mm = mm;
        tlb->fullmm = full_mm_flush;
 
        init_tlb_gather(tlb);
-
-       return tlb;
 }
 
 extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
                               unsigned long end);
 
 static inline void
-tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+tlb_flush_mmu(struct mmu_gather *tlb)
 {
        if (!tlb->need_flush)
                return;
@@ -83,12 +73,10 @@ tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 static inline void
 tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
 {
-       tlb_flush_mmu(tlb, start, end);
+       tlb_flush_mmu(tlb);
 
        /* keep the page table cache within bounds */
        check_pgt_cache();
-
-       put_cpu_var(mmu_gathers);
 }
 
 /* tlb_remove_page
@@ -96,11 +84,16 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
  *     while handling the additional races in SMP caused by other CPUs
  *     caching valid mappings in their TLBs.
  */
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
        tlb->need_flush = 1;
        free_page_and_swap_cache(page);
-       return;
+       return 1; /* avoid calling tlb_flush_mmu */
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       __tlb_remove_page(tlb, page);
 }
 
 /**
index c4617baaa4f2752a84a3cb20fa517e326e5ebaa7..83c7c2ecd61422b7fccd054e79597bad10d4f9a7 100644 (file)
 #define OS_ACC_R_OK    4       /* Test for read permission.  */
 #define OS_ACC_RW_OK   (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */
 
+#ifdef CONFIG_64BIT
+#define OS_LIB_PATH    "/usr/lib64/"
+#else
+#define OS_LIB_PATH    "/usr/lib/"
+#endif
+
 /*
  * types taken from stat_file() in hostfs_user.c
  * (if they are wrong here, they are wrong there...).
@@ -238,6 +244,7 @@ extern int raw(int fd);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(char *buf, int len);
 extern void os_dump_core(void) __attribute__ ((noreturn));
+extern void um_early_printk(const char *s, unsigned int n);
 
 /* time.c */
 extern void idle_sleep(unsigned long long nsecs);
index 1119233597a1eb2f3ac26a22bb4a05183f32b9d9..c4491c15afb213064995f3aa490d2a749a39f8d3 100644 (file)
@@ -17,6 +17,7 @@ obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
 obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
 obj-$(CONFIG_GPROF)    += gprof_syms.o
 obj-$(CONFIG_GCOV)     += gmon_syms.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
 
 USER_OBJS := config.o
 
diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c
new file mode 100644 (file)
index 0000000..ec649bf
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 Richard Weinberger <richrd@nod.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include "os.h"
+
+static void early_console_write(struct console *con, const char *s, unsigned int n)
+{
+       um_early_printk(s, n);
+}
+
+static struct console early_console = {
+       .name = "earlycon",
+       .write = early_console_write,
+       .flags = CON_BOOT,
+       .index = -1,
+};
+
+static int __init setup_early_printk(char *buf)
+{
+       register_console(&early_console);
+
+       return 0;
+}
+
+early_param("earlyprintk", setup_early_printk);
index eefb107d2d734856c376f973913a29ddf18acae7..155206a6690879da2e6521c7604d74ad8f9e52a0 100644 (file)
@@ -7,9 +7,6 @@
 #include "asm/pgalloc.h"
 #include "asm/tlb.h"
 
-/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 #ifdef CONFIG_SMP
 
 #include "linux/sched.h"
index 637c6505dc00de1ce482335023bff8227aedaaa1..8c7b8823d1f0e1257f3a410620048bbd3556d95b 100644 (file)
@@ -113,6 +113,27 @@ out_of_memory:
        return 0;
 }
 
+static void show_segv_info(struct uml_pt_regs *regs)
+{
+       struct task_struct *tsk = current;
+       struct faultinfo *fi = UPT_FAULTINFO(regs);
+
+       if (!unhandled_signal(tsk, SIGSEGV))
+               return;
+
+       if (!printk_ratelimit())
+               return;
+
+       printk("%s%s[%d]: segfault at %lx ip %p sp %p error %x",
+               task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
+               tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi),
+               (void *)UPT_IP(regs), (void *)UPT_SP(regs),
+               fi->error_code);
+
+       print_vma_addr(KERN_CONT " in ", UPT_IP(regs));
+       printk(KERN_CONT "\n");
+}
+
 static void bad_segv(struct faultinfo fi, unsigned long ip)
 {
        struct siginfo si;
@@ -141,6 +162,7 @@ void segv_handler(int sig, struct uml_pt_regs *regs)
        struct faultinfo * fi = UPT_FAULTINFO(regs);
 
        if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) {
+               show_segv_info(regs);
                bad_segv(*fi, UPT_IP(regs));
                return;
        }
@@ -202,6 +224,8 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
                      address, ip);
        }
 
+       show_segv_info(regs);
+
        if (err == -EACCES) {
                si.si_signo = SIGBUS;
                si.si_errno = 0;
index eee69b9f52c92bfd355303fd72b5afbf70502d7e..fb2a97a75fb1b799966785ad8694d08b9f13508b 100644 (file)
@@ -78,7 +78,7 @@ static void install_fatal_handler(int sig)
        }
 }
 
-#define UML_LIB_PATH   ":/usr/lib/uml"
+#define UML_LIB_PATH   ":" OS_LIB_PATH "/uml"
 
 static void setup_env_path(void)
 {
@@ -142,7 +142,6 @@ int __init main(int argc, char **argv, char **envp)
         */
        install_fatal_handler(SIGINT);
        install_fatal_handler(SIGTERM);
-       install_fatal_handler(SIGHUP);
 
        scan_elf_aux(envp);
 
index e0477c3ee89448f72320b01a493a97cb280ecad6..0c45dc8efb055243d9259da46f702760b773ce11 100644 (file)
@@ -253,6 +253,7 @@ void init_new_thread_signals(void)
                    SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM,
                    SIGVTALRM, -1);
        signal(SIGWINCH, SIG_IGN);
+       signal(SIGTERM, SIG_DFL);
 }
 
 int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr)
index 42827cafa6af3ac72f4c57d62e08968b81360faa..5803b188767213eb1a60399c594677a661547287 100644 (file)
@@ -139,3 +139,8 @@ void os_dump_core(void)
 
        uml_abort();
 }
+
+void um_early_printk(const char *s, unsigned int n)
+{
+       printf("%.*s", n, s);
+}
index 3140151ede4502f537bd39ed37b99d2767a945f8..ae2ec334c3c61473ffa6b7b5cf8695c8d64c322b 100644 (file)
@@ -27,13 +27,6 @@ config EARLY_PRINTK
          with klogd/syslogd or the X server. You should normally N here,
          unless you want to debug such a crash.
 
-config DEBUG_STACK_USAGE
-       bool "Enable stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       help
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T output.
-
 # These options are only for real kernel hackers who want to get their hands dirty.
 config DEBUG_LL
        bool "Kernel low-level debugging functions"
index 1fc02633f700a18af47db8e61a85cd55c0210d80..2d3e7112d2a3cbce8d778770e35754ac5a34e753 100644 (file)
@@ -62,7 +62,7 @@ void show_mem(unsigned int filter)
        struct meminfo *mi = &meminfo;
 
        printk(KERN_DEFAULT "Mem-info:\n");
-       show_free_areas();
+       show_free_areas(filter);
 
        for_each_bank(i, mi) {
                struct membank *bank = &mi->bank[i];
index db2d334941b41dd7d1527107ab08bf6e03e98e1a..3e5c3e5a0b4542a99cb1e6bda573ab3dfc002dcc 100644 (file)
@@ -30,8 +30,6 @@
 
 #include "mm.h"
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 /*
  * empty_zero_page is a special page that is used for
  * zero-initialized data and COW.
index 880fcb6c86f484c602afa6bbcfb436d48647f8c9..483775f42d2aab393886ee97ed2987017e0196df 100644 (file)
@@ -17,8 +17,6 @@ config X86_64
 config X86
        def_bool y
        select HAVE_AOUT if X86_32
-       select HAVE_READQ
-       select HAVE_WRITEQ
        select HAVE_UNSTABLE_SCHED_CLOCK
        select HAVE_IDE
        select HAVE_OPROFILE
@@ -917,6 +915,7 @@ config TOSHIBA
 
 config I8K
        tristate "Dell laptop support"
+       select HWMON
        ---help---
          This adds a driver to safely access the System Management Mode
          of the CPU on the Dell Inspiron 8000. The System Management Mode
index 615e18810f4856e500b7964ffbfe82c78a843b20..c0f8a5c889107bf80ab45eaf33468e5120ee6a56 100644 (file)
@@ -66,26 +66,6 @@ config DEBUG_STACKOVERFLOW
          This option will cause messages to be printed if free stack space
          drops below a certain limit.
 
-config DEBUG_STACK_USAGE
-       bool "Stack utilization instrumentation"
-       depends on DEBUG_KERNEL
-       ---help---
-         Enables the display of the minimum amount of free stack which each
-         task has ever had available in the sysrq-T and sysrq-P debug output.
-
-         This option will slow down process creation somewhat.
-
-config DEBUG_PER_CPU_MAPS
-       bool "Debug access to per_cpu maps"
-       depends on DEBUG_KERNEL
-       depends on SMP
-       ---help---
-         Say Y to verify that the per_cpu map being accessed has
-         been setup.  Adds a fair amount of code to kernel memory
-         and decreases performance.
-
-         Say N if unsure.
-
 config X86_PTDUMP
        bool "Export kernel pagetable layout to userspace via debugfs"
        depends on DEBUG_KERNEL
index 072273082528c3bcff89ca88d9d98e26567c38df..d02804d650c4596aa4644a8fccb75ba72d387548 100644 (file)
@@ -38,7 +38,6 @@
 
 #include <linux/string.h>
 #include <linux/compiler.h>
-#include <asm-generic/int-ll64.h>
 #include <asm/page.h>
 
 #include <xen/xen.h>
@@ -87,27 +86,6 @@ build_mmio_write(__writel, "l", unsigned int, "r", )
 build_mmio_read(readq, "q", unsigned long, "=r", :"memory")
 build_mmio_write(writeq, "q", unsigned long, "r", :"memory")
 
-#else
-
-static inline __u64 readq(const volatile void __iomem *addr)
-{
-       const volatile u32 __iomem *p = addr;
-       u32 low, high;
-
-       low = readl(p);
-       high = readl(p + 1);
-
-       return low + ((u64)high << 32);
-}
-
-static inline void writeq(__u64 val, volatile void __iomem *addr)
-{
-       writel(val, addr);
-       writel(val >> 32, addr+4);
-}
-
-#endif
-
 #define readq_relaxed(a)       readq(a)
 
 #define __raw_readq(a)         readq(a)
@@ -117,6 +95,8 @@ static inline void writeq(__u64 val, volatile void __iomem *addr)
 #define readq                  readq
 #define writeq                 writeq
 
+#endif
+
 /**
  *     virt_to_phys    -       map virtual addresses to physical
  *     @address: address to remap
index 605e5ae19c7fe8a1dd754f3c2c96b290b13b48bc..a3e5948670c241eecb15028cefeae8209b37c669 100644 (file)
@@ -946,6 +946,8 @@ void __init setup_arch(char **cmdline_p)
        if (init_ohci1394_dma_early)
                init_ohci1394_dma_on_all_controllers();
 #endif
+       /* Allocate bigger log buffer */
+       setup_log_buf(1);
 
        reserve_initrd();
 
index 998e972f3b1a93638c7456650927db96704e68c6..30ac65df7d4eeaa956777c53e2846997cdd59464 100644 (file)
@@ -110,7 +110,6 @@ static struct mm_struct tboot_mm = {
        .mmap_sem       = __RWSEM_INITIALIZER(init_mm.mmap_sem),
        .page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
        .mmlist         = LIST_HEAD_INIT(init_mm.mmlist),
-       .cpu_vm_mask    = CPU_MASK_ALL,
 };
 
 static inline void switch_to_tboot_pt(void)
index 28418054b8808e190981b8d4b080b11dea9b84b6..bd14bb4c8594c4cb7b8375e6567e6a0aa56c61cc 100644 (file)
@@ -3545,10 +3545,11 @@ static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm,
        return kvm_mmu_prepare_zap_page(kvm, page, invalid_list);
 }
 
-static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
 {
        struct kvm *kvm;
        struct kvm *kvm_freed = NULL;
+       int nr_to_scan = sc->nr_to_scan;
 
        if (nr_to_scan == 0)
                goto out;
index bcb394dfbb3587f8b4d40cc096b6ff7334ce6b12..f7a2a054a3c08f2a7ea9c013fe16cc3421a4b135 100644 (file)
@@ -965,7 +965,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
        struct mm_struct *mm;
        int fault;
        int write = error_code & PF_WRITE;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY |
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
                                        (write ? FAULT_FLAG_WRITE : 0);
 
        tsk = current;
@@ -1138,6 +1138,16 @@ good_area:
                return;
        }
 
+       /*
+        * Pagefault was interrupted by SIGKILL. We have no reason to
+        * continue pagefault.
+        */
+       if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
+               if (!(error_code & PF_USER))
+                       no_context(regs, error_code, address);
+               return;
+       }
+
        /*
         * Major/minor page fault accounting is only done on the
         * initial attempt. If we go through a retry, it is extremely
index d4203988504ae871e9e6bf4f8a294d0e8b696dff..f581a18c0d4d7d07aac5cdfa8fb443106e3d5e92 100644 (file)
@@ -72,7 +72,7 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
        if (!vma_shareable(vma, addr))
                return;
 
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(svma, &iter, &mapping->i_mmap, idx, idx) {
                if (svma == vma)
                        continue;
@@ -97,7 +97,7 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
                put_page(virt_to_page(spte));
        spin_unlock(&mm->page_table_lock);
 out:
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
 }
 
 /*
index 37b8b0fe8320952c89158d29a508568affbd8c8e..30326443ab81d9189224cf0c373ded68da51332d 100644 (file)
@@ -16,8 +16,6 @@
 #include <asm/tlb.h>
 #include <asm/proto.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 unsigned long __initdata pgt_buf_start;
 unsigned long __meminitdata pgt_buf_end;
 unsigned long __meminitdata pgt_buf_top;
index 161bb89e98c8b20f8b76f9c194bffa2727fa6cf2..7a5591a71f85093a8f58effc5a195f4f9b48c147 100644 (file)
@@ -171,10 +171,6 @@ extern void copy_user_page(void*, void*, unsigned long, struct page*);
 #define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 #define page_to_phys(page)     (page_to_pfn(page) << PAGE_SHIFT)
 
-#ifdef CONFIG_MMU
-#define WANT_PAGE_VIRTUAL
-#endif
-
 #endif /* __ASSEMBLY__ */
 
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
index 4bb91a970f1f48eee6919e5104c8075f0481f71e..ca81654f3ec2c34e95f9ec8585c050ad1324f161 100644 (file)
@@ -14,8 +14,6 @@
 #include <asm/mmu_context.h>
 #include <asm/page.h>
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
 void __init paging_init(void)
 {
        memset(swapper_pg_dir, 0, PAGE_SIZE);
diff --git a/arch/xtensa/mm/pgtable.c b/arch/xtensa/mm/pgtable.c
deleted file mode 100644 (file)
index 6979927..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * arch/xtensa/mm/pgtable.c
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- *
- * Chris Zankel <chris@zankel.net>
- */
-
-#if (DCACHE_SIZE > PAGE_SIZE)
-
-pte_t* pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
-       pte_t *pte = NULL, *p;
-       int color = ADDR_COLOR(address);
-       int i;
-
-       p = (pte_t*) __get_free_pages(GFP_KERNEL|__GFP_REPEAT, COLOR_ORDER);
-
-       if (likely(p)) {
-               split_page(virt_to_page(p), COLOR_ORDER);
-
-               for (i = 0; i < COLOR_SIZE; i++) {
-                       if (ADDR_COLOR(p) == color)
-                               pte = p;
-                       else
-                               free_page(p);
-                       p += PTRS_PER_PTE;
-               }
-               clear_page(pte);
-       }
-       return pte;
-}
-
-#ifdef PROFILING
-
-int mask;
-int hit;
-int flush;
-
-#endif
-
-struct page* pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
-       struct page *page = NULL, *p;
-       int color = ADDR_COLOR(address);
-
-       p = alloc_pages(GFP_KERNEL | __GFP_REPEAT, PTE_ORDER);
-
-       if (likely(p)) {
-               split_page(p, COLOR_ORDER);
-
-               for (i = 0; i < PAGE_ORDER; i++) {
-                       if (PADDR_COLOR(page_address(p)) == color)
-                               page = p;
-                       else
-                               __free_page(p);
-                       p++;
-               }
-               clear_highpage(page);
-       }
-
-       return page;
-}
-
-#endif
-
-
-
index 471fdcc5df85e3135dfefac29aa81a889d0ed567..07371cfdfae607c97e7600511fe1c9e7fa13a3d1 100644 (file)
@@ -385,25 +385,40 @@ void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time,
 
        spin_lock_irqsave(&blkg->stats_lock, flags);
        blkg->stats.time += time;
+#ifdef CONFIG_DEBUG_BLK_CGROUP
        blkg->stats.unaccounted_time += unaccounted_time;
+#endif
        spin_unlock_irqrestore(&blkg->stats_lock, flags);
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used);
 
+/*
+ * should be called under rcu read lock or queue lock to make sure blkg pointer
+ * is valid.
+ */
 void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
                                uint64_t bytes, bool direction, bool sync)
 {
-       struct blkio_group_stats *stats;
+       struct blkio_group_stats_cpu *stats_cpu;
        unsigned long flags;
 
-       spin_lock_irqsave(&blkg->stats_lock, flags);
-       stats = &blkg->stats;
-       stats->sectors += bytes >> 9;
-       blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICED], 1, direction,
-                       sync);
-       blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICE_BYTES], bytes,
-                       direction, sync);
-       spin_unlock_irqrestore(&blkg->stats_lock, flags);
+       /*
+        * Disabling interrupts to provide mutual exclusion between two
+        * writes on same cpu. It probably is not needed for 64bit. Not
+        * optimizing that case yet.
+        */
+       local_irq_save(flags);
+
+       stats_cpu = this_cpu_ptr(blkg->stats_cpu);
+
+       u64_stats_update_begin(&stats_cpu->syncp);
+       stats_cpu->sectors += bytes >> 9;
+       blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICED],
+                       1, direction, sync);
+       blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICE_BYTES],
+                       bytes, direction, sync);
+       u64_stats_update_end(&stats_cpu->syncp);
+       local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_dispatch_stats);
 
@@ -426,18 +441,44 @@ void blkiocg_update_completion_stats(struct blkio_group *blkg,
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_completion_stats);
 
+/*  Merged stats are per cpu.  */
 void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
                                        bool sync)
 {
+       struct blkio_group_stats_cpu *stats_cpu;
        unsigned long flags;
 
-       spin_lock_irqsave(&blkg->stats_lock, flags);
-       blkio_add_stat(blkg->stats.stat_arr[BLKIO_STAT_MERGED], 1, direction,
-                       sync);
-       spin_unlock_irqrestore(&blkg->stats_lock, flags);
+       /*
+        * Disabling interrupts to provide mutual exclusion between two
+        * writes on same cpu. It probably is not needed for 64bit. Not
+        * optimizing that case yet.
+        */
+       local_irq_save(flags);
+
+       stats_cpu = this_cpu_ptr(blkg->stats_cpu);
+
+       u64_stats_update_begin(&stats_cpu->syncp);
+       blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_MERGED], 1,
+                               direction, sync);
+       u64_stats_update_end(&stats_cpu->syncp);
+       local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats);
 
+/*
+ * This function allocates the per cpu stats for blkio_group. Should be called
+ * from sleepable context as alloc_per_cpu() requires that.
+ */
+int blkio_alloc_blkg_stats(struct blkio_group *blkg)
+{
+       /* Allocate memory for per cpu stats */
+       blkg->stats_cpu = alloc_percpu(struct blkio_group_stats_cpu);
+       if (!blkg->stats_cpu)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(blkio_alloc_blkg_stats);
+
 void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
                struct blkio_group *blkg, void *key, dev_t dev,
                enum blkio_policy_id plid)
@@ -508,6 +549,30 @@ struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key)
 }
 EXPORT_SYMBOL_GPL(blkiocg_lookup_group);
 
+static void blkio_reset_stats_cpu(struct blkio_group *blkg)
+{
+       struct blkio_group_stats_cpu *stats_cpu;
+       int i, j, k;
+       /*
+        * Note: On 64 bit arch this should not be an issue. This has the
+        * possibility of returning some inconsistent value on 32bit arch
+        * as 64bit update on 32bit is non atomic. Taking care of this
+        * corner case makes code very complicated, like sending IPIs to
+        * cpus, taking care of stats of offline cpus etc.
+        *
+        * reset stats is anyway more of a debug feature and this sounds a
+        * corner case. So I am not complicating the code yet until and
+        * unless this becomes a real issue.
+        */
+       for_each_possible_cpu(i) {
+               stats_cpu = per_cpu_ptr(blkg->stats_cpu, i);
+               stats_cpu->sectors = 0;
+               for(j = 0; j < BLKIO_STAT_CPU_NR; j++)
+                       for (k = 0; k < BLKIO_STAT_TOTAL; k++)
+                               stats_cpu->stat_arr_cpu[j][k] = 0;
+       }
+}
+
 static int
 blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
 {
@@ -552,7 +617,11 @@ blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
                }
 #endif
                spin_unlock(&blkg->stats_lock);
+
+               /* Reset Per cpu stats which don't take blkg->stats_lock */
+               blkio_reset_stats_cpu(blkg);
        }
+
        spin_unlock_irq(&blkcg->lock);
        return 0;
 }
@@ -598,6 +667,59 @@ static uint64_t blkio_fill_stat(char *str, int chars_left, uint64_t val,
        return val;
 }
 
+
+static uint64_t blkio_read_stat_cpu(struct blkio_group *blkg,
+                       enum stat_type_cpu type, enum stat_sub_type sub_type)
+{
+       int cpu;
+       struct blkio_group_stats_cpu *stats_cpu;
+       u64 val = 0, tval;
+
+       for_each_possible_cpu(cpu) {
+               unsigned int start;
+               stats_cpu  = per_cpu_ptr(blkg->stats_cpu, cpu);
+
+               do {
+                       start = u64_stats_fetch_begin(&stats_cpu->syncp);
+                       if (type == BLKIO_STAT_CPU_SECTORS)
+                               tval = stats_cpu->sectors;
+                       else
+                               tval = stats_cpu->stat_arr_cpu[type][sub_type];
+               } while(u64_stats_fetch_retry(&stats_cpu->syncp, start));
+
+               val += tval;
+       }
+
+       return val;
+}
+
+static uint64_t blkio_get_stat_cpu(struct blkio_group *blkg,
+               struct cgroup_map_cb *cb, dev_t dev, enum stat_type_cpu type)
+{
+       uint64_t disk_total, val;
+       char key_str[MAX_KEY_LEN];
+       enum stat_sub_type sub_type;
+
+       if (type == BLKIO_STAT_CPU_SECTORS) {
+               val = blkio_read_stat_cpu(blkg, type, 0);
+               return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, val, cb, dev);
+       }
+
+       for (sub_type = BLKIO_STAT_READ; sub_type < BLKIO_STAT_TOTAL;
+                       sub_type++) {
+               blkio_get_key_name(sub_type, dev, key_str, MAX_KEY_LEN, false);
+               val = blkio_read_stat_cpu(blkg, type, sub_type);
+               cb->fill(cb, key_str, val);
+       }
+
+       disk_total = blkio_read_stat_cpu(blkg, type, BLKIO_STAT_READ) +
+                       blkio_read_stat_cpu(blkg, type, BLKIO_STAT_WRITE);
+
+       blkio_get_key_name(BLKIO_STAT_TOTAL, dev, key_str, MAX_KEY_LEN, false);
+       cb->fill(cb, key_str, disk_total);
+       return disk_total;
+}
+
 /* This should be called with blkg->stats_lock held */
 static uint64_t blkio_get_stat(struct blkio_group *blkg,
                struct cgroup_map_cb *cb, dev_t dev, enum stat_type type)
@@ -609,9 +731,6 @@ static uint64_t blkio_get_stat(struct blkio_group *blkg,
        if (type == BLKIO_STAT_TIME)
                return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
                                        blkg->stats.time, cb, dev);
-       if (type == BLKIO_STAT_SECTORS)
-               return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
-                                       blkg->stats.sectors, cb, dev);
 #ifdef CONFIG_DEBUG_BLK_CGROUP
        if (type == BLKIO_STAT_UNACCOUNTED_TIME)
                return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
@@ -1075,8 +1194,8 @@ static int blkiocg_file_read(struct cgroup *cgrp, struct cftype *cft,
 }
 
 static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
-               struct cftype *cft, struct cgroup_map_cb *cb, enum stat_type type,
-               bool show_total)
+               struct cftype *cft, struct cgroup_map_cb *cb,
+               enum stat_type type, bool show_total, bool pcpu)
 {
        struct blkio_group *blkg;
        struct hlist_node *n;
@@ -1087,10 +1206,15 @@ static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
                if (blkg->dev) {
                        if (!cftype_blkg_same_policy(cft, blkg))
                                continue;
-                       spin_lock_irq(&blkg->stats_lock);
-                       cgroup_total += blkio_get_stat(blkg, cb, blkg->dev,
-                                               type);
-                       spin_unlock_irq(&blkg->stats_lock);
+                       if (pcpu)
+                               cgroup_total += blkio_get_stat_cpu(blkg, cb,
+                                               blkg->dev, type);
+                       else {
+                               spin_lock_irq(&blkg->stats_lock);
+                               cgroup_total += blkio_get_stat(blkg, cb,
+                                               blkg->dev, type);
+                               spin_unlock_irq(&blkg->stats_lock);
+                       }
                }
        }
        if (show_total)
@@ -1114,47 +1238,47 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
                switch(name) {
                case BLKIO_PROP_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_TIME, 0);
+                                               BLKIO_STAT_TIME, 0, 0);
                case BLKIO_PROP_sectors:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SECTORS, 0);
+                                               BLKIO_STAT_CPU_SECTORS, 0, 1);
                case BLKIO_PROP_io_service_bytes:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICE_BYTES, 1);
+                                       BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1);
                case BLKIO_PROP_io_serviced:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICED, 1);
+                                               BLKIO_STAT_CPU_SERVICED, 1, 1);
                case BLKIO_PROP_io_service_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICE_TIME, 1);
+                                               BLKIO_STAT_SERVICE_TIME, 1, 0);
                case BLKIO_PROP_io_wait_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_WAIT_TIME, 1);
+                                               BLKIO_STAT_WAIT_TIME, 1, 0);
                case BLKIO_PROP_io_merged:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_MERGED, 1);
+                                               BLKIO_STAT_CPU_MERGED, 1, 1);
                case BLKIO_PROP_io_queued:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_QUEUED, 1);
+                                               BLKIO_STAT_QUEUED, 1, 0);
 #ifdef CONFIG_DEBUG_BLK_CGROUP
                case BLKIO_PROP_unaccounted_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_UNACCOUNTED_TIME, 0);
+                                       BLKIO_STAT_UNACCOUNTED_TIME, 0, 0);
                case BLKIO_PROP_dequeue:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_DEQUEUE, 0);
+                                               BLKIO_STAT_DEQUEUE, 0, 0);
                case BLKIO_PROP_avg_queue_size:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_AVG_QUEUE_SIZE, 0);
+                                       BLKIO_STAT_AVG_QUEUE_SIZE, 0, 0);
                case BLKIO_PROP_group_wait_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_GROUP_WAIT_TIME, 0);
+                                       BLKIO_STAT_GROUP_WAIT_TIME, 0, 0);
                case BLKIO_PROP_idle_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_IDLE_TIME, 0);
+                                               BLKIO_STAT_IDLE_TIME, 0, 0);
                case BLKIO_PROP_empty_time:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_EMPTY_TIME, 0);
+                                               BLKIO_STAT_EMPTY_TIME, 0, 0);
 #endif
                default:
                        BUG();
@@ -1164,10 +1288,10 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
                switch(name){
                case BLKIO_THROTL_io_service_bytes:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICE_BYTES, 1);
+                                               BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1);
                case BLKIO_THROTL_io_serviced:
                        return blkio_read_blkg_stats(blkcg, cft, cb,
-                                               BLKIO_STAT_SERVICED, 1);
+                                               BLKIO_STAT_CPU_SERVICED, 1, 1);
                default:
                        BUG();
                }
index c774930cc20659de992ccebc21d35ffd1e80e234..a71d2904ffb97c1f6f2e9f9d5480d389b0ffccff 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/cgroup.h>
+#include <linux/u64_stats_sync.h>
 
 enum blkio_policy_id {
        BLKIO_POLICY_PROP = 0,          /* Proportional Bandwidth division */
@@ -36,22 +37,15 @@ enum stat_type {
         * request completion for IOs doen by this cgroup. This may not be
         * accurate when NCQ is turned on. */
        BLKIO_STAT_SERVICE_TIME = 0,
-       /* Total bytes transferred */
-       BLKIO_STAT_SERVICE_BYTES,
-       /* Total IOs serviced, post merge */
-       BLKIO_STAT_SERVICED,
        /* Total time spent waiting in scheduler queue in ns */
        BLKIO_STAT_WAIT_TIME,
-       /* Number of IOs merged */
-       BLKIO_STAT_MERGED,
        /* Number of IOs queued up */
        BLKIO_STAT_QUEUED,
        /* All the single valued stats go below this */
        BLKIO_STAT_TIME,
-       BLKIO_STAT_SECTORS,
+#ifdef CONFIG_DEBUG_BLK_CGROUP
        /* Time not charged to this cgroup */
        BLKIO_STAT_UNACCOUNTED_TIME,
-#ifdef CONFIG_DEBUG_BLK_CGROUP
        BLKIO_STAT_AVG_QUEUE_SIZE,
        BLKIO_STAT_IDLE_TIME,
        BLKIO_STAT_EMPTY_TIME,
@@ -60,6 +54,18 @@ enum stat_type {
 #endif
 };
 
+/* Per cpu stats */
+enum stat_type_cpu {
+       BLKIO_STAT_CPU_SECTORS,
+       /* Total bytes transferred */
+       BLKIO_STAT_CPU_SERVICE_BYTES,
+       /* Total IOs serviced, post merge */
+       BLKIO_STAT_CPU_SERVICED,
+       /* Number of IOs merged */
+       BLKIO_STAT_CPU_MERGED,
+       BLKIO_STAT_CPU_NR
+};
+
 enum stat_sub_type {
        BLKIO_STAT_READ = 0,
        BLKIO_STAT_WRITE,
@@ -116,11 +122,11 @@ struct blkio_cgroup {
 struct blkio_group_stats {
        /* total disk time and nr sectors dispatched by this group */
        uint64_t time;
-       uint64_t sectors;
-       /* Time not charged to this cgroup */
-       uint64_t unaccounted_time;
        uint64_t stat_arr[BLKIO_STAT_QUEUED + 1][BLKIO_STAT_TOTAL];
 #ifdef CONFIG_DEBUG_BLK_CGROUP
+       /* Time not charged to this cgroup */
+       uint64_t unaccounted_time;
+
        /* Sum of number of IOs queued across all samples */
        uint64_t avg_queue_size_sum;
        /* Count of samples taken for average */
@@ -145,6 +151,13 @@ struct blkio_group_stats {
 #endif
 };
 
+/* Per cpu blkio group stats */
+struct blkio_group_stats_cpu {
+       uint64_t sectors;
+       uint64_t stat_arr_cpu[BLKIO_STAT_CPU_NR][BLKIO_STAT_TOTAL];
+       struct u64_stats_sync syncp;
+};
+
 struct blkio_group {
        /* An rcu protected unique identifier for the group */
        void *key;
@@ -160,6 +173,8 @@ struct blkio_group {
        /* Need to serialize the stats in the case of reset/update */
        spinlock_t stats_lock;
        struct blkio_group_stats stats;
+       /* Per cpu stats pointer */
+       struct blkio_group_stats_cpu __percpu *stats_cpu;
 };
 
 struct blkio_policy_node {
@@ -295,6 +310,7 @@ extern struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk);
 extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
        struct blkio_group *blkg, void *key, dev_t dev,
        enum blkio_policy_id plid);
+extern int blkio_alloc_blkg_stats(struct blkio_group *blkg);
 extern int blkiocg_del_blkio_group(struct blkio_group *blkg);
 extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg,
                                                void *key);
@@ -322,6 +338,8 @@ static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
                struct blkio_group *blkg, void *key, dev_t dev,
                enum blkio_policy_id plid) {}
 
+static inline int blkio_alloc_blkg_stats(struct blkio_group *blkg) { return 0; }
+
 static inline int
 blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; }
 
index 3fe00a14822a203cacc0529ad0610cf5ce7dae06..c8303e9d919da239ec5f04a43e11dbe1ceeef111 100644 (file)
@@ -569,8 +569,6 @@ int blk_get_queue(struct request_queue *q)
 
 static inline void blk_free_request(struct request_queue *q, struct request *rq)
 {
-       BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
-
        if (rq->cmd_flags & REQ_ELVPRIV)
                elv_put_request(q, rq);
        mempool_free(rq, q->rq.rq_pool);
@@ -1110,14 +1108,6 @@ static bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
 {
        const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
 
-       /*
-        * Debug stuff, kill later
-        */
-       if (!rq_mergeable(req)) {
-               blk_dump_rq_flags(req, "back");
-               return false;
-       }
-
        if (!ll_back_merge_fn(q, req, bio))
                return false;
 
@@ -1132,6 +1122,7 @@ static bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
        req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
 
        drive_stat_acct(req, 0);
+       elv_bio_merged(q, req, bio);
        return true;
 }
 
@@ -1141,14 +1132,6 @@ static bool bio_attempt_front_merge(struct request_queue *q,
        const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
        sector_t sector;
 
-       /*
-        * Debug stuff, kill later
-        */
-       if (!rq_mergeable(req)) {
-               blk_dump_rq_flags(req, "front");
-               return false;
-       }
-
        if (!ll_front_merge_fn(q, req, bio))
                return false;
 
@@ -1173,6 +1156,7 @@ static bool bio_attempt_front_merge(struct request_queue *q,
        req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
 
        drive_stat_acct(req, 0);
+       elv_bio_merged(q, req, bio);
        return true;
 }
 
@@ -1258,14 +1242,12 @@ static int __make_request(struct request_queue *q, struct bio *bio)
 
        el_ret = elv_merge(q, &req, bio);
        if (el_ret == ELEVATOR_BACK_MERGE) {
-               BUG_ON(req->cmd_flags & REQ_ON_PLUG);
                if (bio_attempt_back_merge(q, req, bio)) {
                        if (!attempt_back_merge(q, req))
                                elv_merged_request(q, req, el_ret);
                        goto out_unlock;
                }
        } else if (el_ret == ELEVATOR_FRONT_MERGE) {
-               BUG_ON(req->cmd_flags & REQ_ON_PLUG);
                if (bio_attempt_front_merge(q, req, bio)) {
                        if (!attempt_front_merge(q, req))
                                elv_merged_request(q, req, el_ret);
@@ -1320,10 +1302,6 @@ get_rq:
                        if (__rq->q != q)
                                plug->should_sort = 1;
                }
-               /*
-                * Debug flag, kill later
-                */
-               req->cmd_flags |= REQ_ON_PLUG;
                list_add_tail(&req->queuelist, &plug->list);
                drive_stat_acct(req, 1);
        } else {
@@ -1550,7 +1528,8 @@ static inline void __generic_make_request(struct bio *bio)
                        goto end_io;
                }
 
-               blk_throtl_bio(q, &bio);
+               if (blk_throtl_bio(q, &bio))
+                       goto end_io;
 
                /*
                 * If bio = NULL, bio has been throttled and will be submitted
@@ -2748,7 +2727,6 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
        while (!list_empty(&list)) {
                rq = list_entry_rq(list.next);
                list_del_init(&rq->queuelist);
-               BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG));
                BUG_ON(!rq->q);
                if (rq->q != q) {
                        /*
@@ -2760,8 +2738,6 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
                        depth = 0;
                        spin_lock(q->queue_lock);
                }
-               rq->cmd_flags &= ~REQ_ON_PLUG;
-
                /*
                 * rq is already accounted, so use raw insert
                 */
index 81e31819a597bb0c6ed6dd4f781eb037c986a243..8a0e7ec056e7a3bd6db31f19ec72202ae97c581e 100644 (file)
@@ -56,7 +56,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
        spin_lock_irq(q->queue_lock);
        __elv_add_request(q, rq, where);
        __blk_run_queue(q);
-       /* the queue is stopped so it won't be plugged+unplugged */
+       /* the queue is stopped so it won't be run */
        if (rq->cmd_type == REQ_TYPE_PM_RESUME)
                q->request_fn(q);
        spin_unlock_irq(q->queue_lock);
index 6c9b5e189e624888860e5185d1d9b3479b3e49a4..bb21e4c36f70ca437162356edd87d2ce3a265a46 100644 (file)
@@ -212,13 +212,19 @@ static void flush_end_io(struct request *flush_rq, int error)
        }
 
        /*
-        * Moving a request silently to empty queue_head may stall the
-        * queue.  Kick the queue in those cases.  This function is called
-        * from request completion path and calling directly into
-        * request_fn may confuse the driver.  Always use kblockd.
+        * Kick the queue to avoid stall for two cases:
+        * 1. Moving a request silently to empty queue_head may stall the
+        * queue.
+        * 2. When flush request is running in non-queueable queue, the
+        * queue is hold. Restart the queue after flush request is finished
+        * to avoid stall.
+        * This function is called from request completion path and calling
+        * directly into request_fn may confuse the driver.  Always use
+        * kblockd.
         */
-       if (queued)
+       if (queued || q->flush_queue_delayed)
                blk_run_queue_async(q);
+       q->flush_queue_delayed = 0;
 }
 
 /**
index b791022beef3158ba02a739c061838bf57500bf5..c898049dafd54d8ea9deed98885b02db10ce43e7 100644 (file)
@@ -96,6 +96,9 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
                INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH);
                INIT_HLIST_HEAD(&ret->cic_list);
                ret->ioc_data = NULL;
+#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
+               ret->cgroup_changed = 0;
+#endif
        }
 
        return ret;
index 25de73e4759b82d624c2a89b545baf6ea859f624..78e627e2581d5a6c80ec12d9267c57c0468ecf5f 100644 (file)
@@ -9,17 +9,20 @@
 
 #include "blk.h"
 
-static void blkdev_discard_end_io(struct bio *bio, int err)
-{
-       if (err) {
-               if (err == -EOPNOTSUPP)
-                       set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
-       }
+struct bio_batch {
+       atomic_t                done;
+       unsigned long           flags;
+       struct completion       *wait;
+};
 
-       if (bio->bi_private)
-               complete(bio->bi_private);
+static void bio_batch_end_io(struct bio *bio, int err)
+{
+       struct bio_batch *bb = bio->bi_private;
 
+       if (err && (err != -EOPNOTSUPP))
+               clear_bit(BIO_UPTODATE, &bb->flags);
+       if (atomic_dec_and_test(&bb->done))
+               complete(bb->wait);
        bio_put(bio);
 }
 
@@ -41,6 +44,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
        struct request_queue *q = bdev_get_queue(bdev);
        int type = REQ_WRITE | REQ_DISCARD;
        unsigned int max_discard_sectors;
+       struct bio_batch bb;
        struct bio *bio;
        int ret = 0;
 
@@ -67,7 +71,11 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                type |= REQ_SECURE;
        }
 
-       while (nr_sects && !ret) {
+       atomic_set(&bb.done, 1);
+       bb.flags = 1 << BIO_UPTODATE;
+       bb.wait = &wait;
+
+       while (nr_sects) {
                bio = bio_alloc(gfp_mask, 1);
                if (!bio) {
                        ret = -ENOMEM;
@@ -75,9 +83,9 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                }
 
                bio->bi_sector = sector;
-               bio->bi_end_io = blkdev_discard_end_io;
+               bio->bi_end_io = bio_batch_end_io;
                bio->bi_bdev = bdev;
-               bio->bi_private = &wait;
+               bio->bi_private = &bb;
 
                if (nr_sects > max_discard_sectors) {
                        bio->bi_size = max_discard_sectors << 9;
@@ -88,45 +96,21 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                        nr_sects = 0;
                }
 
-               bio_get(bio);
+               atomic_inc(&bb.done);
                submit_bio(type, bio);
+       }
 
+       /* Wait for bios in-flight */
+       if (!atomic_dec_and_test(&bb.done))
                wait_for_completion(&wait);
 
-               if (bio_flagged(bio, BIO_EOPNOTSUPP))
-                       ret = -EOPNOTSUPP;
-               else if (!bio_flagged(bio, BIO_UPTODATE))
-                       ret = -EIO;
-               bio_put(bio);
-       }
+       if (!test_bit(BIO_UPTODATE, &bb.flags))
+               ret = -EIO;
 
        return ret;
 }
 EXPORT_SYMBOL(blkdev_issue_discard);
 
-struct bio_batch
-{
-       atomic_t                done;
-       unsigned long           flags;
-       struct completion       *wait;
-};
-
-static void bio_batch_end_io(struct bio *bio, int err)
-{
-       struct bio_batch *bb = bio->bi_private;
-
-       if (err) {
-               if (err == -EOPNOTSUPP)
-                       set_bit(BIO_EOPNOTSUPP, &bb->flags);
-               else
-                       clear_bit(BIO_UPTODATE, &bb->flags);
-       }
-       if (bb)
-               if (atomic_dec_and_test(&bb->done))
-                       complete(bb->wait);
-       bio_put(bio);
-}
-
 /**
  * blkdev_issue_zeroout - generate number of zero filed write bios
  * @bdev:      blockdev to issue
@@ -151,7 +135,6 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
        bb.flags = 1 << BIO_UPTODATE;
        bb.wait = &wait;
 
-submit:
        ret = 0;
        while (nr_sects != 0) {
                bio = bio_alloc(gfp_mask,
@@ -168,9 +151,6 @@ submit:
 
                while (nr_sects != 0) {
                        sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects);
-                       if (sz == 0)
-                               /* bio has maximum size possible */
-                               break;
                        ret = bio_add_page(bio, ZERO_PAGE(0), sz << 9, 0);
                        nr_sects -= ret >> 9;
                        sector += ret >> 9;
@@ -190,16 +170,6 @@ submit:
                /* One of bios in the batch was completed with error.*/
                ret = -EIO;
 
-       if (ret)
-               goto out;
-
-       if (test_bit(BIO_EOPNOTSUPP, &bb.flags)) {
-               ret = -EOPNOTSUPP;
-               goto out;
-       }
-       if (nr_sects != 0)
-               goto submit;
-out:
        return ret;
 }
 EXPORT_SYMBOL(blkdev_issue_zeroout);
index 1fa7692935976f4e60393e8d7289acf1c56c74c3..fa1eb0449a05f0db45de3ab8e6a01a2fc2a95238 100644 (file)
@@ -120,7 +120,7 @@ void blk_set_default_limits(struct queue_limits *lim)
        lim->discard_granularity = 0;
        lim->discard_alignment = 0;
        lim->discard_misaligned = 0;
-       lim->discard_zeroes_data = -1;
+       lim->discard_zeroes_data = 1;
        lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
        lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
        lim->alignment_offset = 0;
@@ -166,6 +166,7 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
 
        blk_set_default_limits(&q->limits);
        blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
+       q->limits.discard_zeroes_data = 0;
 
        /*
         * by default assume old behaviour and bounce for any highmem page
@@ -790,6 +791,12 @@ void blk_queue_flush(struct request_queue *q, unsigned int flush)
 }
 EXPORT_SYMBOL_GPL(blk_queue_flush);
 
+void blk_queue_flush_queueable(struct request_queue *q, bool queueable)
+{
+       q->flush_not_queueable = !queueable;
+}
+EXPORT_SYMBOL_GPL(blk_queue_flush_queueable);
+
 static int __init blk_settings_init(void)
 {
        blk_max_low_pfn = max_low_pfn - 1;
index bd236313f35d59bd08da5a3d375cc29eed6fd86f..d935bd859c87bc1c9a0e39eb61438583f91690f9 100644 (file)
@@ -152,7 +152,8 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
 
 static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
 {
-       return queue_var_show(q->limits.max_discard_sectors << 9, page);
+       return sprintf(page, "%llu\n",
+                      (unsigned long long)q->limits.max_discard_sectors << 9);
 }
 
 static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page)
index 252a81a306f7bef0179f953ab1535a4a06a40798..a62be8d0dc1b34cfdf832947856669a8ee449a84 100644 (file)
@@ -78,6 +78,8 @@ struct throtl_grp {
 
        /* Some throttle limits got updated for the group */
        int limits_changed;
+
+       struct rcu_head rcu_head;
 };
 
 struct throtl_data
@@ -88,7 +90,7 @@ struct throtl_data
        /* service tree for active throtl groups */
        struct throtl_rb_root tg_service_tree;
 
-       struct throtl_grp root_tg;
+       struct throtl_grp *root_tg;
        struct request_queue *queue;
 
        /* Total Number of queued bios on READ and WRITE lists */
@@ -151,56 +153,44 @@ static inline struct throtl_grp *throtl_ref_get_tg(struct throtl_grp *tg)
        return tg;
 }
 
-static void throtl_put_tg(struct throtl_grp *tg)
+static void throtl_free_tg(struct rcu_head *head)
 {
-       BUG_ON(atomic_read(&tg->ref) <= 0);
-       if (!atomic_dec_and_test(&tg->ref))
-               return;
+       struct throtl_grp *tg;
+
+       tg = container_of(head, struct throtl_grp, rcu_head);
+       free_percpu(tg->blkg.stats_cpu);
        kfree(tg);
 }
 
-static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
-                       struct blkio_cgroup *blkcg)
+static void throtl_put_tg(struct throtl_grp *tg)
 {
-       struct throtl_grp *tg = NULL;
-       void *key = td;
-       struct backing_dev_info *bdi = &td->queue->backing_dev_info;
-       unsigned int major, minor;
+       BUG_ON(atomic_read(&tg->ref) <= 0);
+       if (!atomic_dec_and_test(&tg->ref))
+               return;
 
        /*
-        * TODO: Speed up blkiocg_lookup_group() by maintaining a radix
-        * tree of blkg (instead of traversing through hash list all
-        * the time.
+        * A group is freed in rcu manner. But having an rcu lock does not
+        * mean that one can access all the fields of blkg and assume these
+        * are valid. For example, don't try to follow throtl_data and
+        * request queue links.
+        *
+        * Having a reference to blkg under an rcu allows acess to only
+        * values local to groups like group stats and group rate limits
         */
+       call_rcu(&tg->rcu_head, throtl_free_tg);
+}
 
-       /*
-        * This is the common case when there are no blkio cgroups.
-        * Avoid lookup in this case
-        */
-       if (blkcg == &blkio_root_cgroup)
-               tg = &td->root_tg;
-       else
-               tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
-
-       /* Fill in device details for root group */
-       if (tg && !tg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
-               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
-               tg->blkg.dev = MKDEV(major, minor);
-               goto done;
-       }
-
-       if (tg)
-               goto done;
-
-       tg = kzalloc_node(sizeof(*tg), GFP_ATOMIC, td->queue->node);
-       if (!tg)
-               goto done;
-
+static void throtl_init_group(struct throtl_grp *tg)
+{
        INIT_HLIST_NODE(&tg->tg_node);
        RB_CLEAR_NODE(&tg->rb_node);
        bio_list_init(&tg->bio_lists[0]);
        bio_list_init(&tg->bio_lists[1]);
-       td->limits_changed = false;
+       tg->limits_changed = false;
+
+       /* Practically unlimited BW */
+       tg->bps[0] = tg->bps[1] = -1;
+       tg->iops[0] = tg->iops[1] = -1;
 
        /*
         * Take the initial reference that will be released on destroy
@@ -209,33 +199,181 @@ static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
         * exit or cgroup deletion path depending on who is exiting first.
         */
        atomic_set(&tg->ref, 1);
+}
+
+/* Should be called with rcu read lock held (needed for blkcg) */
+static void
+throtl_add_group_to_td_list(struct throtl_data *td, struct throtl_grp *tg)
+{
+       hlist_add_head(&tg->tg_node, &td->tg_list);
+       td->nr_undestroyed_grps++;
+}
+
+static void
+__throtl_tg_fill_dev_details(struct throtl_data *td, struct throtl_grp *tg)
+{
+       struct backing_dev_info *bdi = &td->queue->backing_dev_info;
+       unsigned int major, minor;
+
+       if (!tg || tg->blkg.dev)
+               return;
+
+       /*
+        * Fill in device details for a group which might not have been
+        * filled at group creation time as queue was being instantiated
+        * and driver had not attached a device yet
+        */
+       if (bdi->dev && dev_name(bdi->dev)) {
+               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+               tg->blkg.dev = MKDEV(major, minor);
+       }
+}
+
+/*
+ * Should be called with without queue lock held. Here queue lock will be
+ * taken rarely. It will be taken only once during life time of a group
+ * if need be
+ */
+static void
+throtl_tg_fill_dev_details(struct throtl_data *td, struct throtl_grp *tg)
+{
+       if (!tg || tg->blkg.dev)
+               return;
+
+       spin_lock_irq(td->queue->queue_lock);
+       __throtl_tg_fill_dev_details(td, tg);
+       spin_unlock_irq(td->queue->queue_lock);
+}
+
+static void throtl_init_add_tg_lists(struct throtl_data *td,
+                       struct throtl_grp *tg, struct blkio_cgroup *blkcg)
+{
+       __throtl_tg_fill_dev_details(td, tg);
 
        /* Add group onto cgroup list */
-       sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
        blkiocg_add_blkio_group(blkcg, &tg->blkg, (void *)td,
-                               MKDEV(major, minor), BLKIO_POLICY_THROTL);
+                               tg->blkg.dev, BLKIO_POLICY_THROTL);
 
        tg->bps[READ] = blkcg_get_read_bps(blkcg, tg->blkg.dev);
        tg->bps[WRITE] = blkcg_get_write_bps(blkcg, tg->blkg.dev);
        tg->iops[READ] = blkcg_get_read_iops(blkcg, tg->blkg.dev);
        tg->iops[WRITE] = blkcg_get_write_iops(blkcg, tg->blkg.dev);
 
-       hlist_add_head(&tg->tg_node, &td->tg_list);
-       td->nr_undestroyed_grps++;
-done:
+       throtl_add_group_to_td_list(td, tg);
+}
+
+/* Should be called without queue lock and outside of rcu period */
+static struct throtl_grp *throtl_alloc_tg(struct throtl_data *td)
+{
+       struct throtl_grp *tg = NULL;
+       int ret;
+
+       tg = kzalloc_node(sizeof(*tg), GFP_ATOMIC, td->queue->node);
+       if (!tg)
+               return NULL;
+
+       ret = blkio_alloc_blkg_stats(&tg->blkg);
+
+       if (ret) {
+               kfree(tg);
+               return NULL;
+       }
+
+       throtl_init_group(tg);
        return tg;
 }
 
-static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
+static struct
+throtl_grp *throtl_find_tg(struct throtl_data *td, struct blkio_cgroup *blkcg)
 {
        struct throtl_grp *tg = NULL;
+       void *key = td;
+
+       /*
+        * This is the common case when there are no blkio cgroups.
+        * Avoid lookup in this case
+        */
+       if (blkcg == &blkio_root_cgroup)
+               tg = td->root_tg;
+       else
+               tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
+
+       __throtl_tg_fill_dev_details(td, tg);
+       return tg;
+}
+
+/*
+ * This function returns with queue lock unlocked in case of error, like
+ * request queue is no more
+ */
+static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
+{
+       struct throtl_grp *tg = NULL, *__tg = NULL;
        struct blkio_cgroup *blkcg;
+       struct request_queue *q = td->queue;
 
        rcu_read_lock();
        blkcg = task_blkio_cgroup(current);
-       tg = throtl_find_alloc_tg(td, blkcg);
-       if (!tg)
-               tg = &td->root_tg;
+       tg = throtl_find_tg(td, blkcg);
+       if (tg) {
+               rcu_read_unlock();
+               return tg;
+       }
+
+       /*
+        * Need to allocate a group. Allocation of group also needs allocation
+        * of per cpu stats which in-turn takes a mutex() and can block. Hence
+        * we need to drop rcu lock and queue_lock before we call alloc
+        *
+        * Take the request queue reference to make sure queue does not
+        * go away once we return from allocation.
+        */
+       blk_get_queue(q);
+       rcu_read_unlock();
+       spin_unlock_irq(q->queue_lock);
+
+       tg = throtl_alloc_tg(td);
+       /*
+        * We might have slept in group allocation. Make sure queue is not
+        * dead
+        */
+       if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) {
+               blk_put_queue(q);
+               if (tg)
+                       kfree(tg);
+
+               return ERR_PTR(-ENODEV);
+       }
+       blk_put_queue(q);
+
+       /* Group allocated and queue is still alive. take the lock */
+       spin_lock_irq(q->queue_lock);
+
+       /*
+        * Initialize the new group. After sleeping, read the blkcg again.
+        */
+       rcu_read_lock();
+       blkcg = task_blkio_cgroup(current);
+
+       /*
+        * If some other thread already allocated the group while we were
+        * not holding queue lock, free up the group
+        */
+       __tg = throtl_find_tg(td, blkcg);
+
+       if (__tg) {
+               kfree(tg);
+               rcu_read_unlock();
+               return __tg;
+       }
+
+       /* Group allocation failed. Account the IO to root group */
+       if (!tg) {
+               tg = td->root_tg;
+               return tg;
+       }
+
+       throtl_init_add_tg_lists(td, tg, blkcg);
        rcu_read_unlock();
        return tg;
 }
@@ -544,6 +682,12 @@ static bool tg_with_in_bps_limit(struct throtl_data *td, struct throtl_grp *tg,
        return 0;
 }
 
+static bool tg_no_rule_group(struct throtl_grp *tg, bool rw) {
+       if (tg->bps[rw] == -1 && tg->iops[rw] == -1)
+               return 1;
+       return 0;
+}
+
 /*
  * Returns whether one can dispatch a bio or not. Also returns approx number
  * of jiffies to wait before this bio is with-in IO rate and can be dispatched
@@ -608,10 +752,6 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
        tg->bytes_disp[rw] += bio->bi_size;
        tg->io_disp[rw]++;
 
-       /*
-        * TODO: This will take blkg->stats_lock. Figure out a way
-        * to avoid this cost.
-        */
        blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size, rw, sync);
 }
 
@@ -989,15 +1129,51 @@ int blk_throtl_bio(struct request_queue *q, struct bio **biop)
        struct throtl_grp *tg;
        struct bio *bio = *biop;
        bool rw = bio_data_dir(bio), update_disptime = true;
+       struct blkio_cgroup *blkcg;
 
        if (bio->bi_rw & REQ_THROTTLED) {
                bio->bi_rw &= ~REQ_THROTTLED;
                return 0;
        }
 
+       /*
+        * A throtl_grp pointer retrieved under rcu can be used to access
+        * basic fields like stats and io rates. If a group has no rules,
+        * just update the dispatch stats in lockless manner and return.
+        */
+
+       rcu_read_lock();
+       blkcg = task_blkio_cgroup(current);
+       tg = throtl_find_tg(td, blkcg);
+       if (tg) {
+               throtl_tg_fill_dev_details(td, tg);
+
+               if (tg_no_rule_group(tg, rw)) {
+                       blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size,
+                                       rw, bio->bi_rw & REQ_SYNC);
+                       rcu_read_unlock();
+                       return 0;
+               }
+       }
+       rcu_read_unlock();
+
+       /*
+        * Either group has not been allocated yet or it is not an unlimited
+        * IO group
+        */
+
        spin_lock_irq(q->queue_lock);
        tg = throtl_get_tg(td);
 
+       if (IS_ERR(tg)) {
+               if (PTR_ERR(tg) == -ENODEV) {
+                       /*
+                        * Queue is gone. No queue lock held here.
+                        */
+                       return -ENODEV;
+               }
+       }
+
        if (tg->nr_queued[rw]) {
                /*
                 * There is already another bio queued in same dir. No
@@ -1060,39 +1236,24 @@ int blk_throtl_init(struct request_queue *q)
        INIT_HLIST_HEAD(&td->tg_list);
        td->tg_service_tree = THROTL_RB_ROOT;
        td->limits_changed = false;
+       INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work);
 
-       /* Init root group */
-       tg = &td->root_tg;
-       INIT_HLIST_NODE(&tg->tg_node);
-       RB_CLEAR_NODE(&tg->rb_node);
-       bio_list_init(&tg->bio_lists[0]);
-       bio_list_init(&tg->bio_lists[1]);
-
-       /* Practically unlimited BW */
-       tg->bps[0] = tg->bps[1] = -1;
-       tg->iops[0] = tg->iops[1] = -1;
-       td->limits_changed = false;
+       /* alloc and Init root group. */
+       td->queue = q;
+       tg = throtl_alloc_tg(td);
 
-       /*
-        * Set root group reference to 2. One reference will be dropped when
-        * all groups on tg_list are being deleted during queue exit. Other
-        * reference will remain there as we don't want to delete this group
-        * as it is statically allocated and gets destroyed when throtl_data
-        * goes away.
-        */
-       atomic_set(&tg->ref, 2);
-       hlist_add_head(&tg->tg_node, &td->tg_list);
-       td->nr_undestroyed_grps++;
+       if (!tg) {
+               kfree(td);
+               return -ENOMEM;
+       }
 
-       INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work);
+       td->root_tg = tg;
 
        rcu_read_lock();
-       blkiocg_add_blkio_group(&blkio_root_cgroup, &tg->blkg, (void *)td,
-                                       0, BLKIO_POLICY_THROTL);
+       throtl_init_add_tg_lists(td, tg, &blkio_root_cgroup);
        rcu_read_unlock();
 
        /* Attach throtl data to request queue */
-       td->queue = q;
        q->td = td;
        return 0;
 }
index 61263463e38e17be7c7f742f0bbe9233eec2ecd2..d6586287adc9ccf44e0adc556b552c7b1404ca4b 100644 (file)
@@ -62,7 +62,28 @@ static inline struct request *__elv_next_request(struct request_queue *q)
                        return rq;
                }
 
-               if (!q->elevator->ops->elevator_dispatch_fn(q, 0))
+               /*
+                * Flush request is running and flush request isn't queueable
+                * in the drive, we can hold the queue till flush request is
+                * finished. Even we don't do this, driver can't dispatch next
+                * requests and will requeue them. And this can improve
+                * throughput too. For example, we have request flush1, write1,
+                * flush 2. flush1 is dispatched, then queue is hold, write1
+                * isn't inserted to queue. After flush1 is finished, flush2
+                * will be dispatched. Since disk cache is already clean,
+                * flush2 will be finished very soon, so looks like flush2 is
+                * folded to flush1.
+                * Since the queue is hold, a flag is set to indicate the queue
+                * should be restarted later. Please see flush_end_io() for
+                * details.
+                */
+               if (q->flush_pending_idx != q->flush_running_idx &&
+                               !queue_flush_queueable(q)) {
+                       q->flush_queue_delayed = 1;
+                       return NULL;
+               }
+               if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags) ||
+                   !q->elevator->ops->elevator_dispatch_fn(q, 0))
                        return NULL;
        }
 }
index ab7a9e6a9b1cb12c1952f5fd725ca2ea0dd20fd1..7c52d6888924c53215579b1b663083be376dfa48 100644 (file)
@@ -300,7 +300,9 @@ struct cfq_data {
 
        /* List of cfq groups being managed on this device*/
        struct hlist_head cfqg_list;
-       struct rcu_head rcu;
+
+       /* Number of groups which are on blkcg->blkg_list */
+       unsigned int nr_blkcg_linked_grps;
 };
 
 static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd);
@@ -665,15 +667,11 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2,
        if (rq2 == NULL)
                return rq1;
 
-       if (rq_is_sync(rq1) && !rq_is_sync(rq2))
-               return rq1;
-       else if (rq_is_sync(rq2) && !rq_is_sync(rq1))
-               return rq2;
-       if ((rq1->cmd_flags & REQ_META) && !(rq2->cmd_flags & REQ_META))
-               return rq1;
-       else if ((rq2->cmd_flags & REQ_META) &&
-                !(rq1->cmd_flags & REQ_META))
-               return rq2;
+       if (rq_is_sync(rq1) != rq_is_sync(rq2))
+               return rq_is_sync(rq1) ? rq1 : rq2;
+
+       if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_META)
+               return rq1->cmd_flags & REQ_META ? rq1 : rq2;
 
        s1 = blk_rq_pos(rq1);
        s2 = blk_rq_pos(rq2);
@@ -1014,28 +1012,47 @@ void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
        cfqg->needs_update = true;
 }
 
-static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd,
-               struct blkio_cgroup *blkcg, int create)
+static void cfq_init_add_cfqg_lists(struct cfq_data *cfqd,
+                       struct cfq_group *cfqg, struct blkio_cgroup *blkcg)
 {
-       struct cfq_group *cfqg = NULL;
-       void *key = cfqd;
-       int i, j;
-       struct cfq_rb_root *st;
        struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info;
        unsigned int major, minor;
 
-       cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
-       if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
+       /*
+        * Add group onto cgroup list. It might happen that bdi->dev is
+        * not initialized yet. Initialize this new group without major
+        * and minor info and this info will be filled in once a new thread
+        * comes for IO.
+        */
+       if (bdi->dev) {
                sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
-               cfqg->blkg.dev = MKDEV(major, minor);
-               goto done;
-       }
-       if (cfqg || !create)
-               goto done;
+               cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg,
+                                       (void *)cfqd, MKDEV(major, minor));
+       } else
+               cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg,
+                                       (void *)cfqd, 0);
+
+       cfqd->nr_blkcg_linked_grps++;
+       cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev);
+
+       /* Add group on cfqd list */
+       hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
+}
+
+/*
+ * Should be called from sleepable context. No request queue lock as per
+ * cpu stats are allocated dynamically and alloc_percpu needs to be called
+ * from sleepable context.
+ */
+static struct cfq_group * cfq_alloc_cfqg(struct cfq_data *cfqd)
+{
+       struct cfq_group *cfqg = NULL;
+       int i, j, ret;
+       struct cfq_rb_root *st;
 
        cfqg = kzalloc_node(sizeof(*cfqg), GFP_ATOMIC, cfqd->queue->node);
        if (!cfqg)
-               goto done;
+               return NULL;
 
        for_each_cfqg_st(cfqg, i, j, st)
                *st = CFQ_RB_ROOT;
@@ -1049,43 +1066,94 @@ static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd,
         */
        cfqg->ref = 1;
 
+       ret = blkio_alloc_blkg_stats(&cfqg->blkg);
+       if (ret) {
+               kfree(cfqg);
+               return NULL;
+       }
+
+       return cfqg;
+}
+
+static struct cfq_group *
+cfq_find_cfqg(struct cfq_data *cfqd, struct blkio_cgroup *blkcg)
+{
+       struct cfq_group *cfqg = NULL;
+       void *key = cfqd;
+       struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info;
+       unsigned int major, minor;
+
        /*
-        * Add group onto cgroup list. It might happen that bdi->dev is
-        * not initialized yet. Initialize this new group without major
-        * and minor info and this info will be filled in once a new thread
-        * comes for IO. See code above.
+        * This is the common case when there are no blkio cgroups.
+        * Avoid lookup in this case
         */
-       if (bdi->dev) {
-               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
-               cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
-                                       MKDEV(major, minor));
-       } else
-               cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
-                                       0);
-
-       cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev);
+       if (blkcg == &blkio_root_cgroup)
+               cfqg = &cfqd->root_group;
+       else
+               cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
 
-       /* Add group on cfqd list */
-       hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
+       if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
+               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+               cfqg->blkg.dev = MKDEV(major, minor);
+       }
 
-done:
        return cfqg;
 }
 
 /*
- * Search for the cfq group current task belongs to. If create = 1, then also
- * create the cfq group if it does not exist. request_queue lock must be held.
+ * Search for the cfq group current task belongs to. request_queue lock must
+ * be held.
  */
-static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
+static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd)
 {
        struct blkio_cgroup *blkcg;
-       struct cfq_group *cfqg = NULL;
+       struct cfq_group *cfqg = NULL, *__cfqg = NULL;
+       struct request_queue *q = cfqd->queue;
 
        rcu_read_lock();
        blkcg = task_blkio_cgroup(current);
-       cfqg = cfq_find_alloc_cfqg(cfqd, blkcg, create);
-       if (!cfqg && create)
+       cfqg = cfq_find_cfqg(cfqd, blkcg);
+       if (cfqg) {
+               rcu_read_unlock();
+               return cfqg;
+       }
+
+       /*
+        * Need to allocate a group. Allocation of group also needs allocation
+        * of per cpu stats which in-turn takes a mutex() and can block. Hence
+        * we need to drop rcu lock and queue_lock before we call alloc.
+        *
+        * Not taking any queue reference here and assuming that queue is
+        * around by the time we return. CFQ queue allocation code does
+        * the same. It might be racy though.
+        */
+
+       rcu_read_unlock();
+       spin_unlock_irq(q->queue_lock);
+
+       cfqg = cfq_alloc_cfqg(cfqd);
+
+       spin_lock_irq(q->queue_lock);
+
+       rcu_read_lock();
+       blkcg = task_blkio_cgroup(current);
+
+       /*
+        * If some other thread already allocated the group while we were
+        * not holding queue lock, free up the group
+        */
+       __cfqg = cfq_find_cfqg(cfqd, blkcg);
+
+       if (__cfqg) {
+               kfree(cfqg);
+               rcu_read_unlock();
+               return __cfqg;
+       }
+
+       if (!cfqg)
                cfqg = &cfqd->root_group;
+
+       cfq_init_add_cfqg_lists(cfqd, cfqg, blkcg);
        rcu_read_unlock();
        return cfqg;
 }
@@ -1118,6 +1186,7 @@ static void cfq_put_cfqg(struct cfq_group *cfqg)
                return;
        for_each_cfqg_st(cfqg, i, j, st)
                BUG_ON(!RB_EMPTY_ROOT(&st->rb));
+       free_percpu(cfqg->blkg.stats_cpu);
        kfree(cfqg);
 }
 
@@ -1176,7 +1245,7 @@ void cfq_unlink_blkio_group(void *key, struct blkio_group *blkg)
 }
 
 #else /* GROUP_IOSCHED */
-static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
+static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd)
 {
        return &cfqd->root_group;
 }
@@ -1210,7 +1279,6 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        struct cfq_rb_root *service_tree;
        int left;
        int new_cfqq = 1;
-       int group_changed = 0;
 
        service_tree = service_tree_for(cfqq->cfqg, cfqq_prio(cfqq),
                                                cfqq_type(cfqq));
@@ -1281,7 +1349,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        rb_link_node(&cfqq->rb_node, parent, p);
        rb_insert_color(&cfqq->rb_node, &service_tree->rb);
        service_tree->count++;
-       if ((add_front || !new_cfqq) && !group_changed)
+       if (add_front || !new_cfqq)
                return;
        cfq_group_notify_queue_add(cfqd, cfqq->cfqg);
 }
@@ -2029,7 +2097,7 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 
        WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
 
-       return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
+       return 2 * base_rq * (IOPRIO_BE_NR - cfqq->ioprio);
 }
 
 /*
@@ -2911,7 +2979,7 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync,
        struct cfq_group *cfqg;
 
 retry:
-       cfqg = cfq_get_cfqg(cfqd, 1);
+       cfqg = cfq_get_cfqg(cfqd);
        cic = cfq_cic_lookup(cfqd, ioc);
        /* cic always exists here */
        cfqq = cic_to_cfqq(cic, is_sync);
@@ -3815,15 +3883,11 @@ static void cfq_put_async_queues(struct cfq_data *cfqd)
                cfq_put_queue(cfqd->async_idle_cfqq);
 }
 
-static void cfq_cfqd_free(struct rcu_head *head)
-{
-       kfree(container_of(head, struct cfq_data, rcu));
-}
-
 static void cfq_exit_queue(struct elevator_queue *e)
 {
        struct cfq_data *cfqd = e->elevator_data;
        struct request_queue *q = cfqd->queue;
+       bool wait = false;
 
        cfq_shutdown_timer_wq(cfqd);
 
@@ -3842,7 +3906,13 @@ static void cfq_exit_queue(struct elevator_queue *e)
 
        cfq_put_async_queues(cfqd);
        cfq_release_cfq_groups(cfqd);
-       cfq_blkiocg_del_blkio_group(&cfqd->root_group.blkg);
+
+       /*
+        * If there are groups which we could not unlink from blkcg list,
+        * wait for a rcu period for them to be freed.
+        */
+       if (cfqd->nr_blkcg_linked_grps)
+               wait = true;
 
        spin_unlock_irq(q->queue_lock);
 
@@ -3852,8 +3922,25 @@ static void cfq_exit_queue(struct elevator_queue *e)
        ida_remove(&cic_index_ida, cfqd->cic_index);
        spin_unlock(&cic_index_lock);
 
-       /* Wait for cfqg->blkg->key accessors to exit their grace periods. */
-       call_rcu(&cfqd->rcu, cfq_cfqd_free);
+       /*
+        * Wait for cfqg->blkg->key accessors to exit their grace periods.
+        * Do this wait only if there are other unlinked groups out
+        * there. This can happen if cgroup deletion path claimed the
+        * responsibility of cleaning up a group before queue cleanup code
+        * get to the group.
+        *
+        * Do not call synchronize_rcu() unconditionally as there are drivers
+        * which create/delete request queue hundreds of times during scan/boot
+        * and synchronize_rcu() can take significant time and slow down boot.
+        */
+       if (wait)
+               synchronize_rcu();
+
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+       /* Free up per cpu stats for root group */
+       free_percpu(cfqd->root_group.blkg.stats_cpu);
+#endif
+       kfree(cfqd);
 }
 
 static int cfq_alloc_cic_index(void)
@@ -3886,8 +3973,12 @@ static void *cfq_init_queue(struct request_queue *q)
                return NULL;
 
        cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
-       if (!cfqd)
+       if (!cfqd) {
+               spin_lock(&cic_index_lock);
+               ida_remove(&cic_index_ida, i);
+               spin_unlock(&cic_index_lock);
                return NULL;
+       }
 
        /*
         * Don't need take queue_lock in the routine, since we are
@@ -3909,14 +4000,29 @@ static void *cfq_init_queue(struct request_queue *q)
 
 #ifdef CONFIG_CFQ_GROUP_IOSCHED
        /*
-        * Take a reference to root group which we never drop. This is just
-        * to make sure that cfq_put_cfqg() does not try to kfree root group
+        * Set root group reference to 2. One reference will be dropped when
+        * all groups on cfqd->cfqg_list are being deleted during queue exit.
+        * Other reference will remain there as we don't want to delete this
+        * group as it is statically allocated and gets destroyed when
+        * throtl_data goes away.
         */
-       cfqg->ref = 1;
+       cfqg->ref = 2;
+
+       if (blkio_alloc_blkg_stats(&cfqg->blkg)) {
+               kfree(cfqg);
+               kfree(cfqd);
+               return NULL;
+       }
+
        rcu_read_lock();
+
        cfq_blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg,
                                        (void *)cfqd, 0);
        rcu_read_unlock();
+       cfqd->nr_blkcg_linked_grps++;
+
+       /* Add group on cfqd->cfqg_list */
+       hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
 #endif
        /*
         * Not strictly needed (since RB_ROOT just clears the node and we
index 45ca1e34f58249ff5b3838c0ec89fbc1c6ea2bb7..b0b38ce0dcb6ec4cca1cbf28454e834cf3f1073e 100644 (file)
@@ -155,13 +155,8 @@ static struct elevator_type *elevator_get(const char *name)
 
        e = elevator_find(name);
        if (!e) {
-               char elv[ELV_NAME_MAX + strlen("-iosched")];
-
                spin_unlock(&elv_list_lock);
-
-               snprintf(elv, sizeof(elv), "%s-iosched", name);
-
-               request_module("%s", elv);
+               request_module("%s-iosched", name);
                spin_lock(&elv_list_lock);
                e = elevator_find(name);
        }
@@ -421,8 +416,6 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
        struct list_head *entry;
        int stop_flags;
 
-       BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
-
        if (q->last_merge == rq)
                q->last_merge = NULL;
 
@@ -661,8 +654,6 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
 
        rq->q = q;
 
-       BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
-
        if (rq->cmd_flags & REQ_SOFTBARRIER) {
                /* barriers are scheduling boundary, update end_sector */
                if (rq->cmd_type == REQ_TYPE_FS ||
index 61631edfecc208d611d1d93b6f069e440e2223bc..3bb154d8c8cc778713c28e0d335282cb715594a2 100644 (file)
@@ -54,6 +54,8 @@ source "drivers/spi/Kconfig"
 
 source "drivers/pps/Kconfig"
 
+source "drivers/ptp/Kconfig"
+
 source "drivers/gpio/Kconfig"
 
 source "drivers/w1/Kconfig"
index 145aeadb6c034d4e058ea782c64d90775879c20c..6b17f5864340c37f4ab548e7243f95ca2128c4d5 100644 (file)
@@ -75,6 +75,7 @@ obj-$(CONFIG_I2O)             += message/
 obj-$(CONFIG_RTC_LIB)          += rtc/
 obj-y                          += i2c/ media/
 obj-$(CONFIG_PPS)              += pps/
+obj-$(CONFIG_PTP_1588_CLOCK)   += ptp/
 obj-$(CONFIG_W1)               += w1/
 obj-$(CONFIG_POWER_SUPPLY)     += power/
 obj-$(CONFIG_HWMON)            += hwmon/
@@ -94,7 +95,7 @@ obj-$(CONFIG_CPU_IDLE)                += cpuidle/
 obj-$(CONFIG_DMA_ENGINE)       += dma/
 obj-$(CONFIG_MMC)              += mmc/
 obj-$(CONFIG_MEMSTICK)         += memstick/
-obj-$(CONFIG_NEW_LEDS)         += leds/
+obj-y                          += leds/
 obj-$(CONFIG_INFINIBAND)       += infiniband/
 obj-$(CONFIG_SGI_SN)           += sn/
 obj-y                          += firmware/
index 3a17ca5fff6f022d207107ff741b6b22ba300190..bc2218db5ba9b2661e1f0f1261be48a354973efb 100644 (file)
@@ -73,17 +73,6 @@ config ACPI_PROCFS_POWER
 
          Say N to delete power /proc/acpi/ directories that have moved to /sys/
 
-config ACPI_POWER_METER
-       tristate "ACPI 4.0 power meter"
-       depends on HWMON
-       help
-         This driver exposes ACPI 4.0 power meters as hardware monitoring
-         devices.  Say Y (or M) if you have a computer with ACPI 4.0 firmware
-         and a power meter.
-
-         To compile this driver as a module, choose M here:
-         the module will be called power-meter.
-
 config ACPI_EC_DEBUGFS
        tristate "EC read/write access through /sys/kernel/debug/ec"
        default n
index d113fa5100b20331d8b52d548cb07fcf5f281885..b66fbb2fc85fed5d414d57e7faa68676c1dfd5e7 100644 (file)
@@ -59,7 +59,6 @@ obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
 obj-$(CONFIG_ACPI_BATTERY)     += battery.o
 obj-$(CONFIG_ACPI_SBS)         += sbshc.o
 obj-$(CONFIG_ACPI_SBS)         += sbs.o
-obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
 obj-$(CONFIG_ACPI_HED)         += hed.o
 obj-$(CONFIG_ACPI_EC_DEBUGFS)  += ec_sys.o
 
index 096aebfe7f325aae2e39cb36c9537a53a61b3bae..f74b2ea11f21128dc9c0beff600f18a57d7fbea0 100644 (file)
@@ -101,6 +101,14 @@ static DEFINE_MUTEX(einj_mutex);
 
 static struct einj_parameter *einj_param;
 
+#ifndef writeq
+static inline void writeq(__u64 val, volatile void __iomem *addr)
+{
+       writel(val, addr);
+       writel(val >> 32, addr+4);
+}
+#endif
+
 static void einj_exec_ctx_init(struct apei_exec_context *ctx)
 {
        apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),
index 542e5390389120de7ecd7da4cb7bd059baa18b01..7489b89c300fc3b0ab2f0a55c2bc09ead5e2c738 100644 (file)
@@ -280,9 +280,11 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
        case 32:
                *val = readl(addr);
                break;
+#ifdef readq
        case 64:
                *val = readq(addr);
                break;
+#endif
        default:
                return -EINVAL;
        }
@@ -307,9 +309,11 @@ static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
        case 32:
                writel(val, addr);
                break;
+#ifdef writeq
        case 64:
                writeq(val, addr);
                break;
+#endif
        default:
                return -EINVAL;
        }
index 7025593a58c89d39cb3ff260801b242730d8fdf2..d74926e0939e9f9362bcfa09e8301a105bdfb76b 100644 (file)
@@ -603,6 +603,10 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
        if (ret)
                goto err_out;
 
+       /* Hard-coded primecell ID instead of plug-n-play */
+       if (dev->periphid != 0)
+               goto skip_probe;
+
        /*
         * Dynamically calculate the size of the resource
         * and use this for iomap
@@ -643,6 +647,7 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
        if (ret)
                goto err_release;
 
+ skip_probe:
        ret = device_add(&dev->dev);
        if (ret)
                goto err_release;
index 30ea95f43e7910cf8f4cdc1742d4213e53240fb5..d51f9795c064bbc20b1b4c2a48bc277f09980060 100644 (file)
@@ -1089,21 +1089,21 @@ static int atapi_drain_needed(struct request *rq)
 static int ata_scsi_dev_config(struct scsi_device *sdev,
                               struct ata_device *dev)
 {
+       struct request_queue *q = sdev->request_queue;
+
        if (!ata_id_has_unload(dev->id))
                dev->flags |= ATA_DFLAG_NO_UNLOAD;
 
        /* configure max sectors */
-       blk_queue_max_hw_sectors(sdev->request_queue, dev->max_sectors);
+       blk_queue_max_hw_sectors(q, dev->max_sectors);
 
        if (dev->class == ATA_DEV_ATAPI) {
-               struct request_queue *q = sdev->request_queue;
                void *buf;
 
                sdev->sector_size = ATA_SECT_SIZE;
 
                /* set DMA padding */
-               blk_queue_update_dma_pad(sdev->request_queue,
-                                        ATA_DMA_PAD_SZ - 1);
+               blk_queue_update_dma_pad(q, ATA_DMA_PAD_SZ - 1);
 
                /* configure draining */
                buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL);
@@ -1131,8 +1131,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                        "sector_size=%u > PAGE_SIZE, PIO may malfunction\n",
                        sdev->sector_size);
 
-       blk_queue_update_dma_alignment(sdev->request_queue,
-                                      sdev->sector_size - 1);
+       blk_queue_update_dma_alignment(q, sdev->sector_size - 1);
 
        if (dev->flags & ATA_DFLAG_AN)
                set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
@@ -1145,6 +1144,8 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
        }
 
+       blk_queue_flush_queueable(q, false);
+
        dev->sdev = sdev;
        return 0;
 }
index b3b72d64e80594bdc7527fcf0273dee0fd41e8bf..793f796c4da3e1cd20143e1266d41246f2289b73 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/memory.h>
+#include <linux/vmstat.h>
 #include <linux/node.h>
 #include <linux/hugetlb.h>
 #include <linux/compaction.h>
@@ -179,11 +180,14 @@ static ssize_t node_read_vmstat(struct sys_device *dev,
                                struct sysdev_attribute *attr, char *buf)
 {
        int nid = dev->id;
-       return sprintf(buf,
-               "nr_written %lu\n"
-               "nr_dirtied %lu\n",
-               node_page_state(nid, NR_WRITTEN),
-               node_page_state(nid, NR_DIRTIED));
+       int i;
+       int n = 0;
+
+       for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
+               n += sprintf(buf+n, "%s %lu\n", vmstat_text[i],
+                            node_page_state(nid, i));
+
+       return n;
 }
 static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
 
index 99dd36e8500b8df8706885bcc2d9dc31694e73cb..ffd8797faf4f0d3a10bcd49dbef7264e399347dd 100644 (file)
@@ -171,6 +171,7 @@ static void bcma_host_pci_remove(struct pci_dev *dev)
 }
 
 static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
index 83c32cb72582bd6a1c33524ff61bdc757e76d6f2..717d6e4e18d3d08086fd2d5365574adbd613aef8 100644 (file)
@@ -470,6 +470,27 @@ config XEN_BLKDEV_FRONTEND
          block device driver.  It communicates with a back-end driver
          in another domain which drives the actual block device.
 
+config XEN_BLKDEV_BACKEND
+       tristate "Block-device backend driver"
+       depends on XEN_BACKEND
+       help
+         The block-device backend driver allows the kernel to export its
+         block devices to other guests via a high-performance shared-memory
+         interface.
+
+         The corresponding Linux frontend driver is enabled by the
+         CONFIG_XEN_BLKDEV_FRONTEND configuration option.
+
+         The backend driver attaches itself to a any block device specified
+         in the XenBus configuration. There are no limits to what the block
+         device as long as it has a major and minor.
+
+         If you are compiling a kernel to run in a Xen block backend driver
+         domain (often this is domain 0) you should say Y here. To
+         compile this driver as a module, chose M here: the module
+         will be called xen-blkback.
+
+
 config VIRTIO_BLK
        tristate "Virtio block driver (EXPERIMENTAL)"
        depends on EXPERIMENTAL && VIRTIO
index 40528ba56d1bf1a1a2db7c2728b10219b98cd029..76646e9a1c91528617c22e2c3f429201531acdf4 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_BLK_DEV_UB)      += ub.o
 obj-$(CONFIG_BLK_DEV_HD)       += hd.o
 
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += xen-blkfront.o
+obj-$(CONFIG_XEN_BLKDEV_BACKEND)       += xen-blkback/
 obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/
 obj-$(CONFIG_BLK_DEV_RBD)     += rbd.o
 
index 9bf13988f1a2f813ff20d6d65d5c9dd22426579e..8f4ef656a1af4ca435ff3ecc5e0d6079e6a1e34d 100644 (file)
@@ -64,6 +64,10 @@ MODULE_DESCRIPTION("Driver for HP Smart Array Controllers");
 MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers");
 MODULE_VERSION("3.6.26");
 MODULE_LICENSE("GPL");
+static int cciss_tape_cmds = 6;
+module_param(cciss_tape_cmds, int, 0644);
+MODULE_PARM_DESC(cciss_tape_cmds,
+       "number of commands to allocate for tape devices (default: 6)");
 
 static DEFINE_MUTEX(cciss_mutex);
 static struct proc_dir_entry *proc_cciss;
@@ -194,6 +198,8 @@ static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev,
 static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
        unsigned long *memory_bar);
 static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag);
+static __devinit int write_driver_ver_to_cfgtable(
+       CfgTable_struct __iomem *cfgtable);
 
 /* performant mode helper functions */
 static void  calc_bucket_map(int *bucket, int num_buckets, int nsgs,
@@ -556,7 +562,7 @@ static void __devinit cciss_procinit(ctlr_info_t *h)
 #define to_hba(n) container_of(n, struct ctlr_info, dev)
 #define to_drv(n) container_of(n, drive_info_struct, dev)
 
-/* List of controllers which cannot be reset on kexec with reset_devices */
+/* List of controllers which cannot be hard reset on kexec with reset_devices */
 static u32 unresettable_controller[] = {
        0x324a103C, /* Smart Array P712m */
        0x324b103C, /* SmartArray P711m */
@@ -574,23 +580,45 @@ static u32 unresettable_controller[] = {
        0x409D0E11, /* Smart Array 6400 EM */
 };
 
-static int ctlr_is_resettable(struct ctlr_info *h)
+/* List of controllers which cannot even be soft reset */
+static u32 soft_unresettable_controller[] = {
+       0x409C0E11, /* Smart Array 6400 */
+       0x409D0E11, /* Smart Array 6400 EM */
+};
+
+static int ctlr_is_hard_resettable(u32 board_id)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++)
-               if (unresettable_controller[i] == h->board_id)
+               if (unresettable_controller[i] == board_id)
                        return 0;
        return 1;
 }
 
+static int ctlr_is_soft_resettable(u32 board_id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++)
+               if (soft_unresettable_controller[i] == board_id)
+                       return 0;
+       return 1;
+}
+
+static int ctlr_is_resettable(u32 board_id)
+{
+       return ctlr_is_hard_resettable(board_id) ||
+               ctlr_is_soft_resettable(board_id);
+}
+
 static ssize_t host_show_resettable(struct device *dev,
                                    struct device_attribute *attr,
                                    char *buf)
 {
        struct ctlr_info *h = to_hba(dev);
 
-       return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h));
+       return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h->board_id));
 }
 static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL);
 
@@ -2567,7 +2595,7 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
                }
        } else if (cmd_type == TYPE_MSG) {
                switch (cmd) {
-               case 0: /* ABORT message */
+               case CCISS_ABORT_MSG:
                        c->Request.CDBLen = 12;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_WRITE;
@@ -2577,16 +2605,16 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
                        /* buff contains the tag of the command to abort */
                        memcpy(&c->Request.CDB[4], buff, 8);
                        break;
-               case 1: /* RESET message */
+               case CCISS_RESET_MSG:
                        c->Request.CDBLen = 16;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_NONE;
                        c->Request.Timeout = 0;
                        memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
                        c->Request.CDB[0] = cmd;        /* reset */
-                       c->Request.CDB[1] = 0x03;       /* reset a target */
+                       c->Request.CDB[1] = CCISS_RESET_TYPE_TARGET;
                        break;
-               case 3: /* No-Op message */
+               case CCISS_NOOP_MSG:
                        c->Request.CDBLen = 1;
                        c->Request.Type.Attribute = ATTR_SIMPLE;
                        c->Request.Type.Direction = XFER_WRITE;
@@ -2615,6 +2643,31 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
        return status;
 }
 
+static int __devinit cciss_send_reset(ctlr_info_t *h, unsigned char *scsi3addr,
+       u8 reset_type)
+{
+       CommandList_struct *c;
+       int return_status;
+
+       c = cmd_alloc(h);
+       if (!c)
+               return -ENOMEM;
+       return_status = fill_cmd(h, c, CCISS_RESET_MSG, NULL, 0, 0,
+               CTLR_LUNID, TYPE_MSG);
+       c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */
+       if (return_status != IO_OK) {
+               cmd_special_free(h, c);
+               return return_status;
+       }
+       c->waiting = NULL;
+       enqueue_cmd_and_start_io(h, c);
+       /* Don't wait for completion, the reset won't complete.  Don't free
+        * the command either.  This is the last command we will send before
+        * re-initializing everything, so it doesn't matter and won't leak.
+        */
+       return 0;
+}
+
 static int check_target_status(ctlr_info_t *h, CommandList_struct *c)
 {
        switch (c->err_info->ScsiStatus) {
@@ -3461,6 +3514,63 @@ static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag)
        return next_command(h);
 }
 
+/* Some controllers, like p400, will give us one interrupt
+ * after a soft reset, even if we turned interrupts off.
+ * Only need to check for this in the cciss_xxx_discard_completions
+ * functions.
+ */
+static int ignore_bogus_interrupt(ctlr_info_t *h)
+{
+       if (likely(!reset_devices))
+               return 0;
+
+       if (likely(h->interrupts_enabled))
+               return 0;
+
+       dev_info(&h->pdev->dev, "Received interrupt while interrupts disabled "
+               "(known firmware bug.)  Ignoring.\n");
+
+       return 1;
+}
+
+static irqreturn_t cciss_intx_discard_completions(int irq, void *dev_id)
+{
+       ctlr_info_t *h = dev_id;
+       unsigned long flags;
+       u32 raw_tag;
+
+       if (ignore_bogus_interrupt(h))
+               return IRQ_NONE;
+
+       if (interrupt_not_for_us(h))
+               return IRQ_NONE;
+       spin_lock_irqsave(&h->lock, flags);
+       while (interrupt_pending(h)) {
+               raw_tag = get_next_completion(h);
+               while (raw_tag != FIFO_EMPTY)
+                       raw_tag = next_command(h);
+       }
+       spin_unlock_irqrestore(&h->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cciss_msix_discard_completions(int irq, void *dev_id)
+{
+       ctlr_info_t *h = dev_id;
+       unsigned long flags;
+       u32 raw_tag;
+
+       if (ignore_bogus_interrupt(h))
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&h->lock, flags);
+       raw_tag = get_next_completion(h);
+       while (raw_tag != FIFO_EMPTY)
+               raw_tag = next_command(h);
+       spin_unlock_irqrestore(&h->lock, flags);
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t do_cciss_intx(int irq, void *dev_id)
 {
        ctlr_info_t *h = dev_id;
@@ -4078,6 +4188,9 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
                cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable));
        if (!h->cfgtable)
                return -ENOMEM;
+       rc = write_driver_ver_to_cfgtable(h->cfgtable);
+       if (rc)
+               return rc;
        /* Find performant mode table. */
        trans_offset = readl(&h->cfgtable->TransMethodOffset);
        h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
@@ -4112,7 +4225,7 @@ static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
 static void __devinit cciss_find_board_params(ctlr_info_t *h)
 {
        cciss_get_max_perf_mode_cmds(h);
-       h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+       h->nr_cmds = h->max_commands - 4 - cciss_tape_cmds;
        h->maxsgentries = readl(&(h->cfgtable->MaxSGElements));
        /*
         * Limit in-command s/g elements to 32 save dma'able memory.
@@ -4348,7 +4461,7 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
                tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
                if ((tag & ~3) == paddr32)
                        break;
-               schedule_timeout_uninterruptible(HZ);
+               msleep(CCISS_POST_RESET_NOOP_TIMEOUT_MSECS);
        }
 
        iounmap(vaddr);
@@ -4375,11 +4488,10 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
        return 0;
 }
 
-#define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
 #define cciss_noop(p) cciss_message(p, 3, 0)
 
 static int cciss_controller_hard_reset(struct pci_dev *pdev,
-       void * __iomem vaddr, bool use_doorbell)
+       void * __iomem vaddr, u32 use_doorbell)
 {
        u16 pmcsr;
        int pos;
@@ -4390,8 +4502,7 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
                 * other way using the doorbell register.
                 */
                dev_info(&pdev->dev, "using doorbell to reset controller\n");
-               writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL);
-               msleep(1000);
+               writel(use_doorbell, vaddr + SA5_DOORBELL);
        } else { /* Try to do it the PCI power state way */
 
                /* Quoting from the Open CISS Specification: "The Power
@@ -4422,12 +4533,64 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
                pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
                pmcsr |= PCI_D0;
                pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
-
-               msleep(500);
        }
        return 0;
 }
 
+static __devinit void init_driver_version(char *driver_version, int len)
+{
+       memset(driver_version, 0, len);
+       strncpy(driver_version, "cciss " DRIVER_NAME, len - 1);
+}
+
+static __devinit int write_driver_ver_to_cfgtable(
+       CfgTable_struct __iomem *cfgtable)
+{
+       char *driver_version;
+       int i, size = sizeof(cfgtable->driver_version);
+
+       driver_version = kmalloc(size, GFP_KERNEL);
+       if (!driver_version)
+               return -ENOMEM;
+
+       init_driver_version(driver_version, size);
+       for (i = 0; i < size; i++)
+               writeb(driver_version[i], &cfgtable->driver_version[i]);
+       kfree(driver_version);
+       return 0;
+}
+
+static __devinit void read_driver_ver_from_cfgtable(
+       CfgTable_struct __iomem *cfgtable, unsigned char *driver_ver)
+{
+       int i;
+
+       for (i = 0; i < sizeof(cfgtable->driver_version); i++)
+               driver_ver[i] = readb(&cfgtable->driver_version[i]);
+}
+
+static __devinit int controller_reset_failed(
+       CfgTable_struct __iomem *cfgtable)
+{
+
+       char *driver_ver, *old_driver_ver;
+       int rc, size = sizeof(cfgtable->driver_version);
+
+       old_driver_ver = kmalloc(2 * size, GFP_KERNEL);
+       if (!old_driver_ver)
+               return -ENOMEM;
+       driver_ver = old_driver_ver + size;
+
+       /* After a reset, the 32 bytes of "driver version" in the cfgtable
+        * should have been changed, otherwise we know the reset failed.
+        */
+       init_driver_version(old_driver_ver, size);
+       read_driver_ver_from_cfgtable(cfgtable, driver_ver);
+       rc = !memcmp(driver_ver, old_driver_ver, size);
+       kfree(old_driver_ver);
+       return rc;
+}
+
 /* This does a hard reset of the controller using PCI power management
  * states or using the doorbell register. */
 static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
@@ -4437,10 +4600,10 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
        u64 cfg_base_addr_index;
        void __iomem *vaddr;
        unsigned long paddr;
-       u32 misc_fw_support, active_transport;
+       u32 misc_fw_support;
        int rc;
        CfgTable_struct __iomem *cfgtable;
-       bool use_doorbell;
+       u32 use_doorbell;
        u32 board_id;
        u16 command_register;
 
@@ -4464,12 +4627,16 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
         * likely not be happy.  Just forbid resetting this conjoined mess.
         */
        cciss_lookup_board_id(pdev, &board_id);
-       if (board_id == 0x409C0E11 || board_id == 0x409D0E11) {
+       if (!ctlr_is_resettable(board_id)) {
                dev_warn(&pdev->dev, "Cannot reset Smart Array 640x "
                                "due to shared cache module.");
                return -ENODEV;
        }
 
+       /* if controller is soft- but not hard resettable... */
+       if (!ctlr_is_hard_resettable(board_id))
+               return -ENOTSUPP; /* try soft reset later. */
+
        /* Save the PCI command register */
        pci_read_config_word(pdev, 4, &command_register);
        /* Turn the board off.  This is so that later pci_restore_state()
@@ -4497,16 +4664,28 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
                rc = -ENOMEM;
                goto unmap_vaddr;
        }
+       rc = write_driver_ver_to_cfgtable(cfgtable);
+       if (rc)
+               goto unmap_vaddr;
 
-       /* If reset via doorbell register is supported, use that. */
-       misc_fw_support = readl(&cfgtable->misc_fw_support);
-       use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
-
-       /* The doorbell reset seems to cause lockups on some Smart
-        * Arrays (e.g. P410, P410i, maybe others).  Until this is
-        * fixed or at least isolated, avoid the doorbell reset.
+       /* If reset via doorbell register is supported, use that.
+        * There are two such methods.  Favor the newest method.
         */
-       use_doorbell = 0;
+       misc_fw_support = readl(&cfgtable->misc_fw_support);
+       use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2;
+       if (use_doorbell) {
+               use_doorbell = DOORBELL_CTLR_RESET2;
+       } else {
+               use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
+               if (use_doorbell) {
+                       dev_warn(&pdev->dev, "Controller claims that "
+                               "'Bit 2 doorbell reset' is "
+                               "supported, but not 'bit 5 doorbell reset'.  "
+                               "Firmware update is recommended.\n");
+                       rc = -ENOTSUPP; /* use the soft reset */
+                       goto unmap_cfgtable;
+               }
+       }
 
        rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
        if (rc)
@@ -4524,30 +4703,31 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
        msleep(CCISS_POST_RESET_PAUSE_MSECS);
 
        /* Wait for board to become not ready, then ready. */
-       dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+       dev_info(&pdev->dev, "Waiting for board to reset.\n");
        rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
-       if (rc) /* Don't bail, might be E500, etc. which can't be reset */
-               dev_warn(&pdev->dev,
-                       "failed waiting for board to become not ready\n");
+       if (rc) {
+               dev_warn(&pdev->dev, "Failed waiting for board to hard reset."
+                               "  Will try soft reset.\n");
+               rc = -ENOTSUPP; /* Not expected, but try soft reset later */
+               goto unmap_cfgtable;
+       }
        rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
        if (rc) {
                dev_warn(&pdev->dev,
-                       "failed waiting for board to become ready\n");
+                       "failed waiting for board to become ready "
+                       "after hard reset\n");
                goto unmap_cfgtable;
        }
-       dev_info(&pdev->dev, "board ready.\n");
 
-       /* Controller should be in simple mode at this point.  If it's not,
-        * It means we're on one of those controllers which doesn't support
-        * the doorbell reset method and on which the PCI power management reset
-        * method doesn't work (P800, for example.)
-        * In those cases, don't try to proceed, as it generally doesn't work.
-        */
-       active_transport = readl(&cfgtable->TransportActive);
-       if (active_transport & PERFORMANT_MODE) {
-               dev_warn(&pdev->dev, "Unable to successfully reset controller,"
-                       " Ignoring controller.\n");
-               rc = -ENODEV;
+       rc = controller_reset_failed(vaddr);
+       if (rc < 0)
+               goto unmap_cfgtable;
+       if (rc) {
+               dev_warn(&pdev->dev, "Unable to successfully hard reset "
+                       "controller. Will try soft reset.\n");
+               rc = -ENOTSUPP; /* Not expected, but try soft reset later */
+       } else {
+               dev_info(&pdev->dev, "Board ready after hard reset.\n");
        }
 
 unmap_cfgtable:
@@ -4574,11 +4754,12 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
         * due to concerns about shared bbwc between 6402/6404 pair.
         */
        if (rc == -ENOTSUPP)
-               return 0; /* just try to do the kdump anyhow. */
+               return rc; /* just try to do the kdump anyhow. */
        if (rc)
                return -ENODEV;
 
        /* Now try to get the controller to respond to a no-op */
+       dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n");
        for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
                if (cciss_noop(pdev) == 0)
                        break;
@@ -4591,6 +4772,148 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
        return 0;
 }
 
+static __devinit int cciss_allocate_cmd_pool(ctlr_info_t *h)
+{
+       h->cmd_pool_bits = kmalloc(
+               DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) *
+               sizeof(unsigned long), GFP_KERNEL);
+       h->cmd_pool = pci_alloc_consistent(h->pdev,
+               h->nr_cmds * sizeof(CommandList_struct),
+               &(h->cmd_pool_dhandle));
+       h->errinfo_pool = pci_alloc_consistent(h->pdev,
+               h->nr_cmds * sizeof(ErrorInfo_struct),
+               &(h->errinfo_pool_dhandle));
+       if ((h->cmd_pool_bits == NULL)
+               || (h->cmd_pool == NULL)
+               || (h->errinfo_pool == NULL)) {
+               dev_err(&h->pdev->dev, "out of memory");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static __devinit int cciss_allocate_scatterlists(ctlr_info_t *h)
+{
+       int i;
+
+       /* zero it, so that on free we need not know how many were alloc'ed */
+       h->scatter_list = kzalloc(h->max_commands *
+                               sizeof(struct scatterlist *), GFP_KERNEL);
+       if (!h->scatter_list)
+               return -ENOMEM;
+
+       for (i = 0; i < h->nr_cmds; i++) {
+               h->scatter_list[i] = kmalloc(sizeof(struct scatterlist) *
+                                               h->maxsgentries, GFP_KERNEL);
+               if (h->scatter_list[i] == NULL) {
+                       dev_err(&h->pdev->dev, "could not allocate "
+                               "s/g lists\n");
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
+
+static void cciss_free_scatterlists(ctlr_info_t *h)
+{
+       int i;
+
+       if (h->scatter_list) {
+               for (i = 0; i < h->nr_cmds; i++)
+                       kfree(h->scatter_list[i]);
+               kfree(h->scatter_list);
+       }
+}
+
+static void cciss_free_cmd_pool(ctlr_info_t *h)
+{
+       kfree(h->cmd_pool_bits);
+       if (h->cmd_pool)
+               pci_free_consistent(h->pdev,
+                       h->nr_cmds * sizeof(CommandList_struct),
+                       h->cmd_pool, h->cmd_pool_dhandle);
+       if (h->errinfo_pool)
+               pci_free_consistent(h->pdev,
+                       h->nr_cmds * sizeof(ErrorInfo_struct),
+                       h->errinfo_pool, h->errinfo_pool_dhandle);
+}
+
+static int cciss_request_irq(ctlr_info_t *h,
+       irqreturn_t (*msixhandler)(int, void *),
+       irqreturn_t (*intxhandler)(int, void *))
+{
+       if (h->msix_vector || h->msi_vector) {
+               if (!request_irq(h->intr[PERF_MODE_INT], msixhandler,
+                               IRQF_DISABLED, h->devname, h))
+                       return 0;
+               dev_err(&h->pdev->dev, "Unable to get msi irq %d"
+                       " for %s\n", h->intr[PERF_MODE_INT],
+                       h->devname);
+               return -1;
+       }
+
+       if (!request_irq(h->intr[PERF_MODE_INT], intxhandler,
+                       IRQF_DISABLED, h->devname, h))
+               return 0;
+       dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
+               h->intr[PERF_MODE_INT], h->devname);
+       return -1;
+}
+
+static int __devinit cciss_kdump_soft_reset(ctlr_info_t *h)
+{
+       if (cciss_send_reset(h, CTLR_LUNID, CCISS_RESET_TYPE_CONTROLLER)) {
+               dev_warn(&h->pdev->dev, "Resetting array controller failed.\n");
+               return -EIO;
+       }
+
+       dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n");
+       if (cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) {
+               dev_warn(&h->pdev->dev, "Soft reset had no effect.\n");
+               return -1;
+       }
+
+       dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n");
+       if (cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) {
+               dev_warn(&h->pdev->dev, "Board failed to become ready "
+                       "after soft reset.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h)
+{
+       int ctlr = h->ctlr;
+
+       free_irq(h->intr[PERF_MODE_INT], h);
+#ifdef CONFIG_PCI_MSI
+       if (h->msix_vector)
+               pci_disable_msix(h->pdev);
+       else if (h->msi_vector)
+               pci_disable_msi(h->pdev);
+#endif /* CONFIG_PCI_MSI */
+       cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
+       cciss_free_scatterlists(h);
+       cciss_free_cmd_pool(h);
+       kfree(h->blockFetchTable);
+       if (h->reply_pool)
+               pci_free_consistent(h->pdev, h->max_commands * sizeof(__u64),
+                               h->reply_pool, h->reply_pool_dhandle);
+       if (h->transtable)
+               iounmap(h->transtable);
+       if (h->cfgtable)
+               iounmap(h->cfgtable);
+       if (h->vaddr)
+               iounmap(h->vaddr);
+       unregister_blkdev(h->major, h->devname);
+       cciss_destroy_hba_sysfs_entry(h);
+       pci_release_regions(h->pdev);
+       kfree(h);
+       hba[ctlr] = NULL;
+}
+
 /*
  *  This is it.  Find all the controllers and register them.  I really hate
  *  stealing all these major device numbers.
@@ -4601,15 +4924,28 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 {
        int i;
        int j = 0;
-       int k = 0;
        int rc;
+       int try_soft_reset = 0;
        int dac, return_code;
        InquiryData_struct *inq_buff;
        ctlr_info_t *h;
+       unsigned long flags;
 
        rc = cciss_init_reset_devices(pdev);
-       if (rc)
-               return rc;
+       if (rc) {
+               if (rc != -ENOTSUPP)
+                       return rc;
+               /* If the reset fails in a particular way (it has no way to do
+                * a proper hard reset, so returns -ENOTSUPP) we can try to do
+                * a soft reset once we get the controller configured up to the
+                * point that it can accept a command.
+                */
+               try_soft_reset = 1;
+               rc = 0;
+       }
+
+reinit_after_soft_reset:
+
        i = alloc_cciss_hba(pdev);
        if (i < 0)
                return -1;
@@ -4627,6 +4963,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        sprintf(h->devname, "cciss%d", i);
        h->ctlr = i;
 
+       if (cciss_tape_cmds < 2)
+               cciss_tape_cmds = 2;
+       if (cciss_tape_cmds > 16)
+               cciss_tape_cmds = 16;
+
        init_completion(&h->scan_wait);
 
        if (cciss_create_hba_sysfs_entry(h))
@@ -4662,62 +5003,20 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 
        /* make sure the board interrupts are off */
        h->access.set_intr_mask(h, CCISS_INTR_OFF);
-       if (h->msi_vector || h->msix_vector) {
-               if (request_irq(h->intr[PERF_MODE_INT],
-                               do_cciss_msix_intr,
-                               IRQF_DISABLED, h->devname, h)) {
-                       dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
-                              h->intr[PERF_MODE_INT], h->devname);
-                       goto clean2;
-               }
-       } else {
-               if (request_irq(h->intr[PERF_MODE_INT], do_cciss_intx,
-                               IRQF_DISABLED, h->devname, h)) {
-                       dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
-                              h->intr[PERF_MODE_INT], h->devname);
-                       goto clean2;
-               }
-       }
+       rc = cciss_request_irq(h, do_cciss_msix_intr, do_cciss_intx);
+       if (rc)
+               goto clean2;
 
        dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
               h->devname, pdev->device, pci_name(pdev),
               h->intr[PERF_MODE_INT], dac ? "" : " not");
 
-       h->cmd_pool_bits =
-           kmalloc(DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG)
-                       * sizeof(unsigned long), GFP_KERNEL);
-       h->cmd_pool = (CommandList_struct *)
-           pci_alloc_consistent(h->pdev,
-                   h->nr_cmds * sizeof(CommandList_struct),
-                   &(h->cmd_pool_dhandle));
-       h->errinfo_pool = (ErrorInfo_struct *)
-           pci_alloc_consistent(h->pdev,
-                   h->nr_cmds * sizeof(ErrorInfo_struct),
-                   &(h->errinfo_pool_dhandle));
-       if ((h->cmd_pool_bits == NULL)
-           || (h->cmd_pool == NULL)
-           || (h->errinfo_pool == NULL)) {
-               dev_err(&h->pdev->dev, "out of memory");
+       if (cciss_allocate_cmd_pool(h))
                goto clean4;
-       }
 
-       /* Need space for temp scatter list */
-       h->scatter_list = kmalloc(h->max_commands *
-                                               sizeof(struct scatterlist *),
-                                               GFP_KERNEL);
-       if (!h->scatter_list)
+       if (cciss_allocate_scatterlists(h))
                goto clean4;
 
-       for (k = 0; k < h->nr_cmds; k++) {
-               h->scatter_list[k] = kmalloc(sizeof(struct scatterlist) *
-                                                       h->maxsgentries,
-                                                       GFP_KERNEL);
-               if (h->scatter_list[k] == NULL) {
-                       dev_err(&h->pdev->dev,
-                               "could not allocate s/g lists\n");
-                       goto clean4;
-               }
-       }
        h->cmd_sg_list = cciss_allocate_sg_chain_blocks(h,
                h->chainsize, h->nr_cmds);
        if (!h->cmd_sg_list && h->chainsize > 0)
@@ -4741,6 +5040,62 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                h->gendisk[j] = NULL;
        }
 
+       /* At this point, the controller is ready to take commands.
+        * Now, if reset_devices and the hard reset didn't work, try
+        * the soft reset and see if that works.
+        */
+       if (try_soft_reset) {
+
+               /* This is kind of gross.  We may or may not get a completion
+                * from the soft reset command, and if we do, then the value
+                * from the fifo may or may not be valid.  So, we wait 10 secs
+                * after the reset throwing away any completions we get during
+                * that time.  Unregister the interrupt handler and register
+                * fake ones to scoop up any residual completions.
+                */
+               spin_lock_irqsave(&h->lock, flags);
+               h->access.set_intr_mask(h, CCISS_INTR_OFF);
+               spin_unlock_irqrestore(&h->lock, flags);
+               free_irq(h->intr[PERF_MODE_INT], h);
+               rc = cciss_request_irq(h, cciss_msix_discard_completions,
+                                       cciss_intx_discard_completions);
+               if (rc) {
+                       dev_warn(&h->pdev->dev, "Failed to request_irq after "
+                               "soft reset.\n");
+                       goto clean4;
+               }
+
+               rc = cciss_kdump_soft_reset(h);
+               if (rc) {
+                       dev_warn(&h->pdev->dev, "Soft reset failed.\n");
+                       goto clean4;
+               }
+
+               dev_info(&h->pdev->dev, "Board READY.\n");
+               dev_info(&h->pdev->dev,
+                       "Waiting for stale completions to drain.\n");
+               h->access.set_intr_mask(h, CCISS_INTR_ON);
+               msleep(10000);
+               h->access.set_intr_mask(h, CCISS_INTR_OFF);
+
+               rc = controller_reset_failed(h->cfgtable);
+               if (rc)
+                       dev_info(&h->pdev->dev,
+                               "Soft reset appears to have failed.\n");
+
+               /* since the controller's reset, we have to go back and re-init
+                * everything.  Easiest to just forget what we've done and do it
+                * all over again.
+                */
+               cciss_undo_allocations_after_kdump_soft_reset(h);
+               try_soft_reset = 0;
+               if (rc)
+                       /* don't go to clean4, we already unallocated */
+                       return -ENODEV;
+
+               goto reinit_after_soft_reset;
+       }
+
        cciss_scsi_setup(h);
 
        /* Turn the interrupts on so we can service requests */
@@ -4775,21 +5130,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        return 1;
 
 clean4:
-       kfree(h->cmd_pool_bits);
-       /* Free up sg elements */
-       for (k-- ; k >= 0; k--)
-               kfree(h->scatter_list[k]);
-       kfree(h->scatter_list);
+       cciss_free_cmd_pool(h);
+       cciss_free_scatterlists(h);
        cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
-       if (h->cmd_pool)
-               pci_free_consistent(h->pdev,
-                                   h->nr_cmds * sizeof(CommandList_struct),
-                                   h->cmd_pool, h->cmd_pool_dhandle);
-       if (h->errinfo_pool)
-               pci_free_consistent(h->pdev,
-                                   h->nr_cmds * sizeof(ErrorInfo_struct),
-                                   h->errinfo_pool,
-                                   h->errinfo_pool_dhandle);
        free_irq(h->intr[PERF_MODE_INT], h);
 clean2:
        unregister_blkdev(h->major, h->devname);
@@ -4887,16 +5230,16 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
        iounmap(h->cfgtable);
        iounmap(h->vaddr);
 
-       pci_free_consistent(h->pdev, h->nr_cmds * sizeof(CommandList_struct),
-                           h->cmd_pool, h->cmd_pool_dhandle);
-       pci_free_consistent(h->pdev, h->nr_cmds * sizeof(ErrorInfo_struct),
-                           h->errinfo_pool, h->errinfo_pool_dhandle);
-       kfree(h->cmd_pool_bits);
+       cciss_free_cmd_pool(h);
        /* Free up sg elements */
        for (j = 0; j < h->nr_cmds; j++)
                kfree(h->scatter_list[j]);
        kfree(h->scatter_list);
        cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
+       kfree(h->blockFetchTable);
+       if (h->reply_pool)
+               pci_free_consistent(h->pdev, h->max_commands * sizeof(__u64),
+                               h->reply_pool, h->reply_pool_dhandle);
        /*
         * Deliberately omit pci_disable_device(): it does something nasty to
         * Smart Array controllers that pci_enable_device does not undo
index 554bbd907d144500817a615702ab6155cb7f7243..16b4d58d84dd1e690a63b2f91efdce58aafe8d44 100644 (file)
@@ -200,7 +200,7 @@ struct ctlr_info
  * the above.
  */
 #define CCISS_BOARD_READY_WAIT_SECS (120)
-#define CCISS_BOARD_NOT_READY_WAIT_SECS (10)
+#define CCISS_BOARD_NOT_READY_WAIT_SECS (100)
 #define CCISS_BOARD_READY_POLL_INTERVAL_MSECS (100)
 #define CCISS_BOARD_READY_ITERATIONS \
        ((CCISS_BOARD_READY_WAIT_SECS * 1000) / \
@@ -209,8 +209,9 @@ struct ctlr_info
        ((CCISS_BOARD_NOT_READY_WAIT_SECS * 1000) / \
                CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
 #define CCISS_POST_RESET_PAUSE_MSECS (3000)
-#define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (1000)
+#define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (4000)
 #define CCISS_POST_RESET_NOOP_RETRIES (12)
+#define CCISS_POST_RESET_NOOP_TIMEOUT_MSECS (10000)
 
 /* 
        Send the command to the hardware 
@@ -239,11 +240,13 @@ static void SA5_intr_mask(ctlr_info_t *h, unsigned long val)
        { /* Turn interrupts on */
                h->interrupts_enabled = 1;
                writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
        } else /* Turn them off */
        {
                h->interrupts_enabled = 0;
                writel( SA5_INTR_OFF, 
                        h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
        }
 }
 /*
@@ -257,11 +260,13 @@ static void SA5B_intr_mask(ctlr_info_t *h, unsigned long val)
         { /* Turn interrupts on */
                h->interrupts_enabled = 1;
                 writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
         } else /* Turn them off */
         {
                h->interrupts_enabled = 0;
                 writel( SA5B_INTR_OFF,
                         h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
         }
 }
 
@@ -271,10 +276,12 @@ static void SA5_performant_intr_mask(ctlr_info_t *h, unsigned long val)
        if (val) { /* turn on interrupts */
                h->interrupts_enabled = 1;
                writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
        } else {
                h->interrupts_enabled = 0;
                writel(SA5_PERF_INTR_OFF,
                                h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+               (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
        }
 }
 
index cd441bef031f1a4806ba29df8067c47b050bfae7..d9be6b4d49a6a0e3bc950d3cb395edbef5af6d3b 100644 (file)
@@ -53,6 +53,7 @@
 #define CFGTBL_ChangeReq        0x00000001l
 #define CFGTBL_AccCmds          0x00000001l
 #define DOORBELL_CTLR_RESET     0x00000004l
+#define DOORBELL_CTLR_RESET2    0x00000020l
 
 #define CFGTBL_Trans_Simple     0x00000002l
 #define CFGTBL_Trans_Performant 0x00000004l
@@ -142,6 +143,14 @@ typedef struct _ReadCapdata_struct_16
 #define BMIC_CACHE_FLUSH 0xc2
 #define CCISS_CACHE_FLUSH 0x01 /* C2 was already being used by CCISS */
 
+#define CCISS_ABORT_MSG 0x00
+#define CCISS_RESET_MSG 0x01
+#define CCISS_RESET_TYPE_CONTROLLER 0x00
+#define CCISS_RESET_TYPE_BUS 0x01
+#define CCISS_RESET_TYPE_TARGET 0x03
+#define CCISS_RESET_TYPE_LUN 0x04
+#define CCISS_NOOP_MSG 0x03
+
 /* Command List Structure */
 #define CTLR_LUNID "\0\0\0\0\0\0\0\0"
 
@@ -235,6 +244,8 @@ typedef struct _CfgTable_struct {
   u8              reserved[0x78 - 0x58];
   u32             misc_fw_support; /* offset 0x78 */
 #define MISC_FW_DOORBELL_RESET (0x02)
+#define MISC_FW_DOORBELL_RESET2 (0x10)
+       u8         driver_version[32];
 } CfgTable_struct;
 
 struct TransTable_struct {
index df793803f5ae5c70615df404a442d525442184a0..696100241a6fd017c655c424004af621ae0a491b 100644 (file)
@@ -84,7 +84,6 @@ static struct scsi_host_template cciss_driver_template = {
        .proc_name              = "cciss",
        .proc_info              = cciss_scsi_proc_info,
        .queuecommand           = cciss_scsi_queue_command,
-       .can_queue              = SCSI_CCISS_CAN_QUEUE,
        .this_id                = 7,
        .cmd_per_lun            = 1,
        .use_clustering         = DISABLE_CLUSTERING,
@@ -108,16 +107,13 @@ struct cciss_scsi_cmd_stack_elem_t {
 
 #pragma pack()
 
-#define CMD_STACK_SIZE (SCSI_CCISS_CAN_QUEUE * \
-               CCISS_MAX_SCSI_DEVS_PER_HBA + 2)
-                       // plus two for init time usage
-
 #pragma pack(1)
 struct cciss_scsi_cmd_stack_t {
        struct cciss_scsi_cmd_stack_elem_t *pool;
-       struct cciss_scsi_cmd_stack_elem_t *elem[CMD_STACK_SIZE];
+       struct cciss_scsi_cmd_stack_elem_t **elem;
        dma_addr_t cmd_pool_handle;
        int top;
+       int nelems;
 };
 #pragma pack()
 
@@ -191,7 +187,7 @@ scsi_cmd_free(ctlr_info_t *h, CommandList_struct *c)
        sa = h->scsi_ctlr;
        stk = &sa->cmd_stack; 
        stk->top++;
-       if (stk->top >= CMD_STACK_SIZE) {
+       if (stk->top >= stk->nelems) {
                dev_err(&h->pdev->dev,
                        "scsi_cmd_free called too many times.\n");
                BUG();
@@ -206,13 +202,14 @@ scsi_cmd_stack_setup(ctlr_info_t *h, struct cciss_scsi_adapter_data_t *sa)
        struct cciss_scsi_cmd_stack_t *stk;
        size_t size;
 
+       stk = &sa->cmd_stack;
+       stk->nelems = cciss_tape_cmds + 2;
        sa->cmd_sg_list = cciss_allocate_sg_chain_blocks(h,
-               h->chainsize, CMD_STACK_SIZE);
+               h->chainsize, stk->nelems);
        if (!sa->cmd_sg_list && h->chainsize > 0)
                return -ENOMEM;
 
-       stk = &sa->cmd_stack; 
-       size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+       size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * stk->nelems;
 
        /* Check alignment, see cciss_cmd.h near CommandList_struct def. */
        BUILD_BUG_ON((sizeof(*stk->pool) % COMMANDLIST_ALIGNMENT) != 0);
@@ -221,18 +218,23 @@ scsi_cmd_stack_setup(ctlr_info_t *h, struct cciss_scsi_adapter_data_t *sa)
                pci_alloc_consistent(h->pdev, size, &stk->cmd_pool_handle);
 
        if (stk->pool == NULL) {
-               cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
+               cciss_free_sg_chain_blocks(sa->cmd_sg_list, stk->nelems);
                sa->cmd_sg_list = NULL;
                return -ENOMEM;
        }
-
-       for (i=0; i<CMD_STACK_SIZE; i++) {
+       stk->elem = kmalloc(sizeof(stk->elem[0]) * stk->nelems, GFP_KERNEL);
+       if (!stk->elem) {
+               pci_free_consistent(h->pdev, size, stk->pool,
+               stk->cmd_pool_handle);
+               return -1;
+       }
+       for (i = 0; i < stk->nelems; i++) {
                stk->elem[i] = &stk->pool[i];
                stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + 
                        (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
                stk->elem[i]->cmdindex = i;
        }
-       stk->top = CMD_STACK_SIZE-1;
+       stk->top = stk->nelems-1;
        return 0;
 }
 
@@ -245,16 +247,18 @@ scsi_cmd_stack_free(ctlr_info_t *h)
 
        sa = h->scsi_ctlr;
        stk = &sa->cmd_stack; 
-       if (stk->top != CMD_STACK_SIZE-1) {
+       if (stk->top != stk->nelems-1) {
                dev_warn(&h->pdev->dev,
                        "bug: %d scsi commands are still outstanding.\n",
-                       CMD_STACK_SIZE - stk->top);
+                       stk->nelems - stk->top);
        }
-       size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+       size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * stk->nelems;
 
        pci_free_consistent(h->pdev, size, stk->pool, stk->cmd_pool_handle);
        stk->pool = NULL;
-       cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
+       cciss_free_sg_chain_blocks(sa->cmd_sg_list, stk->nelems);
+       kfree(stk->elem);
+       stk->elem = NULL;
 }
 
 #if 0
@@ -859,6 +863,7 @@ cciss_scsi_detect(ctlr_info_t *h)
        sh->io_port = 0;        // good enough?  FIXME, 
        sh->n_io_port = 0;      // I don't think we use these two...
        sh->this_id = SELF_SCSI_ID;  
+       sh->can_queue = cciss_tape_cmds;
        sh->sg_tablesize = h->maxsgentries;
        sh->max_cmd_len = MAX_COMMAND_SIZE;
 
index 6d5822fe851aeaf6759b76ea68fd39c116ea81d7..e71d986727cac7c4a11b0e2f2b6c568ec4f2e829 100644 (file)
                   addressible natively, and may in fact turn
                   out to be not scsi at all. */
 
-#define SCSI_CCISS_CAN_QUEUE 2
 
 /* 
 
-Note, cmd_per_lun could give us some trouble, so I'm setting it very low.
-Likewise, SCSI_CCISS_CAN_QUEUE is set very conservatively.
-
 If the upper scsi layer tries to track how many commands we have 
 outstanding, it will be operating under the misapprehension that it is
 the only one sending us requests.  We also have the block interface,
index c6828b68d77b00831e3f45ae5555f9c2c2751c7a..09ef9a878ef06335393cbc4509f38425a5465713 100644 (file)
@@ -28,7 +28,7 @@
 #include "drbd_int.h"
 #include "drbd_wrappers.h"
 
-/* We maintain a trivial check sum in our on disk activity log.
+/* We maintain a trivial checksum 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 losing power.
  */
index 76210ba401ac4d3e8871c4eac99336aa67d899cd..f440a02dfdb15519799c64e2ab7c219db9a95ab5 100644 (file)
@@ -74,7 +74,7 @@
  *     as we are "attached" to a local disk, which at 32 GiB for 1PiB storage
  *     seems excessive.
  *
- *     We plan to reduce the amount of in-core bitmap pages by pageing them in
+ *     We plan to reduce the amount of in-core bitmap pages by paging them in
  *     and out against their on-disk location as necessary, but need to make
  *     sure we don't cause too much meta data IO, and must not deadlock in
  *     tight memory situations. This needs some more work.
@@ -200,7 +200,7 @@ void drbd_bm_unlock(struct drbd_conf *mdev)
  * we if bits have been cleared since last IO. */
 #define BM_PAGE_LAZY_WRITEOUT  28
 
-/* store_page_idx uses non-atomic assingment. It is only used directly after
+/* store_page_idx uses non-atomic assignment. It is only used directly after
  * allocating the page.  All other bm_set_page_* and bm_clear_page_* need to
  * use atomic bit manipulation, as set_out_of_sync (and therefore bitmap
  * changes) may happen from various contexts, and wait_on_bit/wake_up_bit
@@ -318,7 +318,7 @@ static void bm_unmap(unsigned long *p_addr)
 /* 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)
+ hm, well, Philipp thinks gcc might not optimize the % into & (... - 1)
  so do it explicitly:
  */
 #define MLPP(X) ((X) & ((PAGE_SIZE/sizeof(long))-1))
index d871b14ed5a186a22d758308f1a498fbfe66de26..ef2ceed3be4b2767f6b3886a48a002609597e2e8 100644 (file)
@@ -700,7 +700,7 @@ struct drbd_request {
         * see drbd_endio_pri(). */
        struct bio *private_bio;
 
-       struct hlist_node colision;
+       struct hlist_node collision;
        sector_t sector;
        unsigned int size;
        unsigned int epoch; /* barrier_nr */
@@ -766,7 +766,7 @@ struct digest_info {
 
 struct drbd_epoch_entry {
        struct drbd_work w;
-       struct hlist_node colision;
+       struct hlist_node collision;
        struct drbd_epoch *epoch; /* for writes */
        struct drbd_conf *mdev;
        struct page *pages;
@@ -1129,6 +1129,8 @@ struct drbd_conf {
        int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */
        int rs_planed;    /* resync sectors already planned */
        atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */
+       int peer_max_bio_size;
+       int local_max_bio_size;
 };
 
 static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
@@ -1218,8 +1220,6 @@ 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);
-enum drbd_req_event;
-extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what);
 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,
@@ -1434,6 +1434,7 @@ struct bm_extent {
  * hash table. */
 #define HT_SHIFT 8
 #define DRBD_MAX_BIO_SIZE (1U<<(9+HT_SHIFT))
+#define DRBD_MAX_BIO_SIZE_SAFE (1 << 12)       /* Works always = 4k */
 
 #define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */
 
@@ -1518,9 +1519,9 @@ 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 *, int);
 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 *, enum dds_flags) __must_hold(local);
+extern enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *, enum dds_flags) __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 void drbd_reconsider_max_bio_size(struct drbd_conf *mdev);
 extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev,
                                        enum drbd_role new_role,
                                        int force);
@@ -1828,6 +1829,8 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
                if (!forcedetach) {
                        if (__ratelimit(&drbd_ratelimit_state))
                                dev_err(DEV, "Local IO failed in %s.\n", where);
+                       if (mdev->state.disk > D_INCONSISTENT)
+                               _drbd_set_state(_NS(mdev, disk, D_INCONSISTENT), CS_HARD, NULL);
                        break;
                }
                /* NOTE fall through to detach case if forcedetach set */
@@ -2153,6 +2156,10 @@ static inline int get_net_conf(struct drbd_conf *mdev)
 static inline void put_ldev(struct drbd_conf *mdev)
 {
        int i = atomic_dec_return(&mdev->local_cnt);
+
+       /* This may be called from some endio handler,
+        * so we must not sleep here. */
+
        __release(local);
        D_ASSERT(i >= 0);
        if (i == 0) {
index 5b525c179f39919d6e245948a434e3248c9f329b..0358e55356c85f13ce96670f94b4cef626ce70ae 100644 (file)
@@ -745,6 +745,9 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
                  mdev->agreed_pro_version < 88)
                rv = SS_NOT_SUPPORTED;
 
+       else if (ns.conn >= C_CONNECTED && ns.pdsk == D_UNKNOWN)
+               rv = SS_CONNECTED_OUTDATES;
+
        return rv;
 }
 
@@ -1565,6 +1568,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
                put_ldev(mdev);
        }
 
+       /* Notify peer that I had a local IO error, and did not detached.. */
+       if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT)
+               drbd_send_state(mdev);
+
        /* 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)) {
@@ -2064,7 +2071,7 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
 {
        struct p_sizes p;
        sector_t d_size, u_size;
-       int q_order_type;
+       int q_order_type, max_bio_size;
        int ok;
 
        if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
@@ -2072,17 +2079,20 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
                d_size = drbd_get_max_capacity(mdev->ldev);
                u_size = mdev->ldev->dc.disk_size;
                q_order_type = drbd_queue_order_type(mdev);
+               max_bio_size = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
+               max_bio_size = min_t(int, max_bio_size, DRBD_MAX_BIO_SIZE);
                put_ldev(mdev);
        } else {
                d_size = 0;
                u_size = 0;
                q_order_type = QUEUE_ORDERED_NONE;
+               max_bio_size = DRBD_MAX_BIO_SIZE; /* ... multiple BIOs per peer_request */
        }
 
        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_bio_size = cpu_to_be32(queue_max_hw_sectors(mdev->rq_queue) << 9);
+       p.max_bio_size = cpu_to_be32(max_bio_size);
        p.queue_order_type = cpu_to_be16(q_order_type);
        p.dds_flags = cpu_to_be16(flags);
 
@@ -2722,7 +2732,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
 
                /* double check digest, sometimes buffers have been modified in flight. */
                if (dgs > 0 && dgs <= 64) {
-                       /* 64 byte, 512 bit, is the larges digest size
+                       /* 64 byte, 512 bit, is the largest digest size
                         * currently supported in kernel crypto. */
                        unsigned char digest[64];
                        drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, digest);
@@ -3041,6 +3051,8 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
        mdev->agreed_pro_version = PRO_VERSION_MAX;
        mdev->write_ordering = WO_bdev_flush;
        mdev->resync_wenr = LC_FREE;
+       mdev->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
+       mdev->local_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
 }
 
 void drbd_mdev_cleanup(struct drbd_conf *mdev)
@@ -3275,7 +3287,7 @@ static void drbd_delete_device(unsigned int minor)
 
        drbd_release_ee_lists(mdev);
 
-       /* should be free'd on disconnect? */
+       /* should be freed on disconnect? */
        kfree(mdev->ee_hash);
        /*
        mdev->ee_hash_s = 0;
@@ -3415,7 +3427,9 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
        q->backing_dev_info.congested_data = mdev;
 
        blk_queue_make_request(q, drbd_make_request);
-       blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE >> 9);
+       /* Setting the max_hw_sectors to an odd value of 8kibyte here
+          This triggers a max_bio_size message upon first attach or connect */
+       blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8);
        blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
        blk_queue_merge_bvec(q, drbd_merge_bvec);
        q->queue_lock = &mdev->req_lock;
@@ -3627,7 +3641,8 @@ struct meta_data_on_disk {
              /* `-- 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];
+       u32 la_peer_max_bio_size;   /* last peer max_bio_size */
+       u32 reserved_u32[3];
 
 } __packed;
 
@@ -3668,6 +3683,7 @@ void drbd_md_sync(struct drbd_conf *mdev)
        buffer->device_uuid = cpu_to_be64(mdev->ldev->md.device_uuid);
 
        buffer->bm_offset = cpu_to_be32(mdev->ldev->md.bm_offset);
+       buffer->la_peer_max_bio_size = cpu_to_be32(mdev->peer_max_bio_size);
 
        D_ASSERT(drbd_md_ss__(mdev, mdev->ldev) == mdev->ldev->md.md_offset);
        sector = mdev->ldev->md.md_offset;
@@ -3751,6 +3767,15 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
        mdev->sync_conf.al_extents = be32_to_cpu(buffer->al_nr_extents);
        bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid);
 
+       spin_lock_irq(&mdev->req_lock);
+       if (mdev->state.conn < C_CONNECTED) {
+               int peer;
+               peer = be32_to_cpu(buffer->la_peer_max_bio_size);
+               peer = max_t(int, peer, DRBD_MAX_BIO_SIZE_SAFE);
+               mdev->peer_max_bio_size = peer;
+       }
+       spin_unlock_irq(&mdev->req_lock);
+
        if (mdev->sync_conf.al_extents < 7)
                mdev->sync_conf.al_extents = 127;
 
index 03b29f78a37d78ac8955db9ae43ca8609b963d91..515bcd948a43d7ee04650a06044e7bea6bc4742c 100644 (file)
@@ -272,9 +272,28 @@ static int _try_outdate_peer_async(void *data)
 {
        struct drbd_conf *mdev = (struct drbd_conf *)data;
        enum drbd_disk_state nps;
+       union drbd_state ns;
 
        nps = drbd_try_outdate_peer(mdev);
-       drbd_request_state(mdev, NS(pdsk, nps));
+
+       /* Not using
+          drbd_request_state(mdev, NS(pdsk, nps));
+          here, because we might were able to re-establish the connection
+          in the meantime. This can only partially be solved in the state's
+          engine is_valid_state() and is_valid_state_transition()
+          functions.
+
+          nps can be D_INCONSISTENT, D_OUTDATED or D_UNKNOWN.
+          pdsk == D_INCONSISTENT while conn >= C_CONNECTED is valid,
+          therefore we have to have the pre state change check here.
+       */
+       spin_lock_irq(&mdev->req_lock);
+       ns = mdev->state;
+       if (ns.conn < C_WF_REPORT_PARAMS) {
+               ns.pdsk = nps;
+               _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+       }
+       spin_unlock_irq(&mdev->req_lock);
 
        return 0;
 }
@@ -577,7 +596,7 @@ void drbd_resume_io(struct drbd_conf *mdev)
  * 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, enum dds_flags flags) __must_hold(local)
+enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags) __must_hold(local)
 {
        sector_t prev_first_sect, prev_size; /* previous meta location */
        sector_t la_size;
@@ -773,30 +792,78 @@ static int drbd_check_al_size(struct drbd_conf *mdev)
        return 0;
 }
 
-void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size) __must_hold(local)
+static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size)
 {
        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;
-       int max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
+       int max_hw_sectors = max_bio_size >> 9;
+       int max_segments = 0;
+
+       if (get_ldev_if_state(mdev, D_ATTACHING)) {
+               struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+
+               max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
+               max_segments = mdev->ldev->dc.max_bio_bvecs;
+               put_ldev(mdev);
+       }
 
        blk_queue_logical_block_size(q, 512);
        blk_queue_max_hw_sectors(q, max_hw_sectors);
        /* This is the workaround for "bio would need to, but cannot, be split" */
        blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
        blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1);
-       blk_queue_stack_limits(q, b);
 
-       dev_info(DEV, "max BIO size = %u\n", queue_max_hw_sectors(q) << 9);
+       if (get_ldev_if_state(mdev, D_ATTACHING)) {
+               struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+
+               blk_queue_stack_limits(q, b);
 
-       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;
+               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;
+               }
+               put_ldev(mdev);
        }
 }
 
+void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
+{
+       int now, new, local, peer;
+
+       now = queue_max_hw_sectors(mdev->rq_queue) << 9;
+       local = mdev->local_max_bio_size; /* Eventually last known value, from volatile memory */
+       peer = mdev->peer_max_bio_size; /* Eventually last known value, from meta data */
+
+       if (get_ldev_if_state(mdev, D_ATTACHING)) {
+               local = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
+               mdev->local_max_bio_size = local;
+               put_ldev(mdev);
+       }
+
+       /* We may ignore peer limits if the peer is modern enough.
+          Because new from 8.3.8 onwards the peer can use multiple
+          BIOs for a single peer_request */
+       if (mdev->state.conn >= C_CONNECTED) {
+               if (mdev->agreed_pro_version < 94)
+                       peer = mdev->peer_max_bio_size;
+               else if (mdev->agreed_pro_version == 94)
+                       peer = DRBD_MAX_SIZE_H80_PACKET;
+               else /* drbd 8.3.8 onwards */
+                       peer = DRBD_MAX_BIO_SIZE;
+       }
+
+       new = min_t(int, local, peer);
+
+       if (mdev->state.role == R_PRIMARY && new < now)
+               dev_err(DEV, "ASSERT FAILED new < now; (%d < %d)\n", new, now);
+
+       if (new != now)
+               dev_info(DEV, "max BIO size = %u\n", new);
+
+       drbd_setup_queue_param(mdev, new);
+}
+
 /* serialize deconfig (worker exiting, doing cleanup)
  * and reconfig (drbdsetup disk, drbdsetup net)
  *
@@ -865,7 +932,6 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        struct block_device *bdev;
        struct lru_cache *resync_lru = NULL;
        union drbd_state ns, os;
-       unsigned int max_bio_size;
        enum drbd_state_rv rv;
        int cp_discovered = 0;
        int logical_block_size;
@@ -1117,20 +1183,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
        mdev->read_cnt = 0;
        mdev->writ_cnt = 0;
 
-       max_bio_size = DRBD_MAX_BIO_SIZE;
-       if (mdev->state.conn == C_CONNECTED) {
-               /* We are Primary, Connected, and now attach a new local
-                * backing store. We must not increase the user visible maximum
-                * bio size on this device to something the peer may not be
-                * able to handle. */
-               if (mdev->agreed_pro_version < 94)
-                       max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9;
-               else if (mdev->agreed_pro_version == 94)
-                       max_bio_size = DRBD_MAX_SIZE_H80_PACKET;
-               /* else: drbd 8.3.9 and later, stay with default */
-       }
-
-       drbd_setup_queue_param(mdev, max_bio_size);
+       drbd_reconsider_max_bio_size(mdev);
 
        /* If I am currently not R_PRIMARY,
         * but meta data primary indicator is set,
@@ -1152,7 +1205,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
            !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
                set_bit(USE_DEGR_WFC_T, &mdev->flags);
 
-       dd = drbd_determin_dev_size(mdev, 0);
+       dd = drbd_determine_dev_size(mdev, 0);
        if (dd == dev_size_error) {
                retcode = ERR_NOMEM_BITMAP;
                goto force_diskless_dec;
@@ -1281,11 +1334,19 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
 static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
                          struct drbd_nl_cfg_reply *reply)
 {
+       enum drbd_ret_code retcode;
+       int ret;
        drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
-       reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
-       if (mdev->state.disk == D_DISKLESS)
-               wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+       retcode = drbd_request_state(mdev, NS(disk, D_FAILED));
+       /* D_FAILED will transition to DISKLESS. */
+       ret = wait_event_interruptible(mdev->misc_wait,
+                       mdev->state.disk != D_FAILED);
        drbd_resume_io(mdev);
+       if ((int)retcode == (int)SS_IS_DISKLESS)
+               retcode = SS_NOTHING_TO_DO;
+       if (ret)
+               retcode = ERR_INTR;
+       reply->ret_code = retcode;
        return 0;
 }
 
@@ -1658,7 +1719,7 @@ static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
 
        mdev->ldev->dc.disk_size = (sector_t)rs.resize_size;
        ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0);
-       dd = drbd_determin_dev_size(mdev, ddsf);
+       dd = drbd_determine_dev_size(mdev, ddsf);
        drbd_md_sync(mdev);
        put_ldev(mdev);
        if (dd == dev_size_error) {
index fd26666c0b08436fe0c648f3f09c016b0c999207..25d32c5aa50ab58e0b2fdb4e7dfde2377ec96878 100644 (file)
@@ -333,7 +333,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
        if (!page)
                goto fail;
 
-       INIT_HLIST_NODE(&e->colision);
+       INIT_HLIST_NODE(&e->collision);
        e->epoch = NULL;
        e->mdev = mdev;
        e->pages = page;
@@ -356,7 +356,7 @@ void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int i
                kfree(e->digest);
        drbd_pp_free(mdev, e->pages, is_net);
        D_ASSERT(atomic_read(&e->pending_bios) == 0);
-       D_ASSERT(hlist_unhashed(&e->colision));
+       D_ASSERT(hlist_unhashed(&e->collision));
        mempool_free(e, drbd_ee_mempool);
 }
 
@@ -787,7 +787,7 @@ static int drbd_connect(struct drbd_conf *mdev)
                }
 
                if (sock && msock) {
-                       schedule_timeout_interruptible(HZ / 10);
+                       schedule_timeout_interruptible(mdev->net_conf->ping_timeo*HZ/10);
                        ok = drbd_socket_okay(mdev, &sock);
                        ok = drbd_socket_okay(mdev, &msock) && ok;
                        if (ok)
@@ -899,11 +899,6 @@ retry:
 
        drbd_thread_start(&mdev->asender);
 
-       if (mdev->agreed_pro_version < 95 && get_ldev(mdev)) {
-               drbd_setup_queue_param(mdev, DRBD_MAX_SIZE_H80_PACKET);
-               put_ldev(mdev);
-       }
-
        if (drbd_send_protocol(mdev) == -1)
                return -1;
        drbd_send_sync_param(mdev, &mdev->sync_conf);
@@ -1418,7 +1413,7 @@ static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int u
        sector_t sector = e->sector;
        int ok;
 
-       D_ASSERT(hlist_unhashed(&e->colision));
+       D_ASSERT(hlist_unhashed(&e->collision));
 
        if (likely((e->flags & EE_WAS_ERROR) == 0)) {
                drbd_set_in_sync(mdev, sector, e->size);
@@ -1487,7 +1482,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi
                return false;
        }
 
-       /* hlist_del(&req->colision) is done in _req_may_be_done, to avoid
+       /* hlist_del(&req->collision) 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);
@@ -1558,11 +1553,11 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
         * 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);
+               D_ASSERT(!hlist_unhashed(&e->collision));
+               hlist_del_init(&e->collision);
                spin_unlock_irq(&mdev->req_lock);
        } else {
-               D_ASSERT(hlist_unhashed(&e->colision));
+               D_ASSERT(hlist_unhashed(&e->collision));
        }
 
        drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0));
@@ -1579,8 +1574,8 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u
        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);
+       D_ASSERT(!hlist_unhashed(&e->collision));
+       hlist_del_init(&e->collision);
        spin_unlock_irq(&mdev->req_lock);
 
        dec_unacked(mdev);
@@ -1755,7 +1750,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
 
                spin_lock_irq(&mdev->req_lock);
 
-               hlist_add_head(&e->colision, ee_hash_slot(mdev, sector));
+               hlist_add_head(&e->collision, ee_hash_slot(mdev, sector));
 
 #define OVERLAPS overlaps(i->sector, i->size, sector, size)
                slot = tl_hash_slot(mdev, sector);
@@ -1765,7 +1760,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
                        int have_conflict = 0;
                        prepare_to_wait(&mdev->misc_wait, &wait,
                                TASK_INTERRUPTIBLE);
-                       hlist_for_each_entry(i, n, slot, colision) {
+                       hlist_for_each_entry(i, n, slot, collision) {
                                if (OVERLAPS) {
                                        /* only ALERT on first iteration,
                                         * we may be woken up early... */
@@ -1804,7 +1799,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
                        }
 
                        if (signal_pending(current)) {
-                               hlist_del_init(&e->colision);
+                               hlist_del_init(&e->collision);
 
                                spin_unlock_irq(&mdev->req_lock);
 
@@ -1862,7 +1857,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
        dev_err(DEV, "submit failed, triggering re-connect\n");
        spin_lock_irq(&mdev->req_lock);
        list_del(&e->w.list);
-       hlist_del_init(&e->colision);
+       hlist_del_init(&e->collision);
        spin_unlock_irq(&mdev->req_lock);
        if (e->flags & EE_CALL_AL_COMPLETE_IO)
                drbd_al_complete_io(mdev, e->sector);
@@ -2916,12 +2911,6 @@ disconnect:
        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)
@@ -2939,7 +2928,6 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
 {
        struct p_sizes *p = &mdev->data.rbuf.sizes;
        enum determine_dev_size dd = unchanged;
-       unsigned int max_bio_size;
        sector_t p_size, p_usize, my_usize;
        int ldsc = 0; /* local disk size changed */
        enum dds_flags ddsf;
@@ -2994,7 +2982,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
 
        ddsf = be16_to_cpu(p->dds_flags);
        if (get_ldev(mdev)) {
-               dd = drbd_determin_dev_size(mdev, ddsf);
+               dd = drbd_determine_dev_size(mdev, ddsf);
                put_ldev(mdev);
                if (dd == dev_size_error)
                        return false;
@@ -3004,23 +2992,15 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
                drbd_set_my_capacity(mdev, p_size);
        }
 
+       mdev->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
+       drbd_reconsider_max_bio_size(mdev);
+
        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;
                }
 
-               if (mdev->agreed_pro_version < 94)
-                       max_bio_size = be32_to_cpu(p->max_bio_size);
-               else if (mdev->agreed_pro_version == 94)
-                       max_bio_size = DRBD_MAX_SIZE_H80_PACKET;
-               else /* drbd 8.3.8 onwards */
-                       max_bio_size = DRBD_MAX_BIO_SIZE;
-
-               if (max_bio_size != queue_max_hw_sectors(mdev->rq_queue) << 9)
-                       drbd_setup_queue_param(mdev, max_bio_size);
-
-               drbd_setup_order_type(mdev, be16_to_cpu(p->queue_order_type));
                put_ldev(mdev);
        }
 
@@ -4275,7 +4255,7 @@ static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev,
        struct hlist_node *n;
        struct drbd_request *req;
 
-       hlist_for_each_entry(req, n, slot, colision) {
+       hlist_for_each_entry(req, n, slot, collision) {
                if ((unsigned long)req == (unsigned long)id) {
                        if (req->sector != sector) {
                                dev_err(DEV, "_ack_id_to_req: found req %p but it has "
@@ -4554,6 +4534,7 @@ int drbd_asender(struct drbd_thread *thi)
        int received = 0;
        int expect   = sizeof(struct p_header80);
        int empty;
+       int ping_timeout_active = 0;
 
        sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev));
 
@@ -4566,6 +4547,7 @@ int drbd_asender(struct drbd_thread *thi)
                        ERR_IF(!drbd_send_ping(mdev)) goto reconnect;
                        mdev->meta.socket->sk->sk_rcvtimeo =
                                mdev->net_conf->ping_timeo*HZ/10;
+                       ping_timeout_active = 1;
                }
 
                /* conditionally cork;
@@ -4620,8 +4602,7 @@ int drbd_asender(struct drbd_thread *thi)
                        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) {
+                       if (ping_timeout_active) {
                                dev_err(DEV, "PingAck did not arrive in time.\n");
                                goto reconnect;
                        }
@@ -4660,6 +4641,11 @@ int drbd_asender(struct drbd_thread *thi)
                        if (!cmd->process(mdev, h))
                                goto reconnect;
 
+                       /* the idle_timeout (ping-int)
+                        * has been restored in got_PingAck() */
+                       if (cmd == get_asender_cmd(P_PING_ACK))
+                               ping_timeout_active = 0;
+
                        buf      = h;
                        received = 0;
                        expect   = sizeof(struct p_header80);
index 5c0c8be1bb0ae144e4d82ef9d3da257ca06af99d..3424d675b769a661857cdd41aa90a30e28c07b59 100644 (file)
@@ -163,7 +163,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev,
                 * 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) {
+               hlist_for_each_entry(i, n, slot, collision) {
                        if (OVERLAPS) {
                                dev_alert(DEV, "LOGIC BUG: completed: %p %llus +%u; "
                                      "other: %p %llus +%u\n",
@@ -187,7 +187,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev,
 #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) {
+               hlist_for_each_entry(e, n, slot, collision) {
                        if (OVERLAPS) {
                                wake_up(&mdev->misc_wait);
                                break;
@@ -260,8 +260,8 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m)
 
                /* remove the request from the conflict detection
                 * respective block_id verification hash */
-               if (!hlist_unhashed(&req->colision))
-                       hlist_del(&req->colision);
+               if (!hlist_unhashed(&req->collision))
+                       hlist_del(&req->collision);
                else
                        D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0);
 
@@ -329,7 +329,7 @@ static int _req_conflicts(struct drbd_request *req)
        struct hlist_node *n;
        struct hlist_head *slot;
 
-       D_ASSERT(hlist_unhashed(&req->colision));
+       D_ASSERT(hlist_unhashed(&req->collision));
 
        if (!get_net_conf(mdev))
                return 0;
@@ -341,7 +341,7 @@ static int _req_conflicts(struct drbd_request *req)
 
 #define OVERLAPS overlaps(i->sector, i->size, sector, size)
        slot = tl_hash_slot(mdev, sector);
-       hlist_for_each_entry(i, n, slot, colision) {
+       hlist_for_each_entry(i, n, slot, collision) {
                if (OVERLAPS) {
                        dev_alert(DEV, "%s[%u] Concurrent local write detected! "
                              "[DISCARD L] new: %llus +%u; "
@@ -359,7 +359,7 @@ static int _req_conflicts(struct drbd_request *req)
 #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) {
+               hlist_for_each_entry(e, n, slot, collision) {
                        if (OVERLAPS) {
                                dev_alert(DEV, "%s[%u] Concurrent remote write detected!"
                                      " [DISCARD L] new: %llus +%u; "
@@ -491,7 +491,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
 
                /* 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));
+               hlist_add_head(&req->collision, ar_hash_slot(mdev, req->sector));
 
                set_bit(UNPLUG_REMOTE, &mdev->flags);
 
@@ -507,7 +507,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
                /* assert something? */
                /* from drbd_make_request_common only */
 
-               hlist_add_head(&req->colision, tl_hash_slot(mdev, req->sector));
+               hlist_add_head(&req->collision, tl_hash_slot(mdev, req->sector));
                /* corresponding hlist_del is in _req_may_be_done() */
 
                /* NOTE
@@ -1033,7 +1033,7 @@ fail_conflicting:
        err = 0;
 
 fail_free_complete:
-       if (rw == WRITE && local)
+       if (req->rq_state & RQ_IN_ACT_LOG)
                drbd_al_complete_io(mdev, sector);
 fail_and_free_req:
        if (local) {
index 32e2c3e6a8134220943873c671cb7ac6adf83a10..68a234a5fdc5bc4ab19e2a5ab85cd198e588b9bd 100644 (file)
@@ -256,7 +256,7 @@ static inline struct drbd_request *_ar_id_to_req(struct drbd_conf *mdev,
        struct hlist_node *n;
        struct drbd_request *req;
 
-       hlist_for_each_entry(req, n, slot, colision) {
+       hlist_for_each_entry(req, n, slot, collision) {
                if ((unsigned long)req == (unsigned long)id) {
                        D_ASSERT(req->sector == sector);
                        return req;
@@ -291,7 +291,7 @@ static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
                req->epoch       = 0;
                req->sector      = bio_src->bi_sector;
                req->size        = bio_src->bi_size;
-               INIT_HLIST_NODE(&req->colision);
+               INIT_HLIST_NODE(&req->collision);
                INIT_LIST_HEAD(&req->tl_requests);
                INIT_LIST_HEAD(&req->w.list);
        }
@@ -323,6 +323,7 @@ extern int __req_mod(struct drbd_request *req, enum drbd_req_event what,
 extern void complete_master_bio(struct drbd_conf *mdev,
                struct bio_and_error *m);
 extern void request_timer_fn(unsigned long data);
+extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what);
 
 /* use this if you don't want to deal with calling complete_master_bio()
  * outside the spinlock, e.g. when walking some list on cleanup. */
index f7e6c92f8d03d001c1a452fe92b0c605c450bd38..4d76b06b6b20966f176e9b3dc9a795345a23798b 100644 (file)
@@ -126,7 +126,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo
        list_del(&e->w.list); /* has been on active_ee or sync_ee */
        list_add_tail(&e->w.list, &mdev->done_ee);
 
-       /* No hlist_del_init(&e->colision) here, we did not send the Ack yet,
+       /* No hlist_del_init(&e->collision) 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 */
@@ -297,42 +297,48 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *
        crypto_hash_final(&desc, digest);
 }
 
-static int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+/* TODO merge common code with w_e_end_ov_req */
+int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
        struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
        int digest_size;
        void *digest;
-       int ok;
+       int ok = 1;
 
        D_ASSERT(e->block_id == DRBD_MAGIC + 0xbeef);
 
-       if (unlikely(cancel)) {
-               drbd_free_ee(mdev, e);
-               return 1;
-       }
+       if (unlikely(cancel))
+               goto out;
 
-       if (likely((e->flags & EE_WAS_ERROR) == 0)) {
-               digest_size = crypto_hash_digestsize(mdev->csums_tfm);
-               digest = kmalloc(digest_size, GFP_NOIO);
-               if (digest) {
-                       drbd_csum_ee(mdev, mdev->csums_tfm, e, digest);
+       if (likely((e->flags & EE_WAS_ERROR) != 0))
+               goto out;
 
-                       inc_rs_pending(mdev);
-                       ok = drbd_send_drequest_csum(mdev,
-                                                    e->sector,
-                                                    e->size,
-                                                    digest,
-                                                    digest_size,
-                                                    P_CSUM_RS_REQUEST);
-                       kfree(digest);
-               } else {
-                       dev_err(DEV, "kmalloc() of digest failed.\n");
-                       ok = 0;
-               }
-       } else
-               ok = 1;
+       digest_size = crypto_hash_digestsize(mdev->csums_tfm);
+       digest = kmalloc(digest_size, GFP_NOIO);
+       if (digest) {
+               sector_t sector = e->sector;
+               unsigned int size = e->size;
+               drbd_csum_ee(mdev, mdev->csums_tfm, e, digest);
+               /* Free e and pages before send.
+                * In case we block on congestion, we could otherwise run into
+                * some distributed deadlock, if the other side blocks on
+                * congestion as well, because our receiver blocks in
+                * drbd_pp_alloc due to pp_in_use > max_buffers. */
+               drbd_free_ee(mdev, e);
+               e = NULL;
+               inc_rs_pending(mdev);
+               ok = drbd_send_drequest_csum(mdev, sector, size,
+                                            digest, digest_size,
+                                            P_CSUM_RS_REQUEST);
+               kfree(digest);
+       } else {
+               dev_err(DEV, "kmalloc() of digest failed.\n");
+               ok = 0;
+       }
 
-       drbd_free_ee(mdev, e);
+out:
+       if (e)
+               drbd_free_ee(mdev, e);
 
        if (unlikely(!ok))
                dev_err(DEV, "drbd_send_drequest(..., csum) failed\n");
@@ -834,7 +840,7 @@ int drbd_resync_finished(struct drbd_conf *mdev)
                        const int ratio =
                                (t == 0)     ? 0 :
                        (t < 100000) ? ((s*100)/t) : (s/(t/100));
-                       dev_info(DEV, "%u %% had equal check sums, eliminated: %luK; "
+                       dev_info(DEV, "%u %% had equal checksums, eliminated: %luK; "
                             "transferred %luK total %luK\n",
                             ratio,
                             Bit2KB(mdev->rs_same_csum),
@@ -1071,9 +1077,12 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
        return ok;
 }
 
+/* TODO merge common code with w_e_send_csum */
 int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
        struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+       sector_t sector = e->sector;
+       unsigned int size = e->size;
        int digest_size;
        void *digest;
        int ok = 1;
@@ -1093,17 +1102,25 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
        else
                memset(digest, 0, digest_size);
 
+       /* Free e and pages before send.
+        * In case we block on congestion, we could otherwise run into
+        * some distributed deadlock, if the other side blocks on
+        * congestion as well, because our receiver blocks in
+        * drbd_pp_alloc due to pp_in_use > max_buffers. */
+       drbd_free_ee(mdev, e);
+       e = NULL;
        inc_rs_pending(mdev);
-       ok = drbd_send_drequest_csum(mdev, e->sector, e->size,
-                                    digest, digest_size, P_OV_REPLY);
+       ok = drbd_send_drequest_csum(mdev, sector, size,
+                                    digest, digest_size,
+                                    P_OV_REPLY);
        if (!ok)
                dec_rs_pending(mdev);
        kfree(digest);
 
 out:
-       drbd_free_ee(mdev, e);
+       if (e)
+               drbd_free_ee(mdev, e);
        dec_unacked(mdev);
-
        return ok;
 }
 
@@ -1122,8 +1139,10 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 {
        struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
        struct digest_info *di;
-       int digest_size;
        void *digest;
+       sector_t sector = e->sector;
+       unsigned int size = e->size;
+       int digest_size;
        int ok, eq = 0;
 
        if (unlikely(cancel)) {
@@ -1153,16 +1172,21 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
                }
        }
 
-       dec_unacked(mdev);
+               /* Free e and pages before send.
+                * In case we block on congestion, we could otherwise run into
+                * some distributed deadlock, if the other side blocks on
+                * congestion as well, because our receiver blocks in
+                * drbd_pp_alloc due to pp_in_use > max_buffers. */
+       drbd_free_ee(mdev, e);
        if (!eq)
-               drbd_ov_oos_found(mdev, e->sector, e->size);
+               drbd_ov_oos_found(mdev, sector, size);
        else
                ov_oos_print(mdev);
 
-       ok = drbd_send_ack_ex(mdev, P_OV_RESULT, e->sector, e->size,
+       ok = drbd_send_ack_ex(mdev, P_OV_RESULT, sector, size,
                              eq ? ID_IN_SYNC : ID_OUT_OF_SYNC);
 
-       drbd_free_ee(mdev, e);
+       dec_unacked(mdev);
 
        --mdev->ov_left;
 
index a076a14ca72d848fbf144042a7272038eab22390..c59a672a3de0d6571fbe173a8328d12a1e03c86b 100644 (file)
@@ -1658,7 +1658,7 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data)
        struct kobject *kobj;
 
        mutex_lock(&loop_devices_mutex);
-       lo = loop_init_one(dev & MINORMASK);
+       lo = loop_init_one(MINOR(dev) >> part_shift);
        kobj = lo ? get_disk(lo->lo_disk) : ERR_PTR(-ENOMEM);
        mutex_unlock(&loop_devices_mutex);
 
@@ -1691,15 +1691,18 @@ static int __init loop_init(void)
        if (max_part > 0)
                part_shift = fls(max_part);
 
+       if ((1UL << part_shift) > DISK_MAX_PARTS)
+               return -EINVAL;
+
        if (max_loop > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
        if (max_loop) {
                nr = max_loop;
-               range = max_loop;
+               range = max_loop << part_shift;
        } else {
                nr = 8;
-               range = 1UL << (MINORBITS - part_shift);
+               range = 1UL << MINORBITS;
        }
 
        if (register_blkdev(LOOP_MAJOR, "loop"))
@@ -1738,7 +1741,7 @@ static void __exit loop_exit(void)
        unsigned long range;
        struct loop_device *lo, *next;
 
-       range = max_loop ? max_loop :  1UL << (MINORBITS - part_shift);
+       range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
 
        list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
                loop_del_one(lo);
index 8690e31d993287e16a68caca0e2125c0c7e6bdb0..a0aabd904a51294605a20e39de391660bff77e90 100644 (file)
@@ -320,6 +320,8 @@ static void pcd_init_units(void)
                disk->first_minor = unit;
                strcpy(disk->disk_name, cd->name);      /* umm... */
                disk->fops = &pcd_bdops;
+               disk->flags = GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+               disk->events = DISK_EVENT_MEDIA_CHANGE;
        }
 }
 
index 9712fad82bc6cf2be78daaa503432e8725ab2a4f..1278098624e6382ab77522c68535d39b3c863916 100644 (file)
@@ -1191,14 +1191,19 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev,
 static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
 {
        struct rbd_device *dev = (struct rbd_device *)data;
+       int rc;
+
        if (!dev)
                return;
 
        dout("rbd_watch_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name,
                notify_id, (int)opcode);
        mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-       __rbd_update_snaps(dev);
+       rc = __rbd_update_snaps(dev);
        mutex_unlock(&ctl_mutex);
+       if (rc)
+               pr_warning(DRV_NAME "%d got notification but failed to update"
+                          " snaps: %d\n", dev->major, rc);
 
        rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name);
 }
@@ -1597,7 +1602,7 @@ static int rbd_header_add_snap(struct rbd_device *dev,
        int name_len = strlen(snap_name);
        u64 new_snapid;
        int ret;
-       void *data, *data_start, *data_end;
+       void *data, *p, *e;
        u64 ver;
 
        /* we should create a snapshot only if we're pointing at the head */
@@ -1614,16 +1619,16 @@ static int rbd_header_add_snap(struct rbd_device *dev,
        if (!data)
                return -ENOMEM;
 
-       data_start = data;
-       data_end = data + name_len + 16;
+       p = data;
+       e = data + name_len + 16;
 
-       ceph_encode_string_safe(&data, data_end, snap_name, name_len, bad);
-       ceph_encode_64_safe(&data, data_end, new_snapid, bad);
+       ceph_encode_string_safe(&p, e, snap_name, name_len, bad);
+       ceph_encode_64_safe(&p, e, new_snapid, bad);
 
        ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add",
-                               data_start, data - data_start, &ver);
+                               data, p - data, &ver);
 
-       kfree(data_start);
+       kfree(data);
 
        if (ret < 0)
                return ret;
@@ -1659,6 +1664,9 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
        if (ret < 0)
                return ret;
 
+       /* resized? */
+       set_capacity(rbd_dev->disk, h.image_size / 512ULL);
+
        down_write(&rbd_dev->header.snap_rwsem);
 
        snap_seq = rbd_dev->header.snapc->seq;
@@ -1716,7 +1724,8 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        if (!disk)
                goto out;
 
-       sprintf(disk->disk_name, DRV_NAME "%d", rbd_dev->id);
+       snprintf(disk->disk_name, sizeof(disk->disk_name), DRV_NAME "%d",
+                rbd_dev->id);
        disk->major = rbd_dev->major;
        disk->first_minor = 0;
        disk->fops = &rbd_bd_ops;
diff --git a/drivers/block/xen-blkback/Makefile b/drivers/block/xen-blkback/Makefile
new file mode 100644 (file)
index 0000000..e491c1b
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_XEN_BLKDEV_BACKEND) := xen-blkback.o
+
+xen-blkback-y  := blkback.o xenbus.o
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
new file mode 100644 (file)
index 0000000..c73910c
--- /dev/null
@@ -0,0 +1,824 @@
+/******************************************************************************
+ *
+ * Back-end of the driver for virtual block devices. This portion of the
+ * driver exports a 'unified' block-device interface that can be accessed
+ * by any operating system that implements a compatible front end. A
+ * reference front-end implementation can be found in:
+ *  drivers/block/xen-blkfront.c
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Copyright (c) 2005, Christopher Clark
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+
+#include <xen/events.h>
+#include <xen/page.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+#include "common.h"
+
+/*
+ * These are rather arbitrary. They are fairly large because adjacent requests
+ * pulled from a communication ring are quite likely to end up being part of
+ * the same scatter/gather request at the disc.
+ *
+ * ** TRY INCREASING 'xen_blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
+ *
+ * This will increase the chances of being able to write whole tracks.
+ * 64 should be enough to keep us competitive with Linux.
+ */
+static int xen_blkif_reqs = 64;
+module_param_named(reqs, xen_blkif_reqs, int, 0);
+MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate");
+
+/* Run-time switchable: /sys/module/blkback/parameters/ */
+static unsigned int log_stats;
+module_param(log_stats, int, 0644);
+
+/*
+ * Each outstanding request that we've passed to the lower device layers has a
+ * 'pending_req' allocated to it. Each buffer_head that completes decrements
+ * the pendcnt towards zero. When it hits zero, the specified domain has a
+ * response queued for it, with the saved 'id' passed back.
+ */
+struct pending_req {
+       struct xen_blkif        *blkif;
+       u64                     id;
+       int                     nr_pages;
+       atomic_t                pendcnt;
+       unsigned short          operation;
+       int                     status;
+       struct list_head        free_list;
+};
+
+#define BLKBACK_INVALID_HANDLE (~0)
+
+struct xen_blkbk {
+       struct pending_req      *pending_reqs;
+       /* List of all 'pending_req' available */
+       struct list_head        pending_free;
+       /* And its spinlock. */
+       spinlock_t              pending_free_lock;
+       wait_queue_head_t       pending_free_wq;
+       /* The list of all pages that are available. */
+       struct page             **pending_pages;
+       /* And the grant handles that are available. */
+       grant_handle_t          *pending_grant_handles;
+};
+
+static struct xen_blkbk *blkbk;
+
+/*
+ * Little helpful macro to figure out the index and virtual address of the
+ * pending_pages[..]. For each 'pending_req' we have have up to
+ * BLKIF_MAX_SEGMENTS_PER_REQUEST (11) pages. The seg would be from 0 through
+ * 10 and would index in the pending_pages[..].
+ */
+static inline int vaddr_pagenr(struct pending_req *req, int seg)
+{
+       return (req - blkbk->pending_reqs) *
+               BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
+}
+
+#define pending_page(req, seg) pending_pages[vaddr_pagenr(req, seg)]
+
+static inline unsigned long vaddr(struct pending_req *req, int seg)
+{
+       unsigned long pfn = page_to_pfn(blkbk->pending_page(req, seg));
+       return (unsigned long)pfn_to_kaddr(pfn);
+}
+
+#define pending_handle(_req, _seg) \
+       (blkbk->pending_grant_handles[vaddr_pagenr(_req, _seg)])
+
+
+static int do_block_io_op(struct xen_blkif *blkif);
+static int dispatch_rw_block_io(struct xen_blkif *blkif,
+                               struct blkif_request *req,
+                               struct pending_req *pending_req);
+static void make_response(struct xen_blkif *blkif, u64 id,
+                         unsigned short op, int st);
+
+/*
+ * Retrieve from the 'pending_reqs' a free pending_req structure to be used.
+ */
+static struct pending_req *alloc_req(void)
+{
+       struct pending_req *req = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&blkbk->pending_free_lock, flags);
+       if (!list_empty(&blkbk->pending_free)) {
+               req = list_entry(blkbk->pending_free.next, struct pending_req,
+                                free_list);
+               list_del(&req->free_list);
+       }
+       spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+       return req;
+}
+
+/*
+ * Return the 'pending_req' structure back to the freepool. We also
+ * wake up the thread if it was waiting for a free page.
+ */
+static void free_req(struct pending_req *req)
+{
+       unsigned long flags;
+       int was_empty;
+
+       spin_lock_irqsave(&blkbk->pending_free_lock, flags);
+       was_empty = list_empty(&blkbk->pending_free);
+       list_add(&req->free_list, &blkbk->pending_free);
+       spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+       if (was_empty)
+               wake_up(&blkbk->pending_free_wq);
+}
+
+/*
+ * Routines for managing virtual block devices (vbds).
+ */
+static int xen_vbd_translate(struct phys_req *req, struct xen_blkif *blkif,
+                            int operation)
+{
+       struct xen_vbd *vbd = &blkif->vbd;
+       int rc = -EACCES;
+
+       if ((operation != READ) && vbd->readonly)
+               goto out;
+
+       if (likely(req->nr_sects)) {
+               blkif_sector_t end = req->sector_number + req->nr_sects;
+
+               if (unlikely(end < req->sector_number))
+                       goto out;
+               if (unlikely(end > vbd_sz(vbd)))
+                       goto out;
+       }
+
+       req->dev  = vbd->pdevice;
+       req->bdev = vbd->bdev;
+       rc = 0;
+
+ out:
+       return rc;
+}
+
+static void xen_vbd_resize(struct xen_blkif *blkif)
+{
+       struct xen_vbd *vbd = &blkif->vbd;
+       struct xenbus_transaction xbt;
+       int err;
+       struct xenbus_device *dev = xen_blkbk_xenbus(blkif->be);
+       unsigned long long new_size = vbd_sz(vbd);
+
+       pr_info(DRV_PFX "VBD Resize: Domid: %d, Device: (%d, %d)\n",
+               blkif->domid, MAJOR(vbd->pdevice), MINOR(vbd->pdevice));
+       pr_info(DRV_PFX "VBD Resize: new size %llu\n", new_size);
+       vbd->size = new_size;
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               pr_warn(DRV_PFX "Error starting transaction");
+               return;
+       }
+       err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
+                           (unsigned long long)vbd_sz(vbd));
+       if (err) {
+               pr_warn(DRV_PFX "Error writing new size");
+               goto abort;
+       }
+       /*
+        * Write the current state; we will use this to synchronize
+        * the front-end. If the current state is "connected" the
+        * front-end will get the new size information online.
+        */
+       err = xenbus_printf(xbt, dev->nodename, "state", "%d", dev->state);
+       if (err) {
+               pr_warn(DRV_PFX "Error writing the state");
+               goto abort;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err == -EAGAIN)
+               goto again;
+       if (err)
+               pr_warn(DRV_PFX "Error ending transaction");
+       return;
+abort:
+       xenbus_transaction_end(xbt, 1);
+}
+
+/*
+ * Notification from the guest OS.
+ */
+static void blkif_notify_work(struct xen_blkif *blkif)
+{
+       blkif->waiting_reqs = 1;
+       wake_up(&blkif->wq);
+}
+
+irqreturn_t xen_blkif_be_int(int irq, void *dev_id)
+{
+       blkif_notify_work(dev_id);
+       return IRQ_HANDLED;
+}
+
+/*
+ * SCHEDULER FUNCTIONS
+ */
+
+static void print_stats(struct xen_blkif *blkif)
+{
+       pr_info("xen-blkback (%s): oo %3d  |  rd %4d  |  wr %4d  |  f %4d\n",
+                current->comm, blkif->st_oo_req,
+                blkif->st_rd_req, blkif->st_wr_req, blkif->st_f_req);
+       blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
+       blkif->st_rd_req = 0;
+       blkif->st_wr_req = 0;
+       blkif->st_oo_req = 0;
+}
+
+int xen_blkif_schedule(void *arg)
+{
+       struct xen_blkif *blkif = arg;
+       struct xen_vbd *vbd = &blkif->vbd;
+
+       xen_blkif_get(blkif);
+
+       while (!kthread_should_stop()) {
+               if (try_to_freeze())
+                       continue;
+               if (unlikely(vbd->size != vbd_sz(vbd)))
+                       xen_vbd_resize(blkif);
+
+               wait_event_interruptible(
+                       blkif->wq,
+                       blkif->waiting_reqs || kthread_should_stop());
+               wait_event_interruptible(
+                       blkbk->pending_free_wq,
+                       !list_empty(&blkbk->pending_free) ||
+                       kthread_should_stop());
+
+               blkif->waiting_reqs = 0;
+               smp_mb(); /* clear flag *before* checking for work */
+
+               if (do_block_io_op(blkif))
+                       blkif->waiting_reqs = 1;
+
+               if (log_stats && time_after(jiffies, blkif->st_print))
+                       print_stats(blkif);
+       }
+
+       if (log_stats)
+               print_stats(blkif);
+
+       blkif->xenblkd = NULL;
+       xen_blkif_put(blkif);
+
+       return 0;
+}
+
+struct seg_buf {
+       unsigned long buf;
+       unsigned int nsec;
+};
+/*
+ * Unmap the grant references, and also remove the M2P over-rides
+ * used in the 'pending_req'.
+ */
+static void xen_blkbk_unmap(struct pending_req *req)
+{
+       struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       unsigned int i, invcount = 0;
+       grant_handle_t handle;
+       int ret;
+
+       for (i = 0; i < req->nr_pages; i++) {
+               handle = pending_handle(req, i);
+               if (handle == BLKBACK_INVALID_HANDLE)
+                       continue;
+               gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i),
+                                   GNTMAP_host_map, handle);
+               pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
+               invcount++;
+       }
+
+       ret = HYPERVISOR_grant_table_op(
+               GNTTABOP_unmap_grant_ref, unmap, invcount);
+       BUG_ON(ret);
+       /*
+        * Note, we use invcount, so nr->pages, so we can't index
+        * using vaddr(req, i).
+        */
+       for (i = 0; i < invcount; i++) {
+               ret = m2p_remove_override(
+                       virt_to_page(unmap[i].host_addr), false);
+               if (ret) {
+                       pr_alert(DRV_PFX "Failed to remove M2P override for %lx\n",
+                                (unsigned long)unmap[i].host_addr);
+                       continue;
+               }
+       }
+}
+
+static int xen_blkbk_map(struct blkif_request *req,
+                        struct pending_req *pending_req,
+                        struct seg_buf seg[])
+{
+       struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       int i;
+       int nseg = req->nr_segments;
+       int ret = 0;
+
+       /*
+        * Fill out preq.nr_sects with proper amount of sectors, and setup
+        * assign map[..] with the PFN of the page in our domain with the
+        * corresponding grant reference for each page.
+        */
+       for (i = 0; i < nseg; i++) {
+               uint32_t flags;
+
+               flags = GNTMAP_host_map;
+               if (pending_req->operation != BLKIF_OP_READ)
+                       flags |= GNTMAP_readonly;
+               gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
+                                 req->u.rw.seg[i].gref,
+                                 pending_req->blkif->domid);
+       }
+
+       ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg);
+       BUG_ON(ret);
+
+       /*
+        * Now swizzle the MFN in our domain with the MFN from the other domain
+        * so that when we access vaddr(pending_req,i) it has the contents of
+        * the page from the other domain.
+        */
+       for (i = 0; i < nseg; i++) {
+               if (unlikely(map[i].status != 0)) {
+                       pr_debug(DRV_PFX "invalid buffer -- could not remap it\n");
+                       map[i].handle = BLKBACK_INVALID_HANDLE;
+                       ret |= 1;
+               }
+
+               pending_handle(pending_req, i) = map[i].handle;
+
+               if (ret)
+                       continue;
+
+               ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr),
+                       blkbk->pending_page(pending_req, i), false);
+               if (ret) {
+                       pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n",
+                                (unsigned long)map[i].dev_bus_addr, ret);
+                       /* We could switch over to GNTTABOP_copy */
+                       continue;
+               }
+
+               seg[i].buf  = map[i].dev_bus_addr |
+                       (req->u.rw.seg[i].first_sect << 9);
+       }
+       return ret;
+}
+
+/*
+ * Completion callback on the bio's. Called as bh->b_end_io()
+ */
+
+static void __end_block_io_op(struct pending_req *pending_req, int error)
+{
+       /* An error fails the entire request. */
+       if ((pending_req->operation == BLKIF_OP_FLUSH_DISKCACHE) &&
+           (error == -EOPNOTSUPP)) {
+               pr_debug(DRV_PFX "flush diskcache op failed, not supported\n");
+               xen_blkbk_flush_diskcache(XBT_NIL, pending_req->blkif->be, 0);
+               pending_req->status = BLKIF_RSP_EOPNOTSUPP;
+       } else if (error) {
+               pr_debug(DRV_PFX "Buffer not up-to-date at end of operation,"
+                        " error=%d\n", error);
+               pending_req->status = BLKIF_RSP_ERROR;
+       }
+
+       /*
+        * If all of the bio's have completed it is time to unmap
+        * the grant references associated with 'request' and provide
+        * the proper response on the ring.
+        */
+       if (atomic_dec_and_test(&pending_req->pendcnt)) {
+               xen_blkbk_unmap(pending_req);
+               make_response(pending_req->blkif, pending_req->id,
+                             pending_req->operation, pending_req->status);
+               xen_blkif_put(pending_req->blkif);
+               free_req(pending_req);
+       }
+}
+
+/*
+ * bio callback.
+ */
+static void end_block_io_op(struct bio *bio, int error)
+{
+       __end_block_io_op(bio->bi_private, error);
+       bio_put(bio);
+}
+
+
+
+/*
+ * Function to copy the from the ring buffer the 'struct blkif_request'
+ * (which has the sectors we want, number of them, grant references, etc),
+ * and transmute  it to the block API to hand it over to the proper block disk.
+ */
+static int do_block_io_op(struct xen_blkif *blkif)
+{
+       union blkif_back_rings *blk_rings = &blkif->blk_rings;
+       struct blkif_request req;
+       struct pending_req *pending_req;
+       RING_IDX rc, rp;
+       int more_to_do = 0;
+
+       rc = blk_rings->common.req_cons;
+       rp = blk_rings->common.sring->req_prod;
+       rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+       while (rc != rp) {
+
+               if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
+                       break;
+
+               if (kthread_should_stop()) {
+                       more_to_do = 1;
+                       break;
+               }
+
+               pending_req = alloc_req();
+               if (NULL == pending_req) {
+                       blkif->st_oo_req++;
+                       more_to_do = 1;
+                       break;
+               }
+
+               switch (blkif->blk_protocol) {
+               case BLKIF_PROTOCOL_NATIVE:
+                       memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc), sizeof(req));
+                       break;
+               case BLKIF_PROTOCOL_X86_32:
+                       blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc));
+                       break;
+               case BLKIF_PROTOCOL_X86_64:
+                       blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc));
+                       break;
+               default:
+                       BUG();
+               }
+               blk_rings->common.req_cons = ++rc; /* before make_response() */
+
+               /* Apply all sanity checks to /private copy/ of request. */
+               barrier();
+
+               if (dispatch_rw_block_io(blkif, &req, pending_req))
+                       break;
+
+               /* Yield point for this unbounded loop. */
+               cond_resched();
+       }
+
+       return more_to_do;
+}
+
+/*
+ * Transmutation of the 'struct blkif_request' to a proper 'struct bio'
+ * and call the 'submit_bio' to pass it to the underlying storage.
+ */
+static int dispatch_rw_block_io(struct xen_blkif *blkif,
+                               struct blkif_request *req,
+                               struct pending_req *pending_req)
+{
+       struct phys_req preq;
+       struct seg_buf seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       unsigned int nseg;
+       struct bio *bio = NULL;
+       struct bio *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       int i, nbio = 0;
+       int operation;
+       struct blk_plug plug;
+
+       switch (req->operation) {
+       case BLKIF_OP_READ:
+               blkif->st_rd_req++;
+               operation = READ;
+               break;
+       case BLKIF_OP_WRITE:
+               blkif->st_wr_req++;
+               operation = WRITE_ODIRECT;
+               break;
+       case BLKIF_OP_FLUSH_DISKCACHE:
+               blkif->st_f_req++;
+               operation = WRITE_FLUSH;
+               break;
+       case BLKIF_OP_WRITE_BARRIER:
+       default:
+               operation = 0; /* make gcc happy */
+               goto fail_response;
+               break;
+       }
+
+       /* Check that the number of segments is sane. */
+       nseg = req->nr_segments;
+       if (unlikely(nseg == 0 && operation != WRITE_FLUSH) ||
+           unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
+               pr_debug(DRV_PFX "Bad number of segments in request (%d)\n",
+                        nseg);
+               /* Haven't submitted any bio's yet. */
+               goto fail_response;
+       }
+
+       preq.dev           = req->handle;
+       preq.sector_number = req->u.rw.sector_number;
+       preq.nr_sects      = 0;
+
+       pending_req->blkif     = blkif;
+       pending_req->id        = req->id;
+       pending_req->operation = req->operation;
+       pending_req->status    = BLKIF_RSP_OKAY;
+       pending_req->nr_pages  = nseg;
+
+       for (i = 0; i < nseg; i++) {
+               seg[i].nsec = req->u.rw.seg[i].last_sect -
+                       req->u.rw.seg[i].first_sect + 1;
+               if ((req->u.rw.seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
+                   (req->u.rw.seg[i].last_sect < req->u.rw.seg[i].first_sect))
+                       goto fail_response;
+               preq.nr_sects += seg[i].nsec;
+
+       }
+
+       if (xen_vbd_translate(&preq, blkif, operation) != 0) {
+               pr_debug(DRV_PFX "access denied: %s of [%llu,%llu] on dev=%04x\n",
+                        operation == READ ? "read" : "write",
+                        preq.sector_number,
+                        preq.sector_number + preq.nr_sects, preq.dev);
+               goto fail_response;
+       }
+
+       /*
+        * This check _MUST_ be done after xen_vbd_translate as the preq.bdev
+        * is set there.
+        */
+       for (i = 0; i < nseg; i++) {
+               if (((int)preq.sector_number|(int)seg[i].nsec) &
+                   ((bdev_logical_block_size(preq.bdev) >> 9) - 1)) {
+                       pr_debug(DRV_PFX "Misaligned I/O request from domain %d",
+                                blkif->domid);
+                       goto fail_response;
+               }
+       }
+
+       /*
+        * If we have failed at this point, we need to undo the M2P override,
+        * set gnttab_set_unmap_op on all of the grant references and perform
+        * the hypercall to unmap the grants - that is all done in
+        * xen_blkbk_unmap.
+        */
+       if (xen_blkbk_map(req, pending_req, seg))
+               goto fail_flush;
+
+       /* This corresponding xen_blkif_put is done in __end_block_io_op */
+       xen_blkif_get(blkif);
+
+       for (i = 0; i < nseg; i++) {
+               while ((bio == NULL) ||
+                      (bio_add_page(bio,
+                                    blkbk->pending_page(pending_req, i),
+                                    seg[i].nsec << 9,
+                                    seg[i].buf & ~PAGE_MASK) == 0)) {
+
+                       bio = bio_alloc(GFP_KERNEL, nseg-i);
+                       if (unlikely(bio == NULL))
+                               goto fail_put_bio;
+
+                       biolist[nbio++] = bio;
+                       bio->bi_bdev    = preq.bdev;
+                       bio->bi_private = pending_req;
+                       bio->bi_end_io  = end_block_io_op;
+                       bio->bi_sector  = preq.sector_number;
+               }
+
+               preq.sector_number += seg[i].nsec;
+       }
+
+       /* This will be hit if the operation was a flush. */
+       if (!bio) {
+               BUG_ON(operation != WRITE_FLUSH);
+
+               bio = bio_alloc(GFP_KERNEL, 0);
+               if (unlikely(bio == NULL))
+                       goto fail_put_bio;
+
+               biolist[nbio++] = bio;
+               bio->bi_bdev    = preq.bdev;
+               bio->bi_private = pending_req;
+               bio->bi_end_io  = end_block_io_op;
+       }
+
+       /*
+        * We set it one so that the last submit_bio does not have to call
+        * atomic_inc.
+        */
+       atomic_set(&pending_req->pendcnt, nbio);
+
+       /* Get a reference count for the disk queue and start sending I/O */
+       blk_start_plug(&plug);
+
+       for (i = 0; i < nbio; i++)
+               submit_bio(operation, biolist[i]);
+
+       /* Let the I/Os go.. */
+       blk_finish_plug(&plug);
+
+       if (operation == READ)
+               blkif->st_rd_sect += preq.nr_sects;
+       else if (operation == WRITE || operation == WRITE_FLUSH)
+               blkif->st_wr_sect += preq.nr_sects;
+
+       return 0;
+
+ fail_flush:
+       xen_blkbk_unmap(pending_req);
+ fail_response:
+       /* Haven't submitted any bio's yet. */
+       make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
+       free_req(pending_req);
+       msleep(1); /* back off a bit */
+       return -EIO;
+
+ fail_put_bio:
+       for (i = 0; i < nbio; i++)
+               bio_put(biolist[i]);
+       __end_block_io_op(pending_req, -EINVAL);
+       msleep(1); /* back off a bit */
+       return -EIO;
+}
+
+
+
+/*
+ * Put a response on the ring on how the operation fared.
+ */
+static void make_response(struct xen_blkif *blkif, u64 id,
+                         unsigned short op, int st)
+{
+       struct blkif_response  resp;
+       unsigned long     flags;
+       union blkif_back_rings *blk_rings = &blkif->blk_rings;
+       int more_to_do = 0;
+       int notify;
+
+       resp.id        = id;
+       resp.operation = op;
+       resp.status    = st;
+
+       spin_lock_irqsave(&blkif->blk_ring_lock, flags);
+       /* Place on the response ring for the relevant domain. */
+       switch (blkif->blk_protocol) {
+       case BLKIF_PROTOCOL_NATIVE:
+               memcpy(RING_GET_RESPONSE(&blk_rings->native, blk_rings->native.rsp_prod_pvt),
+                      &resp, sizeof(resp));
+               break;
+       case BLKIF_PROTOCOL_X86_32:
+               memcpy(RING_GET_RESPONSE(&blk_rings->x86_32, blk_rings->x86_32.rsp_prod_pvt),
+                      &resp, sizeof(resp));
+               break;
+       case BLKIF_PROTOCOL_X86_64:
+               memcpy(RING_GET_RESPONSE(&blk_rings->x86_64, blk_rings->x86_64.rsp_prod_pvt),
+                      &resp, sizeof(resp));
+               break;
+       default:
+               BUG();
+       }
+       blk_rings->common.rsp_prod_pvt++;
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify);
+       if (blk_rings->common.rsp_prod_pvt == blk_rings->common.req_cons) {
+               /*
+                * Tail check for pending requests. Allows frontend to avoid
+                * notifications if requests are already in flight (lower
+                * overheads and promotes batching).
+                */
+               RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do);
+
+       } else if (RING_HAS_UNCONSUMED_REQUESTS(&blk_rings->common)) {
+               more_to_do = 1;
+       }
+
+       spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
+
+       if (more_to_do)
+               blkif_notify_work(blkif);
+       if (notify)
+               notify_remote_via_irq(blkif->irq);
+}
+
+static int __init xen_blkif_init(void)
+{
+       int i, mmap_pages;
+       int rc = 0;
+
+       if (!xen_pv_domain())
+               return -ENODEV;
+
+       blkbk = kzalloc(sizeof(struct xen_blkbk), GFP_KERNEL);
+       if (!blkbk) {
+               pr_alert(DRV_PFX "%s: out of memory!\n", __func__);
+               return -ENOMEM;
+       }
+
+       mmap_pages = xen_blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+       blkbk->pending_reqs          = kmalloc(sizeof(blkbk->pending_reqs[0]) *
+                                       xen_blkif_reqs, GFP_KERNEL);
+       blkbk->pending_grant_handles = kzalloc(sizeof(blkbk->pending_grant_handles[0]) *
+                                       mmap_pages, GFP_KERNEL);
+       blkbk->pending_pages         = kzalloc(sizeof(blkbk->pending_pages[0]) *
+                                       mmap_pages, GFP_KERNEL);
+
+       if (!blkbk->pending_reqs || !blkbk->pending_grant_handles ||
+           !blkbk->pending_pages) {
+               rc = -ENOMEM;
+               goto out_of_memory;
+       }
+
+       for (i = 0; i < mmap_pages; i++) {
+               blkbk->pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
+               blkbk->pending_pages[i] = alloc_page(GFP_KERNEL);
+               if (blkbk->pending_pages[i] == NULL) {
+                       rc = -ENOMEM;
+                       goto out_of_memory;
+               }
+       }
+       rc = xen_blkif_interface_init();
+       if (rc)
+               goto failed_init;
+
+       memset(blkbk->pending_reqs, 0, sizeof(blkbk->pending_reqs));
+
+       INIT_LIST_HEAD(&blkbk->pending_free);
+       spin_lock_init(&blkbk->pending_free_lock);
+       init_waitqueue_head(&blkbk->pending_free_wq);
+
+       for (i = 0; i < xen_blkif_reqs; i++)
+               list_add_tail(&blkbk->pending_reqs[i].free_list,
+                             &blkbk->pending_free);
+
+       rc = xen_blkif_xenbus_init();
+       if (rc)
+               goto failed_init;
+
+       return 0;
+
+ out_of_memory:
+       pr_alert(DRV_PFX "%s: out of memory\n", __func__);
+ failed_init:
+       kfree(blkbk->pending_reqs);
+       kfree(blkbk->pending_grant_handles);
+       for (i = 0; i < mmap_pages; i++) {
+               if (blkbk->pending_pages[i])
+                       __free_page(blkbk->pending_pages[i]);
+       }
+       kfree(blkbk->pending_pages);
+       kfree(blkbk);
+       blkbk = NULL;
+       return rc;
+}
+
+module_init(xen_blkif_init);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
new file mode 100644 (file)
index 0000000..9e40b28
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_BLKIF__BACKEND__COMMON_H__
+#define __XEN_BLKIF__BACKEND__COMMON_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm/hypervisor.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/io/blkif.h>
+#include <xen/interface/io/protocols.h>
+
+#define DRV_PFX "xen-blkback:"
+#define DPRINTK(fmt, args...)                          \
+       pr_debug(DRV_PFX "(%s:%d) " fmt ".\n",  \
+                __func__, __LINE__, ##args)
+
+
+/* Not a real protocol.  Used to generate ring structs which contain
+ * the elements common to all protocols only.  This way we get a
+ * compiler-checkable way to use common struct elements, so we can
+ * avoid using switch(protocol) in a number of places.  */
+struct blkif_common_request {
+       char dummy;
+};
+struct blkif_common_response {
+       char dummy;
+};
+
+/* i386 protocol version */
+#pragma pack(push, 4)
+struct blkif_x86_32_request {
+       uint8_t        operation;    /* BLKIF_OP_???                         */
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       id;           /* private guest value, echoed in resp  */
+       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+       struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_32_response {
+       uint64_t        id;              /* copied from request */
+       uint8_t         operation;       /* copied from request */
+       int16_t         status;          /* BLKIF_RSP_???       */
+};
+#pragma pack(pop)
+
+/* x86_64 protocol version */
+struct blkif_x86_64_request {
+       uint8_t        operation;    /* BLKIF_OP_???                         */
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       __attribute__((__aligned__(8))) id;
+       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+       struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_64_response {
+       uint64_t       __attribute__((__aligned__(8))) id;
+       uint8_t         operation;       /* copied from request */
+       int16_t         status;          /* BLKIF_RSP_???       */
+};
+
+DEFINE_RING_TYPES(blkif_common, struct blkif_common_request,
+                 struct blkif_common_response);
+DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request,
+                 struct blkif_x86_32_response);
+DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request,
+                 struct blkif_x86_64_response);
+
+union blkif_back_rings {
+       struct blkif_back_ring        native;
+       struct blkif_common_back_ring common;
+       struct blkif_x86_32_back_ring x86_32;
+       struct blkif_x86_64_back_ring x86_64;
+};
+
+enum blkif_protocol {
+       BLKIF_PROTOCOL_NATIVE = 1,
+       BLKIF_PROTOCOL_X86_32 = 2,
+       BLKIF_PROTOCOL_X86_64 = 3,
+};
+
+struct xen_vbd {
+       /* What the domain refers to this vbd as. */
+       blkif_vdev_t            handle;
+       /* Non-zero -> read-only */
+       unsigned char           readonly;
+       /* VDISK_xxx */
+       unsigned char           type;
+       /* phys device that this vbd maps to. */
+       u32                     pdevice;
+       struct block_device     *bdev;
+       /* Cached size parameter. */
+       sector_t                size;
+       bool                    flush_support;
+};
+
+struct backend_info;
+
+struct xen_blkif {
+       /* Unique identifier for this interface. */
+       domid_t                 domid;
+       unsigned int            handle;
+       /* Physical parameters of the comms window. */
+       unsigned int            irq;
+       /* Comms information. */
+       enum blkif_protocol     blk_protocol;
+       union blkif_back_rings  blk_rings;
+       struct vm_struct        *blk_ring_area;
+       /* The VBD attached to this interface. */
+       struct xen_vbd          vbd;
+       /* Back pointer to the backend_info. */
+       struct backend_info     *be;
+       /* Private fields. */
+       spinlock_t              blk_ring_lock;
+       atomic_t                refcnt;
+
+       wait_queue_head_t       wq;
+       /* One thread per one blkif. */
+       struct task_struct      *xenblkd;
+       unsigned int            waiting_reqs;
+
+       /* statistics */
+       unsigned long           st_print;
+       int                     st_rd_req;
+       int                     st_wr_req;
+       int                     st_oo_req;
+       int                     st_f_req;
+       int                     st_rd_sect;
+       int                     st_wr_sect;
+
+       wait_queue_head_t       waiting_to_free;
+
+       grant_handle_t          shmem_handle;
+       grant_ref_t             shmem_ref;
+};
+
+
+#define vbd_sz(_v)     ((_v)->bdev->bd_part ? \
+                        (_v)->bdev->bd_part->nr_sects : \
+                         get_capacity((_v)->bdev->bd_disk))
+
+#define xen_blkif_get(_b) (atomic_inc(&(_b)->refcnt))
+#define xen_blkif_put(_b)                              \
+       do {                                            \
+               if (atomic_dec_and_test(&(_b)->refcnt)) \
+                       wake_up(&(_b)->waiting_to_free);\
+       } while (0)
+
+struct phys_req {
+       unsigned short          dev;
+       unsigned short          nr_sects;
+       struct block_device     *bdev;
+       blkif_sector_t          sector_number;
+};
+int xen_blkif_interface_init(void);
+
+int xen_blkif_xenbus_init(void);
+
+irqreturn_t xen_blkif_be_int(int irq, void *dev_id);
+int xen_blkif_schedule(void *arg);
+
+int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
+                             struct backend_info *be, int state);
+
+struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be);
+
+static inline void blkif_get_x86_32_req(struct blkif_request *dst,
+                                       struct blkif_x86_32_request *src)
+{
+       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+       dst->operation = src->operation;
+       dst->nr_segments = src->nr_segments;
+       dst->handle = src->handle;
+       dst->id = src->id;
+       dst->u.rw.sector_number = src->sector_number;
+       barrier();
+       if (n > dst->nr_segments)
+               n = dst->nr_segments;
+       for (i = 0; i < n; i++)
+               dst->u.rw.seg[i] = src->seg[i];
+}
+
+static inline void blkif_get_x86_64_req(struct blkif_request *dst,
+                                       struct blkif_x86_64_request *src)
+{
+       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+       dst->operation = src->operation;
+       dst->nr_segments = src->nr_segments;
+       dst->handle = src->handle;
+       dst->id = src->id;
+       dst->u.rw.sector_number = src->sector_number;
+       barrier();
+       if (n > dst->nr_segments)
+               n = dst->nr_segments;
+       for (i = 0; i < n; i++)
+               dst->u.rw.seg[i] = src->seg[i];
+}
+
+#endif /* __XEN_BLKIF__BACKEND__COMMON_H__ */
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
new file mode 100644 (file)
index 0000000..3457082
--- /dev/null
@@ -0,0 +1,768 @@
+/*  Xenbus code for blkif backend
+    Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
+    Copyright (C) 2005 XenSource Ltd
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT 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 <stdarg.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include "common.h"
+
+struct backend_info {
+       struct xenbus_device    *dev;
+       struct xen_blkif        *blkif;
+       struct xenbus_watch     backend_watch;
+       unsigned                major;
+       unsigned                minor;
+       char                    *mode;
+};
+
+static struct kmem_cache *xen_blkif_cachep;
+static void connect(struct backend_info *);
+static int connect_ring(struct backend_info *);
+static void backend_changed(struct xenbus_watch *, const char **,
+                           unsigned int);
+
+struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be)
+{
+       return be->dev;
+}
+
+static int blkback_name(struct xen_blkif *blkif, char *buf)
+{
+       char *devpath, *devname;
+       struct xenbus_device *dev = blkif->be->dev;
+
+       devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL);
+       if (IS_ERR(devpath))
+               return PTR_ERR(devpath);
+
+       devname = strstr(devpath, "/dev/");
+       if (devname != NULL)
+               devname += strlen("/dev/");
+       else
+               devname  = devpath;
+
+       snprintf(buf, TASK_COMM_LEN, "blkback.%d.%s", blkif->domid, devname);
+       kfree(devpath);
+
+       return 0;
+}
+
+static void xen_update_blkif_status(struct xen_blkif *blkif)
+{
+       int err;
+       char name[TASK_COMM_LEN];
+
+       /* Not ready to connect? */
+       if (!blkif->irq || !blkif->vbd.bdev)
+               return;
+
+       /* Already connected? */
+       if (blkif->be->dev->state == XenbusStateConnected)
+               return;
+
+       /* Attempt to connect: exit if we fail to. */
+       connect(blkif->be);
+       if (blkif->be->dev->state != XenbusStateConnected)
+               return;
+
+       err = blkback_name(blkif, name);
+       if (err) {
+               xenbus_dev_error(blkif->be->dev, err, "get blkback dev name");
+               return;
+       }
+
+       err = filemap_write_and_wait(blkif->vbd.bdev->bd_inode->i_mapping);
+       if (err) {
+               xenbus_dev_error(blkif->be->dev, err, "block flush");
+               return;
+       }
+       invalidate_inode_pages2(blkif->vbd.bdev->bd_inode->i_mapping);
+
+       blkif->xenblkd = kthread_run(xen_blkif_schedule, blkif, name);
+       if (IS_ERR(blkif->xenblkd)) {
+               err = PTR_ERR(blkif->xenblkd);
+               blkif->xenblkd = NULL;
+               xenbus_dev_error(blkif->be->dev, err, "start xenblkd");
+       }
+}
+
+static struct xen_blkif *xen_blkif_alloc(domid_t domid)
+{
+       struct xen_blkif *blkif;
+
+       blkif = kmem_cache_alloc(xen_blkif_cachep, GFP_KERNEL);
+       if (!blkif)
+               return ERR_PTR(-ENOMEM);
+
+       memset(blkif, 0, sizeof(*blkif));
+       blkif->domid = domid;
+       spin_lock_init(&blkif->blk_ring_lock);
+       atomic_set(&blkif->refcnt, 1);
+       init_waitqueue_head(&blkif->wq);
+       blkif->st_print = jiffies;
+       init_waitqueue_head(&blkif->waiting_to_free);
+
+       return blkif;
+}
+
+static int map_frontend_page(struct xen_blkif *blkif, unsigned long shared_page)
+{
+       struct gnttab_map_grant_ref op;
+
+       gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
+                         GNTMAP_host_map, shared_page, blkif->domid);
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+               BUG();
+
+       if (op.status) {
+               DPRINTK("Grant table operation failure !\n");
+               return op.status;
+       }
+
+       blkif->shmem_ref = shared_page;
+       blkif->shmem_handle = op.handle;
+
+       return 0;
+}
+
+static void unmap_frontend_page(struct xen_blkif *blkif)
+{
+       struct gnttab_unmap_grant_ref op;
+
+       gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
+                           GNTMAP_host_map, blkif->shmem_handle);
+
+       if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+               BUG();
+}
+
+static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page,
+                        unsigned int evtchn)
+{
+       int err;
+
+       /* Already connected through? */
+       if (blkif->irq)
+               return 0;
+
+       blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE);
+       if (!blkif->blk_ring_area)
+               return -ENOMEM;
+
+       err = map_frontend_page(blkif, shared_page);
+       if (err) {
+               free_vm_area(blkif->blk_ring_area);
+               return err;
+       }
+
+       switch (blkif->blk_protocol) {
+       case BLKIF_PROTOCOL_NATIVE:
+       {
+               struct blkif_sring *sring;
+               sring = (struct blkif_sring *)blkif->blk_ring_area->addr;
+               BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE);
+               break;
+       }
+       case BLKIF_PROTOCOL_X86_32:
+       {
+               struct blkif_x86_32_sring *sring_x86_32;
+               sring_x86_32 = (struct blkif_x86_32_sring *)blkif->blk_ring_area->addr;
+               BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE);
+               break;
+       }
+       case BLKIF_PROTOCOL_X86_64:
+       {
+               struct blkif_x86_64_sring *sring_x86_64;
+               sring_x86_64 = (struct blkif_x86_64_sring *)blkif->blk_ring_area->addr;
+               BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE);
+               break;
+       }
+       default:
+               BUG();
+       }
+
+       err = bind_interdomain_evtchn_to_irqhandler(blkif->domid, evtchn,
+                                                   xen_blkif_be_int, 0,
+                                                   "blkif-backend", blkif);
+       if (err < 0) {
+               unmap_frontend_page(blkif);
+               free_vm_area(blkif->blk_ring_area);
+               blkif->blk_rings.common.sring = NULL;
+               return err;
+       }
+       blkif->irq = err;
+
+       return 0;
+}
+
+static void xen_blkif_disconnect(struct xen_blkif *blkif)
+{
+       if (blkif->xenblkd) {
+               kthread_stop(blkif->xenblkd);
+               blkif->xenblkd = NULL;
+       }
+
+       atomic_dec(&blkif->refcnt);
+       wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
+       atomic_inc(&blkif->refcnt);
+
+       if (blkif->irq) {
+               unbind_from_irqhandler(blkif->irq, blkif);
+               blkif->irq = 0;
+       }
+
+       if (blkif->blk_rings.common.sring) {
+               unmap_frontend_page(blkif);
+               free_vm_area(blkif->blk_ring_area);
+               blkif->blk_rings.common.sring = NULL;
+       }
+}
+
+void xen_blkif_free(struct xen_blkif *blkif)
+{
+       if (!atomic_dec_and_test(&blkif->refcnt))
+               BUG();
+       kmem_cache_free(xen_blkif_cachep, blkif);
+}
+
+int __init xen_blkif_interface_init(void)
+{
+       xen_blkif_cachep = kmem_cache_create("blkif_cache",
+                                            sizeof(struct xen_blkif),
+                                            0, 0, NULL);
+       if (!xen_blkif_cachep)
+               return -ENOMEM;
+
+       return 0;
+}
+
+/*
+ *  sysfs interface for VBD I/O requests
+ */
+
+#define VBD_SHOW(name, format, args...)                                        \
+       static ssize_t show_##name(struct device *_dev,                 \
+                                  struct device_attribute *attr,       \
+                                  char *buf)                           \
+       {                                                               \
+               struct xenbus_device *dev = to_xenbus_device(_dev);     \
+               struct backend_info *be = dev_get_drvdata(&dev->dev);   \
+                                                                       \
+               return sprintf(buf, format, ##args);                    \
+       }                                                               \
+       static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+VBD_SHOW(oo_req,  "%d\n", be->blkif->st_oo_req);
+VBD_SHOW(rd_req,  "%d\n", be->blkif->st_rd_req);
+VBD_SHOW(wr_req,  "%d\n", be->blkif->st_wr_req);
+VBD_SHOW(f_req,  "%d\n", be->blkif->st_f_req);
+VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
+VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
+
+static struct attribute *xen_vbdstat_attrs[] = {
+       &dev_attr_oo_req.attr,
+       &dev_attr_rd_req.attr,
+       &dev_attr_wr_req.attr,
+       &dev_attr_f_req.attr,
+       &dev_attr_rd_sect.attr,
+       &dev_attr_wr_sect.attr,
+       NULL
+};
+
+static struct attribute_group xen_vbdstat_group = {
+       .name = "statistics",
+       .attrs = xen_vbdstat_attrs,
+};
+
+VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
+VBD_SHOW(mode, "%s\n", be->mode);
+
+int xenvbd_sysfs_addif(struct xenbus_device *dev)
+{
+       int error;
+
+       error = device_create_file(&dev->dev, &dev_attr_physical_device);
+       if (error)
+               goto fail1;
+
+       error = device_create_file(&dev->dev, &dev_attr_mode);
+       if (error)
+               goto fail2;
+
+       error = sysfs_create_group(&dev->dev.kobj, &xen_vbdstat_group);
+       if (error)
+               goto fail3;
+
+       return 0;
+
+fail3: sysfs_remove_group(&dev->dev.kobj, &xen_vbdstat_group);
+fail2: device_remove_file(&dev->dev, &dev_attr_mode);
+fail1: device_remove_file(&dev->dev, &dev_attr_physical_device);
+       return error;
+}
+
+void xenvbd_sysfs_delif(struct xenbus_device *dev)
+{
+       sysfs_remove_group(&dev->dev.kobj, &xen_vbdstat_group);
+       device_remove_file(&dev->dev, &dev_attr_mode);
+       device_remove_file(&dev->dev, &dev_attr_physical_device);
+}
+
+
+static void xen_vbd_free(struct xen_vbd *vbd)
+{
+       if (vbd->bdev)
+               blkdev_put(vbd->bdev, vbd->readonly ? FMODE_READ : FMODE_WRITE);
+       vbd->bdev = NULL;
+}
+
+static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
+                         unsigned major, unsigned minor, int readonly,
+                         int cdrom)
+{
+       struct xen_vbd *vbd;
+       struct block_device *bdev;
+       struct request_queue *q;
+
+       vbd = &blkif->vbd;
+       vbd->handle   = handle;
+       vbd->readonly = readonly;
+       vbd->type     = 0;
+
+       vbd->pdevice  = MKDEV(major, minor);
+
+       bdev = blkdev_get_by_dev(vbd->pdevice, vbd->readonly ?
+                                FMODE_READ : FMODE_WRITE, NULL);
+
+       if (IS_ERR(bdev)) {
+               DPRINTK("xen_vbd_create: device %08x could not be opened.\n",
+                       vbd->pdevice);
+               return -ENOENT;
+       }
+
+       vbd->bdev = bdev;
+       vbd->size = vbd_sz(vbd);
+
+       if (vbd->bdev->bd_disk == NULL) {
+               DPRINTK("xen_vbd_create: device %08x doesn't exist.\n",
+                       vbd->pdevice);
+               xen_vbd_free(vbd);
+               return -ENOENT;
+       }
+
+       if (vbd->bdev->bd_disk->flags & GENHD_FL_CD || cdrom)
+               vbd->type |= VDISK_CDROM;
+       if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
+               vbd->type |= VDISK_REMOVABLE;
+
+       q = bdev_get_queue(bdev);
+       if (q && q->flush_flags)
+               vbd->flush_support = true;
+
+       DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
+               handle, blkif->domid);
+       return 0;
+}
+static int xen_blkbk_remove(struct xenbus_device *dev)
+{
+       struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+       DPRINTK("");
+
+       if (be->major || be->minor)
+               xenvbd_sysfs_delif(dev);
+
+       if (be->backend_watch.node) {
+               unregister_xenbus_watch(&be->backend_watch);
+               kfree(be->backend_watch.node);
+               be->backend_watch.node = NULL;
+       }
+
+       if (be->blkif) {
+               xen_blkif_disconnect(be->blkif);
+               xen_vbd_free(&be->blkif->vbd);
+               xen_blkif_free(be->blkif);
+               be->blkif = NULL;
+       }
+
+       kfree(be);
+       dev_set_drvdata(&dev->dev, NULL);
+       return 0;
+}
+
+int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
+                             struct backend_info *be, int state)
+{
+       struct xenbus_device *dev = be->dev;
+       int err;
+
+       err = xenbus_printf(xbt, dev->nodename, "feature-flush-cache",
+                           "%d", state);
+       if (err)
+               xenbus_dev_fatal(dev, err, "writing feature-flush-cache");
+
+       return err;
+}
+
+/*
+ * Entry point to this code when a new device is created.  Allocate the basic
+ * structures, and watch the store waiting for the hotplug scripts to tell us
+ * the device's physical major and minor numbers.  Switch to InitWait.
+ */
+static int xen_blkbk_probe(struct xenbus_device *dev,
+                          const struct xenbus_device_id *id)
+{
+       int err;
+       struct backend_info *be = kzalloc(sizeof(struct backend_info),
+                                         GFP_KERNEL);
+       if (!be) {
+               xenbus_dev_fatal(dev, -ENOMEM,
+                                "allocating backend structure");
+               return -ENOMEM;
+       }
+       be->dev = dev;
+       dev_set_drvdata(&dev->dev, be);
+
+       be->blkif = xen_blkif_alloc(dev->otherend_id);
+       if (IS_ERR(be->blkif)) {
+               err = PTR_ERR(be->blkif);
+               be->blkif = NULL;
+               xenbus_dev_fatal(dev, err, "creating block interface");
+               goto fail;
+       }
+
+       /* setup back pointer */
+       be->blkif->be = be;
+
+       err = xenbus_watch_pathfmt(dev, &be->backend_watch, backend_changed,
+                                  "%s/%s", dev->nodename, "physical-device");
+       if (err)
+               goto fail;
+
+       err = xenbus_switch_state(dev, XenbusStateInitWait);
+       if (err)
+               goto fail;
+
+       return 0;
+
+fail:
+       DPRINTK("failed");
+       xen_blkbk_remove(dev);
+       return err;
+}
+
+
+/*
+ * Callback received when the hotplug scripts have placed the physical-device
+ * node.  Read it and the mode node, and create a vbd.  If the frontend is
+ * ready, connect.
+ */
+static void backend_changed(struct xenbus_watch *watch,
+                           const char **vec, unsigned int len)
+{
+       int err;
+       unsigned major;
+       unsigned minor;
+       struct backend_info *be
+               = container_of(watch, struct backend_info, backend_watch);
+       struct xenbus_device *dev = be->dev;
+       int cdrom = 0;
+       char *device_type;
+
+       DPRINTK("");
+
+       err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%x:%x",
+                          &major, &minor);
+       if (XENBUS_EXIST_ERR(err)) {
+               /*
+                * Since this watch will fire once immediately after it is
+                * registered, we expect this.  Ignore it, and wait for the
+                * hotplug scripts.
+                */
+               return;
+       }
+       if (err != 2) {
+               xenbus_dev_fatal(dev, err, "reading physical-device");
+               return;
+       }
+
+       if ((be->major || be->minor) &&
+           ((be->major != major) || (be->minor != minor))) {
+               pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n",
+                       be->major, be->minor, major, minor);
+               return;
+       }
+
+       be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL);
+       if (IS_ERR(be->mode)) {
+               err = PTR_ERR(be->mode);
+               be->mode = NULL;
+               xenbus_dev_fatal(dev, err, "reading mode");
+               return;
+       }
+
+       device_type = xenbus_read(XBT_NIL, dev->otherend, "device-type", NULL);
+       if (!IS_ERR(device_type)) {
+               cdrom = strcmp(device_type, "cdrom") == 0;
+               kfree(device_type);
+       }
+
+       if (be->major == 0 && be->minor == 0) {
+               /* Front end dir is a number, which is used as the handle. */
+
+               char *p = strrchr(dev->otherend, '/') + 1;
+               long handle;
+               err = strict_strtoul(p, 0, &handle);
+               if (err)
+                       return;
+
+               be->major = major;
+               be->minor = minor;
+
+               err = xen_vbd_create(be->blkif, handle, major, minor,
+                                (NULL == strchr(be->mode, 'w')), cdrom);
+               if (err) {
+                       be->major = 0;
+                       be->minor = 0;
+                       xenbus_dev_fatal(dev, err, "creating vbd structure");
+                       return;
+               }
+
+               err = xenvbd_sysfs_addif(dev);
+               if (err) {
+                       xen_vbd_free(&be->blkif->vbd);
+                       be->major = 0;
+                       be->minor = 0;
+                       xenbus_dev_fatal(dev, err, "creating sysfs entries");
+                       return;
+               }
+
+               /* We're potentially connected now */
+               xen_update_blkif_status(be->blkif);
+       }
+}
+
+
+/*
+ * Callback received when the frontend's state changes.
+ */
+static void frontend_changed(struct xenbus_device *dev,
+                            enum xenbus_state frontend_state)
+{
+       struct backend_info *be = dev_get_drvdata(&dev->dev);
+       int err;
+
+       DPRINTK("%s", xenbus_strstate(frontend_state));
+
+       switch (frontend_state) {
+       case XenbusStateInitialising:
+               if (dev->state == XenbusStateClosed) {
+                       pr_info(DRV_PFX "%s: prepare for reconnect\n",
+                               dev->nodename);
+                       xenbus_switch_state(dev, XenbusStateInitWait);
+               }
+               break;
+
+       case XenbusStateInitialised:
+       case XenbusStateConnected:
+               /*
+                * Ensure we connect even when two watches fire in
+                * close successsion and we miss the intermediate value
+                * of frontend_state.
+                */
+               if (dev->state == XenbusStateConnected)
+                       break;
+
+               /*
+                * Enforce precondition before potential leak point.
+                * blkif_disconnect() is idempotent.
+                */
+               xen_blkif_disconnect(be->blkif);
+
+               err = connect_ring(be);
+               if (err)
+                       break;
+               xen_update_blkif_status(be->blkif);
+               break;
+
+       case XenbusStateClosing:
+               xen_blkif_disconnect(be->blkif);
+               xenbus_switch_state(dev, XenbusStateClosing);
+               break;
+
+       case XenbusStateClosed:
+               xenbus_switch_state(dev, XenbusStateClosed);
+               if (xenbus_dev_is_online(dev))
+                       break;
+               /* fall through if not online */
+       case XenbusStateUnknown:
+               /* implies blkif_disconnect() via blkback_remove() */
+               device_unregister(&dev->dev);
+               break;
+
+       default:
+               xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+                                frontend_state);
+               break;
+       }
+}
+
+
+/* ** Connection ** */
+
+
+/*
+ * Write the physical details regarding the block device to the store, and
+ * switch to Connected state.
+ */
+static void connect(struct backend_info *be)
+{
+       struct xenbus_transaction xbt;
+       int err;
+       struct xenbus_device *dev = be->dev;
+
+       DPRINTK("%s", dev->otherend);
+
+       /* Supply the information about the device the frontend needs */
+again:
+       err = xenbus_transaction_start(&xbt);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "starting transaction");
+               return;
+       }
+
+       err = xen_blkbk_flush_diskcache(xbt, be, be->blkif->vbd.flush_support);
+       if (err)
+               goto abort;
+
+       err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
+                           (unsigned long long)vbd_sz(&be->blkif->vbd));
+       if (err) {
+               xenbus_dev_fatal(dev, err, "writing %s/sectors",
+                                dev->nodename);
+               goto abort;
+       }
+
+       /* FIXME: use a typename instead */
+       err = xenbus_printf(xbt, dev->nodename, "info", "%u",
+                           be->blkif->vbd.type |
+                           (be->blkif->vbd.readonly ? VDISK_READONLY : 0));
+       if (err) {
+               xenbus_dev_fatal(dev, err, "writing %s/info",
+                                dev->nodename);
+               goto abort;
+       }
+       err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu",
+                           (unsigned long)
+                           bdev_logical_block_size(be->blkif->vbd.bdev));
+       if (err) {
+               xenbus_dev_fatal(dev, err, "writing %s/sector-size",
+                                dev->nodename);
+               goto abort;
+       }
+
+       err = xenbus_transaction_end(xbt, 0);
+       if (err == -EAGAIN)
+               goto again;
+       if (err)
+               xenbus_dev_fatal(dev, err, "ending transaction");
+
+       err = xenbus_switch_state(dev, XenbusStateConnected);
+       if (err)
+               xenbus_dev_fatal(dev, err, "switching to Connected state",
+                                dev->nodename);
+
+       return;
+ abort:
+       xenbus_transaction_end(xbt, 1);
+}
+
+
+static int connect_ring(struct backend_info *be)
+{
+       struct xenbus_device *dev = be->dev;
+       unsigned long ring_ref;
+       unsigned int evtchn;
+       char protocol[64] = "";
+       int err;
+
+       DPRINTK("%s", dev->otherend);
+
+       err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu",
+                           &ring_ref, "event-channel", "%u", &evtchn, NULL);
+       if (err) {
+               xenbus_dev_fatal(dev, err,
+                                "reading %s/ring-ref and event-channel",
+                                dev->otherend);
+               return err;
+       }
+
+       be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
+       err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
+                           "%63s", protocol, NULL);
+       if (err)
+               strcpy(protocol, "unspecified, assuming native");
+       else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
+               be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
+       else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
+               be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
+       else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
+               be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
+       else {
+               xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
+               return -1;
+       }
+       pr_info(DRV_PFX "ring-ref %ld, event-channel %d, protocol %d (%s)\n",
+               ring_ref, evtchn, be->blkif->blk_protocol, protocol);
+
+       /* Map the shared frame, irq etc. */
+       err = xen_blkif_map(be->blkif, ring_ref, evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
+                                ring_ref, evtchn);
+               return err;
+       }
+
+       return 0;
+}
+
+
+/* ** Driver Registration ** */
+
+
+static const struct xenbus_device_id xen_blkbk_ids[] = {
+       { "vbd" },
+       { "" }
+};
+
+
+static struct xenbus_driver xen_blkbk = {
+       .name = "vbd",
+       .owner = THIS_MODULE,
+       .ids = xen_blkbk_ids,
+       .probe = xen_blkbk_probe,
+       .remove = xen_blkbk_remove,
+       .otherend_changed = frontend_changed
+};
+
+
+int xen_blkif_xenbus_init(void)
+{
+       return xenbus_register_backend(&xen_blkbk);
+}
index 9cb8668ff5f412908e99dadcafd6d025904a2cdc..b536a9cef917516d23448e589a7955ad984e6dd3 100644 (file)
@@ -97,6 +97,7 @@ struct blkfront_info
        struct blk_shadow shadow[BLK_RING_SIZE];
        unsigned long shadow_free;
        unsigned int feature_flush;
+       unsigned int flush_op;
        int is_ready;
 };
 
@@ -250,8 +251,7 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode,
 
 /*
  * Generate a Xen blkfront IO request from a blk layer request.  Reads
- * and writes are handled as expected.  Since we lack a loose flush
- * request, we map flushes into a full ordered barrier.
+ * and writes are handled as expected.
  *
  * @req: a request struct
  */
@@ -293,14 +293,13 @@ static int blkif_queue_request(struct request *req)
 
        if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
                /*
-                * Ideally we could just do an unordered
-                * flush-to-disk, but all we have is a full write
-                * barrier at the moment.  However, a barrier write is
+                * Ideally we can do an unordered flush-to-disk. In case the
+                * backend onlysupports barriers, use that. A barrier request
                 * a superset of FUA, so we can implement it the same
                 * way.  (It's also a FLUSH+FUA, since it is
                 * guaranteed ordered WRT previous writes.)
                 */
-               ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+               ring_req->operation = info->flush_op;
        }
 
        ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
@@ -433,8 +432,11 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
 static void xlvbd_flush(struct blkfront_info *info)
 {
        blk_queue_flush(info->rq, info->feature_flush);
-       printk(KERN_INFO "blkfront: %s: barriers %s\n",
+       printk(KERN_INFO "blkfront: %s: %s: %s\n",
               info->gd->disk_name,
+              info->flush_op == BLKIF_OP_WRITE_BARRIER ?
+               "barrier" : (info->flush_op == BLKIF_OP_FLUSH_DISKCACHE ?
+               "flush diskcache" : "barrier or flush"),
               info->feature_flush ? "enabled" : "disabled");
 }
 
@@ -720,15 +722,20 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
 
                error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
                switch (bret->operation) {
+               case BLKIF_OP_FLUSH_DISKCACHE:
                case BLKIF_OP_WRITE_BARRIER:
                        if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
-                               printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+                               printk(KERN_WARNING "blkfront: %s: write %s op failed\n",
+                                      info->flush_op == BLKIF_OP_WRITE_BARRIER ?
+                                      "barrier" :  "flush disk cache",
                                       info->gd->disk_name);
                                error = -EOPNOTSUPP;
                        }
                        if (unlikely(bret->status == BLKIF_RSP_ERROR &&
                                     info->shadow[id].req.nr_segments == 0)) {
-                               printk(KERN_WARNING "blkfront: %s: empty write barrier op failed\n",
+                               printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n",
+                                      info->flush_op == BLKIF_OP_WRITE_BARRIER ?
+                                      "barrier" :  "flush disk cache",
                                       info->gd->disk_name);
                                error = -EOPNOTSUPP;
                        }
@@ -736,6 +743,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                                if (error == -EOPNOTSUPP)
                                        error = 0;
                                info->feature_flush = 0;
+                               info->flush_op = 0;
                                xlvbd_flush(info);
                        }
                        /* fall through */
@@ -1100,7 +1108,7 @@ static void blkfront_connect(struct blkfront_info *info)
        unsigned long sector_size;
        unsigned int binfo;
        int err;
-       int barrier;
+       int barrier, flush;
 
        switch (info->connected) {
        case BLKIF_STATE_CONNECTED:
@@ -1140,8 +1148,11 @@ static void blkfront_connect(struct blkfront_info *info)
                return;
        }
 
+       info->feature_flush = 0;
+       info->flush_op = 0;
+
        err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-                           "feature-barrier", "%lu", &barrier,
+                           "feature-barrier", "%d", &barrier,
                            NULL);
 
        /*
@@ -1151,11 +1162,23 @@ static void blkfront_connect(struct blkfront_info *info)
         *
         * If there are barriers, then we use flush.
         */
-       info->feature_flush = 0;
-
-       if (!err && barrier)
+       if (!err && barrier) {
                info->feature_flush = REQ_FLUSH | REQ_FUA;
+               info->flush_op = BLKIF_OP_WRITE_BARRIER;
+       }
+       /*
+        * And if there is "feature-flush-cache" use that above
+        * barriers.
+        */
+       err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+                           "feature-flush-cache", "%d", &flush,
+                           NULL);
 
+       if (!err && flush) {
+               info->feature_flush = REQ_FLUSH;
+               info->flush_op = BLKIF_OP_FLUSH_DISKCACHE;
+       }
+               
        err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
        if (err) {
                xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
index e427fbe459994a8491945a65fd085201f40ed01f..ae15a4ddaa9b0a3d7ff172e737dbaafd9fe8ac46 100644 (file)
@@ -625,7 +625,9 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        blk_queue_max_hw_sectors(q, 4096 / 512);
        gendisk->queue = q;
        gendisk->fops = &viocd_fops;
-       gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
+       gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE |
+                        GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+       gendisk->events = DISK_EVENT_MEDIA_CHANGE;
        set_capacity(gendisk, 0);
        gendisk->private_data = d;
        d->viocd_disk = gendisk;
index d72433f2d310deb6cf909cb1feb30e92919887cd..6e40072fbf675e3c69b105cc8ea1d05491bba485 100644 (file)
@@ -5,6 +5,9 @@
  *
  * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
  *
+ * Hwmon integration:
+ * Copyright (C) 2011  Jean Delvare <khali@linux-fr.org>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2, or (at your option) any
@@ -24,6 +27,8 @@
 #include <linux/dmi.h>
 #include <linux/capability.h>
 #include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -58,6 +63,7 @@
 
 static DEFINE_MUTEX(i8k_mutex);
 static char bios_version[4];
+static struct device *i8k_hwmon_dev;
 
 MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
 MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -139,8 +145,8 @@ static int i8k_smm(struct smm_regs *regs)
                "movl %%edi,20(%%rax)\n\t"
                "popq %%rdx\n\t"
                "movl %%edx,0(%%rax)\n\t"
-               "lahf\n\t"
-               "shrl $8,%%eax\n\t"
+               "pushfq\n\t"
+               "popq %%rax\n\t"
                "andl $1,%%eax\n"
                :"=a"(rc)
                :    "a"(regs)
@@ -455,6 +461,152 @@ static int i8k_open_fs(struct inode *inode, struct file *file)
        return single_open(file, i8k_proc_show, NULL);
 }
 
+
+/*
+ * Hwmon interface
+ */
+
+static ssize_t i8k_hwmon_show_temp(struct device *dev,
+                                  struct device_attribute *devattr,
+                                  char *buf)
+{
+       int cpu_temp;
+
+       cpu_temp = i8k_get_temp(0);
+       if (cpu_temp < 0)
+               return cpu_temp;
+       return sprintf(buf, "%d\n", cpu_temp * 1000);
+}
+
+static ssize_t i8k_hwmon_show_fan(struct device *dev,
+                                 struct device_attribute *devattr,
+                                 char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       int fan_speed;
+
+       fan_speed = i8k_get_fan_speed(index);
+       if (fan_speed < 0)
+               return fan_speed;
+       return sprintf(buf, "%d\n", fan_speed);
+}
+
+static ssize_t i8k_hwmon_show_label(struct device *dev,
+                                   struct device_attribute *devattr,
+                                   char *buf)
+{
+       static const char *labels[4] = {
+               "i8k",
+               "CPU",
+               "Left Fan",
+               "Right Fan",
+       };
+       int index = to_sensor_dev_attr(devattr)->index;
+
+       return sprintf(buf, "%s\n", labels[index]);
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
+                         I8K_FAN_LEFT);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
+                         I8K_FAN_RIGHT);
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, i8k_hwmon_show_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 3);
+
+static void i8k_hwmon_remove_files(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_temp1_input);
+       device_remove_file(dev, &sensor_dev_attr_fan1_input.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_fan2_input.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_temp1_label.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_fan1_label.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_fan2_label.dev_attr);
+       device_remove_file(dev, &sensor_dev_attr_name.dev_attr);
+}
+
+static int __init i8k_init_hwmon(void)
+{
+       int err;
+
+       i8k_hwmon_dev = hwmon_device_register(NULL);
+       if (IS_ERR(i8k_hwmon_dev)) {
+               err = PTR_ERR(i8k_hwmon_dev);
+               i8k_hwmon_dev = NULL;
+               printk(KERN_ERR "i8k: hwmon registration failed (%d)\n", err);
+               return err;
+       }
+
+       /* Required name attribute */
+       err = device_create_file(i8k_hwmon_dev,
+                                &sensor_dev_attr_name.dev_attr);
+       if (err)
+               goto exit_unregister;
+
+       /* CPU temperature attributes, if temperature reading is OK */
+       err = i8k_get_temp(0);
+       if (err < 0) {
+               dev_dbg(i8k_hwmon_dev,
+                       "Not creating temperature attributes (%d)\n", err);
+       } else {
+               err = device_create_file(i8k_hwmon_dev, &dev_attr_temp1_input);
+               if (err)
+                       goto exit_remove_files;
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_temp1_label.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+       }
+
+       /* Left fan attributes, if left fan is present */
+       err = i8k_get_fan_status(I8K_FAN_LEFT);
+       if (err < 0) {
+               dev_dbg(i8k_hwmon_dev,
+                       "Not creating %s fan attributes (%d)\n", "left", err);
+       } else {
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_fan1_input.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_fan1_label.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+       }
+
+       /* Right fan attributes, if right fan is present */
+       err = i8k_get_fan_status(I8K_FAN_RIGHT);
+       if (err < 0) {
+               dev_dbg(i8k_hwmon_dev,
+                       "Not creating %s fan attributes (%d)\n", "right", err);
+       } else {
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_fan2_input.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+               err = device_create_file(i8k_hwmon_dev,
+                                        &sensor_dev_attr_fan2_label.dev_attr);
+               if (err)
+                       goto exit_remove_files;
+       }
+
+       return 0;
+
+ exit_remove_files:
+       i8k_hwmon_remove_files(i8k_hwmon_dev);
+ exit_unregister:
+       hwmon_device_unregister(i8k_hwmon_dev);
+       return err;
+}
+
+static void __exit i8k_exit_hwmon(void)
+{
+       i8k_hwmon_remove_files(i8k_hwmon_dev);
+       hwmon_device_unregister(i8k_hwmon_dev);
+}
+
 static struct dmi_system_id __initdata i8k_dmi_table[] = {
        {
                .ident = "Dell Inspiron",
@@ -580,6 +732,7 @@ static int __init i8k_probe(void)
 static int __init i8k_init(void)
 {
        struct proc_dir_entry *proc_i8k;
+       int err;
 
        /* Are we running on an supported laptop? */
        if (i8k_probe())
@@ -590,15 +743,24 @@ static int __init i8k_init(void)
        if (!proc_i8k)
                return -ENOENT;
 
+       err = i8k_init_hwmon();
+       if (err)
+               goto exit_remove_proc;
+
        printk(KERN_INFO
               "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
               I8K_VERSION);
 
        return 0;
+
+ exit_remove_proc:
+       remove_proc_entry("i8k", NULL);
+       return err;
 }
 
 static void __exit i8k_exit(void)
 {
+       i8k_exit_hwmon();
        remove_proc_entry("i8k", NULL);
 }
 
index c7f1a6f16b6e6a6b1faf2dfb2a3c180cea7aec1f..e2fc2d21fa6168c16acf5dcab7b75c012879630b 100644 (file)
@@ -39,3 +39,5 @@ obj-$(CONFIG_X86_CPUFREQ_NFORCE2)     += cpufreq-nforce2.o
 
 ##################################################################################d
 
+# ARM SoC drivers
+obj-$(CONFIG_UX500_SOC_DB8500)         += db8500-cpufreq.o
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
new file mode 100644 (file)
index 0000000..d90456a
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <mach/id.h>
+
+static struct cpufreq_frequency_table freq_table[] = {
+       [0] = {
+               .index = 0,
+               .frequency = 300000,
+       },
+       [1] = {
+               .index = 1,
+               .frequency = 600000,
+       },
+       [2] = {
+               /* Used for MAX_OPP, if available */
+               .index = 2,
+               .frequency = CPUFREQ_TABLE_END,
+       },
+       [3] = {
+               .index = 3,
+               .frequency = CPUFREQ_TABLE_END,
+       },
+};
+
+static enum arm_opp idx2opp[] = {
+       ARM_50_OPP,
+       ARM_100_OPP,
+       ARM_MAX_OPP
+};
+
+static struct freq_attr *db8500_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+static int db8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
+{
+       return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static int db8500_cpufreq_target(struct cpufreq_policy *policy,
+                               unsigned int target_freq,
+                               unsigned int relation)
+{
+       struct cpufreq_freqs freqs;
+       unsigned int idx;
+
+       /* scale the target frequency to one of the extremes supported */
+       if (target_freq < policy->cpuinfo.min_freq)
+               target_freq = policy->cpuinfo.min_freq;
+       if (target_freq > policy->cpuinfo.max_freq)
+               target_freq = policy->cpuinfo.max_freq;
+
+       /* Lookup the next frequency */
+       if (cpufreq_frequency_table_target
+           (policy, freq_table, target_freq, relation, &idx)) {
+               return -EINVAL;
+       }
+
+       freqs.old = policy->cur;
+       freqs.new = freq_table[idx].frequency;
+       freqs.cpu = policy->cpu;
+
+       if (freqs.old == freqs.new)
+               return 0;
+
+       /* pre-change notification */
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+       /* request the PRCM unit for opp change */
+       if (prcmu_set_arm_opp(idx2opp[idx])) {
+               pr_err("db8500-cpufreq:  Failed to set OPP level\n");
+               return -EINVAL;
+       }
+
+       /* post change notification */
+       cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+       return 0;
+}
+
+static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
+{
+       int i;
+       /* request the prcm to get the current ARM opp */
+       for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++)
+               ;
+       return freq_table[i].frequency;
+}
+
+static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
+{
+       int res;
+       int i;
+
+       BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
+
+       if (cpu_is_u8500v2() && !prcmu_is_u8400()) {
+               freq_table[0].frequency = 400000;
+               freq_table[1].frequency = 800000;
+               if (prcmu_has_arm_maxopp())
+                       freq_table[2].frequency = 1000000;
+       }
+
+       /* get policy fields based on the table */
+       res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+       if (!res)
+               cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+       else {
+               pr_err("db8500-cpufreq : Failed to read policy table\n");
+               return res;
+       }
+
+       policy->min = policy->cpuinfo.min_freq;
+       policy->max = policy->cpuinfo.max_freq;
+       policy->cur = db8500_cpufreq_getspeed(policy->cpu);
+
+       for (i = 0; freq_table[i].frequency != policy->cur; i++)
+               ;
+
+       policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+       /*
+        * FIXME : Need to take time measurement across the target()
+        *         function with no/some/all drivers in the notification
+        *         list.
+        */
+       policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */
+
+       /* policy sharing between dual CPUs */
+       cpumask_copy(policy->cpus, &cpu_present_map);
+
+       policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+
+       return 0;
+}
+
+static struct cpufreq_driver db8500_cpufreq_driver = {
+       .flags  = CPUFREQ_STICKY,
+       .verify = db8500_cpufreq_verify_speed,
+       .target = db8500_cpufreq_target,
+       .get    = db8500_cpufreq_getspeed,
+       .init   = db8500_cpufreq_init,
+       .name   = "DB8500",
+       .attr   = db8500_cpufreq_attr,
+};
+
+static int __init db8500_cpufreq_register(void)
+{
+       if (!cpu_is_u8500v20_or_later())
+               return -ENODEV;
+
+       pr_info("cpufreq for DB8500 started\n");
+       return cpufreq_register_driver(&db8500_cpufreq_driver);
+}
+device_initcall(db8500_cpufreq_register);
index dcc1b2139fffdbe5809857abfe124f2a0e984a75..636e40925b165e544618692fce8640503ddd65a6 100644 (file)
@@ -213,12 +213,17 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
                                                struct sh_dmae_device, common);
        struct sh_dmae_pdata *pdata = shdev->pdata;
        const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id];
-       u16 __iomem *addr = shdev->dmars + chan_pdata->dmars / sizeof(u16);
+       u16 __iomem *addr = shdev->dmars;
        int shift = chan_pdata->dmars_bit;
 
        if (dmae_is_busy(sh_chan))
                return -EBUSY;
 
+       /* in the case of a missing DMARS resource use first memory window */
+       if (!addr)
+               addr = (u16 __iomem *)shdev->chan_reg;
+       addr += chan_pdata->dmars / sizeof(u16);
+
        __raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
                     addr);
 
@@ -1078,7 +1083,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        unsigned long irqflags = IRQF_DISABLED,
                chan_flag[SH_DMAC_MAX_CHANNELS] = {};
        int errirq, chan_irq[SH_DMAC_MAX_CHANNELS];
-       int err, i, irq_cnt = 0, irqres = 0;
+       int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
        struct sh_dmae_device *shdev;
        struct resource *chan, *dmars, *errirq_res, *chanirq_res;
 
@@ -1087,7 +1092,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
                return -ENODEV;
 
        chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       /* DMARS area is optional, if absent, this controller cannot do slave DMA */
+       /* DMARS area is optional */
        dmars = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        /*
         * IRQ resources:
@@ -1154,7 +1159,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&shdev->common.channels);
 
        dma_cap_set(DMA_MEMCPY, shdev->common.cap_mask);
-       if (dmars)
+       if (pdata->slave && pdata->slave_num)
                dma_cap_set(DMA_SLAVE, shdev->common.cap_mask);
 
        shdev->common.device_alloc_chan_resources
@@ -1203,8 +1208,13 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
            !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
                /* Special case - all multiplexed */
                for (; irq_cnt < pdata->channel_num; irq_cnt++) {
-                       chan_irq[irq_cnt] = chanirq_res->start;
-                       chan_flag[irq_cnt] = IRQF_SHARED;
+                       if (irq_cnt < SH_DMAC_MAX_CHANNELS) {
+                               chan_irq[irq_cnt] = chanirq_res->start;
+                               chan_flag[irq_cnt] = IRQF_SHARED;
+                       } else {
+                               irq_cap = 1;
+                               break;
+                       }
                }
        } else {
                do {
@@ -1218,22 +1228,32 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
                                        "Found IRQ %d for channel %d\n",
                                        i, irq_cnt);
                                chan_irq[irq_cnt++] = i;
+
+                               if (irq_cnt >= SH_DMAC_MAX_CHANNELS)
+                                       break;
+                       }
+
+                       if (irq_cnt >= SH_DMAC_MAX_CHANNELS) {
+                               irq_cap = 1;
+                               break;
                        }
                        chanirq_res = platform_get_resource(pdev,
                                                IORESOURCE_IRQ, ++irqres);
                } while (irq_cnt < pdata->channel_num && chanirq_res);
        }
 
-       if (irq_cnt < pdata->channel_num)
-               goto eirqres;
-
        /* Create DMA Channel */
-       for (i = 0; i < pdata->channel_num; i++) {
+       for (i = 0; i < irq_cnt; i++) {
                err = sh_dmae_chan_probe(shdev, i, chan_irq[i], chan_flag[i]);
                if (err)
                        goto chan_probe_err;
        }
 
+       if (irq_cap)
+               dev_notice(&pdev->dev, "Attempting to register %d DMA "
+                          "channels when a maximum of %d are supported.\n",
+                          pdata->channel_num, SH_DMAC_MAX_CHANNELS);
+
        pm_runtime_put(&pdev->dev);
 
        platform_set_drvdata(pdev, shdev);
@@ -1243,7 +1263,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
 
 chan_probe_err:
        sh_dmae_chan_remove(shdev);
-eirqres:
+
 #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
        free_irq(errirq, shdev);
 eirq_err:
index 3f9d3cd065841d1e7845ef26b1ba8c1009f4a87a..5ae9fc512180c979deac5bbad5687b266778032a 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/list.h>
 
-#define SH_DMAC_MAX_CHANNELS 6
+#define SH_DMAC_MAX_CHANNELS 20
 #define SH_DMA_SLAVE_NUMBER 256
 #define SH_DMA_TCR_MAX 0x00FFFFFF      /* 16MB */
 
index d41f9002da45d403eb8bc36ca5cc1dccaf477490..aa08497a075a70d1e33ee0de9dcdc9a64c9221ea 100644 (file)
@@ -101,6 +101,19 @@ struct i3200_priv {
 
 static int nr_channels;
 
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       low = readl(p);
+       high = readl(p + 1);
+
+       return low + ((u64)high << 32);
+}
+#endif
+
 static int how_many_channels(struct pci_dev *pdev)
 {
        unsigned char capid0_8b; /* 8th byte of CAPID0 */
index 0a775f7987c257237943879a1d08e5ac20f3cd14..1bc621ac35364917be287773d081a2801f12a5be 100644 (file)
@@ -15,6 +15,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  */
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/gpio.h>
 
@@ -138,6 +139,7 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
        return 0;
 }
 
+#ifdef CONFIG_PM
 /*
  * Save register configuration and disable interrupts.
  */
@@ -157,6 +159,7 @@ static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
        /* to store contents of PM register */
        iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm);
 }
+#endif
 
 static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
 {
index 8a98ee5d5f6c636a93c6c88f43c1ab497b02fb6e..ef5aabd8b8b779a52dbc34d1f70465a3c9f3adec 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/gpio.h>
+#include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/pci.h>
index c6289034e29afd78472830324f84b6e25b9b30dc..0b2e167d2bce856c9b9ef55ea73e22174abf7d2f 100644 (file)
@@ -56,9 +56,7 @@ static int i915_gem_phys_pwrite(struct drm_device *dev,
 static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj);
 
 static int i915_gem_inactive_shrink(struct shrinker *shrinker,
-                                   int nr_to_scan,
-                                   gfp_t gfp_mask);
-
+                                   struct shrink_control *sc);
 
 /* some bookkeeping */
 static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
@@ -4092,9 +4090,7 @@ i915_gpu_is_active(struct drm_device *dev)
 }
 
 static int
-i915_gem_inactive_shrink(struct shrinker *shrinker,
-                        int nr_to_scan,
-                        gfp_t gfp_mask)
+i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
 {
        struct drm_i915_private *dev_priv =
                container_of(shrinker,
@@ -4102,6 +4098,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker,
                             mm.inactive_shrinker);
        struct drm_device *dev = dev_priv->dev;
        struct drm_i915_gem_object *obj, *next;
+       int nr_to_scan = sc->nr_to_scan;
        int cnt;
 
        if (!mutex_trylock(&dev->struct_mutex))
index 9d9d92945f8c5e515adc87dc40e9f4b1f97427bc..d948575717bf9407c97fd12dd199d7a57c3e0d7f 100644 (file)
@@ -395,12 +395,14 @@ static int ttm_pool_get_num_unused_pages(void)
 /**
  * Callback for mm to request pool to reduce number of page held.
  */
-static int ttm_pool_mm_shrink(struct shrinker *shrink, int shrink_pages, gfp_t gfp_mask)
+static int ttm_pool_mm_shrink(struct shrinker *shrink,
+                             struct shrink_control *sc)
 {
        static atomic_t start_pool = ATOMIC_INIT(0);
        unsigned i;
        unsigned pool_offset = atomic_add_return(1, &start_pool);
        struct ttm_page_pool *pool;
+       int shrink_pages = sc->nr_to_scan;
 
        pool_offset = pool_offset % NUM_POOLS;
        /* select start pool in round robin fashion */
index 43221beb9e97369b5e245bb489bb8a2e97e42da4..16db83c83c8b9ecea02a19f1e0b0e80971053b1c 100644 (file)
@@ -41,7 +41,7 @@ comment "Native drivers"
 
 config SENSORS_ABITUGURU
        tristate "Abit uGuru (rev 1 & 2)"
-       depends on X86 && EXPERIMENTAL
+       depends on X86 && DMI && EXPERIMENTAL
        help
          If you say yes here you get support for the sensor part of the first
          and second revision of the Abit uGuru chip. The voltage and frequency
@@ -56,7 +56,7 @@ config SENSORS_ABITUGURU
 
 config SENSORS_ABITUGURU3
        tristate "Abit uGuru (rev 3)"
-       depends on X86 && EXPERIMENTAL
+       depends on X86 && DMI && EXPERIMENTAL
        help
          If you say yes here you get support for the sensor part of the
          third revision of the Abit uGuru chip. Only reading the sensors
@@ -213,7 +213,7 @@ config SENSORS_ADT7475
 
 config SENSORS_ASC7621
        tristate "Andigilog aSC7621"
-       depends on HWMON && I2C
+       depends on I2C
        help
          If you say yes here you get support for the aSC7621
          family of SMBus sensors chip found on most Intel X38, X48, X58,
@@ -237,17 +237,27 @@ config SENSORS_K8TEMP
          will be called k8temp.
 
 config SENSORS_K10TEMP
-       tristate "AMD Family 10h/11h/12h/14h temperature sensor"
+       tristate "AMD Family 10h+ temperature sensor"
        depends on X86 && PCI
        help
          If you say yes here you get support for the temperature
          sensor(s) inside your CPU. Supported are later revisions of
          the AMD Family 10h and all revisions of the AMD Family 11h,
-         12h (Llano), and 14h (Brazos) microarchitectures.
+         12h (Llano), 14h (Brazos) and 15h (Bulldozer) microarchitectures.
 
          This driver can also be built as a module.  If so, the module
          will be called k10temp.
 
+config SENSORS_FAM15H_POWER
+       tristate "AMD Family 15h processor power"
+       depends on X86 && PCI
+       help
+         If you say yes here you get support for processor power
+         information of your AMD family 15h CPU.
+
+         This driver can also be built as a module.  If so, the module
+         will be called fam15h_power.
+
 config SENSORS_ASB100
        tristate "Asus ASB100 Bach"
        depends on X86 && I2C && EXPERIMENTAL
@@ -319,7 +329,7 @@ config SENSORS_F71882FG
          If you say yes here you get support for hardware monitoring
          features of many Fintek Super-I/O (LPC) chips. The currently
          supported chips are:
-           F71808E
+           F71808E/A
            F71858FG
            F71862FG
            F71863FG
@@ -978,6 +988,16 @@ config SENSORS_EMC2103
          This driver can also be built as a module.  If so, the module
          will be called emc2103.
 
+config SENSORS_EMC6W201
+       tristate "SMSC EMC6W201"
+       depends on I2C
+       help
+         If you say yes here you get support for the SMSC EMC6W201
+         hardware monitoring chip.
+
+         This driver can also be built as a module.  If so, the module
+         will be called emc6w201.
+
 config SENSORS_SMSC47M1
        tristate "SMSC LPC47M10x and compatibles"
        help
@@ -1341,6 +1361,16 @@ if ACPI
 
 comment "ACPI drivers"
 
+config SENSORS_ACPI_POWER
+       tristate "ACPI 4.0 power meter"
+       help
+         This driver exposes ACPI 4.0 power meters as hardware monitoring
+         devices.  Say Y (or M) if you have a computer with ACPI 4.0 firmware
+         and a power meter.
+
+         To compile this driver as a module, choose M here:
+         the module will be called acpi_power_meter.
+
 config SENSORS_ATK0110
        tristate "ASUS ATK0110"
        depends on X86 && EXPERIMENTAL
index 28e8d52f637923fdfc1e15200fce281760439ac4..28061cfa0cdb11c26558d3e0af68eb5c17c7af33 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_HWMON)             += hwmon.o
 obj-$(CONFIG_HWMON_VID)                += hwmon-vid.o
 
 # APCI drivers
+obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o
 obj-$(CONFIG_SENSORS_ATK0110)  += asus_atk0110.o
 
 # Native drivers
@@ -45,9 +46,11 @@ obj-$(CONFIG_SENSORS_DS620)  += ds620.o
 obj-$(CONFIG_SENSORS_DS1621)   += ds1621.o
 obj-$(CONFIG_SENSORS_EMC1403)  += emc1403.o
 obj-$(CONFIG_SENSORS_EMC2103)  += emc2103.o
+obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o
 obj-$(CONFIG_SENSORS_F71805F)  += f71805f.o
 obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
 obj-$(CONFIG_SENSORS_F75375S)  += f75375s.o
+obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o
 obj-$(CONFIG_SENSORS_FSCHMD)   += fschmd.o
 obj-$(CONFIG_SENSORS_G760A)    += g760a.o
 obj-$(CONFIG_SENSORS_GL518SM)  += gl518sm.o
index e7d4c4687f022dc57546776d00ad3c0d371f6e50..65a35cf5b3c5c57b58803e78ae3eda0b0e99f266 100644 (file)
@@ -1448,15 +1448,12 @@ static int __init abituguru_init(void)
 {
        int address, err;
        struct resource res = { .flags = IORESOURCE_IO };
-
-#ifdef CONFIG_DMI
        const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
 
        /* safety check, refuse to load on non Abit motherboards */
        if (!force && (!board_vendor ||
                        strcmp(board_vendor, "http://www.abit.com.tw/")))
                return -ENODEV;
-#endif
 
        address = abituguru_detect();
        if (address < 0)
index e89d572e33202a45c7d2fc4c444f740d44eec87b..d30855a75786ec7609b624b7492631cda41ab540 100644 (file)
@@ -1119,8 +1119,6 @@ static struct platform_driver abituguru3_driver = {
        .resume = abituguru3_resume
 };
 
-#ifdef CONFIG_DMI
-
 static int __init abituguru3_dmi_detect(void)
 {
        const char *board_vendor, *board_name;
@@ -1159,15 +1157,6 @@ static int __init abituguru3_dmi_detect(void)
        return 1;
 }
 
-#else /* !CONFIG_DMI */
-
-static inline int abituguru3_dmi_detect(void)
-{
-       return 1;
-}
-
-#endif /* CONFIG_DMI */
-
 /* FIXME: Manual detection should die eventually; we need to collect stable
  *        DMI model names first before we can rely entirely on CONFIG_DMI.
  */
@@ -1216,10 +1205,8 @@ static int __init abituguru3_init(void)
                if (err)
                        return err;
 
-#ifdef CONFIG_DMI
                pr_warn("this motherboard was not detected using DMI. "
                        "Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n");
-#endif
        }
 
        err = platform_driver_register(&abituguru3_driver);
index fbdc7655303b71b49027828f8e125e8c6d606b5a..b2cacbe707a8bcc91d6fb3a30194b470e8f715c2 100644 (file)
@@ -62,7 +62,7 @@ static ssize_t adcxx_read(struct device *dev,
 {
        struct spi_device *spi = to_spi_device(dev);
        struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
        u8 tx_buf[2];
        u8 rx_buf[2];
        int status;
@@ -105,7 +105,7 @@ static ssize_t adcxx_show_max(struct device *dev,
                struct device_attribute *devattr, char *buf)
 {
        struct spi_device *spi = to_spi_device(dev);
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
        u32 reference;
 
        if (mutex_lock_interruptible(&adc->lock))
@@ -122,7 +122,7 @@ static ssize_t adcxx_set_max(struct device *dev,
        struct device_attribute *devattr, const char *buf, size_t count)
 {
        struct spi_device *spi = to_spi_device(dev);
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
        unsigned long value;
 
        if (strict_strtoul(buf, 10, &value))
@@ -142,7 +142,7 @@ static ssize_t adcxx_show_name(struct device *dev, struct device_attribute
                              *devattr, char *buf)
 {
        struct spi_device *spi = to_spi_device(dev);
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
 
        return sprintf(buf, "adcxx%ds\n", adc->channels);
 }
@@ -182,7 +182,7 @@ static int __devinit adcxx_probe(struct spi_device *spi)
 
        mutex_lock(&adc->lock);
 
-       dev_set_drvdata(&spi->dev, adc);
+       spi_set_drvdata(spi, adc);
 
        for (i = 0; i < 3 + adc->channels; i++) {
                status = device_create_file(&spi->dev, &ad_input[i].dev_attr);
@@ -206,7 +206,7 @@ out_err:
        for (i--; i >= 0; i--)
                device_remove_file(&spi->dev, &ad_input[i].dev_attr);
 
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        mutex_unlock(&adc->lock);
        kfree(adc);
        return status;
@@ -214,7 +214,7 @@ out_err:
 
 static int __devexit adcxx_remove(struct spi_device *spi)
 {
-       struct adcxx *adc = dev_get_drvdata(&spi->dev);
+       struct adcxx *adc = spi_get_drvdata(spi);
        int i;
 
        mutex_lock(&adc->lock);
@@ -222,7 +222,7 @@ static int __devexit adcxx_remove(struct spi_device *spi)
        for (i = 0; i < 3 + adc->channels; i++)
                device_remove_file(&spi->dev, &ad_input[i].dev_attr);
 
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        mutex_unlock(&adc->lock);
        kfree(adc);
 
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c
new file mode 100644 (file)
index 0000000..e0ef323
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * emc6w201.c - Hardware monitoring driver for the SMSC EMC6W201
+ * Copyright (C) 2011  Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.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>
+
+/*
+ * Addresses to scan
+ */
+
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/*
+ * The EMC6W201 registers
+ */
+
+#define EMC6W201_REG_IN(nr)            (0x20 + (nr))
+#define EMC6W201_REG_TEMP(nr)          (0x26 + (nr))
+#define EMC6W201_REG_FAN(nr)           (0x2C + (nr) * 2)
+#define EMC6W201_REG_COMPANY           0x3E
+#define EMC6W201_REG_VERSTEP           0x3F
+#define EMC6W201_REG_CONFIG            0x40
+#define EMC6W201_REG_IN_LOW(nr)                (0x4A + (nr) * 2)
+#define EMC6W201_REG_IN_HIGH(nr)       (0x4B + (nr) * 2)
+#define EMC6W201_REG_TEMP_LOW(nr)      (0x56 + (nr) * 2)
+#define EMC6W201_REG_TEMP_HIGH(nr)     (0x57 + (nr) * 2)
+#define EMC6W201_REG_FAN_MIN(nr)       (0x62 + (nr) * 2)
+
+enum { input, min, max } subfeature;
+
+/*
+ * Per-device data
+ */
+
+struct emc6w201_data {
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       char valid; /* zero until following fields are valid */
+       unsigned long last_updated; /* in jiffies */
+
+       /* registers values */
+       u8 in[3][6];
+       s8 temp[3][6];
+       u16 fan[2][5];
+};
+
+/*
+ * Combine LSB and MSB registers in a single value
+ * Locking: must be called with data->update_lock held
+ */
+static u16 emc6w201_read16(struct i2c_client *client, u8 reg)
+{
+       int lsb, msb;
+
+       lsb = i2c_smbus_read_byte_data(client, reg);
+       msb = i2c_smbus_read_byte_data(client, reg + 1);
+       if (lsb < 0 || msb < 0) {
+               dev_err(&client->dev, "16-bit read failed at 0x%02x\n", reg);
+               return 0xFFFF;  /* Arbitrary value */
+       }
+
+       return (msb << 8) | lsb;
+}
+
+/*
+ * Write 16-bit value to LSB and MSB registers
+ * Locking: must be called with data->update_lock held
+ */
+static int emc6w201_write16(struct i2c_client *client, u8 reg, u16 val)
+{
+       int err;
+
+       err = i2c_smbus_write_byte_data(client, reg, val & 0xff);
+       if (!err)
+               err = i2c_smbus_write_byte_data(client, reg + 1, val >> 8);
+       if (err < 0)
+               dev_err(&client->dev, "16-bit write failed at 0x%02x\n", reg);
+
+       return err;
+}
+
+static struct emc6w201_data *emc6w201_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+       int nr;
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               for (nr = 0; nr < 6; nr++) {
+                       data->in[input][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_IN(nr));
+                       data->in[min][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_IN_LOW(nr));
+                       data->in[max][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_IN_HIGH(nr));
+               }
+
+               for (nr = 0; nr < 6; nr++) {
+                       data->temp[input][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_TEMP(nr));
+                       data->temp[min][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_TEMP_LOW(nr));
+                       data->temp[max][nr] =
+                               i2c_smbus_read_byte_data(client,
+                                               EMC6W201_REG_TEMP_HIGH(nr));
+               }
+
+               for (nr = 0; nr < 5; nr++) {
+                       data->fan[input][nr] =
+                               emc6w201_read16(client,
+                                               EMC6W201_REG_FAN(nr));
+                       data->fan[min][nr] =
+                               emc6w201_read16(client,
+                                               EMC6W201_REG_FAN_MIN(nr));
+               }
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+
+static const u16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 };
+
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       struct emc6w201_data *data = emc6w201_update_device(dev);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+
+       return sprintf(buf, "%u\n",
+                      (unsigned)data->in[sf][nr] * nominal_mv[nr] / 0xC0);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *devattr,
+                     const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int err;
+       long val;
+       u8 reg;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       val = DIV_ROUND_CLOSEST(val * 0xC0, nominal_mv[nr]);
+       reg = (sf == min) ? EMC6W201_REG_IN_LOW(nr)
+                         : EMC6W201_REG_IN_HIGH(nr);
+
+       mutex_lock(&data->update_lock);
+       data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255);
+       err = i2c_smbus_write_byte_data(client, reg, data->in[sf][nr]);
+       mutex_unlock(&data->update_lock);
+
+       return err < 0 ? err : count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       struct emc6w201_data *data = emc6w201_update_device(dev);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+
+       return sprintf(buf, "%d\n", (int)data->temp[sf][nr] * 1000);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+                       const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int err;
+       long val;
+       u8 reg;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       val /= 1000;
+       reg = (sf == min) ? EMC6W201_REG_TEMP_LOW(nr)
+                         : EMC6W201_REG_TEMP_HIGH(nr);
+
+       mutex_lock(&data->update_lock);
+       data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128);
+       err = i2c_smbus_write_byte_data(client, reg, data->temp[sf][nr]);
+       mutex_unlock(&data->update_lock);
+
+       return err < 0 ? err : count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+       char *buf)
+{
+       struct emc6w201_data *data = emc6w201_update_device(dev);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       unsigned rpm;
+
+       if (data->fan[sf][nr] == 0 || data->fan[sf][nr] == 0xFFFF)
+               rpm = 0;
+       else
+               rpm = 5400000U / data->fan[sf][nr];
+
+       return sprintf(buf, "%u\n", rpm);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *devattr,
+                      const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+       int sf = to_sensor_dev_attr_2(devattr)->index;
+       int nr = to_sensor_dev_attr_2(devattr)->nr;
+       int err;
+       unsigned long val;
+
+       err = strict_strtoul(buf, 10, &val);
+       if (err < 0)
+               return err;
+
+       if (val == 0) {
+               val = 0xFFFF;
+       } else {
+               val = DIV_ROUND_CLOSEST(5400000U, val);
+               val = SENSORS_LIMIT(val, 0, 0xFFFE);
+       }
+
+       mutex_lock(&data->update_lock);
+       data->fan[sf][nr] = val;
+       err = emc6w201_write16(client, EMC6W201_REG_FAN_MIN(nr),
+                              data->fan[sf][nr]);
+       mutex_unlock(&data->update_lock);
+
+       return err < 0 ? err : count;
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           0, min);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           0, max);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           1, min);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           1, max);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           2, min);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           2, max);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           3, min);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           3, max);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           4, min);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           4, max);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, input);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in,
+                           5, min);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in,
+                           5, max);
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           0, min);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           0, max);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           1, min);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           1, max);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           2, min);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           2, max);
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(temp4_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           3, min);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           3, max);
+static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(temp5_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           4, min);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           4, max);
+static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, input);
+static SENSOR_DEVICE_ATTR_2(temp6_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           5, min);
+static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+                           5, max);
+
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           0, min);
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           1, min);
+static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           2, min);
+static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           3, min);
+static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+                           4, min);
+
+static struct attribute *emc6w201_attributes[] = {
+       &sensor_dev_attr_in0_input.dev_attr.attr,
+       &sensor_dev_attr_in0_min.dev_attr.attr,
+       &sensor_dev_attr_in0_max.dev_attr.attr,
+       &sensor_dev_attr_in1_input.dev_attr.attr,
+       &sensor_dev_attr_in1_min.dev_attr.attr,
+       &sensor_dev_attr_in1_max.dev_attr.attr,
+       &sensor_dev_attr_in2_input.dev_attr.attr,
+       &sensor_dev_attr_in2_min.dev_attr.attr,
+       &sensor_dev_attr_in2_max.dev_attr.attr,
+       &sensor_dev_attr_in3_input.dev_attr.attr,
+       &sensor_dev_attr_in3_min.dev_attr.attr,
+       &sensor_dev_attr_in3_max.dev_attr.attr,
+       &sensor_dev_attr_in4_input.dev_attr.attr,
+       &sensor_dev_attr_in4_min.dev_attr.attr,
+       &sensor_dev_attr_in4_max.dev_attr.attr,
+       &sensor_dev_attr_in5_input.dev_attr.attr,
+       &sensor_dev_attr_in5_min.dev_attr.attr,
+       &sensor_dev_attr_in5_max.dev_attr.attr,
+
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp2_input.dev_attr.attr,
+       &sensor_dev_attr_temp2_min.dev_attr.attr,
+       &sensor_dev_attr_temp2_max.dev_attr.attr,
+       &sensor_dev_attr_temp3_input.dev_attr.attr,
+       &sensor_dev_attr_temp3_min.dev_attr.attr,
+       &sensor_dev_attr_temp3_max.dev_attr.attr,
+       &sensor_dev_attr_temp4_input.dev_attr.attr,
+       &sensor_dev_attr_temp4_min.dev_attr.attr,
+       &sensor_dev_attr_temp4_max.dev_attr.attr,
+       &sensor_dev_attr_temp5_input.dev_attr.attr,
+       &sensor_dev_attr_temp5_min.dev_attr.attr,
+       &sensor_dev_attr_temp5_max.dev_attr.attr,
+       &sensor_dev_attr_temp6_input.dev_attr.attr,
+       &sensor_dev_attr_temp6_min.dev_attr.attr,
+       &sensor_dev_attr_temp6_max.dev_attr.attr,
+
+       &sensor_dev_attr_fan1_input.dev_attr.attr,
+       &sensor_dev_attr_fan1_min.dev_attr.attr,
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan2_min.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_min.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_min.dev_attr.attr,
+       &sensor_dev_attr_fan5_input.dev_attr.attr,
+       &sensor_dev_attr_fan5_min.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group emc6w201_group = {
+       .attrs = emc6w201_attributes,
+};
+
+/*
+ * Driver interface
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int emc6w201_detect(struct i2c_client *client,
+                          struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       int company, verstep, config;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       /* Identification */
+       company = i2c_smbus_read_byte_data(client, EMC6W201_REG_COMPANY);
+       if (company != 0x5C)
+               return -ENODEV;
+       verstep = i2c_smbus_read_byte_data(client, EMC6W201_REG_VERSTEP);
+       if (verstep < 0 || (verstep & 0xF0) != 0xB0)
+               return -ENODEV;
+       if ((verstep & 0x0F) > 2) {
+               dev_dbg(&client->dev, "Unknwown EMC6W201 stepping %d\n",
+                       verstep & 0x0F);
+               return -ENODEV;
+       }
+
+       /* Check configuration */
+       config = i2c_smbus_read_byte_data(client, EMC6W201_REG_CONFIG);
+       if ((config & 0xF4) != 0x04)
+               return -ENODEV;
+       if (!(config & 0x01)) {
+               dev_err(&client->dev, "Monitoring not enabled\n");
+               return -ENODEV;
+       }
+
+       strlcpy(info->type, "emc6w201", I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int emc6w201_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct emc6w201_data *data;
+       int err;
+
+       data = kzalloc(sizeof(struct emc6w201_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* Create sysfs attribute */
+       err = sysfs_create_group(&client->dev.kobj, &emc6w201_group);
+       if (err)
+               goto exit_free;
+
+       /* Expose as a hwmon device */
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       return 0;
+
+ exit_remove:
+       sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
+ exit_free:
+       kfree(data);
+ exit:
+       return err;
+}
+
+static int emc6w201_remove(struct i2c_client *client)
+{
+       struct emc6w201_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id emc6w201_id[] = {
+       { "emc6w201", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, emc6w201_id);
+
+static struct i2c_driver emc6w201_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "emc6w201",
+       },
+       .probe          = emc6w201_probe,
+       .remove         = emc6w201_remove,
+       .id_table       = emc6w201_id,
+       .detect         = emc6w201_detect,
+       .address_list   = normal_i2c,
+};
+
+static int __init sensors_emc6w201_init(void)
+{
+       return i2c_add_driver(&emc6w201_driver);
+}
+module_init(sensors_emc6w201_init);
+
+static void __exit sensors_emc6w201_exit(void)
+{
+       i2c_del_driver(&emc6w201_driver);
+}
+module_exit(sensors_emc6w201_exit);
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("SMSC EMC6W201 hardware monitoring driver");
+MODULE_LICENSE("GPL");
index ca07a32447c23406ef8e39523eb1830d42d56286..a4a94a096c90e993a3019e75de2c285939748ab9 100644 (file)
@@ -48,6 +48,7 @@
 
 #define SIO_FINTEK_ID          0x1934  /* Manufacturers ID */
 #define SIO_F71808E_ID         0x0901  /* Chipset ID */
+#define SIO_F71808A_ID         0x1001  /* Chipset ID */
 #define SIO_F71858_ID          0x0507  /* Chipset ID */
 #define SIO_F71862_ID          0x0601  /* Chipset ID */
 #define SIO_F71869_ID          0x0814  /* Chipset ID */
@@ -107,11 +108,12 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
-enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
+enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
             f71889ed, f71889a, f8000, f81865f };
 
 static const char *f71882fg_names[] = {
        "f71808e",
+       "f71808a",
        "f71858fg",
        "f71862fg",
        "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
@@ -125,6 +127,7 @@ static const char *f71882fg_names[] = {
 
 static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
        [f71808e]       = { 1, 1, 1, 1, 1, 1, 0, 1, 1 },
+       [f71808a]       = { 1, 1, 1, 1, 0, 0, 0, 1, 1 },
        [f71858fg]      = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
        [f71862fg]      = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        [f71869]        = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
@@ -138,6 +141,7 @@ static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
 
 static const char f71882fg_has_in1_alarm[] = {
        [f71808e]       = 0,
+       [f71808a]       = 0,
        [f71858fg]      = 0,
        [f71862fg]      = 0,
        [f71869]        = 0,
@@ -149,8 +153,9 @@ static const char f71882fg_has_in1_alarm[] = {
        [f81865f]       = 1,
 };
 
-static const char f71882fg_has_beep[] = {
+static const char f71882fg_fan_has_beep[] = {
        [f71808e]       = 0,
+       [f71808a]       = 0,
        [f71858fg]      = 0,
        [f71862fg]      = 1,
        [f71869]        = 1,
@@ -164,6 +169,7 @@ static const char f71882fg_has_beep[] = {
 
 static const char f71882fg_nr_fans[] = {
        [f71808e]       = 3,
+       [f71808a]       = 2, /* +1 fan which is monitor + simple pwm only */
        [f71858fg]      = 3,
        [f71862fg]      = 3,
        [f71869]        = 3,
@@ -171,12 +177,27 @@ static const char f71882fg_nr_fans[] = {
        [f71889fg]      = 3,
        [f71889ed]      = 3,
        [f71889a]       = 3,
-       [f8000]         = 3,
+       [f8000]         = 3, /* +1 fan which is monitor only */
        [f81865f]       = 2,
 };
 
+static const char f71882fg_temp_has_beep[] = {
+       [f71808e]       = 0,
+       [f71808a]       = 1,
+       [f71858fg]      = 0,
+       [f71862fg]      = 1,
+       [f71869]        = 1,
+       [f71882fg]      = 1,
+       [f71889fg]      = 1,
+       [f71889ed]      = 1,
+       [f71889a]       = 1,
+       [f8000]         = 0,
+       [f81865f]       = 1,
+};
+
 static const char f71882fg_nr_temps[] = {
        [f71808e]       = 2,
+       [f71808a]       = 2,
        [f71858fg]      = 3,
        [f71862fg]      = 3,
        [f71869]        = 3,
@@ -301,6 +322,10 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
        char *buf);
 static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
        const char *buf, size_t count);
+static ssize_t show_simple_pwm(struct device *dev,
+       struct device_attribute *devattr, char *buf);
+static ssize_t store_simple_pwm(struct device *dev,
+       struct device_attribute *devattr, const char *buf, size_t count);
 static ssize_t show_pwm_enable(struct device *dev,
        struct device_attribute *devattr, char *buf);
 static ssize_t store_pwm_enable(struct device *dev,
@@ -550,6 +575,14 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
                      show_pwm_interpolate, store_pwm_interpolate, 0, 3),
 } };
 
+/* Attr for the third fan of the f71808a, which only has manual pwm */
+static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
+       SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
+       SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
+       SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
+                     show_simple_pwm, store_simple_pwm, 0, 2),
+};
+
 /* Attr for models which can beep on Fan alarm */
 static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
        SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
@@ -1146,12 +1179,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                        data->temp_type[3] = (reg & 0x08) ? 2 : 4;
                }
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_fan_has_beep[data->type])
                        data->fan_beep = f71882fg_read8(data,
                                                F71882FG_REG_FAN_BEEP);
+
+               if (f71882fg_temp_has_beep[data->type])
                        data->temp_beep = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_BEEP);
-               }
 
                data->pwm_enable = f71882fg_read8(data,
                                                  F71882FG_REG_PWM_ENABLE);
@@ -1232,7 +1266,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                        data->pwm[nr] =
                            f71882fg_read8(data, F71882FG_REG_PWM(nr));
                }
-               /* The f8000 can monitor 1 more fan, but has no pwm for it */
+               /* Some models have 1 more fan with limited capabilities */
+               if (data->type == f71808a) {
+                       data->fan[2] = f71882fg_read16(data,
+                                               F71882FG_REG_FAN(2));
+                       data->pwm[2] = f71882fg_read8(data,
+                                                       F71882FG_REG_PWM(2));
+               }
                if (data->type == f8000)
                        data->fan[3] = f71882fg_read16(data,
                                                F71882FG_REG_FAN(3));
@@ -1722,6 +1762,38 @@ leave:
        return count;
 }
 
+static ssize_t show_simple_pwm(struct device *dev,
+                              struct device_attribute *devattr, char *buf)
+{
+       struct f71882fg_data *data = f71882fg_update_device(dev);
+       int val, nr = to_sensor_dev_attr_2(devattr)->index;
+
+       val = data->pwm[nr];
+       return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_simple_pwm(struct device *dev,
+                               struct device_attribute *devattr,
+                               const char *buf, size_t count)
+{
+       struct f71882fg_data *data = dev_get_drvdata(dev);
+       int err, nr = to_sensor_dev_attr_2(devattr)->index;
+       long val;
+
+       err = strict_strtol(buf, 10, &val);
+       if (err)
+               return err;
+
+       val = SENSORS_LIMIT(val, 0, 255);
+
+       mutex_lock(&data->update_lock);
+       f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
+       data->pwm[nr] = val;
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
 static ssize_t show_pwm_enable(struct device *dev,
                               struct device_attribute *devattr, char *buf)
 {
@@ -2140,7 +2212,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                if (err)
                        goto exit_unregister_sysfs;
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_temp_has_beep[data->type]) {
                        err = f71882fg_create_sysfs_files(pdev,
                                        &fxxxx_temp_beep_attr[0][0],
                                        ARRAY_SIZE(fxxxx_temp_beep_attr[0])
@@ -2169,6 +2241,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
        if (start_reg & 0x02) {
                switch (data->type) {
                case f71808e:
+               case f71808a:
                case f71869:
                        /* These always have signed auto point temps */
                        data->auto_point_temp_signed = 1;
@@ -2221,7 +2294,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                if (err)
                        goto exit_unregister_sysfs;
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_fan_has_beep[data->type]) {
                        err = f71882fg_create_sysfs_files(pdev,
                                        fxxxx_fan_beep_attr, nr_fans);
                        if (err)
@@ -2230,6 +2303,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
                switch (data->type) {
                case f71808e:
+               case f71808a:
                case f71869:
                case f71889fg:
                case f71889ed:
@@ -2255,6 +2329,16 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                }
 
                switch (data->type) {
+               case f71808a:
+                       err = f71882fg_create_sysfs_files(pdev,
+                               &fxxxx_auto_pwm_attr[0][0],
+                               ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+                       if (err)
+                               goto exit_unregister_sysfs;
+                       err = f71882fg_create_sysfs_files(pdev,
+                                       f71808a_fan3_attr,
+                                       ARRAY_SIZE(f71808a_fan3_attr));
+                       break;
                case f71862fg:
                        err = f71882fg_create_sysfs_files(pdev,
                                        f71862fg_auto_pwm_attr,
@@ -2343,7 +2427,7 @@ static int f71882fg_remove(struct platform_device *pdev)
                                &fxxxx_temp_attr[0][0],
                                ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
                }
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_temp_has_beep[data->type]) {
                        f71882fg_remove_sysfs_files(pdev,
                               &fxxxx_temp_beep_attr[0][0],
                               ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
@@ -2366,12 +2450,20 @@ static int f71882fg_remove(struct platform_device *pdev)
                f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
                                ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
 
-               if (f71882fg_has_beep[data->type]) {
+               if (f71882fg_fan_has_beep[data->type]) {
                        f71882fg_remove_sysfs_files(pdev,
                                        fxxxx_fan_beep_attr, nr_fans);
                }
 
                switch (data->type) {
+               case f71808a:
+                       f71882fg_remove_sysfs_files(pdev,
+                               &fxxxx_auto_pwm_attr[0][0],
+                               ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+                       f71882fg_remove_sysfs_files(pdev,
+                                       f71808a_fan3_attr,
+                                       ARRAY_SIZE(f71808a_fan3_attr));
+                       break;
                case f71862fg:
                        f71882fg_remove_sysfs_files(pdev,
                                        f71862fg_auto_pwm_attr,
@@ -2424,6 +2516,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
        case SIO_F71808E_ID:
                sio_data->type = f71808e;
                break;
+       case SIO_F71808A_ID:
+               sio_data->type = f71808a;
+               break;
        case SIO_F71858_ID:
                sio_data->type = f71858fg;
                break;
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
new file mode 100644 (file)
index 0000000..523f8fb
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * fam15h_power.c - AMD Family 15h processor power monitoring
+ *
+ * Copyright (c) 2011 Advanced Micro Devices, Inc.
+ * Author: Andreas Herrmann <andreas.herrmann3@amd.com>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License; 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <asm/processor.h>
+
+MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
+MODULE_AUTHOR("Andreas Herrmann <andreas.herrmann3@amd.com>");
+MODULE_LICENSE("GPL");
+
+/* D18F3 */
+#define REG_NORTHBRIDGE_CAP            0xe8
+
+/* D18F4 */
+#define REG_PROCESSOR_TDP              0x1b8
+
+/* D18F5 */
+#define REG_TDP_RUNNING_AVERAGE                0xe0
+#define REG_TDP_LIMIT3                 0xe8
+
+struct fam15h_power_data {
+       struct device *hwmon_dev;
+       unsigned int tdp_to_watts;
+       unsigned int base_tdp;
+       unsigned int processor_pwr_watts;
+};
+
+static ssize_t show_power(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       u32 val, tdp_limit, running_avg_range;
+       s32 running_avg_capture;
+       u64 curr_pwr_watts;
+       struct pci_dev *f4 = to_pci_dev(dev);
+       struct fam15h_power_data *data = dev_get_drvdata(dev);
+
+       pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+                                 REG_TDP_RUNNING_AVERAGE, &val);
+       running_avg_capture = (val >> 4) & 0x3fffff;
+       running_avg_capture = sign_extend32(running_avg_capture, 22);
+       running_avg_range = val & 0xf;
+
+       pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+                                 REG_TDP_LIMIT3, &val);
+
+       tdp_limit = val >> 16;
+       curr_pwr_watts = tdp_limit + data->base_tdp -
+               (s32)(running_avg_capture >> (running_avg_range + 1));
+       curr_pwr_watts *= data->tdp_to_watts;
+
+       /*
+        * Convert to microWatt
+        *
+        * power is in Watt provided as fixed point integer with
+        * scaling factor 1/(2^16).  For conversion we use
+        * (10^6)/(2^16) = 15625/(2^10)
+        */
+       curr_pwr_watts = (curr_pwr_watts * 15625) >> 10;
+       return sprintf(buf, "%u\n", (unsigned int) curr_pwr_watts);
+}
+static DEVICE_ATTR(power1_input, S_IRUGO, show_power, NULL);
+
+static ssize_t show_power_crit(struct device *dev,
+                              struct device_attribute *attr, char *buf)
+{
+       struct fam15h_power_data *data = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%u\n", data->processor_pwr_watts);
+}
+static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL);
+
+static ssize_t show_name(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "fam15h_power\n");
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *fam15h_power_attrs[] = {
+       &dev_attr_power1_input.attr,
+       &dev_attr_power1_crit.attr,
+       &dev_attr_name.attr,
+       NULL
+};
+
+static const struct attribute_group fam15h_power_attr_group = {
+       .attrs  = fam15h_power_attrs,
+};
+
+static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4)
+{
+       u32 val;
+
+       pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 3),
+                                 REG_NORTHBRIDGE_CAP, &val);
+       if ((val & BIT(29)) && ((val >> 30) & 3))
+               return false;
+
+       return true;
+}
+
+static void __devinit fam15h_power_init_data(struct pci_dev *f4,
+                                            struct fam15h_power_data *data)
+{
+       u32 val;
+       u64 tmp;
+
+       pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val);
+       data->base_tdp = val >> 16;
+       tmp = val & 0xffff;
+
+       pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+                                 REG_TDP_LIMIT3, &val);
+
+       data->tdp_to_watts = ((val & 0x3ff) << 6) | ((val >> 10) & 0x3f);
+       tmp *= data->tdp_to_watts;
+
+       /* result not allowed to be >= 256W */
+       if ((tmp >> 16) >= 256)
+               dev_warn(&f4->dev, "Bogus value for ProcessorPwrWatts "
+                        "(processor_pwr_watts>=%u)\n",
+                        (unsigned int) (tmp >> 16));
+
+       /* convert to microWatt */
+       data->processor_pwr_watts = (tmp * 15625) >> 10;
+}
+
+static int __devinit fam15h_power_probe(struct pci_dev *pdev,
+                                       const struct pci_device_id *id)
+{
+       struct fam15h_power_data *data;
+       struct device *dev;
+       int err;
+
+       if (!fam15h_power_is_internal_node0(pdev)) {
+               err = -ENODEV;
+               goto exit;
+       }
+
+       data = kzalloc(sizeof(struct fam15h_power_data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto exit;
+       }
+       fam15h_power_init_data(pdev, data);
+       dev = &pdev->dev;
+
+       dev_set_drvdata(dev, data);
+       err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_group);
+       if (err)
+               goto exit_free_data;
+
+       data->hwmon_dev = hwmon_device_register(dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               goto exit_remove_group;
+       }
+
+       return 0;
+
+exit_remove_group:
+       sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
+exit_free_data:
+       kfree(data);
+exit:
+       return err;
+}
+
+static void __devexit fam15h_power_remove(struct pci_dev *pdev)
+{
+       struct device *dev;
+       struct fam15h_power_data *data;
+
+       dev = &pdev->dev;
+       data = dev_get_drvdata(dev);
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
+       dev_set_drvdata(dev, NULL);
+       kfree(data);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
+       {}
+};
+MODULE_DEVICE_TABLE(pci, fam15h_power_id_table);
+
+static struct pci_driver fam15h_power_driver = {
+       .name = "fam15h_power",
+       .id_table = fam15h_power_id_table,
+       .probe = fam15h_power_probe,
+       .remove = __devexit_p(fam15h_power_remove),
+};
+
+static int __init fam15h_power_init(void)
+{
+       return pci_register_driver(&fam15h_power_driver);
+}
+
+static void __exit fam15h_power_exit(void)
+{
+       pci_unregister_driver(&fam15h_power_driver);
+}
+
+module_init(fam15h_power_init)
+module_exit(fam15h_power_exit)
index bc6e2ab3a361d539befcc2055ebcb5a1c119f5a9..537409d07ee730b55e358fcb1e9e6d515d27e1e8 100644 (file)
@@ -523,7 +523,7 @@ static void aem_delete(struct aem_data *data)
        aem_remove_sensors(data);
        hwmon_device_unregister(data->hwmon_dev);
        ipmi_destroy_user(data->ipmi.user);
-       dev_set_drvdata(&data->pdev->dev, NULL);
+       platform_set_drvdata(data->pdev, NULL);
        platform_device_unregister(data->pdev);
        aem_idr_put(data->id);
        kfree(data);
@@ -594,7 +594,7 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
        if (res)
                goto ipmi_err;
 
-       dev_set_drvdata(&data->pdev->dev, data);
+       platform_set_drvdata(data->pdev, data);
 
        /* Set up IPMI interface */
        if (aem_init_ipmi_data(&data->ipmi, probe->interface,
@@ -630,7 +630,7 @@ sensor_err:
 hwmon_reg_err:
        ipmi_destroy_user(data->ipmi.user);
 ipmi_err:
-       dev_set_drvdata(&data->pdev->dev, NULL);
+       platform_set_drvdata(data->pdev, NULL);
        platform_device_unregister(data->pdev);
 dev_err:
        aem_idr_put(data->id);
@@ -727,7 +727,7 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
        if (res)
                goto ipmi_err;
 
-       dev_set_drvdata(&data->pdev->dev, data);
+       platform_set_drvdata(data->pdev, data);
 
        /* Set up IPMI interface */
        if (aem_init_ipmi_data(&data->ipmi, probe->interface,
@@ -763,7 +763,7 @@ sensor_err:
 hwmon_reg_err:
        ipmi_destroy_user(data->ipmi.user);
 ipmi_err:
-       dev_set_drvdata(&data->pdev->dev, NULL);
+       platform_set_drvdata(data->pdev, NULL);
        platform_device_unregister(data->pdev);
 dev_err:
        aem_idr_put(data->id);
index 316b64823f7b39b805823e606453e244a32d3bae..bb6405b92007b7b9a9ba2c95038e49f01211c7a0 100644 (file)
@@ -77,15 +77,13 @@ static struct platform_device *pdev;
 #define        DEVID   0x20    /* Register: Device ID */
 #define        DEVREV  0x22    /* Register: Device Revision */
 
-static inline int
-superio_inb(int reg)
+static inline int superio_inb(int reg)
 {
        outb(reg, REG);
        return inb(VAL);
 }
 
-static inline void
-superio_outb(int reg, int val)
+static inline void superio_outb(int reg, int val)
 {
        outb(reg, REG);
        outb(val, VAL);
@@ -101,27 +99,32 @@ static int superio_inw(int reg)
        return val;
 }
 
-static inline void
-superio_select(int ldn)
+static inline void superio_select(int ldn)
 {
        outb(DEV, REG);
        outb(ldn, VAL);
 }
 
-static inline void
-superio_enter(void)
+static inline int superio_enter(void)
 {
+       /*
+        * Try to reserve REG and REG + 1 for exclusive access.
+        */
+       if (!request_muxed_region(REG, 2, DRVNAME))
+               return -EBUSY;
+
        outb(0x87, REG);
        outb(0x01, REG);
        outb(0x55, REG);
        outb(0x55, REG);
+       return 0;
 }
 
-static inline void
-superio_exit(void)
+static inline void superio_exit(void)
 {
        outb(0x02, REG);
        outb(0x02, VAL);
+       release_region(REG, 2);
 }
 
 /* Logical device 4 registers */
@@ -1542,11 +1545,15 @@ static const struct attribute_group it87_group_label = {
 static int __init it87_find(unsigned short *address,
        struct it87_sio_data *sio_data)
 {
-       int err = -ENODEV;
+       int err;
        u16 chip_type;
        const char *board_vendor, *board_name;
 
-       superio_enter();
+       err = superio_enter();
+       if (err)
+               return err;
+
+       err = -ENODEV;
        chip_type = force_id ? force_id : superio_inw(DEVID);
 
        switch (chip_type) {
index 93499123706182b9bdf42b3da295759eda67b18c..02cebb74e206743f08608ad2f101398ec9ab61d8 100644 (file)
@@ -213,7 +213,7 @@ static const struct dev_pm_ops jc42_dev_pm_ops = {
 
 /* This is the driver that will be inserted */
 static struct i2c_driver jc42_driver = {
-       .class          = I2C_CLASS_HWMON,
+       .class          = I2C_CLASS_SPD,
        .driver = {
                .name   = "jc42",
                .pm = JC42_DEV_PM_OPS,
index 82bf65aa2968bcfb3d89b6c9280e72f437762037..41aa6a319870cdcc6435ad8690be095aa8ab8675 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * k10temp.c - AMD Family 10h/11h/12h/14h processor hardware monitoring
+ * k10temp.c - AMD Family 10h/11h/12h/14h/15h processor hardware monitoring
  *
  * Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
  *
@@ -25,7 +25,7 @@
 #include <linux/pci.h>
 #include <asm/processor.h>
 
-MODULE_DESCRIPTION("AMD Family 10h/11h/12h/14h CPU core temperature monitor");
+MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
 MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
 MODULE_LICENSE("GPL");
 
@@ -173,7 +173,7 @@ static int __devinit k10temp_probe(struct pci_dev *pdev,
                err = PTR_ERR(hwmon_dev);
                goto exit_remove;
        }
-       dev_set_drvdata(&pdev->dev, hwmon_dev);
+       pci_set_drvdata(pdev, hwmon_dev);
 
        if (unreliable && force)
                dev_warn(&pdev->dev,
@@ -194,7 +194,7 @@ exit:
 
 static void __devexit k10temp_remove(struct pci_dev *pdev)
 {
-       hwmon_device_unregister(dev_get_drvdata(&pdev->dev));
+       hwmon_device_unregister(pci_get_drvdata(pdev));
        device_remove_file(&pdev->dev, &dev_attr_name);
        device_remove_file(&pdev->dev, &dev_attr_temp1_input);
        device_remove_file(&pdev->dev, &dev_attr_temp1_max);
@@ -202,13 +202,14 @@ static void __devexit k10temp_remove(struct pci_dev *pdev)
                           &sensor_dev_attr_temp1_crit.dev_attr);
        device_remove_file(&pdev->dev,
                           &sensor_dev_attr_temp1_crit_hyst.dev_attr);
-       dev_set_drvdata(&pdev->dev, NULL);
+       pci_set_drvdata(pdev, NULL);
 }
 
 static const struct pci_device_id k10temp_id_table[] = {
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
        { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
        {}
 };
 MODULE_DEVICE_TABLE(pci, k10temp_id_table);
index 418496f13020ba58f57e23eece28417a48466aea..b923bc2307ad2e09758086daba616863bb2e1a00 100644 (file)
@@ -252,7 +252,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
 
        data->name = "k8temp";
        mutex_init(&data->update_lock);
-       dev_set_drvdata(&pdev->dev, data);
+       pci_set_drvdata(pdev, data);
 
        /* Register sysfs hooks */
        err = device_create_file(&pdev->dev,
@@ -307,7 +307,7 @@ exit_remove:
                           &sensor_dev_attr_temp4_input.dev_attr);
        device_remove_file(&pdev->dev, &dev_attr_name);
 exit_free:
-       dev_set_drvdata(&pdev->dev, NULL);
+       pci_set_drvdata(pdev, NULL);
        kfree(data);
 exit:
        return err;
@@ -315,7 +315,7 @@ exit:
 
 static void __devexit k8temp_remove(struct pci_dev *pdev)
 {
-       struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
+       struct k8temp_data *data = pci_get_drvdata(pdev);
 
        hwmon_device_unregister(data->hwmon_dev);
        device_remove_file(&pdev->dev,
@@ -327,7 +327,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev)
        device_remove_file(&pdev->dev,
                           &sensor_dev_attr_temp4_input.dev_attr);
        device_remove_file(&pdev->dev, &dev_attr_name);
-       dev_set_drvdata(&pdev->dev, NULL);
+       pci_set_drvdata(pdev, NULL);
        kfree(data);
 }
 
index 3b84fb5030535d3e16d60e164a68dd0fb8ef8a4f..c274ea25d899f5766d06d41283c5ec26876adddd 100644 (file)
@@ -58,7 +58,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
        int status, val = 0;
        u8 rxbuf[2];
        s16 raw=0;
-       struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
+       struct lm70 *p_lm70 = spi_get_drvdata(spi);
 
        if (mutex_lock_interruptible(&p_lm70->lock))
                return -ERESTARTSYS;
@@ -163,7 +163,7 @@ static int __devinit lm70_probe(struct spi_device *spi)
                status = PTR_ERR(p_lm70->hwmon_dev);
                goto out_dev_reg_failed;
        }
-       dev_set_drvdata(&spi->dev, p_lm70);
+       spi_set_drvdata(spi, p_lm70);
 
        if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
         || (status = device_create_file(&spi->dev, &dev_attr_name))) {
@@ -177,19 +177,19 @@ out_dev_create_file_failed:
        device_remove_file(&spi->dev, &dev_attr_temp1_input);
        hwmon_device_unregister(p_lm70->hwmon_dev);
 out_dev_reg_failed:
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        kfree(p_lm70);
        return status;
 }
 
 static int __devexit lm70_remove(struct spi_device *spi)
 {
-       struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
+       struct lm70 *p_lm70 = spi_get_drvdata(spi);
 
        device_remove_file(&spi->dev, &dev_attr_temp1_input);
        device_remove_file(&spi->dev, &dev_attr_name);
        hwmon_device_unregister(p_lm70->hwmon_dev);
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        kfree(p_lm70);
 
        return 0;
index 9a11532ecae84384d105e1f2c0b070a5107c0c3c..ece3aafa54b3f42a23518d958ca515b29b13d25f 100644 (file)
 #include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 
-/*
- * Addresses to scan. There are four disjoint possibilities, by pin config.
- */
-
-static const unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b,
-                                               I2C_CLIENT_END};
-
 /*
  * Insmod parameters
  */
@@ -114,8 +107,6 @@ module_param(clock, int, S_IRUGO);
 
 static int max6650_probe(struct i2c_client *client,
                         const struct i2c_device_id *id);
-static int max6650_detect(struct i2c_client *client,
-                         struct i2c_board_info *info);
 static int max6650_init_client(struct i2c_client *client);
 static int max6650_remove(struct i2c_client *client);
 static struct max6650_data *max6650_update_device(struct device *dev);
@@ -125,21 +116,19 @@ static struct max6650_data *max6650_update_device(struct device *dev);
  */
 
 static const struct i2c_device_id max6650_id[] = {
-       { "max6650", 0 },
+       { "max6650", 1 },
+       { "max6651", 4 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, max6650_id);
 
 static struct i2c_driver max6650_driver = {
-       .class          = I2C_CLASS_HWMON,
        .driver = {
                .name   = "max6650",
        },
        .probe          = max6650_probe,
        .remove         = max6650_remove,
        .id_table       = max6650_id,
-       .detect         = max6650_detect,
-       .address_list   = normal_i2c,
 };
 
 /*
@@ -150,6 +139,7 @@ struct max6650_data
 {
        struct device *hwmon_dev;
        struct mutex update_lock;
+       int nr_fans;
        char valid; /* zero until following fields are valid */
        unsigned long last_updated; /* in jiffies */
 
@@ -501,9 +491,6 @@ static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
 
 static struct attribute *max6650_attrs[] = {
        &sensor_dev_attr_fan1_input.dev_attr.attr,
-       &sensor_dev_attr_fan2_input.dev_attr.attr,
-       &sensor_dev_attr_fan3_input.dev_attr.attr,
-       &sensor_dev_attr_fan4_input.dev_attr.attr,
        &dev_attr_fan1_target.attr,
        &dev_attr_fan1_div.attr,
        &dev_attr_pwm1_enable.attr,
@@ -521,42 +508,21 @@ static struct attribute_group max6650_attr_grp = {
        .is_visible = max6650_attrs_visible,
 };
 
+static struct attribute *max6651_attrs[] = {
+       &sensor_dev_attr_fan2_input.dev_attr.attr,
+       &sensor_dev_attr_fan3_input.dev_attr.attr,
+       &sensor_dev_attr_fan4_input.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group max6651_attr_grp = {
+       .attrs = max6651_attrs,
+};
+
 /*
  * Real code
  */
 
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int max6650_detect(struct i2c_client *client,
-                         struct i2c_board_info *info)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       int address = client->addr;
-
-       dev_dbg(&adapter->dev, "max6650_detect called\n");
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "
-                                       "byte read mode, skipping.\n");
-               return -ENODEV;
-       }
-
-       if (((i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0)
-           ||(i2c_smbus_read_byte_data(client, MAX6650_REG_GPIO_STAT) & 0xE0)
-           ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN) & 0xE0)
-           ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM) & 0xE0)
-           ||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) {
-               dev_dbg(&adapter->dev,
-                       "max6650: detection failed at 0x%02x.\n", address);
-               return -ENODEV;
-       }
-
-       dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address);
-
-       strlcpy(info->type, "max6650", I2C_NAME_SIZE);
-
-       return 0;
-}
-
 static int max6650_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
@@ -570,6 +536,7 @@ static int max6650_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
+       data->nr_fans = id->driver_data;
 
        /*
         * Initialize the max6650 chip
@@ -581,6 +548,12 @@ static int max6650_probe(struct i2c_client *client,
        err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
        if (err)
                goto err_free;
+       /* 3 additional fan inputs for the MAX6651 */
+       if (data->nr_fans == 4) {
+               err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp);
+               if (err)
+                       goto err_remove;
+       }
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (!IS_ERR(data->hwmon_dev))
@@ -588,6 +561,9 @@ static int max6650_probe(struct i2c_client *client,
 
        err = PTR_ERR(data->hwmon_dev);
        dev_err(&client->dev, "error registering hwmon device.\n");
+       if (data->nr_fans == 4)
+               sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
+err_remove:
        sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
 err_free:
        kfree(data);
@@ -598,8 +574,10 @@ static int max6650_remove(struct i2c_client *client)
 {
        struct max6650_data *data = i2c_get_clientdata(client);
 
-       sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
        hwmon_device_unregister(data->hwmon_dev);
+       if (data->nr_fans == 4)
+               sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
+       sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
        kfree(data);
        return 0;
 }
@@ -712,7 +690,7 @@ static struct max6650_data *max6650_update_device(struct device *dev)
                                                       MAX6650_REG_SPEED);
                data->config = i2c_smbus_read_byte_data(client,
                                                        MAX6650_REG_CONFIG);
-               for (i = 0; i < 4; i++) {
+               for (i = 0; i < data->nr_fans; i++) {
                        data->tach[i] = i2c_smbus_read_byte_data(client,
                                                                 tach_reg[i]);
                }
index 9a51dcca9b0db6410779c1bccb26b13d584b6676..020c87273ea11d6c60383889a8a9cccae7dfdf02 100644 (file)
@@ -52,6 +52,9 @@
 #define SCH5627_COMPANY_ID             0x5c
 #define SCH5627_PRIMARY_ID             0xa0
 
+#define SCH5627_CMD_READ               0x02
+#define SCH5627_CMD_WRITE              0x03
+
 #define SCH5627_REG_BUILD_CODE         0x39
 #define SCH5627_REG_BUILD_ID           0x3a
 #define SCH5627_REG_HWMON_ID           0x3c
@@ -94,11 +97,13 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
 struct sch5627_data {
        unsigned short addr;
        struct device *hwmon_dev;
+       u8 control;
        u8 temp_max[SCH5627_NO_TEMPS];
        u8 temp_crit[SCH5627_NO_TEMPS];
        u16 fan_min[SCH5627_NO_FANS];
 
        struct mutex update_lock;
+       unsigned long last_battery;     /* In jiffies */
        char valid;                     /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
        u16 temp[SCH5627_NO_TEMPS];
@@ -140,7 +145,7 @@ static inline void superio_exit(int base)
        release_region(base, 2);
 }
 
-static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
+static int sch5627_send_cmd(struct sch5627_data *data, u8 cmd, u16 reg, u8 v)
 {
        u8 val;
        int i;
@@ -163,10 +168,14 @@ static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
        outb(0x80, data->addr + 3);
 
        /* Write Request Packet Header */
-       outb(0x02, data->addr + 4); /* Access Type: VREG read */
+       outb(cmd, data->addr + 4); /* VREG Access Type read:0x02 write:0x03 */
        outb(0x01, data->addr + 5); /* # of Entries: 1 Byte (8-bit) */
        outb(0x04, data->addr + 2); /* Mailbox AP to first data entry loc. */
 
+       /* Write Value field */
+       if (cmd == SCH5627_CMD_WRITE)
+               outb(v, data->addr + 4);
+
        /* Write Address field */
        outb(reg & 0xff, data->addr + 6);
        outb(reg >> 8, data->addr + 7);
@@ -224,8 +233,22 @@ static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
         * But if we do that things don't work, so let's not.
         */
 
-       /* Read Data from Mailbox */
-       return inb(data->addr + 4);
+       /* Read Value field */
+       if (cmd == SCH5627_CMD_READ)
+               return inb(data->addr + 4);
+
+       return 0;
+}
+
+static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
+{
+       return sch5627_send_cmd(data, SCH5627_CMD_READ, reg, 0);
+}
+
+static int sch5627_write_virtual_reg(struct sch5627_data *data,
+                                    u16 reg, u8 val)
+{
+       return sch5627_send_cmd(data, SCH5627_CMD_WRITE, reg, val);
 }
 
 static int sch5627_read_virtual_reg16(struct sch5627_data *data, u16 reg)
@@ -272,6 +295,13 @@ static struct sch5627_data *sch5627_update_device(struct device *dev)
 
        mutex_lock(&data->update_lock);
 
+       /* Trigger a Vbat voltage measurement every 5 minutes */
+       if (time_after(jiffies, data->last_battery + 300 * HZ)) {
+               sch5627_write_virtual_reg(data, SCH5627_REG_CTRL,
+                                         data->control | 0x10);
+               data->last_battery = jiffies;
+       }
+
        /* Cache the values for 1 second */
        if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
                for (i = 0; i < SCH5627_NO_TEMPS; i++) {
@@ -696,11 +726,17 @@ static int __devinit sch5627_probe(struct platform_device *pdev)
                err = val;
                goto error;
        }
-       if (!(val & 0x01)) {
+       data->control = val;
+       if (!(data->control & 0x01)) {
                pr_err("hardware monitoring not enabled\n");
                err = -ENODEV;
                goto error;
        }
+       /* Trigger a Vbat voltage measurement, so that we get a valid reading
+          the first time we read Vbat */
+       sch5627_write_virtual_reg(data, SCH5627_REG_CTRL,
+                                 data->control | 0x10);
+       data->last_battery = jiffies;
 
        /*
         * Read limits, we do this only once as reading a register on
index 1f36c635d93341727c26976daedcd0c953e5b6ad..27a62711e0a6170c4d32fa1c608660af761b9a48 100644 (file)
@@ -258,7 +258,7 @@ static int __devinit env_probe(struct platform_device *op)
                goto out_sysfs_remove_group;
        }
 
-       dev_set_drvdata(&op->dev, p);
+       platform_set_drvdata(op, p);
        err = 0;
 
 out:
@@ -277,7 +277,7 @@ out_free:
 
 static int __devexit env_remove(struct platform_device *op)
 {
-       struct env *p = dev_get_drvdata(&op->dev);
+       struct env *p = platform_get_drvdata(op);
 
        if (p) {
                sysfs_remove_group(&op->dev.kobj, &env_group);
index a5ec5a7cb381bbffac45a13c9e2cdccfd0a7d8b0..6e5123b1d341746341d9c3feda2ad445606c327c 100644 (file)
@@ -1781,7 +1781,8 @@ static int ide_cd_probe(ide_drive_t *drive)
 
        ide_cd_read_toc(drive, &sense);
        g->fops = &idecd_ops;
-       g->flags |= GENHD_FL_REMOVABLE;
+       g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+       g->events = DISK_EVENT_MEDIA_CHANGE;
        add_disk(g);
        return 0;
 
index 4d8ea32e8a001847746a796c43cf79dc70ae3c3c..22be27b424def00dbd8cc0167439b508b2564b78 100644 (file)
@@ -19,7 +19,7 @@
 
 /* Note to the author of this code: did it ever occur to
    you why the ifdefs are needed? Think about it again. -AK */
-#ifdef CONFIG_X86_64
+#if defined(CONFIG_X86_64) || defined(CONFIG_TILE)
 #  define INPUT_COMPAT_TEST is_compat_task()
 #elif defined(CONFIG_S390)
 #  define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT)
index 54ae71a907f937c8fcf3d443bf79d4a43a5499bd..db25b6b2ae3911a808a8f2dfb968bc37a4fe6e65 100644 (file)
@@ -1072,6 +1072,12 @@ nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                return -ENODEV;
        }
 
+       if (pdev->subsystem_vendor == 0xb100 &&
+           pdev->subsystem_device == 0x0003 ) {
+               pr_notice("Netjet: Digium TDM400P not handled yet\n");
+               return -ENODEV;
+       }
+
        card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC);
        if (!card) {
                pr_info("No kmem for Netjet\n");
index 9bec8699b8a327e107ddeb4fcfadb01e588c54e7..1d027b475b22563c7d0c5eea64103b4e0b48d307 100644 (file)
@@ -14,6 +14,13 @@ config LEDS_CLASS
          This option enables the led sysfs class in /sys/class/leds.  You'll
          need this to do anything useful with LEDs.  If unsure, say N.
 
+config LEDS_GPIO_REGISTER
+       bool
+       help
+         This option provides the function gpio_led_register_device.
+         As this function is used by arch code it must not be compiled as a
+         module.
+
 if NEW_LEDS
 
 comment "LED drivers"
@@ -115,13 +122,6 @@ config LEDS_ALIX2
          This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
          You have to set leds-alix2.force=1 for boards with Award BIOS.
 
-config LEDS_H1940
-       tristate "LED Support for iPAQ H1940 device"
-       depends on LEDS_CLASS
-       depends on ARCH_H1940
-       help
-         This option enables support for the LEDs on the h1940.
-
 config LEDS_COBALT_QUBE
        tristate "LED Support for the Cobalt Qube series front LED"
        depends on LEDS_CLASS
@@ -162,6 +162,16 @@ config LEDS_PCA9532
          LED controller. It is generally only useful
          as a platform driver
 
+config LEDS_PCA9532_GPIO
+       bool "Enable GPIO support for PCA9532"
+       depends on LEDS_PCA9532
+       depends on GPIOLIB
+       help
+         Allow unused pins on PCA9532 to be used as gpio.
+
+         To use a pin as gpio pca9532_type in pca9532_platform data needs to
+         set to PCA9532_TYPE_GPIO.
+
 config LEDS_GPIO
        tristate "LED Support for GPIO connected LEDs"
        depends on LEDS_CLASS
index 39c80fca84d276e3327ec4a69a902a85ebc6ae44..bccb96c9bb45b467cbf14d0bf0c4e338796f8dce 100644 (file)
@@ -17,11 +17,11 @@ obj-$(CONFIG_LEDS_NET48XX)          += leds-net48xx.o
 obj-$(CONFIG_LEDS_NET5501)             += leds-net5501.o
 obj-$(CONFIG_LEDS_WRAP)                        += leds-wrap.o
 obj-$(CONFIG_LEDS_ALIX2)               += leds-alix2.o
-obj-$(CONFIG_LEDS_H1940)               += leds-h1940.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)         += leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)          += leds-cobalt-raq.o
 obj-$(CONFIG_LEDS_SUNFIRE)             += leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
+obj-$(CONFIG_LEDS_GPIO_REGISTER)       += leds-gpio-register.o
 obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
 obj-$(CONFIG_LEDS_LP3944)              += leds-lp3944.o
 obj-$(CONFIG_LEDS_LP5521)              += leds-lp5521.o
index d5a4ade88991eb690e053a6a4218de0512ad9387..dc3d3d83191a043de95e7e7b41a5aa47cf57100c 100644 (file)
@@ -131,7 +131,8 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
        if (!led_cdev->blink_brightness)
                led_cdev->blink_brightness = led_cdev->max_brightness;
 
-       if (delay_on == led_cdev->blink_delay_on &&
+       if (led_get_trigger_data(led_cdev) &&
+           delay_on == led_cdev->blink_delay_on &&
            delay_off == led_cdev->blink_delay_off)
                return;
 
diff --git a/drivers/leds/leds-gpio-register.c b/drivers/leds/leds-gpio-register.c
new file mode 100644 (file)
index 0000000..1c4ed55
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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.
+ */
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+
+/**
+ * gpio_led_register_device - register a gpio-led device
+ * @pdata: the platform data used for the new device
+ *
+ * Makes a copy of pdata and pdata->leds and registers a new leds-gpio device
+ * with the result. This allows to have pdata and pdata-leds in .init.rodata
+ * and so saves some bytes compared to a static struct platform_device with
+ * static platform data.
+ *
+ * Returns the registered device or an error pointer.
+ */
+struct platform_device *__init gpio_led_register_device(
+               int id, const struct gpio_led_platform_data *pdata)
+{
+       struct platform_device *ret;
+       struct gpio_led_platform_data _pdata = *pdata;
+
+       _pdata.leds = kmemdup(pdata->leds,
+                       pdata->num_leds * sizeof(*pdata->leds), GFP_KERNEL);
+       if (!_pdata.leds)
+               return ERR_PTR(-ENOMEM);
+
+       ret = platform_device_register_resndata(NULL, "leds-gpio", id,
+                       NULL, 0, &_pdata, sizeof(_pdata));
+       if (IS_ERR(ret))
+               kfree(_pdata.leds);
+
+       return ret;
+}
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
deleted file mode 100644 (file)
index 173d104..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * drivers/leds/leds-h1940.c
- * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
- *
- * 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.
- *
- * H1940 leds driver
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/leds.h>
-#include <linux/gpio.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/hardware.h>
-#include <mach/h1940-latch.h>
-
-/*
- * Green led.
- */
-static void h1940_greenled_set(struct led_classdev *led_dev,
-                              enum led_brightness value)
-{
-       switch (value) {
-       case LED_HALF:
-               h1940_latch_control(0, H1940_LATCH_LED_FLASH);
-               s3c2410_gpio_setpin(S3C2410_GPA7, 1);
-               break;
-       case LED_FULL:
-               h1940_latch_control(0, H1940_LATCH_LED_GREEN);
-               s3c2410_gpio_setpin(S3C2410_GPA7, 1);
-               break;
-       default:
-       case LED_OFF:
-               h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
-               h1940_latch_control(H1940_LATCH_LED_GREEN, 0);
-               s3c2410_gpio_setpin(S3C2410_GPA7, 0);
-               break;
-       }
-}
-
-static struct led_classdev h1940_greenled = {
-       .name                   = "h1940:green",
-       .brightness_set         = h1940_greenled_set,
-       .default_trigger        = "h1940-charger",
-};
-
-/*
- * Red led.
- */
-static void h1940_redled_set(struct led_classdev *led_dev,
-                            enum led_brightness value)
-{
-       switch (value) {
-       case LED_HALF:
-               h1940_latch_control(0, H1940_LATCH_LED_FLASH);
-               s3c2410_gpio_setpin(S3C2410_GPA1, 1);
-               break;
-       case LED_FULL:
-               h1940_latch_control(0, H1940_LATCH_LED_RED);
-               s3c2410_gpio_setpin(S3C2410_GPA1, 1);
-               break;
-       default:
-       case LED_OFF:
-               h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
-               h1940_latch_control(H1940_LATCH_LED_RED, 0);
-               s3c2410_gpio_setpin(S3C2410_GPA1, 0);
-               break;
-       }
-}
-
-static struct led_classdev h1940_redled = {
-       .name                   = "h1940:red",
-       .brightness_set         = h1940_redled_set,
-       .default_trigger        = "h1940-charger",
-};
-
-/*
- * Blue led.
- * (it can only be blue flashing led)
- */
-static void h1940_blueled_set(struct led_classdev *led_dev,
-                             enum led_brightness value)
-{
-       if (value) {
-               /* flashing Blue */
-               h1940_latch_control(0, H1940_LATCH_LED_FLASH);
-               s3c2410_gpio_setpin(S3C2410_GPA3, 1);
-       } else {
-               h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
-               s3c2410_gpio_setpin(S3C2410_GPA3, 0);
-       }
-
-}
-
-static struct led_classdev h1940_blueled = {
-       .name                   = "h1940:blue",
-       .brightness_set         = h1940_blueled_set,
-       .default_trigger        = "h1940-bluetooth",
-};
-
-static int __devinit h1940leds_probe(struct platform_device *pdev)
-{
-       int ret;
-
-       ret = led_classdev_register(&pdev->dev, &h1940_greenled);
-       if (ret)
-               goto err_green;
-
-       ret = led_classdev_register(&pdev->dev, &h1940_redled);
-       if (ret)
-               goto err_red;
-
-       ret = led_classdev_register(&pdev->dev, &h1940_blueled);
-       if (ret)
-               goto err_blue;
-
-       return 0;
-
-err_blue:
-       led_classdev_unregister(&h1940_redled);
-err_red:
-       led_classdev_unregister(&h1940_greenled);
-err_green:
-       return ret;
-}
-
-static int h1940leds_remove(struct platform_device *pdev)
-{
-       led_classdev_unregister(&h1940_greenled);
-       led_classdev_unregister(&h1940_redled);
-       led_classdev_unregister(&h1940_blueled);
-       return 0;
-}
-
-
-static struct platform_driver h1940leds_driver = {
-       .driver         = {
-               .name   = "h1940-leds",
-               .owner  = THIS_MODULE,
-       },
-       .probe          = h1940leds_probe,
-       .remove         = h1940leds_remove,
-};
-
-
-static int __init h1940leds_init(void)
-{
-       return platform_driver_register(&h1940leds_driver);
-}
-
-static void __exit h1940leds_exit(void)
-{
-       platform_driver_unregister(&h1940leds_driver);
-}
-
-module_init(h1940leds_init);
-module_exit(h1940leds_exit);
-
-MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
-MODULE_DESCRIPTION("LED driver for the iPAQ H1940");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:h1940-leds");
index b37e6186d0fa007e2edc23f8186643b803429b2b..4d7ce7631acf93eca1d0e3eaf88d8bfac7414c79 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/input.h>
 #include <linux/led-lm3530.h>
 #include <linux/types.h>
+#include <linux/regulator/consumer.h>
 
 #define LM3530_LED_DEV "lcd-backlight"
 #define LM3530_NAME "lm3530-led"
@@ -96,12 +97,18 @@ static struct lm3530_mode_map mode_map[] = {
  * @client: i2c client
  * @pdata: LM3530 platform data
  * @mode: mode of operation - manual, ALS, PWM
+ * @regulator: regulator
+ * @brighness: previous brightness value
+ * @enable: regulator is enabled
  */
 struct lm3530_data {
        struct led_classdev led_dev;
        struct i2c_client *client;
        struct lm3530_platform_data *pdata;
        enum lm3530_mode mode;
+       struct regulator *regulator;
+       enum led_brightness brightness;
+       bool enable;
 };
 
 static const u8 lm3530_reg[LM3530_REG_MAX] = {
@@ -172,7 +179,10 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
        brt_ramp = (pltfm->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
                        (pltfm->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
 
-       brightness = pltfm->brt_val;
+       if (drvdata->brightness)
+               brightness = drvdata->brightness;
+       else
+               brightness = drvdata->brightness = pltfm->brt_val;
 
        reg_val[0] = gen_config;        /* LM3530_GEN_CONFIG */
        reg_val[1] = als_config;        /* LM3530_ALS_CONFIG */
@@ -190,6 +200,16 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
        reg_val[13] = LM3530_DEF_ZT_3;  /* LM3530_ALS_Z3T_REG */
        reg_val[14] = LM3530_DEF_ZT_4;  /* LM3530_ALS_Z4T_REG */
 
+       if (!drvdata->enable) {
+               ret = regulator_enable(drvdata->regulator);
+               if (ret) {
+                       dev_err(&drvdata->client->dev,
+                                       "Enable regulator failed\n");
+                       return ret;
+               }
+               drvdata->enable = true;
+       }
+
        for (i = 0; i < LM3530_REG_MAX; i++) {
                ret = i2c_smbus_write_byte_data(client,
                                lm3530_reg[i], reg_val[i]);
@@ -210,12 +230,31 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
        switch (drvdata->mode) {
        case LM3530_BL_MODE_MANUAL:
 
+               if (!drvdata->enable) {
+                       err = lm3530_init_registers(drvdata);
+                       if (err) {
+                               dev_err(&drvdata->client->dev,
+                                       "Register Init failed: %d\n", err);
+                               break;
+                       }
+               }
+
                /* set the brightness in brightness control register*/
                err = i2c_smbus_write_byte_data(drvdata->client,
                                LM3530_BRT_CTRL_REG, brt_val / 2);
                if (err)
                        dev_err(&drvdata->client->dev,
                                "Unable to set brightness: %d\n", err);
+               else
+                       drvdata->brightness = brt_val / 2;
+
+               if (brt_val == 0) {
+                       err = regulator_disable(drvdata->regulator);
+                       if (err)
+                               dev_err(&drvdata->client->dev,
+                                       "Disable regulator failed\n");
+                       drvdata->enable = false;
+               }
                break;
        case LM3530_BL_MODE_ALS:
                break;
@@ -297,20 +336,31 @@ static int __devinit lm3530_probe(struct i2c_client *client,
        drvdata->mode = pdata->mode;
        drvdata->client = client;
        drvdata->pdata = pdata;
+       drvdata->brightness = LED_OFF;
+       drvdata->enable = false;
        drvdata->led_dev.name = LM3530_LED_DEV;
        drvdata->led_dev.brightness_set = lm3530_brightness_set;
 
        i2c_set_clientdata(client, drvdata);
 
-       err = lm3530_init_registers(drvdata);
-       if (err < 0) {
-               dev_err(&client->dev, "Register Init failed: %d\n", err);
-               err = -ENODEV;
-               goto err_reg_init;
+       drvdata->regulator = regulator_get(&client->dev, "vin");
+       if (IS_ERR(drvdata->regulator)) {
+               dev_err(&client->dev, "regulator get failed\n");
+               err = PTR_ERR(drvdata->regulator);
+               drvdata->regulator = NULL;
+               goto err_regulator_get;
        }
 
-       err = led_classdev_register((struct device *)
-                                     &client->dev, &drvdata->led_dev);
+       if (drvdata->pdata->brt_val) {
+               err = lm3530_init_registers(drvdata);
+               if (err < 0) {
+                       dev_err(&client->dev,
+                               "Register Init failed: %d\n", err);
+                       err = -ENODEV;
+                       goto err_reg_init;
+               }
+       }
+       err = led_classdev_register(&client->dev, &drvdata->led_dev);
        if (err < 0) {
                dev_err(&client->dev, "Register led class failed: %d\n", err);
                err = -ENODEV;
@@ -330,6 +380,9 @@ err_create_file:
        led_classdev_unregister(&drvdata->led_dev);
 err_class_register:
 err_reg_init:
+       regulator_put(drvdata->regulator);
+err_regulator_get:
+       i2c_set_clientdata(client, NULL);
        kfree(drvdata);
 err_out:
        return err;
@@ -340,6 +393,10 @@ static int __devexit lm3530_remove(struct i2c_client *client)
        struct lm3530_data *drvdata = i2c_get_clientdata(client);
 
        device_remove_file(drvdata->led_dev.dev, &dev_attr_mode);
+
+       if (drvdata->enable)
+               regulator_disable(drvdata->regulator);
+       regulator_put(drvdata->regulator);
        led_classdev_unregister(&drvdata->led_dev);
        kfree(drvdata);
        return 0;
index 5bf63af09ddf04adb63dac74bfa97b8882e0c754..d8d3a1e910a1bbb7f81e9c1d7c4cb58452415691 100644 (file)
@@ -1,13 +1,14 @@
 /*
  * pca9532.c - 16-bit Led dimmer
  *
+ * Copyright (C) 2011 Jan Weitzel
  * Copyright (C) 2008 Riku Voipio
  *
  * This program is free software; 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.
  *
- * Datasheet: http://www.nxp.com/acrobat/datasheets/PCA9532_3.pdf
+ * Datasheet: http://www.nxp.com/documents/data_sheet/PCA9532.pdf
  *
  */
 
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
 #include <linux/leds-pca9532.h>
+#include <linux/gpio.h>
 
-#define PCA9532_REG_PSC(i) (0x2+(i)*2)
-#define PCA9532_REG_PWM(i) (0x3+(i)*2)
-#define PCA9532_REG_LS0  0x6
-#define LED_REG(led) ((led>>2)+PCA9532_REG_LS0)
-#define LED_NUM(led) (led & 0x3)
+/* m =  num_leds*/
+#define PCA9532_REG_INPUT(i)   ((i) >> 3)
+#define PCA9532_REG_OFFSET(m)  ((m) >> 4)
+#define PCA9532_REG_PSC(m, i)  (PCA9532_REG_OFFSET(m) + 0x1 + (i) * 2)
+#define PCA9532_REG_PWM(m, i)  (PCA9532_REG_OFFSET(m) + 0x2 + (i) * 2)
+#define LED_REG(m, led)                (PCA9532_REG_OFFSET(m) + 0x5 + (led >> 2))
+#define LED_NUM(led)           (led & 0x3)
 
 #define ldev_to_led(c)       container_of(c, struct pca9532_led, ldev)
 
+struct pca9532_chip_info {
+       u8      num_leds;
+};
+
 struct pca9532_data {
        struct i2c_client *client;
        struct pca9532_led leds[16];
        struct mutex update_lock;
        struct input_dev *idev;
        struct work_struct work;
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+       struct gpio_chip gpio;
+#endif
+       const struct pca9532_chip_info *chip_info;
        u8 pwm[2];
        u8 psc[2];
 };
@@ -42,16 +54,41 @@ static int pca9532_probe(struct i2c_client *client,
        const struct i2c_device_id *id);
 static int pca9532_remove(struct i2c_client *client);
 
+enum {
+       pca9530,
+       pca9531,
+       pca9532,
+       pca9533,
+};
+
 static const struct i2c_device_id pca9532_id[] = {
-       { "pca9532", 0 },
+       { "pca9530", pca9530 },
+       { "pca9531", pca9531 },
+       { "pca9532", pca9532 },
+       { "pca9533", pca9533 },
        { }
 };
 
 MODULE_DEVICE_TABLE(i2c, pca9532_id);
 
+static const struct pca9532_chip_info pca9532_chip_info_tbl[] = {
+       [pca9530] = {
+               .num_leds = 2,
+       },
+       [pca9531] = {
+               .num_leds = 8,
+       },
+       [pca9532] = {
+               .num_leds = 16,
+       },
+       [pca9533] = {
+               .num_leds = 4,
+       },
+};
+
 static struct i2c_driver pca9532_driver = {
        .driver = {
-               .name = "pca9532",
+               .name = "pca953x",
        },
        .probe = pca9532_probe,
        .remove = pca9532_remove,
@@ -68,7 +105,7 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
 {
        int a = 0, b = 0, i = 0;
        struct pca9532_data *data = i2c_get_clientdata(client);
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < data->chip_info->num_leds; i++) {
                if (data->leds[i].type == PCA9532_TYPE_LED &&
                        data->leds[i].state == PCA9532_PWM0+pwm) {
                                a++;
@@ -92,10 +129,12 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
 static int pca9532_setpwm(struct i2c_client *client, int pwm)
 {
        struct pca9532_data *data = i2c_get_clientdata(client);
+       u8 maxleds = data->chip_info->num_leds;
+
        mutex_lock(&data->update_lock);
-       i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
+       i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(maxleds, pwm),
                data->pwm[pwm]);
-       i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
+       i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(maxleds, pwm),
                data->psc[pwm]);
        mutex_unlock(&data->update_lock);
        return 0;
@@ -106,15 +145,16 @@ static void pca9532_setled(struct pca9532_led *led)
 {
        struct i2c_client *client = led->client;
        struct pca9532_data *data = i2c_get_clientdata(client);
+       u8 maxleds = data->chip_info->num_leds;
        char reg;
 
        mutex_lock(&data->update_lock);
-       reg = i2c_smbus_read_byte_data(client, LED_REG(led->id));
+       reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id));
        /* zero led bits */
        reg = reg & ~(0x3<<LED_NUM(led->id)*2);
        /* set the new value */
        reg = reg | (led->state << LED_NUM(led->id)*2);
-       i2c_smbus_write_byte_data(client, LED_REG(led->id), reg);
+       i2c_smbus_write_byte_data(client, LED_REG(maxleds, led->id), reg);
        mutex_unlock(&data->update_lock);
 }
 
@@ -183,10 +223,12 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
 
 static void pca9532_input_work(struct work_struct *work)
 {
-       struct pca9532_data *data;
-       data = container_of(work, struct pca9532_data, work);
+       struct pca9532_data *data =
+               container_of(work, struct pca9532_data, work);
+       u8 maxleds = data->chip_info->num_leds;
+
        mutex_lock(&data->update_lock);
-       i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
+       i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(maxleds, 1),
                data->pwm[1]);
        mutex_unlock(&data->update_lock);
 }
@@ -200,16 +242,68 @@ static void pca9532_led_work(struct work_struct *work)
        pca9532_setled(led);
 }
 
-static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
+{
+       struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+       struct pca9532_led *led = &data->leds[offset];
+
+       if (led->type == PCA9532_TYPE_GPIO)
+               return 0;
+
+       return -EBUSY;
+}
+
+static void pca9532_gpio_set_value(struct gpio_chip *gc, unsigned offset, int val)
+{
+       struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+       struct pca9532_led *led = &data->leds[offset];
+
+       if (val)
+               led->state = PCA9532_ON;
+       else
+               led->state = PCA9532_OFF;
+
+       pca9532_setled(led);
+}
+
+static int pca9532_gpio_get_value(struct gpio_chip *gc, unsigned offset)
+{
+       struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+       unsigned char reg;
+
+       reg = i2c_smbus_read_byte_data(data->client, PCA9532_REG_INPUT(offset));
+
+       return !!(reg & (1 << (offset % 8)));
+}
+
+static int pca9532_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+       /* To use as input ensure pin is not driven */
+       pca9532_gpio_set_value(gc, offset, 0);
+
+       return 0;
+}
+
+static int pca9532_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int val)
+{
+       pca9532_gpio_set_value(gc, offset, val);
+
+       return 0;
+}
+#endif /* CONFIG_LEDS_PCA9532_GPIO */
+
+static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
 {
        int i = n_devs;
 
        if (!data)
-               return;
+               return -EINVAL;
 
        while (--i >= 0) {
                switch (data->leds[i].type) {
                case PCA9532_TYPE_NONE:
+               case PCA9532_TYPE_GPIO:
                        break;
                case PCA9532_TYPE_LED:
                        led_classdev_unregister(&data->leds[i].ldev);
@@ -224,23 +318,38 @@ static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
                        break;
                }
        }
+
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+       if (data->gpio.dev) {
+               int err = gpiochip_remove(&data->gpio);
+               if (err) {
+                       dev_err(&data->client->dev, "%s failed, %d\n",
+                                               "gpiochip_remove()", err);
+                       return err;
+               }
+       }
+#endif
+
+       return 0;
 }
 
 static int pca9532_configure(struct i2c_client *client,
        struct pca9532_data *data, struct pca9532_platform_data *pdata)
 {
        int i, err = 0;
+       int gpios = 0;
+       u8 maxleds = data->chip_info->num_leds;
 
        for (i = 0; i < 2; i++) {
                data->pwm[i] = pdata->pwm[i];
                data->psc[i] = pdata->psc[i];
-               i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(i),
+               i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(maxleds, i),
                        data->pwm[i]);
-               i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(i),
+               i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(maxleds, i),
                        data->psc[i]);
        }
 
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < data->chip_info->num_leds; i++) {
                struct pca9532_led *led = &data->leds[i];
                struct pca9532_led *pled = &pdata->leds[i];
                led->client = client;
@@ -249,6 +358,9 @@ static int pca9532_configure(struct i2c_client *client,
                switch (led->type) {
                case PCA9532_TYPE_NONE:
                        break;
+               case PCA9532_TYPE_GPIO:
+                       gpios++;
+                       break;
                case PCA9532_TYPE_LED:
                        led->state = pled->state;
                        led->name = pled->name;
@@ -297,6 +409,34 @@ static int pca9532_configure(struct i2c_client *client,
                        break;
                }
        }
+
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+       if (gpios) {
+               data->gpio.label = "gpio-pca9532";
+               data->gpio.direction_input = pca9532_gpio_direction_input;
+               data->gpio.direction_output = pca9532_gpio_direction_output;
+               data->gpio.set = pca9532_gpio_set_value;
+               data->gpio.get = pca9532_gpio_get_value;
+               data->gpio.request = pca9532_gpio_request_pin;
+               data->gpio.can_sleep = 1;
+               data->gpio.base = pdata->gpio_base;
+               data->gpio.ngpio = data->chip_info->num_leds;
+               data->gpio.dev = &client->dev;
+               data->gpio.owner = THIS_MODULE;
+
+               err = gpiochip_add(&data->gpio);
+               if (err) {
+                       /* Use data->gpio.dev as a flag for freeing gpiochip */
+                       data->gpio.dev = NULL;
+                       dev_warn(&client->dev, "could not add gpiochip\n");
+               } else {
+                       dev_info(&client->dev, "gpios %i...%i\n",
+                               data->gpio.base, data->gpio.base +
+                               data->gpio.ngpio - 1);
+               }
+       }
+#endif
+
        return 0;
 
 exit:
@@ -322,6 +462,8 @@ static int pca9532_probe(struct i2c_client *client,
        if (!data)
                return -ENOMEM;
 
+       data->chip_info = &pca9532_chip_info_tbl[id->driver_data];
+
        dev_info(&client->dev, "setting platform data\n");
        i2c_set_clientdata(client, data);
        data->client = client;
@@ -337,7 +479,12 @@ static int pca9532_probe(struct i2c_client *client,
 static int pca9532_remove(struct i2c_client *client)
 {
        struct pca9532_data *data = i2c_get_clientdata(client);
-       pca9532_destroy_devices(data, 16);
+       int err;
+
+       err = pca9532_destroy_devices(data, data->chip_info->num_leds);
+       if (err)
+               return err;
+
        kfree(data);
        return 0;
 }
index 2dd8ecbfdc3155250d3608897db8d1d0047fc317..e77c7f8dcdd469bfa8b84472dabb81e2df1b10e7 100644 (file)
@@ -40,10 +40,17 @@ void led_trigger_set_default(struct led_classdev *led_cdev);
 void led_trigger_set(struct led_classdev *led_cdev,
                        struct led_trigger *trigger);
 void led_trigger_remove(struct led_classdev *led_cdev);
+
+static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
+{
+       return led_cdev->trigger_data;
+}
+
 #else
 #define led_trigger_set_default(x) do {} while (0)
 #define led_trigger_set(x, y) do {} while (0)
 #define led_trigger_remove(x) do {} while (0)
+#define led_get_trigger_data(x) (NULL)
 #endif
 
 ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
index b09bcbeade9c433c56365204b4848690bf08a366..d87c9d02f786df2570385faea517e54e883c5b30 100644 (file)
@@ -91,6 +91,9 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
        if (rc)
                goto err_out_delayon;
 
+       led_blink_set(led_cdev, &led_cdev->blink_delay_on,
+                     &led_cdev->blink_delay_off);
+
        led_cdev->trigger_data = (void *)1;
 
        return;
index d4fe7bc92a1d82525f77a43f31e4d9ef856bdbde..4ada9be1d430d0f50f9f63e866b5ca82e835226a 100644 (file)
@@ -47,7 +47,7 @@
 #include <plat/dma.h>
 #include <plat/vram.h>
 #include <plat/vrfb.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "omap_voutlib.h"
 #include "omap_voutdef.h"
index ea3a047f8bca6bd32a6cb0b78b68b9c678ee717d..659497b849965e9c017ec5a0846291bb513337ca 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef OMAP_VOUTDEF_H
 #define OMAP_VOUTDEF_H
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define YUYV_BPP        2
 #define RGB565_BPP      2
index 3ed3ff06be5d7e93d8e276ab78623a81610b30fa..481770ab271618cda7507576358ad21708bfcb02 100644 (file)
@@ -538,7 +538,7 @@ config AB8500_CORE
 
 config AB8500_I2C_CORE
        bool "AB8500 register access via PRCMU I2C"
-       depends on AB8500_CORE && UX500_SOC_DB8500
+       depends on AB8500_CORE && MFD_DB8500_PRCMU
        default y
        help
          This enables register access to the AB8500 chip via PRCMU I2C.
@@ -575,6 +575,26 @@ config AB3550_CORE
          LEDs, vibrator, system power and temperature, power management
          and ALSA sound.
 
+config MFD_DB8500_PRCMU
+       bool "ST-Ericsson DB8500 Power Reset Control Management Unit"
+       depends on UX500_SOC_DB8500
+       select MFD_CORE
+       help
+         Select this option to enable support for the DB8500 Power Reset
+         and Control Management Unit. This is basically an autonomous
+         system controller running an XP70 microprocessor, which is accessed
+         through a register map.
+
+config MFD_DB5500_PRCMU
+       bool "ST-Ericsson DB5500 Power Reset Control Management Unit"
+       depends on UX500_SOC_DB5500
+       select MFD_CORE
+       help
+         Select this option to enable support for the DB5500 Power Reset
+         and Control Management Unit. This is basically an autonomous
+         system controller running an XP70 microprocessor, which is accessed
+         through a register map.
+
 config MFD_CS5535
        tristate "Support for CS5535 and CS5536 southbridge core functions"
        select MFD_CORE
index 419caa9d7dcfe395282ef85c8b50bf2238ce0308..24aa44448daf5043f926512023d9cb06ff3a5648 100644 (file)
@@ -74,9 +74,12 @@ obj-$(CONFIG_AB3100_CORE)    += ab3100-core.o
 obj-$(CONFIG_AB3100_OTP)       += ab3100-otp.o
 obj-$(CONFIG_AB3550_CORE)      += ab3550-core.o
 obj-$(CONFIG_AB8500_CORE)      += ab8500-core.o ab8500-sysctrl.o
-obj-$(CONFIG_AB8500_I2C_CORE)  += ab8500-i2c.o
 obj-$(CONFIG_AB8500_DEBUG)     += ab8500-debugfs.o
 obj-$(CONFIG_AB8500_GPADC)     += ab8500-gpadc.o
+obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
+# ab8500-i2c need to come after db8500-prcmu (which provides the channel)
+obj-$(CONFIG_AB8500_I2C_CORE)  += ab8500-i2c.o
+obj-$(CONFIG_MFD_DB5500_PRCMU) += db5500-prcmu.o
 obj-$(CONFIG_MFD_TIMBERDALE)    += timberdale.o
 obj-$(CONFIG_PMIC_ADP5520)     += adp5520.o
 obj-$(CONFIG_LPC_SCH)          += lpc_sch.o
index 821e6b86afd2a82a73811f65176fca1b3e835110..9be541c6b004c8adc9cf6cde3416c6bff31c9e31 100644 (file)
@@ -11,8 +11,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/ab8500.h>
-
-#include <mach/prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
 
 static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
 {
similarity index 80%
rename from arch/arm/mach-ux500/include/mach/prcmu-regs.h
rename to drivers/mfd/db5500-prcmu-regs.h
index 455467e887915d628cd13ea416e47fc5d86ebdc6..9a8e9e4ddd3319c08388f5f98da83fca29208d03 100644 (file)
 
 #include <mach/hardware.h>
 
-#define _PRCMU_BASE            IO_ADDRESS(U8500_PRCMU_BASE)
-
 #define PRCM_ARM_PLLDIVPS      (_PRCMU_BASE + 0x118)
+#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE         0x3f
+#define PRCM_ARM_PLLDIVPS_MAX_MASK             0xf
+
+#define PRCM_PLLARM_LOCKP       (_PRCMU_BASE + 0x0a8)
+#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3   0x2
+
 #define PRCM_ARM_CHGCLKREQ     (_PRCMU_BASE + 0x114)
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ  0x1
+
 #define PRCM_PLLARM_ENABLE     (_PRCMU_BASE + 0x98)
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE  0x1
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON 0x100
+
 #define PRCM_ARMCLKFIX_MGT     (_PRCMU_BASE + 0x0)
 #define PRCM_A9_RESETN_CLR     (_PRCMU_BASE + 0x1f4)
 #define PRCM_A9_RESETN_SET     (_PRCMU_BASE + 0x1f0)
@@ -28,7 +37,8 @@
 
 /* ARM WFI Standby signal register */
 #define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
-#define PRCMU_IOCR              (_PRCMU_BASE + 0x310)
+#define PRCM_IOCR              (_PRCMU_BASE + 0x310)
+#define PRCM_IOCR_IOFORCE                      0x1
 
 /* CPU mailbox registers */
 #define PRCM_MBOX_CPU_VAL      (_PRCMU_BASE + 0x0fc)
@@ -37,6 +47,8 @@
 
 /* Dual A9 core interrupt management unit registers */
 #define PRCM_A9_MASK_REQ       (_PRCMU_BASE + 0x328)
+#define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ      0x1
+
 #define PRCM_A9_MASK_ACK       (_PRCMU_BASE + 0x32c)
 #define PRCM_ARMITMSK31TO0     (_PRCMU_BASE + 0x11c)
 #define PRCM_ARMITMSK63TO32    (_PRCMU_BASE + 0x120)
 /* PRCMU clock/PLL/reset registers */
 #define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
 #define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
+#define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_LCDCLK_MGT            (_PRCMU_BASE + 0x044)
 #define PRCM_MCDECLK_MGT           (_PRCMU_BASE + 0x064)
 #define PRCM_HDMICLK_MGT           (_PRCMU_BASE + 0x058)
 #define PRCM_TVCLK_MGT             (_PRCMU_BASE + 0x07c)
 #define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
 #define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
+#define PRCM_PLLDSI_LOCKP          (_PRCMU_BASE + 0x508)
 #define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
 #define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
+#define PRCM_CLKOCR               (_PRCMU_BASE + 0x1CC)
 
 /* ePOD and memory power signal control registers */
 #define PRCM_EPOD_C_SET            (_PRCMU_BASE + 0x410)
 
 /* Miscellaneous unit registers */
 #define PRCM_DSI_SW_RESET          (_PRCMU_BASE + 0x324)
+#define PRCM_GPIOCR                (_PRCMU_BASE + 0x138)
+#define PRCM_GPIOCR_DBG_STM_MOD_CMD1            0x800
+#define PRCM_GPIOCR_DBG_UARTMOD_CMD0            0x1
+
 
-#endif /* __MACH_PRCMU_REGS_H */
+#endif /* __MACH_PRCMU__REGS_H */
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c
new file mode 100644 (file)
index 0000000..9dbb3ca
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U5500 PRCM Unit interface driver
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/db5500-prcmu.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/db5500-regs.h>
+#include "db5500-prcmu-regs.h"
+
+#define _PRCM_MB_HEADER (tcdm_base + 0xFE8)
+#define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0)
+#define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1)
+#define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2)
+#define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3)
+#define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4)
+#define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5)
+#define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6)
+#define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7)
+#define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8)
+#define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9)
+#define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa)
+#define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb)
+#define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc)
+#define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd)
+#define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe)
+#define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf)
+
+/* Req Mailboxes */
+#define PRCM_REQ_MB0 (tcdm_base + 0xFD8)
+#define PRCM_REQ_MB1 (tcdm_base + 0xFCC)
+#define PRCM_REQ_MB2 (tcdm_base + 0xFC4)
+#define PRCM_REQ_MB3 (tcdm_base + 0xFC0)
+#define PRCM_REQ_MB4 (tcdm_base + 0xF98)
+#define PRCM_REQ_MB5 (tcdm_base + 0xF90)
+#define PRCM_REQ_MB6 (tcdm_base + 0xF8C)
+#define PRCM_REQ_MB7 (tcdm_base + 0xF84)
+
+/* Ack Mailboxes */
+#define PRCM_ACK_MB0 (tcdm_base + 0xF38)
+#define PRCM_ACK_MB1 (tcdm_base + 0xF30)
+#define PRCM_ACK_MB2 (tcdm_base + 0xF24)
+#define PRCM_ACK_MB3 (tcdm_base + 0xF20)
+#define PRCM_ACK_MB4 (tcdm_base + 0xF1C)
+#define PRCM_ACK_MB5 (tcdm_base + 0xF14)
+#define PRCM_ACK_MB6 (tcdm_base + 0xF0C)
+#define PRCM_ACK_MB7 (tcdm_base + 0xF08)
+
+enum mb_return_code {
+       RC_SUCCESS,
+       RC_FAIL,
+};
+
+/* Mailbox 0 headers. */
+enum mb0_header {
+       /* request */
+       RMB0H_PWR_STATE_TRANS = 1,
+       RMB0H_WAKE_UP_CFG,
+       RMB0H_RD_WAKE_UP_ACK,
+       /* acknowledge */
+       AMB0H_WAKE_UP = 1,
+};
+
+/* Mailbox 5 headers. */
+enum mb5_header {
+       MB5H_I2C_WRITE = 1,
+       MB5H_I2C_READ,
+};
+
+/* Request mailbox 5 fields. */
+#define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0)
+#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1)
+#define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2)
+#define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4)
+
+/* Acknowledge mailbox 5 fields. */
+#define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0)
+#define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4)
+
+#define NUM_MB 8
+#define MBOX_BIT BIT
+#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
+
+/*
+* Used by MCDE to setup all necessary PRCMU registers
+*/
+#define PRCMU_RESET_DSIPLL                     0x00004000
+#define PRCMU_UNCLAMP_DSIPLL                   0x00400800
+
+/* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/
+#define PRCMU_DSI_CLOCK_SETTING                        0x00000128
+/* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */
+#define PRCMU_DSI_LP_CLOCK_SETTING             0x00000135
+#define PRCMU_PLLDSI_FREQ_SETTING              0x0004013C
+#define PRCMU_DSI_PLLOUT_SEL_SETTING           0x00000002
+#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV          0x03000101
+#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV         0x00000101
+
+#define PRCMU_ENABLE_PLLDSI                    0x00000001
+#define PRCMU_DISABLE_PLLDSI                   0x00000000
+
+#define PRCMU_DSI_RESET_SW                     0x00000003
+
+#define PRCMU_PLLDSI_LOCKP_LOCKED              0x3
+
+/*
+ * mb0_transfer - state needed for mailbox 0 communication.
+ * @lock:              The transaction lock.
+ */
+static struct {
+       spinlock_t lock;
+} mb0_transfer;
+
+/*
+ * mb5_transfer - state needed for mailbox 5 communication.
+ * @lock:      The transaction lock.
+ * @work:      The transaction completion structure.
+ * @ack:       Reply ("acknowledge") data.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+       struct {
+               u8 header;
+               u8 status;
+               u8 value[4];
+       } ack;
+} mb5_transfer;
+
+/* PRCMU TCDM base IO address. */
+static __iomem void *tcdm_base;
+
+/**
+ * db5500_prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The read out value(s).
+ * @size:      The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be <= 4.
+ */
+int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if ((size < 1) || (4 < size))
+               return -EINVAL;
+
+       mutex_lock(&mb5_transfer.lock);
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+       writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
+       writeb(reg, PRCM_REQ_MB5_I2C_REG);
+       writeb(size, PRCM_REQ_MB5_I2C_SIZE);
+       writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER);
+
+       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+       wait_for_completion(&mb5_transfer.work);
+
+       r = 0;
+       if ((mb5_transfer.ack.header == MB5H_I2C_READ) &&
+               (mb5_transfer.ack.status == RC_SUCCESS))
+               memcpy(value, mb5_transfer.ack.value, (size_t)size);
+       else
+               r = -EIO;
+
+       mutex_unlock(&mb5_transfer.lock);
+
+       return r;
+}
+
+/**
+ * db5500_prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The value(s) to write.
+ * @size:      The number of registers to write.
+ *
+ * Writes register value(s) to the ABB.
+ * @size has to be <= 4.
+ */
+int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if ((size < 1) || (4 < size))
+               return -EINVAL;
+
+       mutex_lock(&mb5_transfer.lock);
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+       writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
+       writeb(reg, PRCM_REQ_MB5_I2C_REG);
+       writeb(size, PRCM_REQ_MB5_I2C_SIZE);
+       memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size);
+       writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER);
+
+       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+       wait_for_completion(&mb5_transfer.work);
+
+       if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) &&
+               (mb5_transfer.ack.status == RC_SUCCESS))
+               r = 0;
+       else
+               r = -EIO;
+
+       mutex_unlock(&mb5_transfer.lock);
+
+       return r;
+}
+
+int db5500_prcmu_enable_dsipll(void)
+{
+       int i;
+
+       /* Enable DSIPLL_RESETN resets */
+       writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
+       /* Unclamp DSIPLL in/out */
+       writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
+       /* Set DSI PLL FREQ */
+       writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
+       writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
+               PRCM_DSI_PLLOUT_SEL);
+       /* Enable Escape clocks */
+       writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
+
+       /* Start DSI PLL */
+       writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
+       /* Reset DSI PLL */
+       writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET);
+       for (i = 0; i < 10; i++) {
+               if ((readl(PRCM_PLLDSI_LOCKP) &
+                       PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED)
+                       break;
+               udelay(100);
+       }
+       /* Release DSIPLL_RESETN */
+       writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET);
+       return 0;
+}
+
+int db5500_prcmu_disable_dsipll(void)
+{
+       /* Disable dsi pll */
+       writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
+       /* Disable  escapeclock */
+       writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
+       return 0;
+}
+
+int db5500_prcmu_set_display_clocks(void)
+{
+       /* HDMI and TVCLK Should be handled somewhere else */
+       /* PLLDIV=8, PLLSW=2, CLKEN=1 */
+       writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
+       /* PLLDIV=14, PLLSW=2, CLKEN=1 */
+       writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
+       return 0;
+}
+
+static void ack_dbb_wakeup(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+               cpu_relax();
+
+       writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER);
+       writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static inline void print_unknown_header_warning(u8 n, u8 header)
+{
+       pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+               header, n);
+}
+
+static bool read_mailbox_0(void)
+{
+       bool r;
+       u8 header;
+
+       header = readb(PRCM_ACK_MB0_HEADER);
+       switch (header) {
+       case AMB0H_WAKE_UP:
+               r = true;
+               break;
+       default:
+               print_unknown_header_warning(0, header);
+               r = false;
+               break;
+       }
+       writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
+       return r;
+}
+
+static bool read_mailbox_1(void)
+{
+       writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_2(void)
+{
+       writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_3(void)
+{
+       writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_4(void)
+{
+       writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_5(void)
+{
+       u8 header;
+
+       header = readb(PRCM_ACK_MB5_HEADER);
+       switch (header) {
+       case MB5H_I2C_READ:
+               memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4);
+       case MB5H_I2C_WRITE:
+               mb5_transfer.ack.header = header;
+               mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE);
+               complete(&mb5_transfer.work);
+               break;
+       default:
+               print_unknown_header_warning(5, header);
+               break;
+       }
+       writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_6(void)
+{
+       writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool read_mailbox_7(void)
+{
+       writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
+       return false;
+}
+
+static bool (* const read_mailbox[NUM_MB])(void) = {
+       read_mailbox_0,
+       read_mailbox_1,
+       read_mailbox_2,
+       read_mailbox_3,
+       read_mailbox_4,
+       read_mailbox_5,
+       read_mailbox_6,
+       read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+       u32 bits;
+       u8 n;
+       irqreturn_t r;
+
+       bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
+       if (unlikely(!bits))
+               return IRQ_NONE;
+
+       r = IRQ_HANDLED;
+       for (n = 0; bits; n++) {
+               if (bits & MBOX_BIT(n)) {
+                       bits -= MBOX_BIT(n);
+                       if (read_mailbox[n]())
+                               r = IRQ_WAKE_THREAD;
+               }
+       }
+       return r;
+}
+
+static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
+{
+       ack_dbb_wakeup();
+       return IRQ_HANDLED;
+}
+
+void __init db5500_prcmu_early_init(void)
+{
+       tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
+       spin_lock_init(&mb0_transfer.lock);
+       mutex_init(&mb5_transfer.lock);
+       init_completion(&mb5_transfer.work);
+}
+
+/**
+ * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
+ *
+ */
+int __init db5500_prcmu_init(void)
+{
+       int r = 0;
+
+       if (ux500_is_svp() || !cpu_is_u5500())
+               return -ENODEV;
+
+       /* Clean up the mailbox interrupts after pre-kernel code. */
+       writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLEAR);
+
+       r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler,
+               prcmu_irq_thread_fn, 0, "prcmu", NULL);
+       if (r < 0) {
+               pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n");
+               return -EBUSY;
+       }
+       return 0;
+}
+
+arch_initcall(db5500_prcmu_init);
diff --git a/drivers/mfd/db8500-prcmu-regs.h b/drivers/mfd/db8500-prcmu-regs.h
new file mode 100644 (file)
index 0000000..3bbf04d
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * PRCM Unit registers
+ */
+#ifndef __DB8500_PRCMU_REGS_H
+#define __DB8500_PRCMU_REGS_H
+
+#include <linux/bitops.h>
+#include <mach/hardware.h>
+
+#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
+
+#define PRCM_ARM_PLLDIVPS 0x118
+#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE BITS(0, 5)
+#define PRCM_ARM_PLLDIVPS_MAX_MASK     0xF
+
+#define PRCM_PLLARM_LOCKP 0x0A8
+#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 BIT(1)
+
+#define PRCM_ARM_CHGCLKREQ 0x114
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0)
+
+#define PRCM_PLLARM_ENABLE 0x98
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE  BIT(0)
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON BIT(8)
+
+#define PRCM_ARMCLKFIX_MGT     0x0
+#define PRCM_A9_RESETN_CLR     0x1f4
+#define PRCM_A9_RESETN_SET     0x1f0
+#define PRCM_ARM_LS_CLAMP      0x30C
+#define PRCM_SRAM_A9           0x308
+
+/* ARM WFI Standby signal register */
+#define PRCM_ARM_WFI_STANDBY   0x130
+#define PRCM_IOCR              0x310
+#define PRCM_IOCR_IOFORCE BIT(0)
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL 0x0FC
+#define PRCM_MBOX_CPU_SET 0x100
+
+/* Dual A9 core interrupt management unit registers */
+#define PRCM_A9_MASK_REQ 0x328
+#define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ BIT(0)
+
+#define PRCM_A9_MASK_ACK       0x32C
+#define PRCM_ARMITMSK31TO0     0x11C
+#define PRCM_ARMITMSK63TO32    0x120
+#define PRCM_ARMITMSK95TO64    0x124
+#define PRCM_ARMITMSK127TO96   0x128
+#define PRCM_POWER_STATE_VAL   0x25C
+#define PRCM_ARMITVAL31TO0     0x260
+#define PRCM_ARMITVAL63TO32    0x264
+#define PRCM_ARMITVAL95TO64    0x268
+#define PRCM_ARMITVAL127TO96   0x26C
+
+#define PRCM_HOSTACCESS_REQ 0x334
+#define PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ BIT(0)
+
+#define PRCM_ARM_IT1_CLR 0x48C
+#define PRCM_ARM_IT1_VAL 0x494
+
+#define PRCM_ITSTATUS0         0x148
+#define PRCM_ITSTATUS1         0x150
+#define PRCM_ITSTATUS2         0x158
+#define PRCM_ITSTATUS3         0x160
+#define PRCM_ITSTATUS4         0x168
+#define PRCM_ITSTATUS5         0x484
+#define PRCM_ITCLEAR5          0x488
+#define PRCM_ARMIT_MASKXP70_IT 0x1018
+
+/* System reset register */
+#define PRCM_APE_SOFTRST 0x228
+
+/* Level shifter and clamp control registers */
+#define PRCM_MMIP_LS_CLAMP_SET 0x420
+#define PRCM_MMIP_LS_CLAMP_CLR 0x424
+
+/* PRCMU HW semaphore */
+#define PRCM_SEM 0x400
+#define PRCM_SEM_PRCM_SEM BIT(0)
+
+/* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLDSI_FREQ       0x500
+#define PRCM_PLLDSI_ENABLE     0x504
+#define PRCM_PLLDSI_LOCKP      0x508
+#define PRCM_DSI_PLLOUT_SEL    0x530
+#define PRCM_DSITVCLK_DIV      0x52C
+#define PRCM_APE_RESETN_SET    0x1E4
+#define PRCM_APE_RESETN_CLR    0x1E8
+
+#define PRCM_TCR               0x1C8
+#define PRCM_TCR_TENSEL_MASK   BITS(0, 7)
+#define PRCM_TCR_STOP_TIMERS   BIT(16)
+#define PRCM_TCR_DOZE_MODE     BIT(17)
+
+#define PRCM_CLKOCR                    0x1CC
+#define PRCM_CLKOCR_CLKODIV0_SHIFT     0
+#define PRCM_CLKOCR_CLKODIV0_MASK      BITS(0, 5)
+#define PRCM_CLKOCR_CLKOSEL0_SHIFT     6
+#define PRCM_CLKOCR_CLKOSEL0_MASK      BITS(6, 8)
+#define PRCM_CLKOCR_CLKODIV1_SHIFT     16
+#define PRCM_CLKOCR_CLKODIV1_MASK      BITS(16, 21)
+#define PRCM_CLKOCR_CLKOSEL1_SHIFT     22
+#define PRCM_CLKOCR_CLKOSEL1_MASK      BITS(22, 24)
+#define PRCM_CLKOCR_CLK1TYPE           BIT(28)
+
+#define PRCM_SGACLK_MGT                0x014
+#define PRCM_UARTCLK_MGT       0x018
+#define PRCM_MSP02CLK_MGT      0x01C
+#define PRCM_MSP1CLK_MGT       0x288
+#define PRCM_I2CCLK_MGT                0x020
+#define PRCM_SDMMCCLK_MGT      0x024
+#define PRCM_SLIMCLK_MGT       0x028
+#define PRCM_PER1CLK_MGT       0x02C
+#define PRCM_PER2CLK_MGT       0x030
+#define PRCM_PER3CLK_MGT       0x034
+#define PRCM_PER5CLK_MGT       0x038
+#define PRCM_PER6CLK_MGT       0x03C
+#define PRCM_PER7CLK_MGT       0x040
+#define PRCM_LCDCLK_MGT                0x044
+#define PRCM_BMLCLK_MGT                0x04C
+#define PRCM_HSITXCLK_MGT      0x050
+#define PRCM_HSIRXCLK_MGT      0x054
+#define PRCM_HDMICLK_MGT       0x058
+#define PRCM_APEATCLK_MGT      0x05C
+#define PRCM_APETRACECLK_MGT   0x060
+#define PRCM_MCDECLK_MGT       0x064
+#define PRCM_IPI2CCLK_MGT      0x068
+#define PRCM_DSIALTCLK_MGT     0x06C
+#define PRCM_DMACLK_MGT                0x074
+#define PRCM_B2R2CLK_MGT       0x078
+#define PRCM_TVCLK_MGT         0x07C
+#define PRCM_UNIPROCLK_MGT     0x278
+#define PRCM_SSPCLK_MGT                0x280
+#define PRCM_RNGCLK_MGT                0x284
+#define PRCM_UICCCLK_MGT       0x27C
+
+#define PRCM_CLK_MGT_CLKPLLDIV_MASK    BITS(0, 4)
+#define PRCM_CLK_MGT_CLKPLLSW_MASK     BITS(5, 7)
+#define PRCM_CLK_MGT_CLKEN             BIT(8)
+
+/* ePOD and memory power signal control registers */
+#define PRCM_EPOD_C_SET                0x410
+#define PRCM_SRAM_LS_SLEEP     0x304
+
+/* Debug power control unit registers */
+#define PRCM_POWER_STATE_SET 0x254
+
+/* Miscellaneous unit registers */
+#define PRCM_DSI_SW_RESET 0x324
+#define PRCM_GPIOCR            0x138
+
+/* GPIOCR register */
+#define PRCM_GPIOCR_SPI2_SELECT BIT(23)
+
+#define PRCM_DDR_SUBSYS_APE_MINBW  0x438
+
+#endif /* __DB8500_PRCMU_REGS_H */
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
new file mode 100644 (file)
index 0000000..e637821
--- /dev/null
@@ -0,0 +1,2069 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U8500 PRCM Unit interface driver
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <linux/regulator/db8500-prcmu.h>
+#include <linux/regulator/machine.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/db8500-regs.h>
+#include <mach/id.h>
+#include "db8500-prcmu-regs.h"
+
+/* Offset for the firmware version within the TCPM */
+#define PRCMU_FW_VERSION_OFFSET 0xA4
+
+/* PRCMU project numbers, defined by PRCMU FW */
+#define PRCMU_PROJECT_ID_8500V1_0 1
+#define PRCMU_PROJECT_ID_8500V2_0 2
+#define PRCMU_PROJECT_ID_8400V2_0 3
+
+/* Index of different voltages to be used when accessing AVSData */
+#define PRCM_AVS_BASE          0x2FC
+#define PRCM_AVS_VBB_RET       (PRCM_AVS_BASE + 0x0)
+#define PRCM_AVS_VBB_MAX_OPP   (PRCM_AVS_BASE + 0x1)
+#define PRCM_AVS_VBB_100_OPP   (PRCM_AVS_BASE + 0x2)
+#define PRCM_AVS_VBB_50_OPP    (PRCM_AVS_BASE + 0x3)
+#define PRCM_AVS_VARM_MAX_OPP  (PRCM_AVS_BASE + 0x4)
+#define PRCM_AVS_VARM_100_OPP  (PRCM_AVS_BASE + 0x5)
+#define PRCM_AVS_VARM_50_OPP   (PRCM_AVS_BASE + 0x6)
+#define PRCM_AVS_VARM_RET      (PRCM_AVS_BASE + 0x7)
+#define PRCM_AVS_VAPE_100_OPP  (PRCM_AVS_BASE + 0x8)
+#define PRCM_AVS_VAPE_50_OPP   (PRCM_AVS_BASE + 0x9)
+#define PRCM_AVS_VMOD_100_OPP  (PRCM_AVS_BASE + 0xA)
+#define PRCM_AVS_VMOD_50_OPP   (PRCM_AVS_BASE + 0xB)
+#define PRCM_AVS_VSAFE         (PRCM_AVS_BASE + 0xC)
+
+#define PRCM_AVS_VOLTAGE               0
+#define PRCM_AVS_VOLTAGE_MASK          0x3f
+#define PRCM_AVS_ISSLOWSTARTUP         6
+#define PRCM_AVS_ISSLOWSTARTUP_MASK    (1 << PRCM_AVS_ISSLOWSTARTUP)
+#define PRCM_AVS_ISMODEENABLE          7
+#define PRCM_AVS_ISMODEENABLE_MASK     (1 << PRCM_AVS_ISMODEENABLE)
+
+#define PRCM_BOOT_STATUS       0xFFF
+#define PRCM_ROMCODE_A2P       0xFFE
+#define PRCM_ROMCODE_P2A       0xFFD
+#define PRCM_XP70_CUR_PWR_STATE 0xFFC      /* 4 BYTES */
+
+#define PRCM_SW_RST_REASON 0xFF8 /* 2 bytes */
+
+#define _PRCM_MBOX_HEADER              0xFE8 /* 16 bytes */
+#define PRCM_MBOX_HEADER_REQ_MB0       (_PRCM_MBOX_HEADER + 0x0)
+#define PRCM_MBOX_HEADER_REQ_MB1       (_PRCM_MBOX_HEADER + 0x1)
+#define PRCM_MBOX_HEADER_REQ_MB2       (_PRCM_MBOX_HEADER + 0x2)
+#define PRCM_MBOX_HEADER_REQ_MB3       (_PRCM_MBOX_HEADER + 0x3)
+#define PRCM_MBOX_HEADER_REQ_MB4       (_PRCM_MBOX_HEADER + 0x4)
+#define PRCM_MBOX_HEADER_REQ_MB5       (_PRCM_MBOX_HEADER + 0x5)
+#define PRCM_MBOX_HEADER_ACK_MB0       (_PRCM_MBOX_HEADER + 0x8)
+
+/* Req Mailboxes */
+#define PRCM_REQ_MB0 0xFDC /* 12 bytes  */
+#define PRCM_REQ_MB1 0xFD0 /* 12 bytes  */
+#define PRCM_REQ_MB2 0xFC0 /* 16 bytes  */
+#define PRCM_REQ_MB3 0xE4C /* 372 bytes  */
+#define PRCM_REQ_MB4 0xE48 /* 4 bytes  */
+#define PRCM_REQ_MB5 0xE44 /* 4 bytes  */
+
+/* Ack Mailboxes */
+#define PRCM_ACK_MB0 0xE08 /* 52 bytes  */
+#define PRCM_ACK_MB1 0xE04 /* 4 bytes */
+#define PRCM_ACK_MB2 0xE00 /* 4 bytes */
+#define PRCM_ACK_MB3 0xDFC /* 4 bytes */
+#define PRCM_ACK_MB4 0xDF8 /* 4 bytes */
+#define PRCM_ACK_MB5 0xDF4 /* 4 bytes */
+
+/* Mailbox 0 headers */
+#define MB0H_POWER_STATE_TRANS         0
+#define MB0H_CONFIG_WAKEUPS_EXE                1
+#define MB0H_READ_WAKEUP_ACK           3
+#define MB0H_CONFIG_WAKEUPS_SLEEP      4
+
+#define MB0H_WAKEUP_EXE 2
+#define MB0H_WAKEUP_SLEEP 5
+
+/* Mailbox 0 REQs */
+#define PRCM_REQ_MB0_AP_POWER_STATE    (PRCM_REQ_MB0 + 0x0)
+#define PRCM_REQ_MB0_AP_PLL_STATE      (PRCM_REQ_MB0 + 0x1)
+#define PRCM_REQ_MB0_ULP_CLOCK_STATE   (PRCM_REQ_MB0 + 0x2)
+#define PRCM_REQ_MB0_DO_NOT_WFI                (PRCM_REQ_MB0 + 0x3)
+#define PRCM_REQ_MB0_WAKEUP_8500       (PRCM_REQ_MB0 + 0x4)
+#define PRCM_REQ_MB0_WAKEUP_4500       (PRCM_REQ_MB0 + 0x8)
+
+/* Mailbox 0 ACKs */
+#define PRCM_ACK_MB0_AP_PWRSTTR_STATUS (PRCM_ACK_MB0 + 0x0)
+#define PRCM_ACK_MB0_READ_POINTER      (PRCM_ACK_MB0 + 0x1)
+#define PRCM_ACK_MB0_WAKEUP_0_8500     (PRCM_ACK_MB0 + 0x4)
+#define PRCM_ACK_MB0_WAKEUP_0_4500     (PRCM_ACK_MB0 + 0x8)
+#define PRCM_ACK_MB0_WAKEUP_1_8500     (PRCM_ACK_MB0 + 0x1C)
+#define PRCM_ACK_MB0_WAKEUP_1_4500     (PRCM_ACK_MB0 + 0x20)
+#define PRCM_ACK_MB0_EVENT_4500_NUMBERS        20
+
+/* Mailbox 1 headers */
+#define MB1H_ARM_APE_OPP 0x0
+#define MB1H_RESET_MODEM 0x2
+#define MB1H_REQUEST_APE_OPP_100_VOLT 0x3
+#define MB1H_RELEASE_APE_OPP_100_VOLT 0x4
+#define MB1H_RELEASE_USB_WAKEUP 0x5
+
+/* Mailbox 1 Requests */
+#define PRCM_REQ_MB1_ARM_OPP                   (PRCM_REQ_MB1 + 0x0)
+#define PRCM_REQ_MB1_APE_OPP                   (PRCM_REQ_MB1 + 0x1)
+#define PRCM_REQ_MB1_APE_OPP_100_RESTORE       (PRCM_REQ_MB1 + 0x4)
+#define PRCM_REQ_MB1_ARM_OPP_100_RESTORE       (PRCM_REQ_MB1 + 0x8)
+
+/* Mailbox 1 ACKs */
+#define PRCM_ACK_MB1_CURRENT_ARM_OPP   (PRCM_ACK_MB1 + 0x0)
+#define PRCM_ACK_MB1_CURRENT_APE_OPP   (PRCM_ACK_MB1 + 0x1)
+#define PRCM_ACK_MB1_APE_VOLTAGE_STATUS        (PRCM_ACK_MB1 + 0x2)
+#define PRCM_ACK_MB1_DVFS_STATUS       (PRCM_ACK_MB1 + 0x3)
+
+/* Mailbox 2 headers */
+#define MB2H_DPS       0x0
+#define MB2H_AUTO_PWR  0x1
+
+/* Mailbox 2 REQs */
+#define PRCM_REQ_MB2_SVA_MMDSP         (PRCM_REQ_MB2 + 0x0)
+#define PRCM_REQ_MB2_SVA_PIPE          (PRCM_REQ_MB2 + 0x1)
+#define PRCM_REQ_MB2_SIA_MMDSP         (PRCM_REQ_MB2 + 0x2)
+#define PRCM_REQ_MB2_SIA_PIPE          (PRCM_REQ_MB2 + 0x3)
+#define PRCM_REQ_MB2_SGA               (PRCM_REQ_MB2 + 0x4)
+#define PRCM_REQ_MB2_B2R2_MCDE         (PRCM_REQ_MB2 + 0x5)
+#define PRCM_REQ_MB2_ESRAM12           (PRCM_REQ_MB2 + 0x6)
+#define PRCM_REQ_MB2_ESRAM34           (PRCM_REQ_MB2 + 0x7)
+#define PRCM_REQ_MB2_AUTO_PM_SLEEP     (PRCM_REQ_MB2 + 0x8)
+#define PRCM_REQ_MB2_AUTO_PM_IDLE      (PRCM_REQ_MB2 + 0xC)
+
+/* Mailbox 2 ACKs */
+#define PRCM_ACK_MB2_DPS_STATUS (PRCM_ACK_MB2 + 0x0)
+#define HWACC_PWR_ST_OK 0xFE
+
+/* Mailbox 3 headers */
+#define MB3H_ANC       0x0
+#define MB3H_SIDETONE  0x1
+#define MB3H_SYSCLK    0xE
+
+/* Mailbox 3 Requests */
+#define PRCM_REQ_MB3_ANC_FIR_COEFF     (PRCM_REQ_MB3 + 0x0)
+#define PRCM_REQ_MB3_ANC_IIR_COEFF     (PRCM_REQ_MB3 + 0x20)
+#define PRCM_REQ_MB3_ANC_SHIFTER       (PRCM_REQ_MB3 + 0x60)
+#define PRCM_REQ_MB3_ANC_WARP          (PRCM_REQ_MB3 + 0x64)
+#define PRCM_REQ_MB3_SIDETONE_FIR_GAIN (PRCM_REQ_MB3 + 0x68)
+#define PRCM_REQ_MB3_SIDETONE_FIR_COEFF        (PRCM_REQ_MB3 + 0x6C)
+#define PRCM_REQ_MB3_SYSCLK_MGT                (PRCM_REQ_MB3 + 0x16C)
+
+/* Mailbox 4 headers */
+#define MB4H_DDR_INIT  0x0
+#define MB4H_MEM_ST    0x1
+#define MB4H_HOTDOG    0x12
+#define MB4H_HOTMON    0x13
+#define MB4H_HOT_PERIOD        0x14
+
+/* Mailbox 4 Requests */
+#define PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE      (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE       (PRCM_REQ_MB4 + 0x1)
+#define PRCM_REQ_MB4_ESRAM0_ST                 (PRCM_REQ_MB4 + 0x3)
+#define PRCM_REQ_MB4_HOTDOG_THRESHOLD          (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_HOTMON_LOW                        (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_HOTMON_HIGH               (PRCM_REQ_MB4 + 0x1)
+#define PRCM_REQ_MB4_HOTMON_CONFIG             (PRCM_REQ_MB4 + 0x2)
+#define PRCM_REQ_MB4_HOT_PERIOD                        (PRCM_REQ_MB4 + 0x0)
+#define HOTMON_CONFIG_LOW                      BIT(0)
+#define HOTMON_CONFIG_HIGH                     BIT(1)
+
+/* Mailbox 5 Requests */
+#define PRCM_REQ_MB5_I2C_SLAVE_OP      (PRCM_REQ_MB5 + 0x0)
+#define PRCM_REQ_MB5_I2C_HW_BITS       (PRCM_REQ_MB5 + 0x1)
+#define PRCM_REQ_MB5_I2C_REG           (PRCM_REQ_MB5 + 0x2)
+#define PRCM_REQ_MB5_I2C_VAL           (PRCM_REQ_MB5 + 0x3)
+#define PRCMU_I2C_WRITE(slave) \
+       (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
+#define PRCMU_I2C_READ(slave) \
+       (((slave) << 1) | BIT(0) | (cpu_is_u8500v2() ? BIT(6) : 0))
+#define PRCMU_I2C_STOP_EN              BIT(3)
+
+/* Mailbox 5 ACKs */
+#define PRCM_ACK_MB5_I2C_STATUS        (PRCM_ACK_MB5 + 0x1)
+#define PRCM_ACK_MB5_I2C_VAL   (PRCM_ACK_MB5 + 0x3)
+#define I2C_WR_OK 0x1
+#define I2C_RD_OK 0x2
+
+#define NUM_MB 8
+#define MBOX_BIT BIT
+#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
+
+/*
+ * Wakeups/IRQs
+ */
+
+#define WAKEUP_BIT_RTC BIT(0)
+#define WAKEUP_BIT_RTT0 BIT(1)
+#define WAKEUP_BIT_RTT1 BIT(2)
+#define WAKEUP_BIT_HSI0 BIT(3)
+#define WAKEUP_BIT_HSI1 BIT(4)
+#define WAKEUP_BIT_CA_WAKE BIT(5)
+#define WAKEUP_BIT_USB BIT(6)
+#define WAKEUP_BIT_ABB BIT(7)
+#define WAKEUP_BIT_ABB_FIFO BIT(8)
+#define WAKEUP_BIT_SYSCLK_OK BIT(9)
+#define WAKEUP_BIT_CA_SLEEP BIT(10)
+#define WAKEUP_BIT_AC_WAKE_ACK BIT(11)
+#define WAKEUP_BIT_SIDE_TONE_OK BIT(12)
+#define WAKEUP_BIT_ANC_OK BIT(13)
+#define WAKEUP_BIT_SW_ERROR BIT(14)
+#define WAKEUP_BIT_AC_SLEEP_ACK BIT(15)
+#define WAKEUP_BIT_ARM BIT(17)
+#define WAKEUP_BIT_HOTMON_LOW BIT(18)
+#define WAKEUP_BIT_HOTMON_HIGH BIT(19)
+#define WAKEUP_BIT_MODEM_SW_RESET_REQ BIT(20)
+#define WAKEUP_BIT_GPIO0 BIT(23)
+#define WAKEUP_BIT_GPIO1 BIT(24)
+#define WAKEUP_BIT_GPIO2 BIT(25)
+#define WAKEUP_BIT_GPIO3 BIT(26)
+#define WAKEUP_BIT_GPIO4 BIT(27)
+#define WAKEUP_BIT_GPIO5 BIT(28)
+#define WAKEUP_BIT_GPIO6 BIT(29)
+#define WAKEUP_BIT_GPIO7 BIT(30)
+#define WAKEUP_BIT_GPIO8 BIT(31)
+
+/*
+ * This vector maps irq numbers to the bits in the bit field used in
+ * communication with the PRCMU firmware.
+ *
+ * The reason for having this is to keep the irq numbers contiguous even though
+ * the bits in the bit field are not. (The bits also have a tendency to move
+ * around, to further complicate matters.)
+ */
+#define IRQ_INDEX(_name) ((IRQ_PRCMU_##_name) - IRQ_PRCMU_BASE)
+#define IRQ_ENTRY(_name)[IRQ_INDEX(_name)] = (WAKEUP_BIT_##_name)
+static u32 prcmu_irq_bit[NUM_PRCMU_WAKEUPS] = {
+       IRQ_ENTRY(RTC),
+       IRQ_ENTRY(RTT0),
+       IRQ_ENTRY(RTT1),
+       IRQ_ENTRY(HSI0),
+       IRQ_ENTRY(HSI1),
+       IRQ_ENTRY(CA_WAKE),
+       IRQ_ENTRY(USB),
+       IRQ_ENTRY(ABB),
+       IRQ_ENTRY(ABB_FIFO),
+       IRQ_ENTRY(CA_SLEEP),
+       IRQ_ENTRY(ARM),
+       IRQ_ENTRY(HOTMON_LOW),
+       IRQ_ENTRY(HOTMON_HIGH),
+       IRQ_ENTRY(MODEM_SW_RESET_REQ),
+       IRQ_ENTRY(GPIO0),
+       IRQ_ENTRY(GPIO1),
+       IRQ_ENTRY(GPIO2),
+       IRQ_ENTRY(GPIO3),
+       IRQ_ENTRY(GPIO4),
+       IRQ_ENTRY(GPIO5),
+       IRQ_ENTRY(GPIO6),
+       IRQ_ENTRY(GPIO7),
+       IRQ_ENTRY(GPIO8)
+};
+
+#define VALID_WAKEUPS (BIT(NUM_PRCMU_WAKEUP_INDICES) - 1)
+#define WAKEUP_ENTRY(_name)[PRCMU_WAKEUP_INDEX_##_name] = (WAKEUP_BIT_##_name)
+static u32 prcmu_wakeup_bit[NUM_PRCMU_WAKEUP_INDICES] = {
+       WAKEUP_ENTRY(RTC),
+       WAKEUP_ENTRY(RTT0),
+       WAKEUP_ENTRY(RTT1),
+       WAKEUP_ENTRY(HSI0),
+       WAKEUP_ENTRY(HSI1),
+       WAKEUP_ENTRY(USB),
+       WAKEUP_ENTRY(ABB),
+       WAKEUP_ENTRY(ABB_FIFO),
+       WAKEUP_ENTRY(ARM)
+};
+
+/*
+ * mb0_transfer - state needed for mailbox 0 communication.
+ * @lock:              The transaction lock.
+ * @dbb_events_lock:   A lock used to handle concurrent access to (parts of)
+ *                     the request data.
+ * @mask_work:         Work structure used for (un)masking wakeup interrupts.
+ * @req:               Request data that need to persist between requests.
+ */
+static struct {
+       spinlock_t lock;
+       spinlock_t dbb_irqs_lock;
+       struct work_struct mask_work;
+       struct mutex ac_wake_lock;
+       struct completion ac_wake_work;
+       struct {
+               u32 dbb_irqs;
+               u32 dbb_wakeups;
+               u32 abb_events;
+       } req;
+} mb0_transfer;
+
+/*
+ * mb1_transfer - state needed for mailbox 1 communication.
+ * @lock:      The transaction lock.
+ * @work:      The transaction completion structure.
+ * @ack:       Reply ("acknowledge") data.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+       struct {
+               u8 header;
+               u8 arm_opp;
+               u8 ape_opp;
+               u8 ape_voltage_status;
+       } ack;
+} mb1_transfer;
+
+/*
+ * mb2_transfer - state needed for mailbox 2 communication.
+ * @lock:            The transaction lock.
+ * @work:            The transaction completion structure.
+ * @auto_pm_lock:    The autonomous power management configuration lock.
+ * @auto_pm_enabled: A flag indicating whether autonomous PM is enabled.
+ * @req:             Request data that need to persist between requests.
+ * @ack:             Reply ("acknowledge") data.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+       spinlock_t auto_pm_lock;
+       bool auto_pm_enabled;
+       struct {
+               u8 status;
+       } ack;
+} mb2_transfer;
+
+/*
+ * mb3_transfer - state needed for mailbox 3 communication.
+ * @lock:              The request lock.
+ * @sysclk_lock:       A lock used to handle concurrent sysclk requests.
+ * @sysclk_work:       Work structure used for sysclk requests.
+ */
+static struct {
+       spinlock_t lock;
+       struct mutex sysclk_lock;
+       struct completion sysclk_work;
+} mb3_transfer;
+
+/*
+ * mb4_transfer - state needed for mailbox 4 communication.
+ * @lock:      The transaction lock.
+ * @work:      The transaction completion structure.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+} mb4_transfer;
+
+/*
+ * mb5_transfer - state needed for mailbox 5 communication.
+ * @lock:      The transaction lock.
+ * @work:      The transaction completion structure.
+ * @ack:       Reply ("acknowledge") data.
+ */
+static struct {
+       struct mutex lock;
+       struct completion work;
+       struct {
+               u8 status;
+               u8 value;
+       } ack;
+} mb5_transfer;
+
+static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
+
+/* Spinlocks */
+static DEFINE_SPINLOCK(clkout_lock);
+static DEFINE_SPINLOCK(gpiocr_lock);
+
+/* Global var to runtime determine TCDM base for v2 or v1 */
+static __iomem void *tcdm_base;
+
+struct clk_mgt {
+       unsigned int offset;
+       u32 pllsw;
+};
+
+static DEFINE_SPINLOCK(clk_mgt_lock);
+
+#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT), 0 }
+struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
+       CLK_MGT_ENTRY(SGACLK),
+       CLK_MGT_ENTRY(UARTCLK),
+       CLK_MGT_ENTRY(MSP02CLK),
+       CLK_MGT_ENTRY(MSP1CLK),
+       CLK_MGT_ENTRY(I2CCLK),
+       CLK_MGT_ENTRY(SDMMCCLK),
+       CLK_MGT_ENTRY(SLIMCLK),
+       CLK_MGT_ENTRY(PER1CLK),
+       CLK_MGT_ENTRY(PER2CLK),
+       CLK_MGT_ENTRY(PER3CLK),
+       CLK_MGT_ENTRY(PER5CLK),
+       CLK_MGT_ENTRY(PER6CLK),
+       CLK_MGT_ENTRY(PER7CLK),
+       CLK_MGT_ENTRY(LCDCLK),
+       CLK_MGT_ENTRY(BMLCLK),
+       CLK_MGT_ENTRY(HSITXCLK),
+       CLK_MGT_ENTRY(HSIRXCLK),
+       CLK_MGT_ENTRY(HDMICLK),
+       CLK_MGT_ENTRY(APEATCLK),
+       CLK_MGT_ENTRY(APETRACECLK),
+       CLK_MGT_ENTRY(MCDECLK),
+       CLK_MGT_ENTRY(IPI2CCLK),
+       CLK_MGT_ENTRY(DSIALTCLK),
+       CLK_MGT_ENTRY(DMACLK),
+       CLK_MGT_ENTRY(B2R2CLK),
+       CLK_MGT_ENTRY(TVCLK),
+       CLK_MGT_ENTRY(SSPCLK),
+       CLK_MGT_ENTRY(RNGCLK),
+       CLK_MGT_ENTRY(UICCCLK),
+};
+
+/*
+* Used by MCDE to setup all necessary PRCMU registers
+*/
+#define PRCMU_RESET_DSIPLL             0x00004000
+#define PRCMU_UNCLAMP_DSIPLL           0x00400800
+
+#define PRCMU_CLK_PLL_DIV_SHIFT                0
+#define PRCMU_CLK_PLL_SW_SHIFT         5
+#define PRCMU_CLK_38                   (1 << 9)
+#define PRCMU_CLK_38_SRC               (1 << 10)
+#define PRCMU_CLK_38_DIV               (1 << 11)
+
+/* PLLDIV=12, PLLSW=4 (PLLDDR) */
+#define PRCMU_DSI_CLOCK_SETTING                0x0000008C
+
+/* PLLDIV=8, PLLSW=4 (PLLDDR) */
+#define PRCMU_DSI_CLOCK_SETTING_U8400  0x00000088
+
+/* DPI 50000000 Hz */
+#define PRCMU_DPI_CLOCK_SETTING                ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
+                                         (16 << PRCMU_CLK_PLL_DIV_SHIFT))
+#define PRCMU_DSI_LP_CLOCK_SETTING     0x00000E00
+
+/* D=101, N=1, R=4, SELDIV2=0 */
+#define PRCMU_PLLDSI_FREQ_SETTING      0x00040165
+
+/* D=70, N=1, R=3, SELDIV2=0 */
+#define PRCMU_PLLDSI_FREQ_SETTING_U8400        0x00030146
+
+#define PRCMU_ENABLE_PLLDSI            0x00000001
+#define PRCMU_DISABLE_PLLDSI           0x00000000
+#define PRCMU_RELEASE_RESET_DSS                0x0000400C
+#define PRCMU_DSI_PLLOUT_SEL_SETTING   0x00000202
+/* ESC clk, div0=1, div1=1, div2=3 */
+#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV  0x07030101
+#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00030101
+#define PRCMU_DSI_RESET_SW             0x00000007
+
+#define PRCMU_PLLDSI_LOCKP_LOCKED      0x3
+
+static struct {
+       u8 project_number;
+       u8 api_version;
+       u8 func_version;
+       u8 errata;
+} prcmu_version;
+
+
+int prcmu_enable_dsipll(void)
+{
+       int i;
+       unsigned int plldsifreq;
+
+       /* Clear DSIPLL_RESETN */
+       writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_CLR));
+       /* Unclamp DSIPLL in/out */
+       writel(PRCMU_UNCLAMP_DSIPLL, (_PRCMU_BASE + PRCM_MMIP_LS_CLAMP_CLR));
+
+       if (prcmu_is_u8400())
+               plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400;
+       else
+               plldsifreq = PRCMU_PLLDSI_FREQ_SETTING;
+       /* Set DSI PLL FREQ */
+       writel(plldsifreq, (_PRCMU_BASE + PRCM_PLLDSI_FREQ));
+       writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
+               (_PRCMU_BASE + PRCM_DSI_PLLOUT_SEL));
+       /* Enable Escape clocks */
+       writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV,
+                                       (_PRCMU_BASE + PRCM_DSITVCLK_DIV));
+
+       /* Start DSI PLL */
+       writel(PRCMU_ENABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE));
+       /* Reset DSI PLL */
+       writel(PRCMU_DSI_RESET_SW, (_PRCMU_BASE + PRCM_DSI_SW_RESET));
+       for (i = 0; i < 10; i++) {
+               if ((readl(_PRCMU_BASE + PRCM_PLLDSI_LOCKP) &
+                       PRCMU_PLLDSI_LOCKP_LOCKED)
+                                       == PRCMU_PLLDSI_LOCKP_LOCKED)
+                       break;
+               udelay(100);
+       }
+       /* Set DSIPLL_RESETN */
+       writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_SET));
+       return 0;
+}
+
+int prcmu_disable_dsipll(void)
+{
+       /* Disable dsi pll */
+       writel(PRCMU_DISABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE));
+       /* Disable  escapeclock */
+       writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV,
+                                       (_PRCMU_BASE + PRCM_DSITVCLK_DIV));
+       return 0;
+}
+
+int prcmu_set_display_clocks(void)
+{
+       unsigned long flags;
+       unsigned int dsiclk;
+
+       if (prcmu_is_u8400())
+               dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400;
+       else
+               dsiclk = PRCMU_DSI_CLOCK_SETTING;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       writel(dsiclk, (_PRCMU_BASE + PRCM_HDMICLK_MGT));
+       writel(PRCMU_DSI_LP_CLOCK_SETTING, (_PRCMU_BASE + PRCM_TVCLK_MGT));
+       writel(PRCMU_DPI_CLOCK_SETTING, (_PRCMU_BASE + PRCM_LCDCLK_MGT));
+
+       /* Release the HW semaphore. */
+       writel(0, (_PRCMU_BASE + PRCM_SEM));
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+
+       return 0;
+}
+
+/**
+ * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
+ */
+void prcmu_enable_spi2(void)
+{
+       u32 reg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpiocr_lock, flags);
+       reg = readl(_PRCMU_BASE + PRCM_GPIOCR);
+       writel(reg | PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR);
+       spin_unlock_irqrestore(&gpiocr_lock, flags);
+}
+
+/**
+ * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
+ */
+void prcmu_disable_spi2(void)
+{
+       u32 reg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpiocr_lock, flags);
+       reg = readl(_PRCMU_BASE + PRCM_GPIOCR);
+       writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR);
+       spin_unlock_irqrestore(&gpiocr_lock, flags);
+}
+
+bool prcmu_has_arm_maxopp(void)
+{
+       return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
+               PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
+}
+
+bool prcmu_is_u8400(void)
+{
+       return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0;
+}
+
+/**
+ * prcmu_get_boot_status - PRCMU boot status checking
+ * Returns: the current PRCMU boot status
+ */
+int prcmu_get_boot_status(void)
+{
+       return readb(tcdm_base + PRCM_BOOT_STATUS);
+}
+
+/**
+ * prcmu_set_rc_a2p - This function is used to run few power state sequences
+ * @val: Value to be set, i.e. transition requested
+ * Returns: 0 on success, -EINVAL on invalid argument
+ *
+ * This function is used to run the following power state sequences -
+ * any state to ApReset,  ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
+ */
+int prcmu_set_rc_a2p(enum romcode_write val)
+{
+       if (val < RDY_2_DS || val > RDY_2_XP70_RST)
+               return -EINVAL;
+       writeb(val, (tcdm_base + PRCM_ROMCODE_A2P));
+       return 0;
+}
+
+/**
+ * prcmu_get_rc_p2a - This function is used to get power state sequences
+ * Returns: the power transition that has last happened
+ *
+ * This function can return the following transitions-
+ * any state to ApReset,  ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
+ */
+enum romcode_read prcmu_get_rc_p2a(void)
+{
+       return readb(tcdm_base + PRCM_ROMCODE_P2A);
+}
+
+/**
+ * prcmu_get_current_mode - Return the current XP70 power mode
+ * Returns: Returns the current AP(ARM) power mode: init,
+ * apBoot, apExecute, apDeepSleep, apSleep, apIdle, apReset
+ */
+enum ap_pwrst prcmu_get_xp70_current_state(void)
+{
+       return readb(tcdm_base + PRCM_XP70_CUR_PWR_STATE);
+}
+
+/**
+ * prcmu_config_clkout - Configure one of the programmable clock outputs.
+ * @clkout:    The CLKOUT number (0 or 1).
+ * @source:    The clock to be used (one of the PRCMU_CLKSRC_*).
+ * @div:       The divider to be applied.
+ *
+ * Configures one of the programmable clock outputs (CLKOUTs).
+ * @div should be in the range [1,63] to request a configuration, or 0 to
+ * inform that the configuration is no longer requested.
+ */
+int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
+{
+       static int requests[2];
+       int r = 0;
+       unsigned long flags;
+       u32 val;
+       u32 bits;
+       u32 mask;
+       u32 div_mask;
+
+       BUG_ON(clkout > 1);
+       BUG_ON(div > 63);
+       BUG_ON((clkout == 0) && (source > PRCMU_CLKSRC_CLK009));
+
+       if (!div && !requests[clkout])
+               return -EINVAL;
+
+       switch (clkout) {
+       case 0:
+               div_mask = PRCM_CLKOCR_CLKODIV0_MASK;
+               mask = (PRCM_CLKOCR_CLKODIV0_MASK | PRCM_CLKOCR_CLKOSEL0_MASK);
+               bits = ((source << PRCM_CLKOCR_CLKOSEL0_SHIFT) |
+                       (div << PRCM_CLKOCR_CLKODIV0_SHIFT));
+               break;
+       case 1:
+               div_mask = PRCM_CLKOCR_CLKODIV1_MASK;
+               mask = (PRCM_CLKOCR_CLKODIV1_MASK | PRCM_CLKOCR_CLKOSEL1_MASK |
+                       PRCM_CLKOCR_CLK1TYPE);
+               bits = ((source << PRCM_CLKOCR_CLKOSEL1_SHIFT) |
+                       (div << PRCM_CLKOCR_CLKODIV1_SHIFT));
+               break;
+       }
+       bits &= mask;
+
+       spin_lock_irqsave(&clkout_lock, flags);
+
+       val = readl(_PRCMU_BASE + PRCM_CLKOCR);
+       if (val & div_mask) {
+               if (div) {
+                       if ((val & mask) != bits) {
+                               r = -EBUSY;
+                               goto unlock_and_return;
+                       }
+               } else {
+                       if ((val & mask & ~div_mask) != bits) {
+                               r = -EINVAL;
+                               goto unlock_and_return;
+                       }
+               }
+       }
+       writel((bits | (val & ~mask)), (_PRCMU_BASE + PRCM_CLKOCR));
+       requests[clkout] += (div ? 1 : -1);
+
+unlock_and_return:
+       spin_unlock_irqrestore(&clkout_lock, flags);
+
+       return r;
+}
+
+int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
+{
+       unsigned long flags;
+
+       BUG_ON((state < PRCMU_AP_SLEEP) || (PRCMU_AP_DEEP_IDLE < state));
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+               cpu_relax();
+
+       writeb(MB0H_POWER_STATE_TRANS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
+       writeb(state, (tcdm_base + PRCM_REQ_MB0_AP_POWER_STATE));
+       writeb((keep_ap_pll ? 1 : 0), (tcdm_base + PRCM_REQ_MB0_AP_PLL_STATE));
+       writeb((keep_ulp_clk ? 1 : 0),
+               (tcdm_base + PRCM_REQ_MB0_ULP_CLOCK_STATE));
+       writeb(0, (tcdm_base + PRCM_REQ_MB0_DO_NOT_WFI));
+       writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+
+       return 0;
+}
+
+/* This function should only be called while mb0_transfer.lock is held. */
+static void config_wakeups(void)
+{
+       const u8 header[2] = {
+               MB0H_CONFIG_WAKEUPS_EXE,
+               MB0H_CONFIG_WAKEUPS_SLEEP
+       };
+       static u32 last_dbb_events;
+       static u32 last_abb_events;
+       u32 dbb_events;
+       u32 abb_events;
+       unsigned int i;
+
+       dbb_events = mb0_transfer.req.dbb_irqs | mb0_transfer.req.dbb_wakeups;
+       dbb_events |= (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK);
+
+       abb_events = mb0_transfer.req.abb_events;
+
+       if ((dbb_events == last_dbb_events) && (abb_events == last_abb_events))
+               return;
+
+       for (i = 0; i < 2; i++) {
+               while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+                       cpu_relax();
+               writel(dbb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_8500));
+               writel(abb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_4500));
+               writeb(header[i], (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
+               writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       }
+       last_dbb_events = dbb_events;
+       last_abb_events = abb_events;
+}
+
+void prcmu_enable_wakeups(u32 wakeups)
+{
+       unsigned long flags;
+       u32 bits;
+       int i;
+
+       BUG_ON(wakeups != (wakeups & VALID_WAKEUPS));
+
+       for (i = 0, bits = 0; i < NUM_PRCMU_WAKEUP_INDICES; i++) {
+               if (wakeups & BIT(i))
+                       bits |= prcmu_wakeup_bit[i];
+       }
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       mb0_transfer.req.dbb_wakeups = bits;
+       config_wakeups();
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+void prcmu_config_abb_event_readout(u32 abb_events)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       mb0_transfer.req.abb_events = abb_events;
+       config_wakeups();
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+void prcmu_get_abb_event_buffer(void __iomem **buf)
+{
+       if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1)
+               *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_1_4500);
+       else
+               *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_0_4500);
+}
+
+/**
+ * prcmu_set_arm_opp - set the appropriate ARM OPP
+ * @opp: The new ARM operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the the operating point of the ARM.
+ */
+int prcmu_set_arm_opp(u8 opp)
+{
+       int r;
+
+       if (opp < ARM_NO_CHANGE || opp > ARM_EXTCLK)
+               return -EINVAL;
+
+       r = 0;
+
+       mutex_lock(&mb1_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+       writeb(opp, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
+       writeb(APE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) ||
+               (mb1_transfer.ack.arm_opp != opp))
+               r = -EIO;
+
+       mutex_unlock(&mb1_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_get_arm_opp - get the current ARM OPP
+ *
+ * Returns: the current ARM OPP
+ */
+int prcmu_get_arm_opp(void)
+{
+       return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_ARM_OPP);
+}
+
+/**
+ * prcmu_get_ddr_opp - get the current DDR OPP
+ *
+ * Returns: the current DDR OPP
+ */
+int prcmu_get_ddr_opp(void)
+{
+       return readb(_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW);
+}
+
+/**
+ * set_ddr_opp - set the appropriate DDR OPP
+ * @opp: The new DDR operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the operating point of the DDR.
+ */
+int prcmu_set_ddr_opp(u8 opp)
+{
+       if (opp < DDR_100_OPP || opp > DDR_25_OPP)
+               return -EINVAL;
+       /* Changing the DDR OPP can hang the hardware pre-v21 */
+       if (cpu_is_u8500v20_or_later() && !cpu_is_u8500v20())
+               writeb(opp, (_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW));
+
+       return 0;
+}
+/**
+ * set_ape_opp - set the appropriate APE OPP
+ * @opp: The new APE operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the operating point of the APE.
+ */
+int prcmu_set_ape_opp(u8 opp)
+{
+       int r = 0;
+
+       mutex_lock(&mb1_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+       writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
+       writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) ||
+               (mb1_transfer.ack.ape_opp != opp))
+               r = -EIO;
+
+       mutex_unlock(&mb1_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_get_ape_opp - get the current APE OPP
+ *
+ * Returns: the current APE OPP
+ */
+int prcmu_get_ape_opp(void)
+{
+       return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
+}
+
+/**
+ * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
+ * @enable: true to request the higher voltage, false to drop a request.
+ *
+ * Calls to this function to enable and disable requests must be balanced.
+ */
+int prcmu_request_ape_opp_100_voltage(bool enable)
+{
+       int r = 0;
+       u8 header;
+       static unsigned int requests;
+
+       mutex_lock(&mb1_transfer.lock);
+
+       if (enable) {
+               if (0 != requests++)
+                       goto unlock_and_return;
+               header = MB1H_REQUEST_APE_OPP_100_VOLT;
+       } else {
+               if (requests == 0) {
+                       r = -EIO;
+                       goto unlock_and_return;
+               } else if (1 != requests--) {
+                       goto unlock_and_return;
+               }
+               header = MB1H_RELEASE_APE_OPP_100_VOLT;
+       }
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(header, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       if ((mb1_transfer.ack.header != header) ||
+               ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0))
+               r = -EIO;
+
+unlock_and_return:
+       mutex_unlock(&mb1_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_release_usb_wakeup_state - release the state required by a USB wakeup
+ *
+ * This function releases the power state requirements of a USB wakeup.
+ */
+int prcmu_release_usb_wakeup_state(void)
+{
+       int r = 0;
+
+       mutex_lock(&mb1_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(MB1H_RELEASE_USB_WAKEUP,
+               (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       if ((mb1_transfer.ack.header != MB1H_RELEASE_USB_WAKEUP) ||
+               ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0))
+               r = -EIO;
+
+       mutex_unlock(&mb1_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_set_epod - set the state of a EPOD (power domain)
+ * @epod_id: The EPOD to set
+ * @epod_state: The new EPOD state
+ *
+ * This function sets the state of a EPOD (power domain). It may not be called
+ * from interrupt context.
+ */
+int prcmu_set_epod(u16 epod_id, u8 epod_state)
+{
+       int r = 0;
+       bool ram_retention = false;
+       int i;
+
+       /* check argument */
+       BUG_ON(epod_id >= NUM_EPOD_ID);
+
+       /* set flag if retention is possible */
+       switch (epod_id) {
+       case EPOD_ID_SVAMMDSP:
+       case EPOD_ID_SIAMMDSP:
+       case EPOD_ID_ESRAM12:
+       case EPOD_ID_ESRAM34:
+               ram_retention = true;
+               break;
+       }
+
+       /* check argument */
+       BUG_ON(epod_state > EPOD_STATE_ON);
+       BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention);
+
+       /* get lock */
+       mutex_lock(&mb2_transfer.lock);
+
+       /* wait for mailbox */
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(2))
+               cpu_relax();
+
+       /* fill in mailbox */
+       for (i = 0; i < NUM_EPOD_ID; i++)
+               writeb(EPOD_STATE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB2 + i));
+       writeb(epod_state, (tcdm_base + PRCM_REQ_MB2 + epod_id));
+
+       writeb(MB2H_DPS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB2));
+
+       writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       /*
+        * The current firmware version does not handle errors correctly,
+        * and we cannot recover if there is an error.
+        * This is expected to change when the firmware is updated.
+        */
+       if (!wait_for_completion_timeout(&mb2_transfer.work,
+                       msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+               r = -EIO;
+               goto unlock_and_return;
+       }
+
+       if (mb2_transfer.ack.status != HWACC_PWR_ST_OK)
+               r = -EIO;
+
+unlock_and_return:
+       mutex_unlock(&mb2_transfer.lock);
+       return r;
+}
+
+/**
+ * prcmu_configure_auto_pm - Configure autonomous power management.
+ * @sleep: Configuration for ApSleep.
+ * @idle:  Configuration for ApIdle.
+ */
+void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
+       struct prcmu_auto_pm_config *idle)
+{
+       u32 sleep_cfg;
+       u32 idle_cfg;
+       unsigned long flags;
+
+       BUG_ON((sleep == NULL) || (idle == NULL));
+
+       sleep_cfg = (sleep->sva_auto_pm_enable & 0xF);
+       sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_auto_pm_enable & 0xF));
+       sleep_cfg = ((sleep_cfg << 8) | (sleep->sva_power_on & 0xFF));
+       sleep_cfg = ((sleep_cfg << 8) | (sleep->sia_power_on & 0xFF));
+       sleep_cfg = ((sleep_cfg << 4) | (sleep->sva_policy & 0xF));
+       sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_policy & 0xF));
+
+       idle_cfg = (idle->sva_auto_pm_enable & 0xF);
+       idle_cfg = ((idle_cfg << 4) | (idle->sia_auto_pm_enable & 0xF));
+       idle_cfg = ((idle_cfg << 8) | (idle->sva_power_on & 0xFF));
+       idle_cfg = ((idle_cfg << 8) | (idle->sia_power_on & 0xFF));
+       idle_cfg = ((idle_cfg << 4) | (idle->sva_policy & 0xF));
+       idle_cfg = ((idle_cfg << 4) | (idle->sia_policy & 0xF));
+
+       spin_lock_irqsave(&mb2_transfer.auto_pm_lock, flags);
+
+       /*
+        * The autonomous power management configuration is done through
+        * fields in mailbox 2, but these fields are only used as shared
+        * variables - i.e. there is no need to send a message.
+        */
+       writel(sleep_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_SLEEP));
+       writel(idle_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_IDLE));
+
+       mb2_transfer.auto_pm_enabled =
+               ((sleep->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
+                (sleep->sia_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
+                (idle->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
+                (idle->sia_auto_pm_enable == PRCMU_AUTO_PM_ON));
+
+       spin_unlock_irqrestore(&mb2_transfer.auto_pm_lock, flags);
+}
+EXPORT_SYMBOL(prcmu_configure_auto_pm);
+
+bool prcmu_is_auto_pm_enabled(void)
+{
+       return mb2_transfer.auto_pm_enabled;
+}
+
+static int request_sysclk(bool enable)
+{
+       int r;
+       unsigned long flags;
+
+       r = 0;
+
+       mutex_lock(&mb3_transfer.sysclk_lock);
+
+       spin_lock_irqsave(&mb3_transfer.lock, flags);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(3))
+               cpu_relax();
+
+       writeb((enable ? ON : OFF), (tcdm_base + PRCM_REQ_MB3_SYSCLK_MGT));
+
+       writeb(MB3H_SYSCLK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB3));
+       writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       spin_unlock_irqrestore(&mb3_transfer.lock, flags);
+
+       /*
+        * The firmware only sends an ACK if we want to enable the
+        * SysClk, and it succeeds.
+        */
+       if (enable && !wait_for_completion_timeout(&mb3_transfer.sysclk_work,
+                       msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+               r = -EIO;
+       }
+
+       mutex_unlock(&mb3_transfer.sysclk_lock);
+
+       return r;
+}
+
+static int request_timclk(bool enable)
+{
+       u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK);
+
+       if (!enable)
+               val |= PRCM_TCR_STOP_TIMERS;
+       writel(val, (_PRCMU_BASE + PRCM_TCR));
+
+       return 0;
+}
+
+static int request_reg_clock(u8 clock, bool enable)
+{
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+       if (enable) {
+               val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
+       } else {
+               clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
+               val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
+       }
+       writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+
+       /* Release the HW semaphore. */
+       writel(0, (_PRCMU_BASE + PRCM_SEM));
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+
+       return 0;
+}
+
+/**
+ * prcmu_request_clock() - Request for a clock to be enabled or disabled.
+ * @clock:      The clock for which the request is made.
+ * @enable:     Whether the clock should be enabled (true) or disabled (false).
+ *
+ * This function should only be used by the clock implementation.
+ * Do not use it from any other place!
+ */
+int prcmu_request_clock(u8 clock, bool enable)
+{
+       if (clock < PRCMU_NUM_REG_CLOCKS)
+               return request_reg_clock(clock, enable);
+       else if (clock == PRCMU_TIMCLK)
+               return request_timclk(enable);
+       else if (clock == PRCMU_SYSCLK)
+               return request_sysclk(enable);
+       else
+               return -EINVAL;
+}
+
+int prcmu_config_esram0_deep_sleep(u8 state)
+{
+       if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) ||
+           (state < ESRAM0_DEEP_SLEEP_STATE_OFF))
+               return -EINVAL;
+
+       mutex_lock(&mb4_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+               cpu_relax();
+
+       writeb(MB4H_MEM_ST, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+       writeb(((DDR_PWR_STATE_OFFHIGHLAT << 4) | DDR_PWR_STATE_ON),
+              (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE));
+       writeb(DDR_PWR_STATE_ON,
+              (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE));
+       writeb(state, (tcdm_base + PRCM_REQ_MB4_ESRAM0_ST));
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb4_transfer.work);
+
+       mutex_unlock(&mb4_transfer.lock);
+
+       return 0;
+}
+
+int prcmu_config_hotdog(u8 threshold)
+{
+       mutex_lock(&mb4_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+               cpu_relax();
+
+       writeb(threshold, (tcdm_base + PRCM_REQ_MB4_HOTDOG_THRESHOLD));
+       writeb(MB4H_HOTDOG, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb4_transfer.work);
+
+       mutex_unlock(&mb4_transfer.lock);
+
+       return 0;
+}
+
+int prcmu_config_hotmon(u8 low, u8 high)
+{
+       mutex_lock(&mb4_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+               cpu_relax();
+
+       writeb(low, (tcdm_base + PRCM_REQ_MB4_HOTMON_LOW));
+       writeb(high, (tcdm_base + PRCM_REQ_MB4_HOTMON_HIGH));
+       writeb((HOTMON_CONFIG_LOW | HOTMON_CONFIG_HIGH),
+               (tcdm_base + PRCM_REQ_MB4_HOTMON_CONFIG));
+       writeb(MB4H_HOTMON, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb4_transfer.work);
+
+       mutex_unlock(&mb4_transfer.lock);
+
+       return 0;
+}
+
+static int config_hot_period(u16 val)
+{
+       mutex_lock(&mb4_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+               cpu_relax();
+
+       writew(val, (tcdm_base + PRCM_REQ_MB4_HOT_PERIOD));
+       writeb(MB4H_HOT_PERIOD, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb4_transfer.work);
+
+       mutex_unlock(&mb4_transfer.lock);
+
+       return 0;
+}
+
+int prcmu_start_temp_sense(u16 cycles32k)
+{
+       if (cycles32k == 0xFFFF)
+               return -EINVAL;
+
+       return config_hot_period(cycles32k);
+}
+
+int prcmu_stop_temp_sense(void)
+{
+       return config_hot_period(0xFFFF);
+}
+
+/**
+ * prcmu_set_clock_divider() - Configure the clock divider.
+ * @clock:     The clock for which the request is made.
+ * @divider:   The clock divider. (< 32)
+ *
+ * This function should only be used by the clock implementation.
+ * Do not use it from any other place!
+ */
+int prcmu_set_clock_divider(u8 clock, u8 divider)
+{
+       u32 val;
+       unsigned long flags;
+
+       if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider))
+               return -EINVAL;
+
+       spin_lock_irqsave(&clk_mgt_lock, flags);
+
+       /* Grab the HW semaphore. */
+       while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+               cpu_relax();
+
+       val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+       val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK);
+       val |= (u32)divider;
+       writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+
+       /* Release the HW semaphore. */
+       writel(0, (_PRCMU_BASE + PRCM_SEM));
+
+       spin_unlock_irqrestore(&clk_mgt_lock, flags);
+
+       return 0;
+}
+
+/**
+ * prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The read out value(s).
+ * @size:      The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if (size != 1)
+               return -EINVAL;
+
+       mutex_lock(&mb5_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+
+       writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
+       writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
+       writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
+       writeb(0, (tcdm_base + PRCM_REQ_MB5_I2C_VAL));
+
+       writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       if (!wait_for_completion_timeout(&mb5_transfer.work,
+                               msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+               r = -EIO;
+       } else {
+               r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
+       }
+
+       if (!r)
+               *value = mb5_transfer.ack.value;
+
+       mutex_unlock(&mb5_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The value(s) to write.
+ * @size:      The number of registers to write.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if (size != 1)
+               return -EINVAL;
+
+       mutex_lock(&mb5_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+
+       writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
+       writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
+       writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
+       writeb(*value, (tcdm_base + PRCM_REQ_MB5_I2C_VAL));
+
+       writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       if (!wait_for_completion_timeout(&mb5_transfer.work,
+                               msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+               r = -EIO;
+       } else {
+               r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
+       }
+
+       mutex_unlock(&mb5_transfer.lock);
+
+       return r;
+}
+
+/**
+ * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
+ */
+void prcmu_ac_wake_req(void)
+{
+       u32 val;
+
+       mutex_lock(&mb0_transfer.ac_wake_lock);
+
+       val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ);
+       if (val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ)
+               goto unlock_and_return;
+
+       atomic_set(&ac_wake_req_state, 1);
+
+       writel((val | PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ),
+               (_PRCMU_BASE + PRCM_HOSTACCESS_REQ));
+
+       if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
+                       msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+       }
+
+unlock_and_return:
+       mutex_unlock(&mb0_transfer.ac_wake_lock);
+}
+
+/**
+ * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem
+ */
+void prcmu_ac_sleep_req()
+{
+       u32 val;
+
+       mutex_lock(&mb0_transfer.ac_wake_lock);
+
+       val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ);
+       if (!(val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ))
+               goto unlock_and_return;
+
+       writel((val & ~PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ),
+               (_PRCMU_BASE + PRCM_HOSTACCESS_REQ));
+
+       if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
+                       msecs_to_jiffies(20000))) {
+               pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+                       __func__);
+       }
+
+       atomic_set(&ac_wake_req_state, 0);
+
+unlock_and_return:
+       mutex_unlock(&mb0_transfer.ac_wake_lock);
+}
+
+bool prcmu_is_ac_wake_requested(void)
+{
+       return (atomic_read(&ac_wake_req_state) != 0);
+}
+
+/**
+ * prcmu_system_reset - System reset
+ *
+ * Saves the reset reason code and then sets the APE_SOFRST register which
+ * fires interrupt to fw
+ */
+void prcmu_system_reset(u16 reset_code)
+{
+       writew(reset_code, (tcdm_base + PRCM_SW_RST_REASON));
+       writel(1, (_PRCMU_BASE + PRCM_APE_SOFTRST));
+}
+
+/**
+ * prcmu_reset_modem - ask the PRCMU to reset modem
+ */
+void prcmu_modem_reset(void)
+{
+       mutex_lock(&mb1_transfer.lock);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+               cpu_relax();
+
+       writeb(MB1H_RESET_MODEM, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+       wait_for_completion(&mb1_transfer.work);
+
+       /*
+        * No need to check return from PRCMU as modem should go in reset state
+        * This state is already managed by upper layer
+        */
+
+       mutex_unlock(&mb1_transfer.lock);
+}
+
+static void ack_dbb_wakeup(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+               cpu_relax();
+
+       writeb(MB0H_READ_WAKEUP_ACK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
+       writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static inline void print_unknown_header_warning(u8 n, u8 header)
+{
+       pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+               header, n);
+}
+
+static bool read_mailbox_0(void)
+{
+       bool r;
+       u32 ev;
+       unsigned int n;
+       u8 header;
+
+       header = readb(tcdm_base + PRCM_MBOX_HEADER_ACK_MB0);
+       switch (header) {
+       case MB0H_WAKEUP_EXE:
+       case MB0H_WAKEUP_SLEEP:
+               if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1)
+                       ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_1_8500);
+               else
+                       ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_0_8500);
+
+               if (ev & (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK))
+                       complete(&mb0_transfer.ac_wake_work);
+               if (ev & WAKEUP_BIT_SYSCLK_OK)
+                       complete(&mb3_transfer.sysclk_work);
+
+               ev &= mb0_transfer.req.dbb_irqs;
+
+               for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) {
+                       if (ev & prcmu_irq_bit[n])
+                               generic_handle_irq(IRQ_PRCMU_BASE + n);
+               }
+               r = true;
+               break;
+       default:
+               print_unknown_header_warning(0, header);
+               r = false;
+               break;
+       }
+       writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       return r;
+}
+
+static bool read_mailbox_1(void)
+{
+       mb1_transfer.ack.header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB1);
+       mb1_transfer.ack.arm_opp = readb(tcdm_base +
+               PRCM_ACK_MB1_CURRENT_ARM_OPP);
+       mb1_transfer.ack.ape_opp = readb(tcdm_base +
+               PRCM_ACK_MB1_CURRENT_APE_OPP);
+       mb1_transfer.ack.ape_voltage_status = readb(tcdm_base +
+               PRCM_ACK_MB1_APE_VOLTAGE_STATUS);
+       writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       complete(&mb1_transfer.work);
+       return false;
+}
+
+static bool read_mailbox_2(void)
+{
+       mb2_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB2_DPS_STATUS);
+       writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       complete(&mb2_transfer.work);
+       return false;
+}
+
+static bool read_mailbox_3(void)
+{
+       writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       return false;
+}
+
+static bool read_mailbox_4(void)
+{
+       u8 header;
+       bool do_complete = true;
+
+       header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB4);
+       switch (header) {
+       case MB4H_MEM_ST:
+       case MB4H_HOTDOG:
+       case MB4H_HOTMON:
+       case MB4H_HOT_PERIOD:
+               break;
+       default:
+               print_unknown_header_warning(4, header);
+               do_complete = false;
+               break;
+       }
+
+       writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+
+       if (do_complete)
+               complete(&mb4_transfer.work);
+
+       return false;
+}
+
+static bool read_mailbox_5(void)
+{
+       mb5_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB5_I2C_STATUS);
+       mb5_transfer.ack.value = readb(tcdm_base + PRCM_ACK_MB5_I2C_VAL);
+       writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       complete(&mb5_transfer.work);
+       return false;
+}
+
+static bool read_mailbox_6(void)
+{
+       writel(MBOX_BIT(6), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       return false;
+}
+
+static bool read_mailbox_7(void)
+{
+       writel(MBOX_BIT(7), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+       return false;
+}
+
+static bool (* const read_mailbox[NUM_MB])(void) = {
+       read_mailbox_0,
+       read_mailbox_1,
+       read_mailbox_2,
+       read_mailbox_3,
+       read_mailbox_4,
+       read_mailbox_5,
+       read_mailbox_6,
+       read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+       u32 bits;
+       u8 n;
+       irqreturn_t r;
+
+       bits = (readl(_PRCMU_BASE + PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
+       if (unlikely(!bits))
+               return IRQ_NONE;
+
+       r = IRQ_HANDLED;
+       for (n = 0; bits; n++) {
+               if (bits & MBOX_BIT(n)) {
+                       bits -= MBOX_BIT(n);
+                       if (read_mailbox[n]())
+                               r = IRQ_WAKE_THREAD;
+               }
+       }
+       return r;
+}
+
+static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
+{
+       ack_dbb_wakeup();
+       return IRQ_HANDLED;
+}
+
+static void prcmu_mask_work(struct work_struct *work)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+       config_wakeups();
+
+       spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static void prcmu_irq_mask(struct irq_data *d)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
+
+       mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE];
+
+       spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
+
+       if (d->irq != IRQ_PRCMU_CA_SLEEP)
+               schedule_work(&mb0_transfer.mask_work);
+}
+
+static void prcmu_irq_unmask(struct irq_data *d)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
+
+       mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE];
+
+       spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
+
+       if (d->irq != IRQ_PRCMU_CA_SLEEP)
+               schedule_work(&mb0_transfer.mask_work);
+}
+
+static void noop(struct irq_data *d)
+{
+}
+
+static struct irq_chip prcmu_irq_chip = {
+       .name           = "prcmu",
+       .irq_disable    = prcmu_irq_mask,
+       .irq_ack        = noop,
+       .irq_mask       = prcmu_irq_mask,
+       .irq_unmask     = prcmu_irq_unmask,
+};
+
+void __init prcmu_early_init(void)
+{
+       unsigned int i;
+
+       if (cpu_is_u8500v1()) {
+               tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
+       } else if (cpu_is_u8500v2()) {
+               void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K);
+
+               if (tcpm_base != NULL) {
+                       int version;
+                       version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
+                       prcmu_version.project_number = version & 0xFF;
+                       prcmu_version.api_version = (version >> 8) & 0xFF;
+                       prcmu_version.func_version = (version >> 16) & 0xFF;
+                       prcmu_version.errata = (version >> 24) & 0xFF;
+                       pr_info("PRCMU firmware version %d.%d.%d\n",
+                               (version >> 8) & 0xFF, (version >> 16) & 0xFF,
+                               (version >> 24) & 0xFF);
+                       iounmap(tcpm_base);
+               }
+
+               tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
+       } else {
+               pr_err("prcmu: Unsupported chip version\n");
+               BUG();
+       }
+
+       spin_lock_init(&mb0_transfer.lock);
+       spin_lock_init(&mb0_transfer.dbb_irqs_lock);
+       mutex_init(&mb0_transfer.ac_wake_lock);
+       init_completion(&mb0_transfer.ac_wake_work);
+       mutex_init(&mb1_transfer.lock);
+       init_completion(&mb1_transfer.work);
+       mutex_init(&mb2_transfer.lock);
+       init_completion(&mb2_transfer.work);
+       spin_lock_init(&mb2_transfer.auto_pm_lock);
+       spin_lock_init(&mb3_transfer.lock);
+       mutex_init(&mb3_transfer.sysclk_lock);
+       init_completion(&mb3_transfer.sysclk_work);
+       mutex_init(&mb4_transfer.lock);
+       init_completion(&mb4_transfer.work);
+       mutex_init(&mb5_transfer.lock);
+       init_completion(&mb5_transfer.work);
+
+       INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
+
+       /* Initalize irqs. */
+       for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) {
+               unsigned int irq;
+
+               irq = IRQ_PRCMU_BASE + i;
+               irq_set_chip_and_handler(irq, &prcmu_irq_chip,
+                                        handle_simple_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+}
+
+/*
+ * Power domain switches (ePODs) modeled as regulators for the DB8500 SoC
+ */
+static struct regulator_consumer_supply db8500_vape_consumers[] = {
+       REGULATOR_SUPPLY("v-ape", NULL),
+       REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"),
+       REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"),
+       REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"),
+       REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"),
+       /* "v-mmc" changed to "vcore" in the mainline kernel */
+       REGULATOR_SUPPLY("vcore", "sdi0"),
+       REGULATOR_SUPPLY("vcore", "sdi1"),
+       REGULATOR_SUPPLY("vcore", "sdi2"),
+       REGULATOR_SUPPLY("vcore", "sdi3"),
+       REGULATOR_SUPPLY("vcore", "sdi4"),
+       REGULATOR_SUPPLY("v-dma", "dma40.0"),
+       REGULATOR_SUPPLY("v-ape", "ab8500-usb.0"),
+       /* "v-uart" changed to "vcore" in the mainline kernel */
+       REGULATOR_SUPPLY("vcore", "uart0"),
+       REGULATOR_SUPPLY("vcore", "uart1"),
+       REGULATOR_SUPPLY("vcore", "uart2"),
+       REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
+};
+
+static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
+       /* CG2900 and CW1200 power to off-chip peripherals */
+       REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"),
+       REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"),
+       REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
+       /* AV8100 regulator */
+       REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
+};
+
+static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
+       REGULATOR_SUPPLY("vsupply", "b2r2.0"),
+       REGULATOR_SUPPLY("vsupply", "mcde.0"),
+};
+
+static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
+       [DB8500_REGULATOR_VAPE] = {
+               .constraints = {
+                       .name = "db8500-vape",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+               .consumer_supplies = db8500_vape_consumers,
+               .num_consumer_supplies = ARRAY_SIZE(db8500_vape_consumers),
+       },
+       [DB8500_REGULATOR_VARM] = {
+               .constraints = {
+                       .name = "db8500-varm",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VMODEM] = {
+               .constraints = {
+                       .name = "db8500-vmodem",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VPLL] = {
+               .constraints = {
+                       .name = "db8500-vpll",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VSMPS1] = {
+               .constraints = {
+                       .name = "db8500-vsmps1",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VSMPS2] = {
+               .constraints = {
+                       .name = "db8500-vsmps2",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+               .consumer_supplies = db8500_vsmps2_consumers,
+               .num_consumer_supplies = ARRAY_SIZE(db8500_vsmps2_consumers),
+       },
+       [DB8500_REGULATOR_VSMPS3] = {
+               .constraints = {
+                       .name = "db8500-vsmps3",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_VRF1] = {
+               .constraints = {
+                       .name = "db8500-vrf1",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sva-mmdsp",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
+               .constraints = {
+                       /* "ret" means "retention" */
+                       .name = "db8500-sva-mmdsp-ret",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sva-pipe",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sia-mmdsp",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
+               .constraints = {
+                       .name = "db8500-sia-mmdsp-ret",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sia-pipe",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SGA] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-sga",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-b2r2-mcde",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+               .consumer_supplies = db8500_b2r2_mcde_consumers,
+               .num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM12] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-esram12",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
+               .constraints = {
+                       .name = "db8500-esram12-ret",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM34] = {
+               .supply_regulator = "db8500-vape",
+               .constraints = {
+                       .name = "db8500-esram34",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
+               .constraints = {
+                       .name = "db8500-esram34-ret",
+                       .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+               },
+       },
+};
+
+static struct mfd_cell db8500_prcmu_devs[] = {
+       {
+               .name = "db8500-prcmu-regulators",
+               .mfd_data = &db8500_regulators,
+       },
+       {
+               .name = "cpufreq-u8500",
+       },
+};
+
+/**
+ * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
+ *
+ */
+static int __init db8500_prcmu_probe(struct platform_device *pdev)
+{
+       int err = 0;
+
+       if (ux500_is_svp())
+               return -ENODEV;
+
+       /* Clean up the mailbox interrupts after pre-kernel code. */
+       writel(ALL_MBOX_BITS, (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+
+       err = request_threaded_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler,
+               prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
+       if (err < 0) {
+               pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n");
+               err = -EBUSY;
+               goto no_irq_return;
+       }
+
+       if (cpu_is_u8500v20_or_later())
+               prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
+
+       err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
+                             ARRAY_SIZE(db8500_prcmu_devs), NULL,
+                             0);
+
+       if (err)
+               pr_err("prcmu: Failed to add subdevices\n");
+       else
+               pr_info("DB8500 PRCMU initialized\n");
+
+no_irq_return:
+       return err;
+}
+
+static struct platform_driver db8500_prcmu_driver = {
+       .driver = {
+               .name = "db8500-prcmu",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init db8500_prcmu_init(void)
+{
+       return platform_driver_probe(&db8500_prcmu_driver, db8500_prcmu_probe);
+}
+
+arch_initcall(db8500_prcmu_init);
+
+MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com>");
+MODULE_DESCRIPTION("DB8500 PRCM Unit driver");
+MODULE_LICENSE("GPL v2");
index 61d233a7c1180e4b9fea129104ad60f631e60de2..71da5641e258e041cb9b72439d3d18eac9d9baa9 100644 (file)
 #include <linux/mutex.h>
 #include <linux/scatterlist.h>
 #include <linux/string_helpers.h>
+#include <linux/delay.h>
+#include <linux/capability.h>
+#include <linux/compat.h>
 
+#include <linux/mmc/ioctl.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
@@ -48,6 +52,13 @@ MODULE_ALIAS("mmc:block");
 #endif
 #define MODULE_PARAM_PREFIX "mmcblk."
 
+#define INAND_CMD38_ARG_EXT_CSD  113
+#define INAND_CMD38_ARG_ERASE    0x00
+#define INAND_CMD38_ARG_TRIM     0x01
+#define INAND_CMD38_ARG_SECERASE 0x80
+#define INAND_CMD38_ARG_SECTRIM1 0x81
+#define INAND_CMD38_ARG_SECTRIM2 0x88
+
 static DEFINE_MUTEX(block_mutex);
 
 /*
@@ -64,6 +75,7 @@ static int max_devices;
 
 /* 256 minors, so at most 256 separate devices */
 static DECLARE_BITMAP(dev_use, 256);
+static DECLARE_BITMAP(name_use, 256);
 
 /*
  * There is one mmc_blk_data per slot.
@@ -72,9 +84,24 @@ struct mmc_blk_data {
        spinlock_t      lock;
        struct gendisk  *disk;
        struct mmc_queue queue;
+       struct list_head part;
+
+       unsigned int    flags;
+#define MMC_BLK_CMD23  (1 << 0)        /* Can do SET_BLOCK_COUNT for multiblock */
+#define MMC_BLK_REL_WR (1 << 1)        /* MMC Reliable write support */
 
        unsigned int    usage;
        unsigned int    read_only;
+       unsigned int    part_type;
+       unsigned int    name_idx;
+
+       /*
+        * Only set in main mmc_blk_data associated
+        * with mmc_card with mmc_set_drvdata, and keeps
+        * track of the current selected device partition.
+        */
+       unsigned int    part_curr;
+       struct device_attribute force_ro;
 };
 
 static DEFINE_MUTEX(open_lock);
@@ -97,17 +124,22 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
        return md;
 }
 
+static inline int mmc_get_devidx(struct gendisk *disk)
+{
+       int devmaj = MAJOR(disk_devt(disk));
+       int devidx = MINOR(disk_devt(disk)) / perdev_minors;
+
+       if (!devmaj)
+               devidx = disk->first_minor / perdev_minors;
+       return devidx;
+}
+
 static void mmc_blk_put(struct mmc_blk_data *md)
 {
        mutex_lock(&open_lock);
        md->usage--;
        if (md->usage == 0) {
-               int devmaj = MAJOR(disk_devt(md->disk));
-               int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
-
-               if (!devmaj)
-                       devidx = md->disk->first_minor / perdev_minors;
-
+               int devidx = mmc_get_devidx(md->disk);
                blk_cleanup_queue(md->queue.queue);
 
                __clear_bit(devidx, dev_use);
@@ -118,6 +150,38 @@ static void mmc_blk_put(struct mmc_blk_data *md)
        mutex_unlock(&open_lock);
 }
 
+static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
+                            char *buf)
+{
+       int ret;
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+
+       ret = snprintf(buf, PAGE_SIZE, "%d",
+                      get_disk_ro(dev_to_disk(dev)) ^
+                      md->read_only);
+       mmc_blk_put(md);
+       return ret;
+}
+
+static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
+                             const char *buf, size_t count)
+{
+       int ret;
+       char *end;
+       struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+       unsigned long set = simple_strtoul(buf, &end, 0);
+       if (end == buf) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       set_disk_ro(dev_to_disk(dev), set || md->read_only);
+       ret = count;
+out:
+       mmc_blk_put(md);
+       return ret;
+}
+
 static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
 {
        struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -158,35 +222,255 @@ mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return 0;
 }
 
+struct mmc_blk_ioc_data {
+       struct mmc_ioc_cmd ic;
+       unsigned char *buf;
+       u64 buf_bytes;
+};
+
+static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
+       struct mmc_ioc_cmd __user *user)
+{
+       struct mmc_blk_ioc_data *idata;
+       int err;
+
+       idata = kzalloc(sizeof(*idata), GFP_KERNEL);
+       if (!idata) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       if (copy_from_user(&idata->ic, user, sizeof(idata->ic))) {
+               err = -EFAULT;
+               goto idata_err;
+       }
+
+       idata->buf_bytes = (u64) idata->ic.blksz * idata->ic.blocks;
+       if (idata->buf_bytes > MMC_IOC_MAX_BYTES) {
+               err = -EOVERFLOW;
+               goto idata_err;
+       }
+
+       idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
+       if (!idata->buf) {
+               err = -ENOMEM;
+               goto idata_err;
+       }
+
+       if (copy_from_user(idata->buf, (void __user *)(unsigned long)
+                                       idata->ic.data_ptr, idata->buf_bytes)) {
+               err = -EFAULT;
+               goto copy_err;
+       }
+
+       return idata;
+
+copy_err:
+       kfree(idata->buf);
+idata_err:
+       kfree(idata);
+out:
+       return ERR_PTR(err);
+}
+
+static int mmc_blk_ioctl_cmd(struct block_device *bdev,
+       struct mmc_ioc_cmd __user *ic_ptr)
+{
+       struct mmc_blk_ioc_data *idata;
+       struct mmc_blk_data *md;
+       struct mmc_card *card;
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
+       struct mmc_request mrq = {0};
+       struct scatterlist sg;
+       int err;
+
+       /*
+        * The caller must have CAP_SYS_RAWIO, and must be calling this on the
+        * whole block device, not on a partition.  This prevents overspray
+        * between sibling partitions.
+        */
+       if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
+               return -EPERM;
+
+       idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
+       if (IS_ERR(idata))
+               return PTR_ERR(idata);
+
+       cmd.opcode = idata->ic.opcode;
+       cmd.arg = idata->ic.arg;
+       cmd.flags = idata->ic.flags;
+
+       data.sg = &sg;
+       data.sg_len = 1;
+       data.blksz = idata->ic.blksz;
+       data.blocks = idata->ic.blocks;
+
+       sg_init_one(data.sg, idata->buf, idata->buf_bytes);
+
+       if (idata->ic.write_flag)
+               data.flags = MMC_DATA_WRITE;
+       else
+               data.flags = MMC_DATA_READ;
+
+       mrq.cmd = &cmd;
+       mrq.data = &data;
+
+       md = mmc_blk_get(bdev->bd_disk);
+       if (!md) {
+               err = -EINVAL;
+               goto cmd_done;
+       }
+
+       card = md->queue.card;
+       if (IS_ERR(card)) {
+               err = PTR_ERR(card);
+               goto cmd_done;
+       }
+
+       mmc_claim_host(card->host);
+
+       if (idata->ic.is_acmd) {
+               err = mmc_app_cmd(card->host, card);
+               if (err)
+                       goto cmd_rel_host;
+       }
+
+       /* data.flags must already be set before doing this. */
+       mmc_set_data_timeout(&data, card);
+       /* Allow overriding the timeout_ns for empirical tuning. */
+       if (idata->ic.data_timeout_ns)
+               data.timeout_ns = idata->ic.data_timeout_ns;
+
+       if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
+               /*
+                * Pretend this is a data transfer and rely on the host driver
+                * to compute timeout.  When all host drivers support
+                * cmd.cmd_timeout for R1B, this can be changed to:
+                *
+                *     mrq.data = NULL;
+                *     cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
+                */
+               data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
+       }
+
+       mmc_wait_for_req(card->host, &mrq);
+
+       if (cmd.error) {
+               dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
+                                               __func__, cmd.error);
+               err = cmd.error;
+               goto cmd_rel_host;
+       }
+       if (data.error) {
+               dev_err(mmc_dev(card->host), "%s: data error %d\n",
+                                               __func__, data.error);
+               err = data.error;
+               goto cmd_rel_host;
+       }
+
+       /*
+        * According to the SD specs, some commands require a delay after
+        * issuing the command.
+        */
+       if (idata->ic.postsleep_min_us)
+               usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
+
+       if (copy_to_user(&(ic_ptr->response), cmd.resp, sizeof(cmd.resp))) {
+               err = -EFAULT;
+               goto cmd_rel_host;
+       }
+
+       if (!idata->ic.write_flag) {
+               if (copy_to_user((void __user *)(unsigned long) idata->ic.data_ptr,
+                                               idata->buf, idata->buf_bytes)) {
+                       err = -EFAULT;
+                       goto cmd_rel_host;
+               }
+       }
+
+cmd_rel_host:
+       mmc_release_host(card->host);
+
+cmd_done:
+       mmc_blk_put(md);
+       kfree(idata->buf);
+       kfree(idata);
+       return err;
+}
+
+static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
+       unsigned int cmd, unsigned long arg)
+{
+       int ret = -EINVAL;
+       if (cmd == MMC_IOC_CMD)
+               ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg);
+       return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static int mmc_blk_compat_ioctl(struct block_device *bdev, fmode_t mode,
+       unsigned int cmd, unsigned long arg)
+{
+       return mmc_blk_ioctl(bdev, mode, cmd, (unsigned long) compat_ptr(arg));
+}
+#endif
+
 static const struct block_device_operations mmc_bdops = {
        .open                   = mmc_blk_open,
        .release                = mmc_blk_release,
        .getgeo                 = mmc_blk_getgeo,
        .owner                  = THIS_MODULE,
+       .ioctl                  = mmc_blk_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl           = mmc_blk_compat_ioctl,
+#endif
 };
 
 struct mmc_blk_request {
        struct mmc_request      mrq;
+       struct mmc_command      sbc;
        struct mmc_command      cmd;
        struct mmc_command      stop;
        struct mmc_data         data;
 };
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+                                     struct mmc_blk_data *md)
+{
+       int ret;
+       struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+       if (main_md->part_curr == md->part_type)
+               return 0;
+
+       if (mmc_card_mmc(card)) {
+               card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+               card->ext_csd.part_config |= md->part_type;
+
+               ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+                                card->ext_csd.part_time);
+               if (ret)
+                       return ret;
+}
+
+       main_md->part_curr = md->part_type;
+       return 0;
+}
+
 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 {
        int err;
        u32 result;
        __be32 *blocks;
 
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        unsigned int timeout_us;
 
        struct scatterlist sg;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_APP_CMD;
        cmd.arg = card->rca << 16;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
@@ -203,8 +487,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
        cmd.arg = 0;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
-       memset(&data, 0, sizeof(struct mmc_data));
-
        data.timeout_ns = card->csd.tacc_ns * 100;
        data.timeout_clks = card->csd.tacc_clks * 100;
 
@@ -223,8 +505,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
        data.sg = &sg;
        data.sg_len = 1;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
@@ -247,10 +527,9 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 
 static u32 get_card_status(struct mmc_card *card, struct request *req)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
        cmd.opcode = MMC_SEND_STATUS;
        if (!mmc_host_is_spi(card->host))
                cmd.arg = card->rca << 16;
@@ -269,8 +548,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
        unsigned int from, nr, arg;
        int err = 0;
 
-       mmc_claim_host(card->host);
-
        if (!mmc_can_erase(card)) {
                err = -EOPNOTSUPP;
                goto out;
@@ -284,14 +561,22 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
        else
                arg = MMC_ERASE_ARG;
 
+       if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                INAND_CMD38_ARG_EXT_CSD,
+                                arg == MMC_TRIM_ARG ?
+                                INAND_CMD38_ARG_TRIM :
+                                INAND_CMD38_ARG_ERASE,
+                                0);
+               if (err)
+                       goto out;
+       }
        err = mmc_erase(card, from, nr, arg);
 out:
        spin_lock_irq(&md->lock);
        __blk_end_request(req, err, blk_rq_bytes(req));
        spin_unlock_irq(&md->lock);
 
-       mmc_release_host(card->host);
-
        return err ? 0 : 1;
 }
 
@@ -303,8 +588,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
        unsigned int from, nr, arg;
        int err = 0;
 
-       mmc_claim_host(card->host);
-
        if (!mmc_can_secure_erase_trim(card)) {
                err = -EOPNOTSUPP;
                goto out;
@@ -318,19 +601,74 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
        else
                arg = MMC_SECURE_ERASE_ARG;
 
+       if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                INAND_CMD38_ARG_EXT_CSD,
+                                arg == MMC_SECURE_TRIM1_ARG ?
+                                INAND_CMD38_ARG_SECTRIM1 :
+                                INAND_CMD38_ARG_SECERASE,
+                                0);
+               if (err)
+                       goto out;
+       }
        err = mmc_erase(card, from, nr, arg);
-       if (!err && arg == MMC_SECURE_TRIM1_ARG)
+       if (!err && arg == MMC_SECURE_TRIM1_ARG) {
+               if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                        INAND_CMD38_ARG_EXT_CSD,
+                                        INAND_CMD38_ARG_SECTRIM2,
+                                        0);
+                       if (err)
+                               goto out;
+               }
                err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
+       }
 out:
        spin_lock_irq(&md->lock);
        __blk_end_request(req, err, blk_rq_bytes(req));
        spin_unlock_irq(&md->lock);
 
-       mmc_release_host(card->host);
-
        return err ? 0 : 1;
 }
 
+static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
+{
+       struct mmc_blk_data *md = mq->data;
+
+       /*
+        * No-op, only service this because we need REQ_FUA for reliable
+        * writes.
+        */
+       spin_lock_irq(&md->lock);
+       __blk_end_request_all(req, 0);
+       spin_unlock_irq(&md->lock);
+
+       return 1;
+}
+
+/*
+ * Reformat current write as a reliable write, supporting
+ * both legacy and the enhanced reliable write MMC cards.
+ * In each transfer we'll handle only as much as a single
+ * reliable write can handle, thus finish the request in
+ * partial completions.
+ */
+static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
+                                   struct mmc_card *card,
+                                   struct request *req)
+{
+       if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN)) {
+               /* Legacy mode imposes restrictions on transfers. */
+               if (!IS_ALIGNED(brq->cmd.arg, card->ext_csd.rel_sectors))
+                       brq->data.blocks = 1;
+
+               if (brq->data.blocks > card->ext_csd.rel_sectors)
+                       brq->data.blocks = card->ext_csd.rel_sectors;
+               else if (brq->data.blocks < card->ext_csd.rel_sectors)
+                       brq->data.blocks = 1;
+       }
+}
+
 static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 {
        struct mmc_blk_data *md = mq->data;
@@ -338,10 +676,17 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
        struct mmc_blk_request brq;
        int ret = 1, disable_multi = 0;
 
-       mmc_claim_host(card->host);
+       /*
+        * Reliable writes are used to implement Forced Unit Access and
+        * REQ_META accesses, and are supported only on MMCs.
+        */
+       bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
+                         (req->cmd_flags & REQ_META)) &&
+               (rq_data_dir(req) == WRITE) &&
+               (md->flags & MMC_BLK_REL_WR);
 
        do {
-               struct mmc_command cmd;
+               struct mmc_command cmd = {0};
                u32 readcmd, writecmd, status = 0;
 
                memset(&brq, 0, sizeof(struct mmc_blk_request));
@@ -374,12 +719,12 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                if (disable_multi && brq.data.blocks > 1)
                        brq.data.blocks = 1;
 
-               if (brq.data.blocks > 1) {
+               if (brq.data.blocks > 1 || do_rel_wr) {
                        /* SPI multiblock writes terminate using a special
                         * token, not a STOP_TRANSMISSION request.
                         */
-                       if (!mmc_host_is_spi(card->host)
-                                       || rq_data_dir(req) == READ)
+                       if (!mmc_host_is_spi(card->host) ||
+                           rq_data_dir(req) == READ)
                                brq.mrq.stop = &brq.stop;
                        readcmd = MMC_READ_MULTIPLE_BLOCK;
                        writecmd = MMC_WRITE_MULTIPLE_BLOCK;
@@ -396,6 +741,38 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                        brq.data.flags |= MMC_DATA_WRITE;
                }
 
+               if (do_rel_wr)
+                       mmc_apply_rel_rw(&brq, card, req);
+
+               /*
+                * Pre-defined multi-block transfers are preferable to
+                * open ended-ones (and necessary for reliable writes).
+                * However, it is not sufficient to just send CMD23,
+                * and avoid the final CMD12, as on an error condition
+                * CMD12 (stop) needs to be sent anyway. This, coupled
+                * with Auto-CMD23 enhancements provided by some
+                * hosts, means that the complexity of dealing
+                * with this is best left to the host. If CMD23 is
+                * supported by card and host, we'll fill sbc in and let
+                * the host deal with handling it correctly. This means
+                * that for hosts that don't expose MMC_CAP_CMD23, no
+                * change of behavior will be observed.
+                *
+                * N.B: Some MMC cards experience perf degradation.
+                * We'll avoid using CMD23-bounded multiblock writes for
+                * these, while retaining features like reliable writes.
+                */
+
+               if ((md->flags & MMC_BLK_CMD23) &&
+                   mmc_op_multi(brq.cmd.opcode) &&
+                   (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+                       brq.sbc.opcode = MMC_SET_BLOCK_COUNT;
+                       brq.sbc.arg = brq.data.blocks |
+                               (do_rel_wr ? (1 << 31) : 0);
+                       brq.sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+                       brq.mrq.sbc = &brq.sbc;
+               }
+
                mmc_set_data_timeout(&brq.data, card);
 
                brq.data.sg = mq->sg;
@@ -431,7 +808,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                 * until later as we need to wait for the card to leave
                 * programming mode even when things go wrong.
                 */
-               if (brq.cmd.error || brq.data.error || brq.stop.error) {
+               if (brq.sbc.error || brq.cmd.error ||
+                   brq.data.error || brq.stop.error) {
                        if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
                                /* Redo read one sector at a time */
                                printk(KERN_WARNING "%s: retrying using single "
@@ -442,6 +820,13 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                        status = get_card_status(card, req);
                }
 
+               if (brq.sbc.error) {
+                       printk(KERN_ERR "%s: error %d sending SET_BLOCK_COUNT "
+                              "command, response %#x, card status %#x\n",
+                              req->rq_disk->disk_name, brq.sbc.error,
+                              brq.sbc.resp[0], status);
+               }
+
                if (brq.cmd.error) {
                        printk(KERN_ERR "%s: error %d sending read/write "
                               "command, response %#x, card status %#x\n",
@@ -520,8 +905,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                spin_unlock_irq(&md->lock);
        } while (ret);
 
-       mmc_release_host(card->host);
-
        return 1;
 
  cmd_err:
@@ -548,8 +931,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                spin_unlock_irq(&md->lock);
        }
 
-       mmc_release_host(card->host);
-
        spin_lock_irq(&md->lock);
        while (ret)
                ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -560,14 +941,31 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
 
 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 {
+       int ret;
+       struct mmc_blk_data *md = mq->data;
+       struct mmc_card *card = md->queue.card;
+
+       mmc_claim_host(card->host);
+       ret = mmc_blk_part_switch(card, md);
+       if (ret) {
+               ret = 0;
+               goto out;
+       }
+
        if (req->cmd_flags & REQ_DISCARD) {
                if (req->cmd_flags & REQ_SECURE)
-                       return mmc_blk_issue_secdiscard_rq(mq, req);
+                       ret = mmc_blk_issue_secdiscard_rq(mq, req);
                else
-                       return mmc_blk_issue_discard_rq(mq, req);
+                       ret = mmc_blk_issue_discard_rq(mq, req);
+       } else if (req->cmd_flags & REQ_FLUSH) {
+               ret = mmc_blk_issue_flush(mq, req);
        } else {
-               return mmc_blk_issue_rw_rq(mq, req);
+               ret = mmc_blk_issue_rw_rq(mq, req);
        }
+
+out:
+       mmc_release_host(card->host);
+       return ret;
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -576,7 +974,11 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
               !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+                                             struct device *parent,
+                                             sector_t size,
+                                             bool default_ro,
+                                             const char *subname)
 {
        struct mmc_blk_data *md;
        int devidx, ret;
@@ -592,6 +994,19 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
                goto out;
        }
 
+       /*
+        * !subname implies we are creating main mmc_blk_data that will be
+        * associated with mmc_card with mmc_set_drvdata. Due to device
+        * partitions, devidx will not coincide with a per-physical card
+        * index anymore so we keep track of a name index.
+        */
+       if (!subname) {
+               md->name_idx = find_first_zero_bit(name_use, max_devices);
+               __set_bit(md->name_idx, name_use);
+       }
+       else
+               md->name_idx = ((struct mmc_blk_data *)
+                               dev_to_disk(parent)->private_data)->name_idx;
 
        /*
         * Set the read-only status based on the supported commands
@@ -606,6 +1021,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
        }
 
        spin_lock_init(&md->lock);
+       INIT_LIST_HEAD(&md->part);
        md->usage = 1;
 
        ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -620,8 +1036,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
        md->disk->fops = &mmc_bdops;
        md->disk->private_data = md;
        md->disk->queue = md->queue.queue;
-       md->disk->driverfs_dev = &card->dev;
-       set_disk_ro(md->disk, md->read_only);
+       md->disk->driverfs_dev = parent;
+       set_disk_ro(md->disk, md->read_only || default_ro);
 
        /*
         * As discussed on lkml, GENHD_FL_REMOVABLE should:
@@ -636,32 +1052,107 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
         */
 
        snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
-               "mmcblk%d", devidx);
+                "mmcblk%d%s", md->name_idx, subname ? subname : "");
 
        blk_queue_logical_block_size(md->queue.queue, 512);
+       set_capacity(md->disk, size);
+
+       if (mmc_host_cmd23(card->host)) {
+               if (mmc_card_mmc(card) ||
+                   (mmc_card_sd(card) &&
+                    card->scr.cmds & SD_SCR_CMD23_SUPPORT))
+                       md->flags |= MMC_BLK_CMD23;
+       }
+
+       if (mmc_card_mmc(card) &&
+           md->flags & MMC_BLK_CMD23 &&
+           ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||
+            card->ext_csd.rel_sectors)) {
+               md->flags |= MMC_BLK_REL_WR;
+               blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
+       }
+
+       return md;
+
+ err_putdisk:
+       put_disk(md->disk);
+ err_kfree:
+       kfree(md);
+ out:
+       return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+       sector_t size;
+       struct mmc_blk_data *md;
 
        if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
                /*
                 * The EXT_CSD sector count is in number or 512 byte
                 * sectors.
                 */
-               set_capacity(md->disk, card->ext_csd.sectors);
+               size = card->ext_csd.sectors;
        } else {
                /*
                 * The CSD capacity field is in units of read_blkbits.
                 * set_capacity takes units of 512 bytes.
                 */
-               set_capacity(md->disk,
-                       card->csd.capacity << (card->csd.read_blkbits - 9));
+               size = card->csd.capacity << (card->csd.read_blkbits - 9);
        }
+
+       md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
        return md;
+}
 
- err_putdisk:
-       put_disk(md->disk);
- err_kfree:
-       kfree(md);
- out:
-       return ERR_PTR(ret);
+static int mmc_blk_alloc_part(struct mmc_card *card,
+                             struct mmc_blk_data *md,
+                             unsigned int part_type,
+                             sector_t size,
+                             bool default_ro,
+                             const char *subname)
+{
+       char cap_str[10];
+       struct mmc_blk_data *part_md;
+
+       part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
+                                   subname);
+       if (IS_ERR(part_md))
+               return PTR_ERR(part_md);
+       part_md->part_type = part_type;
+       list_add(&part_md->part, &md->part);
+
+       string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+                       cap_str, sizeof(cap_str));
+       printk(KERN_INFO "%s: %s %s partition %u %s\n",
+              part_md->disk->disk_name, mmc_card_id(card),
+              mmc_card_name(card), part_md->part_type, cap_str);
+       return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+       int ret = 0;
+
+       if (!mmc_card_mmc(card))
+               return 0;
+
+       if (card->ext_csd.boot_size) {
+               ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0,
+                                        card->ext_csd.boot_size >> 9,
+                                        true,
+                                        "boot0");
+               if (ret)
+                       return ret;
+               ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1,
+                                        card->ext_csd.boot_size >> 9,
+                                        true,
+                                        "boot1");
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
 }
 
 static int
@@ -682,9 +1173,81 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
        return 0;
 }
 
+static void mmc_blk_remove_req(struct mmc_blk_data *md)
+{
+       if (md) {
+               if (md->disk->flags & GENHD_FL_UP) {
+                       device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+
+                       /* Stop new requests from getting into the queue */
+                       del_gendisk(md->disk);
+               }
+
+               /* Then flush out any already in there */
+               mmc_cleanup_queue(&md->queue);
+               mmc_blk_put(md);
+       }
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+                                struct mmc_blk_data *md)
+{
+       struct list_head *pos, *q;
+       struct mmc_blk_data *part_md;
+
+       __clear_bit(md->name_idx, name_use);
+       list_for_each_safe(pos, q, &md->part) {
+               part_md = list_entry(pos, struct mmc_blk_data, part);
+               list_del(pos);
+               mmc_blk_remove_req(part_md);
+       }
+}
+
+static int mmc_add_disk(struct mmc_blk_data *md)
+{
+       int ret;
+
+       add_disk(md->disk);
+       md->force_ro.show = force_ro_show;
+       md->force_ro.store = force_ro_store;
+       sysfs_attr_init(&md->force_ro.attr);
+       md->force_ro.attr.name = "force_ro";
+       md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
+       ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
+       if (ret)
+               del_gendisk(md->disk);
+
+       return ret;
+}
+
+static const struct mmc_fixup blk_fixups[] =
+{
+       MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+       MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+
+       /*
+        * Some MMC cards experience performance degradation with CMD23
+        * instead of CMD12-bounded multiblock transfers. For now we'll
+        * black list what's bad...
+        * - Certain Toshiba cards.
+        *
+        * N.B. This doesn't affect SD cards.
+        */
+       MMC_FIXUP("MMC08G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       MMC_FIXUP("MMC16G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+                 MMC_QUIRK_BLK_NO_CMD23),
+       END_FIXUP
+};
+
 static int mmc_blk_probe(struct mmc_card *card)
 {
-       struct mmc_blk_data *md;
+       struct mmc_blk_data *md, *part_md;
        int err;
        char cap_str[10];
 
@@ -708,14 +1271,24 @@ static int mmc_blk_probe(struct mmc_card *card)
                md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
                cap_str, md->read_only ? "(ro)" : "");
 
+       if (mmc_blk_alloc_parts(card, md))
+               goto out;
+
        mmc_set_drvdata(card, md);
-       add_disk(md->disk);
+       mmc_fixup_device(card, blk_fixups);
+
+       if (mmc_add_disk(md))
+               goto out;
+
+       list_for_each_entry(part_md, &md->part, part) {
+               if (mmc_add_disk(part_md))
+                       goto out;
+       }
        return 0;
 
  out:
-       mmc_cleanup_queue(&md->queue);
-       mmc_blk_put(md);
-
+       mmc_blk_remove_parts(card, md);
+       mmc_blk_remove_req(md);
        return err;
 }
 
@@ -723,36 +1296,43 @@ static void mmc_blk_remove(struct mmc_card *card)
 {
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
-       if (md) {
-               /* Stop new requests from getting into the queue */
-               del_gendisk(md->disk);
-
-               /* Then flush out any already in there */
-               mmc_cleanup_queue(&md->queue);
-
-               mmc_blk_put(md);
-       }
+       mmc_blk_remove_parts(card, md);
+       mmc_blk_remove_req(md);
        mmc_set_drvdata(card, NULL);
 }
 
 #ifdef CONFIG_PM
 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
 {
+       struct mmc_blk_data *part_md;
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
        if (md) {
                mmc_queue_suspend(&md->queue);
+               list_for_each_entry(part_md, &md->part, part) {
+                       mmc_queue_suspend(&part_md->queue);
+               }
        }
        return 0;
 }
 
 static int mmc_blk_resume(struct mmc_card *card)
 {
+       struct mmc_blk_data *part_md;
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
        if (md) {
                mmc_blk_set_blksize(md, card);
+
+               /*
+                * Resume involves the card going into idle state,
+                * so current partition is always the main one.
+                */
+               md->part_curr = md->part_type;
                mmc_queue_resume(&md->queue);
+               list_for_each_entry(part_md, &md->part, part) {
+                       mmc_queue_resume(&part_md->queue);
+               }
        }
        return 0;
 }
index abc1a63bcc5ee9f0ceb1c76ded78fda2b4fd5f97..233cdfae92f4bdff7c814737ad2c6a4a4dd1c26e 100644 (file)
@@ -212,7 +212,7 @@ static int mmc_test_busy(struct mmc_command *cmd)
 static int mmc_test_wait_busy(struct mmc_test_card *test)
 {
        int ret, busy;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        busy = 0;
        do {
@@ -246,18 +246,13 @@ static int mmc_test_buffer_transfer(struct mmc_test_card *test,
 {
        int ret;
 
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_command stop;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_command stop = {0};
+       struct mmc_data data = {0};
 
        struct scatterlist sg;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-       memset(&stop, 0, sizeof(struct mmc_command));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
        mrq.stop = &stop;
@@ -731,15 +726,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
        struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
        unsigned blocks, unsigned blksz, int write)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_command stop;
-       struct mmc_data data;
-
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-       memset(&stop, 0, sizeof(struct mmc_command));
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_command stop = {0};
+       struct mmc_data data = {0};
 
        mrq.cmd = &cmd;
        mrq.data = &data;
@@ -761,18 +751,13 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
 static int mmc_test_broken_transfer(struct mmc_test_card *test,
        unsigned blocks, unsigned blksz, int write)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_command stop;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_command stop = {0};
+       struct mmc_data data = {0};
 
        struct scatterlist sg;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-       memset(&stop, 0, sizeof(struct mmc_command));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
        mrq.stop = &stop;
@@ -1401,8 +1386,9 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
  */
 static int mmc_test_area_fill(struct mmc_test_card *test)
 {
-       return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
-                               1, 0, 0);
+       struct mmc_test_area *t = &test->area;
+
+       return mmc_test_area_io(test, t->max_tfr, t->dev_addr, 1, 0, 0);
 }
 
 /*
@@ -1415,7 +1401,7 @@ static int mmc_test_area_erase(struct mmc_test_card *test)
        if (!mmc_can_erase(test->card))
                return 0;
 
-       return mmc_erase(test->card, t->dev_addr, test->area.max_sz >> 9,
+       return mmc_erase(test->card, t->dev_addr, t->max_sz >> 9,
                         MMC_ERASE_ARG);
 }
 
@@ -1542,8 +1528,10 @@ static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
 static int mmc_test_best_performance(struct mmc_test_card *test, int write,
                                     int max_scatter)
 {
-       return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
-                               write, max_scatter, 1);
+       struct mmc_test_area *t = &test->area;
+
+       return mmc_test_area_io(test, t->max_tfr, t->dev_addr, write,
+                               max_scatter, 1);
 }
 
 /*
@@ -1583,18 +1571,19 @@ static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test)
  */
 static int mmc_test_profile_read_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        unsigned int dev_addr;
        int ret;
 
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
-               dev_addr = test->area.dev_addr + (sz >> 9);
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
+               dev_addr = t->dev_addr + (sz >> 9);
                ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
                if (ret)
                        return ret;
        }
-       sz = test->area.max_tfr;
-       dev_addr = test->area.dev_addr;
+       sz = t->max_tfr;
+       dev_addr = t->dev_addr;
        return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
 }
 
@@ -1603,6 +1592,7 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test)
  */
 static int mmc_test_profile_write_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        unsigned int dev_addr;
        int ret;
@@ -1610,8 +1600,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
-               dev_addr = test->area.dev_addr + (sz >> 9);
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
+               dev_addr = t->dev_addr + (sz >> 9);
                ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
                if (ret)
                        return ret;
@@ -1619,8 +1609,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
-       sz = test->area.max_tfr;
-       dev_addr = test->area.dev_addr;
+       sz = t->max_tfr;
+       dev_addr = t->dev_addr;
        return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
 }
 
@@ -1629,6 +1619,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
  */
 static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        unsigned int dev_addr;
        struct timespec ts1, ts2;
@@ -1640,8 +1631,8 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
        if (!mmc_can_erase(test->card))
                return RESULT_UNSUP_HOST;
 
-       for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
-               dev_addr = test->area.dev_addr + (sz >> 9);
+       for (sz = 512; sz < t->max_sz; sz <<= 1) {
+               dev_addr = t->dev_addr + (sz >> 9);
                getnstimeofday(&ts1);
                ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
                if (ret)
@@ -1649,7 +1640,7 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
                getnstimeofday(&ts2);
                mmc_test_print_rate(test, sz, &ts1, &ts2);
        }
-       dev_addr = test->area.dev_addr;
+       dev_addr = t->dev_addr;
        getnstimeofday(&ts1);
        ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
        if (ret)
@@ -1661,12 +1652,13 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
 
 static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned int dev_addr, i, cnt;
        struct timespec ts1, ts2;
        int ret;
 
-       cnt = test->area.max_sz / sz;
-       dev_addr = test->area.dev_addr;
+       cnt = t->max_sz / sz;
+       dev_addr = t->dev_addr;
        getnstimeofday(&ts1);
        for (i = 0; i < cnt; i++) {
                ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
@@ -1684,20 +1676,22 @@ static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
  */
 static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        int ret;
 
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
                ret = mmc_test_seq_read_perf(test, sz);
                if (ret)
                        return ret;
        }
-       sz = test->area.max_tfr;
+       sz = t->max_tfr;
        return mmc_test_seq_read_perf(test, sz);
 }
 
 static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned int dev_addr, i, cnt;
        struct timespec ts1, ts2;
        int ret;
@@ -1705,8 +1699,8 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
-       cnt = test->area.max_sz / sz;
-       dev_addr = test->area.dev_addr;
+       cnt = t->max_sz / sz;
+       dev_addr = t->dev_addr;
        getnstimeofday(&ts1);
        for (i = 0; i < cnt; i++) {
                ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
@@ -1724,15 +1718,16 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
  */
 static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        int ret;
 
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
                ret = mmc_test_seq_write_perf(test, sz);
                if (ret)
                        return ret;
        }
-       sz = test->area.max_tfr;
+       sz = t->max_tfr;
        return mmc_test_seq_write_perf(test, sz);
 }
 
@@ -1741,6 +1736,7 @@ static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
  */
 static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned long sz;
        unsigned int dev_addr, i, cnt;
        struct timespec ts1, ts2;
@@ -1752,15 +1748,15 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
        if (!mmc_can_erase(test->card))
                return RESULT_UNSUP_HOST;
 
-       for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
+       for (sz = 512; sz <= t->max_sz; sz <<= 1) {
                ret = mmc_test_area_erase(test);
                if (ret)
                        return ret;
                ret = mmc_test_area_fill(test);
                if (ret)
                        return ret;
-               cnt = test->area.max_sz / sz;
-               dev_addr = test->area.dev_addr;
+               cnt = t->max_sz / sz;
+               dev_addr = t->dev_addr;
                getnstimeofday(&ts1);
                for (i = 0; i < cnt; i++) {
                        ret = mmc_erase(test->card, dev_addr, sz >> 9,
@@ -1823,11 +1819,12 @@ static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
 
 static int mmc_test_random_perf(struct mmc_test_card *test, int write)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned int next;
        unsigned long sz;
        int ret;
 
-       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+       for (sz = 512; sz < t->max_tfr; sz <<= 1) {
                /*
                 * When writing, try to get more consistent results by running
                 * the test twice with exactly the same I/O but outputting the
@@ -1844,7 +1841,7 @@ static int mmc_test_random_perf(struct mmc_test_card *test, int write)
                if (ret)
                        return ret;
        }
-       sz = test->area.max_tfr;
+       sz = t->max_tfr;
        if (write) {
                next = rnd_next;
                ret = mmc_test_rnd_perf(test, write, 0, sz);
@@ -1874,17 +1871,18 @@ static int mmc_test_random_write_perf(struct mmc_test_card *test)
 static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
                             unsigned int tot_sz, int max_scatter)
 {
+       struct mmc_test_area *t = &test->area;
        unsigned int dev_addr, i, cnt, sz, ssz;
        struct timespec ts1, ts2;
        int ret;
 
-       sz = test->area.max_tfr;
+       sz = t->max_tfr;
+
        /*
         * In the case of a maximally scattered transfer, the maximum transfer
         * size is further limited by using PAGE_SIZE segments.
         */
        if (max_scatter) {
-               struct mmc_test_area *t = &test->area;
                unsigned long max_tfr;
 
                if (t->max_seg_sz >= PAGE_SIZE)
index 2ae727568df92b9edeaf330ea46751d6e0493474..c07322c2658cd171049bf59d4325f2e04ae2a90c 100644 (file)
@@ -343,18 +343,14 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
  */
 void mmc_queue_bounce_pre(struct mmc_queue *mq)
 {
-       unsigned long flags;
-
        if (!mq->bounce_buf)
                return;
 
        if (rq_data_dir(mq->req) != WRITE)
                return;
 
-       local_irq_save(flags);
        sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
                mq->bounce_buf, mq->sg[0].length);
-       local_irq_restore(flags);
 }
 
 /*
@@ -363,17 +359,13 @@ void mmc_queue_bounce_pre(struct mmc_queue *mq)
  */
 void mmc_queue_bounce_post(struct mmc_queue *mq)
 {
-       unsigned long flags;
-
        if (!mq->bounce_buf)
                return;
 
        if (rq_data_dir(mq->req) != READ)
                return;
 
-       local_irq_save(flags);
        sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
                mq->bounce_buf, mq->sg[0].length);
-       local_irq_restore(flags);
 }
 
index d6d62fd07ee9fd0b492d6c7e0a80d116840009b2..393d817ed04076dca934511f4522b698776073ae 100644 (file)
@@ -274,8 +274,12 @@ int mmc_add_card(struct mmc_card *card)
                break;
        case MMC_TYPE_SD:
                type = "SD";
-               if (mmc_card_blockaddr(card))
-                       type = "SDHC";
+               if (mmc_card_blockaddr(card)) {
+                       if (mmc_card_ext_capacity(card))
+                               type = "SDXC";
+                       else
+                               type = "SDHC";
+               }
                break;
        case MMC_TYPE_SDIO:
                type = "SDIO";
@@ -299,7 +303,8 @@ int mmc_add_card(struct mmc_card *card)
        } else {
                printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
                        mmc_hostname(card->host),
-                       mmc_card_highspeed(card) ? "high speed " : "",
+                       mmc_sd_card_uhs(card) ? "ultra high speed " :
+                       (mmc_card_highspeed(card) ? "high speed " : ""),
                        mmc_card_ddr_mode(card) ? "DDR " : "",
                        type, card->rca);
        }
index 1f453acc8682b8f828b4f6c9574f2b0f6e1ff7f9..68091dda3f31f49ab9d7130cbad178e93d5ca1c8 100644 (file)
@@ -236,12 +236,10 @@ EXPORT_SYMBOL(mmc_wait_for_req);
  */
 int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
 {
-       struct mmc_request mrq;
+       struct mmc_request mrq = {0};
 
        WARN_ON(!host->claimed);
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-
        memset(cmd->resp, 0, sizeof(cmd->resp));
        cmd->retries = retries;
 
@@ -719,23 +717,13 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
        mmc_set_ios(host);
 }
 
-/*
- * Change data bus width and DDR mode of a host.
- */
-void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
-                          unsigned int ddr)
-{
-       host->ios.bus_width = width;
-       host->ios.ddr = ddr;
-       mmc_set_ios(host);
-}
-
 /*
  * Change data bus width of a host.
  */
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
 {
-       mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
+       host->ios.bus_width = width;
+       mmc_set_ios(host);
 }
 
 /**
@@ -944,6 +932,38 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
        return ocr;
 }
 
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11)
+{
+       struct mmc_command cmd = {0};
+       int err = 0;
+
+       BUG_ON(!host);
+
+       /*
+        * Send CMD11 only if the request is to switch the card to
+        * 1.8V signalling.
+        */
+       if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) {
+               cmd.opcode = SD_SWITCH_VOLTAGE;
+               cmd.arg = 0;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+               err = mmc_wait_for_cmd(host, &cmd, 0);
+               if (err)
+                       return err;
+
+               if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
+                       return -EIO;
+       }
+
+       host->ios.signal_voltage = signal_voltage;
+
+       if (host->ops->start_signal_voltage_switch)
+               err = host->ops->start_signal_voltage_switch(host, &host->ios);
+
+       return err;
+}
+
 /*
  * Select timing parameters for host.
  */
@@ -953,6 +973,15 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
        mmc_set_ios(host);
 }
 
+/*
+ * Select appropriate driver type for host.
+ */
+void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
+{
+       host->ios.drv_type = drv_type;
+       mmc_set_ios(host);
+}
+
 /*
  * Apply power to the MMC stack.  This is a two-stage process.
  * First, we enable power to the card without the clock running.
@@ -1187,9 +1216,8 @@ void mmc_init_erase(struct mmc_card *card)
        }
 }
 
-static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
-                                     struct mmc_command *cmd,
-                                     unsigned int arg, unsigned int qty)
+static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
+                                         unsigned int arg, unsigned int qty)
 {
        unsigned int erase_timeout;
 
@@ -1246,44 +1274,48 @@ static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
        if (mmc_host_is_spi(card->host) && erase_timeout < 1000)
                erase_timeout = 1000;
 
-       cmd->erase_timeout = erase_timeout;
+       return erase_timeout;
 }
 
-static void mmc_set_sd_erase_timeout(struct mmc_card *card,
-                                    struct mmc_command *cmd, unsigned int arg,
-                                    unsigned int qty)
+static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
+                                        unsigned int arg,
+                                        unsigned int qty)
 {
+       unsigned int erase_timeout;
+
        if (card->ssr.erase_timeout) {
                /* Erase timeout specified in SD Status Register (SSR) */
-               cmd->erase_timeout = card->ssr.erase_timeout * qty +
-                                    card->ssr.erase_offset;
+               erase_timeout = card->ssr.erase_timeout * qty +
+                               card->ssr.erase_offset;
        } else {
                /*
                 * Erase timeout not specified in SD Status Register (SSR) so
                 * use 250ms per write block.
                 */
-               cmd->erase_timeout = 250 * qty;
+               erase_timeout = 250 * qty;
        }
 
        /* Must not be less than 1 second */
-       if (cmd->erase_timeout < 1000)
-               cmd->erase_timeout = 1000;
+       if (erase_timeout < 1000)
+               erase_timeout = 1000;
+
+       return erase_timeout;
 }
 
-static void mmc_set_erase_timeout(struct mmc_card *card,
-                                 struct mmc_command *cmd, unsigned int arg,
-                                 unsigned int qty)
+static unsigned int mmc_erase_timeout(struct mmc_card *card,
+                                     unsigned int arg,
+                                     unsigned int qty)
 {
        if (mmc_card_sd(card))
-               mmc_set_sd_erase_timeout(card, cmd, arg, qty);
+               return mmc_sd_erase_timeout(card, arg, qty);
        else
-               mmc_set_mmc_erase_timeout(card, cmd, arg, qty);
+               return mmc_mmc_erase_timeout(card, arg, qty);
 }
 
 static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                        unsigned int to, unsigned int arg)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        unsigned int qty = 0;
        int err;
 
@@ -1317,7 +1349,6 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                to <<= 9;
        }
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
        if (mmc_card_sd(card))
                cmd.opcode = SD_ERASE_WR_BLK_START;
        else
@@ -1351,7 +1382,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        cmd.opcode = MMC_ERASE;
        cmd.arg = arg;
        cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-       mmc_set_erase_timeout(card, &cmd, arg, qty);
+       cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
                printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n",
@@ -1487,12 +1518,11 @@ EXPORT_SYMBOL(mmc_erase_group_aligned);
 
 int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
                return 0;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
        cmd.opcode = MMC_SET_BLOCKLEN;
        cmd.arg = blocklen;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
@@ -1578,7 +1608,7 @@ void mmc_rescan(struct work_struct *work)
        for (i = 0; i < ARRAY_SIZE(freqs); i++) {
                if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
                        break;
-               if (freqs[i] < host->f_min)
+               if (freqs[i] <= host->f_min)
                        break;
        }
        mmc_release_host(host);
@@ -1746,7 +1776,7 @@ int mmc_suspend_host(struct mmc_host *host)
        }
        mmc_bus_put(host);
 
-       if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER))
+       if (!err && !mmc_card_keep_power(host))
                mmc_power_off(host);
 
        return err;
@@ -1764,7 +1794,7 @@ int mmc_resume_host(struct mmc_host *host)
 
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
-               if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
+               if (!mmc_card_keep_power(host)) {
                        mmc_power_up(host);
                        mmc_select_voltage(host, host->ocr);
                        /*
@@ -1789,6 +1819,7 @@ int mmc_resume_host(struct mmc_host *host)
                        err = 0;
                }
        }
+       host->pm_flags &= ~MMC_PM_KEEP_POWER;
        mmc_bus_put(host);
 
        return err;
index 20b1c0831eac8f01e0bd8234d547f37618bd1494..d9411ed2a39bf6490a5a788629d45a628e14e6fe 100644 (file)
@@ -38,10 +38,11 @@ void mmc_ungate_clock(struct mmc_host *host);
 void mmc_set_ungated(struct mmc_host *host);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
-void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
-                          unsigned int ddr);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
+                          bool cmd11);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
+void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
 
 static inline void mmc_delay(unsigned int ms)
 {
@@ -61,8 +62,6 @@ int mmc_attach_mmc(struct mmc_host *host);
 int mmc_attach_sd(struct mmc_host *host);
 int mmc_attach_sdio(struct mmc_host *host);
 
-void mmc_fixup_device(struct mmc_card *card);
-
 /* Module parameters */
 extern int use_spi_crc;
 
index 461e6a17fb90e8526d96054f2ec90f44a85e70c3..b29d3e8fd3a2ad713525c4be82c9b2f9699910ec 100644 (file)
@@ -325,12 +325,12 @@ int mmc_add_host(struct mmc_host *host)
        WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
                !host->ops->enable_sdio_irq);
 
-       led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
-
        err = device_add(&host->class_dev);
        if (err)
                return err;
 
+       led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
+
 #ifdef CONFIG_DEBUG_FS
        mmc_add_host_debugfs(host);
 #endif
index 772d0d0a541b6f9bbfc5208cba135e03ea38b57f..2a7e43bc796dfd1e798ad60a1ae6d0e7b98278a2 100644 (file)
@@ -20,6 +20,7 @@
 #include "core.h"
 #include "bus.h"
 #include "mmc_ops.h"
+#include "sd_ops.h"
 
 static const unsigned int tran_exp[] = {
        10000,          100000,         1000000,        10000000,
@@ -173,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
 }
 
 /*
- * Read and decode extended CSD.
+ * Read extended CSD.
  */
-static int mmc_read_ext_csd(struct mmc_card *card)
+static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
 {
        int err;
        u8 *ext_csd;
 
        BUG_ON(!card);
+       BUG_ON(!new_ext_csd);
+
+       *new_ext_csd = NULL;
 
        if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
                return 0;
@@ -198,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
        err = mmc_send_ext_csd(card, ext_csd);
        if (err) {
+               kfree(ext_csd);
+               *new_ext_csd = NULL;
+
                /* If the host or the card can't do the switch,
                 * fail more gracefully. */
                if ((err != -EINVAL)
                 && (err != -ENOSYS)
                 && (err != -EFAULT))
-                       goto out;
+                       return err;
 
                /*
                 * High capacity cards should have this "magic" size
@@ -221,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
                                mmc_hostname(card->host));
                        err = 0;
                }
+       } else
+               *new_ext_csd = ext_csd;
 
-               goto out;
-       }
+       return err;
+}
+
+/*
+ * Decode extended CSD.
+ */
+static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+       int err = 0;
+
+       BUG_ON(!card);
+
+       if (!ext_csd)
+               return 0;
 
        /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
        if (card->csd.structure == 3) {
@@ -288,6 +309,10 @@ static int mmc_read_ext_csd(struct mmc_card *card)
 
        if (card->ext_csd.rev >= 3) {
                u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
+               card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
+
+               /* EXT_CSD value is in units of 10ms, but we store in ms */
+               card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
 
                /* Sleep / awake timeout in 100ns units */
                if (sa_shift > 0 && sa_shift <= 0x17)
@@ -299,6 +324,14 @@ static int mmc_read_ext_csd(struct mmc_card *card)
                        ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
                card->ext_csd.hc_erase_size =
                        ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
+
+               card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
+
+               /*
+                * There are two boot regions of equal size, defined in
+                * multiples of 128K.
+                */
+               card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
        }
 
        if (card->ext_csd.rev >= 4) {
@@ -350,14 +383,78 @@ static int mmc_read_ext_csd(struct mmc_card *card)
                        ext_csd[EXT_CSD_TRIM_MULT];
        }
 
+       if (card->ext_csd.rev >= 5)
+               card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+
        if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
                card->erased_byte = 0xFF;
        else
                card->erased_byte = 0x0;
 
 out:
+       return err;
+}
+
+static inline void mmc_free_ext_csd(u8 *ext_csd)
+{
        kfree(ext_csd);
+}
+
+
+static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
+                       unsigned bus_width)
+{
+       u8 *bw_ext_csd;
+       int err;
+
+       err = mmc_get_ext_csd(card, &bw_ext_csd);
+       if (err)
+               return err;
+
+       if ((ext_csd == NULL || bw_ext_csd == NULL)) {
+               if (bus_width != MMC_BUS_WIDTH_1)
+                       err = -EINVAL;
+               goto out;
+       }
 
+       if (bus_width == MMC_BUS_WIDTH_1)
+               goto out;
+
+       /* only compare read only fields */
+       err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
+                       bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
+               (ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
+                       bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
+               (ext_csd[EXT_CSD_REV] ==
+                       bw_ext_csd[EXT_CSD_REV]) &&
+               (ext_csd[EXT_CSD_STRUCTURE] ==
+                       bw_ext_csd[EXT_CSD_STRUCTURE]) &&
+               (ext_csd[EXT_CSD_CARD_TYPE] ==
+                       bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
+               (ext_csd[EXT_CSD_S_A_TIMEOUT] ==
+                       bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
+               (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
+                       bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
+               (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
+                       bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
+               (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
+                       bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
+               (ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
+                       bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
+               (ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
+                       bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
+               (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
+                       bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
+               (ext_csd[EXT_CSD_TRIM_MULT] ==
+                       bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
+               memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+                      &bw_ext_csd[EXT_CSD_SEC_CNT],
+                      4) != 0);
+       if (err)
+               err = -EINVAL;
+
+out:
+       mmc_free_ext_csd(bw_ext_csd);
        return err;
 }
 
@@ -422,6 +519,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        u32 cid[4];
        unsigned int max_dtr;
        u32 rocr;
+       u8 *ext_csd = NULL;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
@@ -520,7 +618,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                /*
                 * Fetch and process extended CSD.
                 */
-               err = mmc_read_ext_csd(card);
+
+               err = mmc_get_ext_csd(card, &ext_csd);
+               if (err)
+                       goto free_card;
+               err = mmc_read_ext_csd(card, ext_csd);
                if (err)
                        goto free_card;
 
@@ -542,7 +644,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         */
        if (card->ext_csd.enhanced_area_en) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                               EXT_CSD_ERASE_GROUP_DEF, 1);
+                                EXT_CSD_ERASE_GROUP_DEF, 1, 0);
 
                if (err && err != -EBADMSG)
                        goto free_card;
@@ -567,13 +669,25 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
+       /*
+        * Ensure eMMC user default partition is enabled
+        */
+       if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) {
+               card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
+                                card->ext_csd.part_config,
+                                card->ext_csd.part_time);
+               if (err && err != -EBADMSG)
+                       goto free_card;
+       }
+
        /*
         * Activate high speed (if supported)
         */
        if ((card->ext_csd.hs_max_dtr != 0) &&
                (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                       EXT_CSD_HS_TIMING, 1);
+                                EXT_CSD_HS_TIMING, 1, 0);
                if (err && err != -EBADMSG)
                        goto free_card;
 
@@ -606,10 +720,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         */
        if (mmc_card_highspeed(card)) {
                if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
-                       && (host->caps & (MMC_CAP_1_8V_DDR)))
+                       && ((host->caps & (MMC_CAP_1_8V_DDR |
+                            MMC_CAP_UHS_DDR50))
+                               == (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
                                ddr = MMC_1_8V_DDR_MODE;
                else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
-                       && (host->caps & (MMC_CAP_1_2V_DDR)))
+                       && ((host->caps & (MMC_CAP_1_2V_DDR |
+                            MMC_CAP_UHS_DDR50))
+                               == (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
                                ddr = MMC_1_2V_DDR_MODE;
        }
 
@@ -640,18 +758,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                                ddr = 0; /* no DDR for 1-bit width */
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                         EXT_CSD_BUS_WIDTH,
-                                        ext_csd_bits[idx][0]);
+                                        ext_csd_bits[idx][0],
+                                        0);
                        if (!err) {
-                               mmc_set_bus_width_ddr(card->host,
-                                                     bus_width, MMC_SDR_MODE);
+                               mmc_set_bus_width(card->host, bus_width);
+
                                /*
                                 * If controller can't handle bus width test,
-                                * use the highest bus width to maintain
-                                * compatibility with previous MMC behavior.
+                                * compare ext_csd previously read in 1 bit mode
+                                * against ext_csd at new bus width
                                 */
                                if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
-                                       break;
-                               err = mmc_bus_test(card, bus_width);
+                                       err = mmc_compare_ext_csds(card,
+                                               ext_csd,
+                                               bus_width);
+                               else
+                                       err = mmc_bus_test(card, bus_width);
                                if (!err)
                                        break;
                        }
@@ -659,8 +781,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
                if (!err && ddr) {
                        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                       EXT_CSD_BUS_WIDTH,
-                                       ext_csd_bits[idx][1]);
+                                        EXT_CSD_BUS_WIDTH,
+                                        ext_csd_bits[idx][1],
+                                        0);
                }
                if (err) {
                        printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
@@ -668,20 +791,43 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                                1 << bus_width, ddr);
                        goto free_card;
                } else if (ddr) {
+                       /*
+                        * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+                        * signaling.
+                        *
+                        * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+                        *
+                        * 1.8V vccq at 3.3V core voltage (vcc) is not required
+                        * in the JEDEC spec for DDR.
+                        *
+                        * Do not force change in vccq since we are obviously
+                        * working and no change to vccq is needed.
+                        *
+                        * WARNING: eMMC rules are NOT the same as SD DDR
+                        */
+                       if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) {
+                               err = mmc_set_signal_voltage(host,
+                                       MMC_SIGNAL_VOLTAGE_120, 0);
+                               if (err)
+                                       goto err;
+                       }
                        mmc_card_set_ddr_mode(card);
-                       mmc_set_bus_width_ddr(card->host, bus_width, ddr);
+                       mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
+                       mmc_set_bus_width(card->host, bus_width);
                }
        }
 
        if (!oldcard)
                host->card = card;
 
+       mmc_free_ext_csd(ext_csd);
        return 0;
 
 free_card:
        if (!oldcard)
                mmc_remove_card(card);
 err:
+       mmc_free_ext_csd(ext_csd);
 
        return err;
 }
index f3b22bf89cc98b68ab3e107154ec82b11aeb8a02..845ce7c533b901b0895a6bf4c5715c676c5cd902 100644 (file)
 static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SELECT_CARD;
 
        if (card) {
@@ -60,15 +58,13 @@ int mmc_deselect_cards(struct mmc_host *host)
 
 int mmc_card_sleepawake(struct mmc_host *host, int sleep)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        struct mmc_card *card = host->card;
        int err;
 
        if (sleep)
                mmc_deselect_cards(host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SLEEP_AWAKE;
        cmd.arg = card->rca << 16;
        if (sleep)
@@ -97,7 +93,7 @@ int mmc_card_sleepawake(struct mmc_host *host, int sleep)
 int mmc_go_idle(struct mmc_host *host)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        /*
         * Non-SPI hosts need to prevent chipselect going active during
@@ -113,8 +109,6 @@ int mmc_go_idle(struct mmc_host *host)
                mmc_delay(1);
        }
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_GO_IDLE_STATE;
        cmd.arg = 0;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
@@ -135,13 +129,11 @@ int mmc_go_idle(struct mmc_host *host)
 
 int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int i, err = 0;
 
        BUG_ON(!host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SEND_OP_COND;
        cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
@@ -178,13 +170,11 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
        BUG_ON(!cid);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_ALL_SEND_CID;
        cmd.arg = 0;
        cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
@@ -201,13 +191,11 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
 int mmc_set_relative_addr(struct mmc_card *card)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!card);
        BUG_ON(!card->host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SET_RELATIVE_ADDR;
        cmd.arg = card->rca << 16;
        cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -223,13 +211,11 @@ static int
 mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
        BUG_ON(!cxd);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = opcode;
        cmd.arg = arg;
        cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
@@ -247,9 +233,9 @@ static int
 mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
                u32 opcode, void *buf, unsigned len)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
        void *data_buf;
 
@@ -260,10 +246,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
        if (data_buf == NULL)
                return -ENOMEM;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
@@ -355,11 +337,9 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
 
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SPI_READ_OCR;
        cmd.arg = highcap ? (1 << 30) : 0;
        cmd.flags = MMC_RSP_SPI_R3;
@@ -372,11 +352,9 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
 
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SPI_CRC_ON_OFF;
        cmd.flags = MMC_RSP_SPI_R1;
        cmd.arg = use_crc;
@@ -387,23 +365,34 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
        return err;
 }
 
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
+/**
+ *     mmc_switch - modify EXT_CSD register
+ *     @card: the MMC card associated with the data transfer
+ *     @set: cmd set values
+ *     @index: EXT_CSD register index
+ *     @value: value to program into EXT_CSD register
+ *     @timeout_ms: timeout (ms) for operation performed by register write,
+ *                   timeout of zero implies maximum possible timeout
+ *
+ *     Modifies the EXT_CSD register for selected card.
+ */
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+              unsigned int timeout_ms)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        u32 status;
 
        BUG_ON(!card);
        BUG_ON(!card->host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SWITCH;
        cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
                  (index << 16) |
                  (value << 8) |
                  set;
        cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+       cmd.cmd_timeout_ms = timeout_ms;
 
        err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
        if (err)
@@ -433,17 +422,16 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(mmc_switch);
 
 int mmc_send_status(struct mmc_card *card, u32 *status)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!card);
        BUG_ON(!card->host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = MMC_SEND_STATUS;
        if (!mmc_host_is_spi(card->host))
                cmd.arg = card->rca << 16;
@@ -466,9 +454,9 @@ static int
 mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
                  u8 len)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
        u8 *data_buf;
        u8 *test_buf;
@@ -497,10 +485,6 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
        if (opcode == MMC_BUS_TEST_W)
                memcpy(data_buf, test_buf, len);
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
        cmd.opcode = opcode;
index e6d44b8a18db52b438f7c422970c3cc6444588fc..9276946fa5b719b8d1128c2ed94dedc73406ab12 100644 (file)
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_set_relative_addr(struct mmc_card *card);
 int mmc_send_csd(struct mmc_card *card, u32 *csd);
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
index 11118b74eb20dc3c82f9fc96401d00c754c49b41..3a596217029e1e94fbd9797f2d324fa5dde03472 100644 (file)
@@ -1,7 +1,8 @@
 /*
- *  This file contains work-arounds for many known sdio hardware
- *  bugs.
+ *  This file contains work-arounds for many known SD/MMC
+ *  and SDIO hardware bugs.
  *
+ *  Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>
  *  Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
  *  Inspired from pci fixup code:
  *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mmc/card.h>
-#include <linux/mod_devicetable.h>
 
-/*
- *  The world is not perfect and supplies us with broken mmc/sdio devices.
- *  For at least a part of these bugs we need a work-around
- */
-
-struct mmc_fixup {
-       u16 vendor, device;     /* You can use SDIO_ANY_ID here of course */
-       void (*vendor_fixup)(struct mmc_card *card, int data);
-       int data;
-};
-
-/*
- * This hook just adds a quirk unconditionnally
- */
-static void __maybe_unused add_quirk(struct mmc_card *card, int data)
-{
-       card->quirks |= data;
-}
+#ifndef SDIO_VENDOR_ID_TI
+#define SDIO_VENDOR_ID_TI              0x0097
+#endif
 
-/*
- * This hook just removes a quirk unconditionnally
- */
-static void __maybe_unused remove_quirk(struct mmc_card *card, int data)
-{
-       card->quirks &= ~data;
-}
+#ifndef SDIO_DEVICE_ID_TI_WL1271
+#define SDIO_DEVICE_ID_TI_WL1271       0x4076
+#endif
 
 /*
  * This hook just adds a quirk for all sdio devices
@@ -49,33 +30,47 @@ static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
                card->quirks |= data;
 }
 
-#ifndef SDIO_VENDOR_ID_TI
-#define SDIO_VENDOR_ID_TI              0x0097
-#endif
-
-#ifndef SDIO_DEVICE_ID_TI_WL1271
-#define SDIO_DEVICE_ID_TI_WL1271       0x4076
-#endif
-
 static const struct mmc_fixup mmc_fixup_methods[] = {
        /* by default sdio devices are considered CLK_GATING broken */
        /* good cards will be whitelisted as they are tested */
-       { SDIO_ANY_ID, SDIO_ANY_ID,
-               add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING },
-       { SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
-               remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING },
-       { 0 }
+       SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
+                  add_quirk_for_sdio_devices,
+                  MMC_QUIRK_BROKEN_CLK_GATING),
+
+       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+                  remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
+       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+                  add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
+
+       SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+                  add_quirk, MMC_QUIRK_DISABLE_CD),
+
+       END_FIXUP
 };
 
-void mmc_fixup_device(struct mmc_card *card)
+void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
 {
        const struct mmc_fixup *f;
+       u64 rev = cid_rev_card(card);
+
+       /* Non-core specific workarounds. */
+       if (!table)
+               table = mmc_fixup_methods;
 
-       for (f = mmc_fixup_methods; f->vendor_fixup; f++) {
-               if ((f->vendor == card->cis.vendor
-                    || f->vendor == (u16) SDIO_ANY_ID) &&
-                   (f->device == card->cis.device
-                    || f->device == (u16) SDIO_ANY_ID)) {
+       for (f = table; f->vendor_fixup; f++) {
+               if ((f->manfid == CID_MANFID_ANY ||
+                    f->manfid == card->cid.manfid) &&
+                   (f->oemid == CID_OEMID_ANY ||
+                    f->oemid == card->cid.oemid) &&
+                   (f->name == CID_NAME_ANY ||
+                    !strncmp(f->name, card->cid.prod_name,
+                             sizeof(card->cid.prod_name))) &&
+                   (f->cis_vendor == card->cis.vendor ||
+                    f->cis_vendor == (u16) SDIO_ANY_ID) &&
+                   (f->cis_device == card->cis.device ||
+                    f->cis_device == (u16) SDIO_ANY_ID) &&
+                   rev >= f->rev_start && rev <= f->rev_end) {
                        dev_dbg(&card->dev, "calling %pF\n", f->vendor_fixup);
                        f->vendor_fixup(card, f->data);
                }
index 6dac89fe0535ad02b272e5fbe658627d0263fd29..ff2774128aa93b1231538b1f5e014b0df987e7ca 100644 (file)
@@ -130,7 +130,7 @@ static int mmc_decode_csd(struct mmc_card *card)
                break;
        case 1:
                /*
-                * This is a block-addressed SDHC card. Most
+                * This is a block-addressed SDHC or SDXC card. Most
                 * interesting fields are unused and have fixed
                 * values. To avoid getting tripped by buggy cards,
                 * we assume those fixed values ourselves.
@@ -144,6 +144,11 @@ static int mmc_decode_csd(struct mmc_card *card)
                e = UNSTUFF_BITS(resp, 96, 3);
                csd->max_dtr      = tran_exp[e] * tran_mant[m];
                csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
+               csd->c_size       = UNSTUFF_BITS(resp, 48, 22);
+
+               /* SDXC cards have a minimum C_SIZE of 0x00FFFF */
+               if (csd->c_size >= 0xFFFF)
+                       mmc_card_set_ext_capacity(card);
 
                m = UNSTUFF_BITS(resp, 48, 22);
                csd->capacity     = (1 + m) << 10;
@@ -189,12 +194,17 @@ static int mmc_decode_scr(struct mmc_card *card)
 
        scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
        scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+       if (scr->sda_vsn == SCR_SPEC_VER_2)
+               /* Check if Physical Layer Spec v3.0 is supported */
+               scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1);
 
        if (UNSTUFF_BITS(resp, 55, 1))
                card->erased_byte = 0xFF;
        else
                card->erased_byte = 0x0;
 
+       if (scr->sda_spec3)
+               scr->cmds = UNSTUFF_BITS(resp, 32, 2);
        return 0;
 }
 
@@ -274,29 +284,74 @@ static int mmc_read_switch(struct mmc_card *card)
        status = kmalloc(64, GFP_KERNEL);
        if (!status) {
                printk(KERN_ERR "%s: could not allocate a buffer for "
-                       "switch capabilities.\n", mmc_hostname(card->host));
+                       "switch capabilities.\n",
+                       mmc_hostname(card->host));
                return -ENOMEM;
        }
 
+       /* Find out the supported Bus Speed Modes. */
        err = mmc_sd_switch(card, 0, 0, 1, status);
        if (err) {
-               /* If the host or the card can't do the switch,
-                * fail more gracefully. */
-               if ((err != -EINVAL)
-                && (err != -ENOSYS)
-                && (err != -EFAULT))
+               /*
+                * If the host or the card can't do the switch,
+                * fail more gracefully.
+                */
+               if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
                        goto out;
 
-               printk(KERN_WARNING "%s: problem reading switch "
-                       "capabilities, performance might suffer.\n",
+               printk(KERN_WARNING "%s: problem reading Bus Speed modes.\n",
                        mmc_hostname(card->host));
                err = 0;
 
                goto out;
        }
 
-       if (status[13] & 0x02)
-               card->sw_caps.hs_max_dtr = 50000000;
+       if (card->scr.sda_spec3) {
+               card->sw_caps.sd3_bus_mode = status[13];
+
+               /* Find out Driver Strengths supported by the card */
+               err = mmc_sd_switch(card, 0, 2, 1, status);
+               if (err) {
+                       /*
+                        * If the host or the card can't do the switch,
+                        * fail more gracefully.
+                        */
+                       if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
+                               goto out;
+
+                       printk(KERN_WARNING "%s: problem reading "
+                               "Driver Strength.\n",
+                               mmc_hostname(card->host));
+                       err = 0;
+
+                       goto out;
+               }
+
+               card->sw_caps.sd3_drv_type = status[9];
+
+               /* Find out Current Limits supported by the card */
+               err = mmc_sd_switch(card, 0, 3, 1, status);
+               if (err) {
+                       /*
+                        * If the host or the card can't do the switch,
+                        * fail more gracefully.
+                        */
+                       if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
+                               goto out;
+
+                       printk(KERN_WARNING "%s: problem reading "
+                               "Current Limit.\n",
+                               mmc_hostname(card->host));
+                       err = 0;
+
+                       goto out;
+               }
+
+               card->sw_caps.sd3_curr_limit = status[7];
+       } else {
+               if (status[13] & 0x02)
+                       card->sw_caps.hs_max_dtr = 50000000;
+       }
 
 out:
        kfree(status);
@@ -352,6 +407,232 @@ out:
        return err;
 }
 
+static int sd_select_driver_type(struct mmc_card *card, u8 *status)
+{
+       int host_drv_type = 0, card_drv_type = 0;
+       int err;
+
+       /*
+        * If the host doesn't support any of the Driver Types A,C or D,
+        * default Driver Type B is used.
+        */
+       if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C
+           | MMC_CAP_DRIVER_TYPE_D)))
+               return 0;
+
+       if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) {
+               host_drv_type = MMC_SET_DRIVER_TYPE_A;
+               if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_A;
+               else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_B;
+               else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_C;
+       } else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) {
+               host_drv_type = MMC_SET_DRIVER_TYPE_C;
+               if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_C;
+       } else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) {
+               /*
+                * If we are here, that means only the default driver type
+                * B is supported by the host.
+                */
+               host_drv_type = MMC_SET_DRIVER_TYPE_B;
+               if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_B;
+               else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+                       card_drv_type = MMC_SET_DRIVER_TYPE_C;
+       }
+
+       err = mmc_sd_switch(card, 1, 2, card_drv_type, status);
+       if (err)
+               return err;
+
+       if ((status[15] & 0xF) != card_drv_type) {
+               printk(KERN_WARNING "%s: Problem setting driver strength!\n",
+                       mmc_hostname(card->host));
+               return 0;
+       }
+
+       mmc_set_driver_type(card->host, host_drv_type);
+
+       return 0;
+}
+
+static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
+{
+       unsigned int bus_speed = 0, timing = 0;
+       int err;
+
+       /*
+        * If the host doesn't support any of the UHS-I modes, fallback on
+        * default speed.
+        */
+       if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+           MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
+               return 0;
+
+       if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
+           (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
+                       bus_speed = UHS_SDR104_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_SDR104;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+       } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
+                       bus_speed = UHS_DDR50_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_DDR50;
+                       card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
+                   SD_MODE_UHS_SDR50)) {
+                       bus_speed = UHS_SDR50_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_SDR50;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
+                       bus_speed = UHS_SDR25_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_SDR25;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+       } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+                   MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
+                   MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
+                   SD_MODE_UHS_SDR12)) {
+                       bus_speed = UHS_SDR12_BUS_SPEED;
+                       timing = MMC_TIMING_UHS_SDR12;
+                       card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+       }
+
+       card->sd_bus_speed = bus_speed;
+       err = mmc_sd_switch(card, 1, 0, bus_speed, status);
+       if (err)
+               return err;
+
+       if ((status[16] & 0xF) != bus_speed)
+               printk(KERN_WARNING "%s: Problem setting bus speed mode!\n",
+                       mmc_hostname(card->host));
+       else {
+               mmc_set_timing(card->host, timing);
+               mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
+       }
+
+       return 0;
+}
+
+static int sd_set_current_limit(struct mmc_card *card, u8 *status)
+{
+       int current_limit = 0;
+       int err;
+
+       /*
+        * Current limit switch is only defined for SDR50, SDR104, and DDR50
+        * bus speed modes. For other bus speed modes, we set the default
+        * current limit of 200mA.
+        */
+       if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
+           (card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
+           (card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
+               if (card->host->caps & MMC_CAP_MAX_CURRENT_800) {
+                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
+                               current_limit = SD_SET_CURRENT_LIMIT_800;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_600)
+                               current_limit = SD_SET_CURRENT_LIMIT_600;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_400)
+                               current_limit = SD_SET_CURRENT_LIMIT_400;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_200)
+                               current_limit = SD_SET_CURRENT_LIMIT_200;
+               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) {
+                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
+                               current_limit = SD_SET_CURRENT_LIMIT_600;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_400)
+                               current_limit = SD_SET_CURRENT_LIMIT_400;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_200)
+                               current_limit = SD_SET_CURRENT_LIMIT_200;
+               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) {
+                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
+                               current_limit = SD_SET_CURRENT_LIMIT_400;
+                       else if (card->sw_caps.sd3_curr_limit &
+                                       SD_MAX_CURRENT_200)
+                               current_limit = SD_SET_CURRENT_LIMIT_200;
+               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) {
+                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
+                               current_limit = SD_SET_CURRENT_LIMIT_200;
+               }
+       } else
+               current_limit = SD_SET_CURRENT_LIMIT_200;
+
+       err = mmc_sd_switch(card, 1, 3, current_limit, status);
+       if (err)
+               return err;
+
+       if (((status[15] >> 4) & 0x0F) != current_limit)
+               printk(KERN_WARNING "%s: Problem setting current limit!\n",
+                       mmc_hostname(card->host));
+
+       return 0;
+}
+
+/*
+ * UHS-I specific initialization procedure
+ */
+static int mmc_sd_init_uhs_card(struct mmc_card *card)
+{
+       int err;
+       u8 *status;
+
+       if (!card->scr.sda_spec3)
+               return 0;
+
+       if (!(card->csd.cmdclass & CCC_SWITCH))
+               return 0;
+
+       status = kmalloc(64, GFP_KERNEL);
+       if (!status) {
+               printk(KERN_ERR "%s: could not allocate a buffer for "
+                       "switch capabilities.\n", mmc_hostname(card->host));
+               return -ENOMEM;
+       }
+
+       /* Set 4-bit bus width */
+       if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
+           (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+               err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+               if (err)
+                       goto out;
+
+               mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+       }
+
+       /* Set the driver strength for the card */
+       err = sd_select_driver_type(card, status);
+       if (err)
+               goto out;
+
+       /* Set bus speed mode of the card */
+       err = sd_set_bus_speed_mode(card, status);
+       if (err)
+               goto out;
+
+       /* Set current limit for the card */
+       err = sd_set_current_limit(card, status);
+       if (err)
+               goto out;
+
+       /* SPI mode doesn't define CMD19 */
+       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
+               err = card->host->ops->execute_tuning(card->host);
+
+out:
+       kfree(status);
+
+       return err;
+}
+
 MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
        card->raw_cid[2], card->raw_cid[3]);
 MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
@@ -400,7 +681,7 @@ struct device_type sd_type = {
 /*
  * Fetch CID from card.
  */
-int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
+int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
 {
        int err;
 
@@ -420,12 +701,39 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
         */
        err = mmc_send_if_cond(host, ocr);
        if (!err)
-               ocr |= 1 << 30;
+               ocr |= SD_OCR_CCS;
+
+       /*
+        * If the host supports one of UHS-I modes, request the card
+        * to switch to 1.8V signaling level.
+        */
+       if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+           MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
+               ocr |= SD_OCR_S18R;
+
+       /* If the host can supply more than 150mA, XPC should be set to 1. */
+       if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
+           MMC_CAP_SET_XPC_180))
+               ocr |= SD_OCR_XPC;
 
-       err = mmc_send_app_op_cond(host, ocr, NULL);
+try_again:
+       err = mmc_send_app_op_cond(host, ocr, rocr);
        if (err)
                return err;
 
+       /*
+        * In case CCS and S18A in the response is set, start Signal Voltage
+        * Switch procedure. SPI mode doesn't support CMD11.
+        */
+       if (!mmc_host_is_spi(host) && rocr &&
+          ((*rocr & 0x41000000) == 0x41000000)) {
+               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
+               if (err) {
+                       ocr &= ~SD_OCR_S18R;
+                       goto try_again;
+               }
+       }
+
        if (mmc_host_is_spi(host))
                err = mmc_send_cid(host, cid);
        else
@@ -553,11 +861,12 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        struct mmc_card *card;
        int err;
        u32 cid[4];
+       u32 rocr = 0;
 
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
-       err = mmc_sd_get_cid(host, ocr, cid);
+       err = mmc_sd_get_cid(host, ocr, cid, &rocr);
        if (err)
                return err;
 
@@ -610,30 +919,47 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        if (err)
                goto free_card;
 
-       /*
-        * Attempt to change to high-speed (if supported)
-        */
-       err = mmc_sd_switch_hs(card);
-       if (err > 0)
-               mmc_sd_go_highspeed(card);
-       else if (err)
-               goto free_card;
+       /* Initialization sequence for UHS-I cards */
+       if (rocr & SD_ROCR_S18A) {
+               err = mmc_sd_init_uhs_card(card);
+               if (err)
+                       goto free_card;
 
-       /*
-        * Set bus speed.
-        */
-       mmc_set_clock(host, mmc_sd_get_max_clock(card));
+               /* Card is an ultra-high-speed card */
+               mmc_sd_card_set_uhs(card);
 
-       /*
-        * Switch to wider bus (if supported).
-        */
-       if ((host->caps & MMC_CAP_4_BIT_DATA) &&
-               (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
-               err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
-               if (err)
+               /*
+                * Since initialization is now complete, enable preset
+                * value registers for UHS-I cards.
+                */
+               if (host->ops->enable_preset_value)
+                       host->ops->enable_preset_value(host, true);
+       } else {
+               /*
+                * Attempt to change to high-speed (if supported)
+                */
+               err = mmc_sd_switch_hs(card);
+               if (err > 0)
+                       mmc_sd_go_highspeed(card);
+               else if (err)
                        goto free_card;
 
-               mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+               /*
+                * Set bus speed.
+                */
+               mmc_set_clock(host, mmc_sd_get_max_clock(card));
+
+               /*
+                * Switch to wider bus (if supported).
+                */
+               if ((host->caps & MMC_CAP_4_BIT_DATA) &&
+                       (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+                       err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+                       if (err)
+                               goto free_card;
+
+                       mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+               }
        }
 
        host->card = card;
@@ -773,6 +1099,15 @@ int mmc_attach_sd(struct mmc_host *host)
        BUG_ON(!host);
        WARN_ON(!host->claimed);
 
+       /* Make sure we are at 3.3V signalling voltage */
+       err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
+       if (err)
+               return err;
+
+       /* Disable preset value enable if already set since last time */
+       if (host->ops->enable_preset_value)
+               host->ops->enable_preset_value(host, false);
+
        err = mmc_send_app_op_cond(host, 0, &ocr);
        if (err)
                return err;
index 3d8800fa7600ac011acc72d168a23939b14b4409..4b34b24f3f762f62ea026b491661f9e496d99b8d 100644 (file)
@@ -5,7 +5,7 @@
 
 extern struct device_type sd_type;
 
-int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid);
+int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
 int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card);
 void mmc_decode_cid(struct mmc_card *card);
 int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
index 76af349c14b41e41c8e6de62878ee364c6a61232..021fed153804cf0c9d3ad20598895ae093b36e5d 100644 (file)
 #include "core.h"
 #include "sd_ops.h"
 
-static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
        BUG_ON(card && (card->host != host));
@@ -49,6 +49,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(mmc_app_cmd);
 
 /**
  *     mmc_wait_for_app_cmd - start an application command and wait for
@@ -66,7 +67,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
 int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
        struct mmc_command *cmd, int retries)
 {
-       struct mmc_request mrq;
+       struct mmc_request mrq = {0};
 
        int i, err;
 
@@ -119,13 +120,11 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd);
 int mmc_app_set_bus_width(struct mmc_card *card, int width)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!card);
        BUG_ON(!card->host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_APP_SET_BUS_WIDTH;
        cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
@@ -149,13 +148,11 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
 
 int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int i, err = 0;
 
        BUG_ON(!host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_APP_OP_COND;
        if (mmc_host_is_spi(host))
                cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
@@ -194,7 +191,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 
 int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
        static const u8 test_pattern = 0xAA;
        u8 result_pattern;
@@ -226,13 +223,11 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
 int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
 {
        int err;
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
 
        BUG_ON(!host);
        BUG_ON(!rca);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_SEND_RELATIVE_ADDR;
        cmd.arg = 0;
        cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
@@ -249,9 +244,9 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
 int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
 {
        int err;
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
        void *data_buf;
 
@@ -272,10 +267,6 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
        if (data_buf == NULL)
                return -ENOMEM;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
@@ -312,9 +303,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
        u8 value, u8 *resp)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
 
        BUG_ON(!card);
@@ -325,10 +316,6 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
        mode = !!mode;
        value &= 0xF;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
@@ -361,9 +348,9 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
 int mmc_app_sd_status(struct mmc_card *card, void *ssr)
 {
        int err;
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
 
        BUG_ON(!card);
@@ -376,10 +363,6 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
        if (err)
                return err;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
index db0f0b44d684617b006b7eaa787e07fd0cd1017b..4d0c15bfa51465c91026972417c17652129e09d8 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
 
 #include "core.h"
 #include "bus.h"
@@ -31,6 +32,11 @@ static int sdio_read_fbr(struct sdio_func *func)
        int ret;
        unsigned char data;
 
+       if (mmc_card_nonstd_func_interface(func->card)) {
+               func->class = SDIO_CLASS_NONE;
+               return 0;
+       }
+
        ret = mmc_io_rw_direct(func->card, 0, 0,
                SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data);
        if (ret)
@@ -181,7 +187,7 @@ static int sdio_disable_cd(struct mmc_card *card)
        int ret;
        u8 ctrl;
 
-       if (!card->cccr.disable_cd)
+       if (!mmc_card_disable_cd(card))
                return 0;
 
        ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
@@ -363,8 +369,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
                goto err;
        }
 
-       if (ocr & R4_MEMORY_PRESENT
-           && mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid) == 0) {
+       if ((ocr & R4_MEMORY_PRESENT) &&
+           mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid, NULL) == 0) {
                card->type = MMC_TYPE_SD_COMBO;
 
                if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
@@ -466,7 +472,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
 
                card = oldcard;
        }
-       mmc_fixup_device(card);
+       mmc_fixup_device(card, NULL);
 
        if (card->type == MMC_TYPE_SD_COMBO) {
                err = mmc_sd_setup_card(host, card, oldcard != NULL);
@@ -625,7 +631,7 @@ static int mmc_sdio_suspend(struct mmc_host *host)
                }
        }
 
-       if (!err && host->pm_flags & MMC_PM_KEEP_POWER) {
+       if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
                mmc_claim_host(host);
                sdio_disable_wide(host->card);
                mmc_release_host(host);
@@ -645,10 +651,10 @@ static int mmc_sdio_resume(struct mmc_host *host)
        mmc_claim_host(host);
 
        /* No need to reinitialize powered-resumed nonremovable cards */
-       if (mmc_card_is_removable(host) || !mmc_card_is_powered_resumed(host))
+       if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
                err = mmc_sdio_init_card(host, host->ocr, host->card,
-                                (host->pm_flags & MMC_PM_KEEP_POWER));
-       else if (mmc_card_is_powered_resumed(host)) {
+                                       mmc_card_keep_power(host));
+       else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
                /* We may have switched to 1-bit mode during suspend */
                err = sdio_enable_4bit_bus(host->card);
                if (err > 0) {
@@ -691,7 +697,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
 
        mmc_claim_host(host);
        ret = mmc_sdio_init_card(host, host->ocr, host->card,
-                       (host->pm_flags & MMC_PM_KEEP_POWER));
+                               mmc_card_keep_power(host));
        if (!ret && host->sdio_irqs)
                mmc_signal_sdio_irq(host);
        mmc_release_host(host);
index b3001617e67d764c8157f45f60c4d677eaa6d161..03ead028d2ce147ac9a33387814b040ec1e91e53 100644 (file)
@@ -31,6 +31,17 @@ static int process_sdio_pending_irqs(struct mmc_card *card)
 {
        int i, ret, count;
        unsigned char pending;
+       struct sdio_func *func;
+
+       /*
+        * Optimization, if there is only 1 function interrupt registered
+        * call irq handler directly
+        */
+       func = card->sdio_single_irq;
+       if (func) {
+               func->irq_handler(func);
+               return 1;
+       }
 
        ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
        if (ret) {
@@ -42,7 +53,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card)
        count = 0;
        for (i = 1; i <= 7; i++) {
                if (pending & (1 << i)) {
-                       struct sdio_func *func = card->sdio_func[i - 1];
+                       func = card->sdio_func[i - 1];
                        if (!func) {
                                printk(KERN_WARNING "%s: pending IRQ for "
                                        "non-existent function\n",
@@ -186,6 +197,24 @@ static int sdio_card_irq_put(struct mmc_card *card)
        return 0;
 }
 
+/* If there is only 1 function registered set sdio_single_irq */
+static void sdio_single_irq_set(struct mmc_card *card)
+{
+       struct sdio_func *func;
+       int i;
+
+       card->sdio_single_irq = NULL;
+       if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
+           card->host->sdio_irqs == 1)
+               for (i = 0; i < card->sdio_funcs; i++) {
+                      func = card->sdio_func[i];
+                      if (func && func->irq_handler) {
+                              card->sdio_single_irq = func;
+                              break;
+                      }
+              }
+}
+
 /**
  *     sdio_claim_irq - claim the IRQ for a SDIO function
  *     @func: SDIO function
@@ -227,6 +256,7 @@ int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
        ret = sdio_card_irq_get(func->card);
        if (ret)
                func->irq_handler = NULL;
+       sdio_single_irq_set(func->card);
 
        return ret;
 }
@@ -251,6 +281,7 @@ int sdio_release_irq(struct sdio_func *func)
        if (func->irq_handler) {
                func->irq_handler = NULL;
                sdio_card_irq_put(func->card);
+               sdio_single_irq_set(func->card);
        }
 
        ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
index dea36d9c22e6df01afa6ca5689455c195b0d6685..f087d876c5731ebb0feefe14244811936ddefa70 100644 (file)
 
 int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int i, err = 0;
 
        BUG_ON(!host);
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_IO_SEND_OP_COND;
        cmd.arg = ocr;
        cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
@@ -70,7 +68,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
 static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
        unsigned addr, u8 in, u8 *out)
 {
-       struct mmc_command cmd;
+       struct mmc_command cmd = {0};
        int err;
 
        BUG_ON(!host);
@@ -80,8 +78,6 @@ static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
        if (addr & ~0x1FFFF)
                return -EINVAL;
 
-       memset(&cmd, 0, sizeof(struct mmc_command));
-
        cmd.opcode = SD_IO_RW_DIRECT;
        cmd.arg = write ? 0x80000000 : 0x00000000;
        cmd.arg |= fn << 28;
@@ -125,9 +121,9 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
 int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
 {
-       struct mmc_request mrq;
-       struct mmc_command cmd;
-       struct mmc_data data;
+       struct mmc_request mrq = {0};
+       struct mmc_command cmd = {0};
+       struct mmc_data data = {0};
        struct scatterlist sg;
 
        BUG_ON(!card);
@@ -140,10 +136,6 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        if (addr & ~0x1FFFF)
                return -EINVAL;
 
-       memset(&mrq, 0, sizeof(struct mmc_request));
-       memset(&cmd, 0, sizeof(struct mmc_command));
-       memset(&data, 0, sizeof(struct mmc_data));
-
        mrq.cmd = &cmd;
        mrq.data = &data;
 
index 94df40531c38caaa597fc05086b9e14b36f166d5..56dbf3f6ad08a495075b2e254dccc1cb61d2c707 100644 (file)
@@ -154,7 +154,7 @@ config MMC_SDHCI_DOVE
          If unsure, say N.
 
 config MMC_SDHCI_TEGRA
-       tristate "SDHCI platform support for the Tegra SD/MMC Controller"
+       bool "SDHCI platform support for the Tegra SD/MMC Controller"
        depends on MMC_SDHCI_PLTFM && ARCH_TEGRA
        select MMC_SDHCI_IO_ACCESSORS
        help
@@ -535,6 +535,37 @@ config MMC_JZ4740
          If you have a board based on such a SoC and with a SD/MMC slot,
          say Y or M here.
 
+config MMC_VUB300
+       tristate "VUB300 USB to SDIO/SD/MMC Host Controller support"
+       depends on USB
+       help
+         This selects support for Elan Digital Systems' VUB300 chip.
+
+         The VUB300 is a USB-SDIO Host Controller Interface chip
+         that enables the host computer to use SDIO/SD/MMC cards
+         via a USB 2.0 or USB 1.1 host.
+
+         The VUB300 chip will be found in both physically separate
+         USB to SDIO/SD/MMC adapters and embedded on some motherboards.
+
+         The VUB300 chip supports SD and MMC memory cards in addition
+         to single and multifunction SDIO cards.
+
+         Some SDIO cards will need a firmware file to be loaded and
+         sent to VUB300 chip in order to achieve better data throughput.
+         Download these "Offload Pseudocode" from Elan Digital Systems'
+         web-site http://www.elandigitalsystems.com/support/downloads.php
+         and put them in /lib/firmware. Note that without these additional
+         firmware files the VUB300 chip will still function, but not at
+         the best obtainable data rate.
+
+         To compile this mmc host controller driver as a module,
+         choose M here: the module will be called vub300.
+
+         If you have a computer with an embedded VUB300 chip
+         or if you intend connecting a USB adapter based on a
+         VUB300 chip say Y or M here.
+
 config MMC_USHC
        tristate "USB SD Host Controller (USHC) support"
        depends on USB
index 4f1df0aae574eb429f2f0356d20ffd57a7da1e8d..58a5cf73d6e9a0fa77646b5a4ca40c5f48a8f847 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_SDH_BFIN)                += bfin_sdh.o
 obj-$(CONFIG_MMC_DW)           += dw_mmc.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)       += jz4740_mmc.o
+obj-$(CONFIG_MMC_VUB300)       += vub300.o
 obj-$(CONFIG_MMC_USHC)         += ushc.o
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)                  += sdhci-platform.o
index 87e1f57ec9bae7ea4711c9ddfed81600ce819dcb..66dcddb9c20592690c31cd233af7354018c1f4b2 100644 (file)
@@ -1769,9 +1769,6 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
        int i, ret;
        struct dw_mci *host = platform_get_drvdata(pdev);
 
-       if (host->vmmc)
-               regulator_enable(host->vmmc);
-
        for (i = 0; i < host->num_slots; i++) {
                struct dw_mci_slot *slot = host->slot[i];
                if (!slot)
@@ -1798,6 +1795,9 @@ static int dw_mci_resume(struct platform_device *pdev)
        int i, ret;
        struct dw_mci *host = platform_get_drvdata(pdev);
 
+       if (host->vmmc)
+               regulator_enable(host->vmmc);
+
        if (host->dma_ops->init)
                host->dma_ops->init(host);
 
index 4941e06fe2e17511b552bd5a605ea12fb86c5880..5da5bea0f9f09ed49eedf281da1308c04a0b7341 100644 (file)
@@ -51,6 +51,7 @@ static unsigned int fmax = 515633;
  *               is asserted (likewise for RX)
  * @sdio: variant supports SDIO
  * @st_clkdiv: true if using a ST-specific clock divider algorithm
+ * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
  */
 struct variant_data {
        unsigned int            clkreg;
@@ -60,6 +61,7 @@ struct variant_data {
        unsigned int            fifohalfsize;
        bool                    sdio;
        bool                    st_clkdiv;
+       bool                    blksz_datactrl16;
 };
 
 static struct variant_data variant_arm = {
@@ -92,6 +94,17 @@ static struct variant_data variant_ux500 = {
        .st_clkdiv              = true,
 };
 
+static struct variant_data variant_ux500v2 = {
+       .fifosize               = 30 * 4,
+       .fifohalfsize           = 8 * 4,
+       .clkreg                 = MCI_CLK_ENABLE,
+       .clkreg_enable          = MCI_ST_UX500_HWFCEN,
+       .datalength_bits        = 24,
+       .sdio                   = true,
+       .st_clkdiv              = true,
+       .blksz_datactrl16       = true,
+};
+
 /*
  * This must be called with host->lock held
  */
@@ -465,7 +478,10 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
        blksz_bits = ffs(data->blksz) - 1;
        BUG_ON(1 << blksz_bits != data->blksz);
 
-       datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
+       if (variant->blksz_datactrl16)
+               datactrl = MCI_DPSM_ENABLE | (data->blksz << 16);
+       else
+               datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
 
        if (data->flags & MMC_DATA_READ)
                datactrl |= MCI_DPSM_DIRECTION;
@@ -1311,9 +1327,14 @@ static struct amba_id mmci_ids[] = {
        },
        {
                .id     = 0x00480180,
-               .mask   = 0x00ffffff,
+               .mask   = 0xf0ffffff,
                .data   = &variant_ux500,
        },
+       {
+               .id     = 0x10480180,
+               .mask   = 0xf0ffffff,
+               .data   = &variant_ux500v2,
+       },
        { 0, 0 },
 };
 
index f8b5f37007b2a0b8115e62032664e6d96a04e214..936bbca19c0a47b13066b935221f2b583c574a3c 100644 (file)
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/device.h>
-
 #include <linux/mmc/host.h>
-
-#include <asm/scatterlist.h>
-#include <asm/io.h>
+#include <linux/scatterlist.h>
+#include <linux/io.h>
 
 #include "sdhci.h"
 
@@ -46,14 +44,14 @@ struct sdhci_pci_slot;
 struct sdhci_pci_fixes {
        unsigned int            quirks;
 
-       int                     (*probe)(struct sdhci_pci_chip*);
+       int                     (*probe) (struct sdhci_pci_chip *);
 
-       int                     (*probe_slot)(struct sdhci_pci_slot*);
-       void                    (*remove_slot)(struct sdhci_pci_slot*, int);
+       int                     (*probe_slot) (struct sdhci_pci_slot *);
+       void                    (*remove_slot) (struct sdhci_pci_slot *, int);
 
-       int                     (*suspend)(struct sdhci_pci_chip*,
+       int                     (*suspend) (struct sdhci_pci_chip *,
                                        pm_message_t);
-       int                     (*resume)(struct sdhci_pci_chip*);
+       int                     (*resume) (struct sdhci_pci_chip *);
 };
 
 struct sdhci_pci_slot {
@@ -329,6 +327,11 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
                return ret;
        }
 
+       /* quirk for unsable RO-detection on JM388 chips */
+       if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD ||
+           chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
+               chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT;
+
        return 0;
 }
 
@@ -402,7 +405,7 @@ static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state)
 
        if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
            chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
-               for (i = 0;i < chip->num_slots;i++)
+               for (i = 0; i < chip->num_slots; i++)
                        jmicron_enable_mmc(chip->slots[i]->host, 0);
        }
 
@@ -415,7 +418,7 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
 
        if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
            chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
-               for (i = 0;i < chip->num_slots;i++)
+               for (i = 0; i < chip->num_slots; i++)
                        jmicron_enable_mmc(chip->slots[i]->host, 1);
        }
 
@@ -798,7 +801,7 @@ static struct sdhci_ops sdhci_pci_ops = {
 
 #ifdef CONFIG_PM
 
-static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
+static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct sdhci_pci_chip *chip;
        struct sdhci_pci_slot *slot;
@@ -810,7 +813,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
        if (!chip)
                return 0;
 
-       for (i = 0;i < chip->num_slots;i++) {
+       for (i = 0; i < chip->num_slots; i++) {
                slot = chip->slots[i];
                if (!slot)
                        continue;
@@ -818,7 +821,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
                ret = sdhci_suspend_host(slot->host, state);
 
                if (ret) {
-                       for (i--;i >= 0;i--)
+                       for (i--; i >= 0; i--)
                                sdhci_resume_host(chip->slots[i]->host);
                        return ret;
                }
@@ -833,7 +836,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
        if (chip->fixes && chip->fixes->suspend) {
                ret = chip->fixes->suspend(chip, state);
                if (ret) {
-                       for (i = chip->num_slots - 1;i >= 0;i--)
+                       for (i = chip->num_slots - 1; i >= 0; i--)
                                sdhci_resume_host(chip->slots[i]->host);
                        return ret;
                }
@@ -855,7 +858,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
-static int sdhci_pci_resume (struct pci_dev *pdev)
+static int sdhci_pci_resume(struct pci_dev *pdev)
 {
        struct sdhci_pci_chip *chip;
        struct sdhci_pci_slot *slot;
@@ -877,7 +880,7 @@ static int sdhci_pci_resume (struct pci_dev *pdev)
                        return ret;
        }
 
-       for (i = 0;i < chip->num_slots;i++) {
+       for (i = 0; i < chip->num_slots; i++) {
                slot = chip->slots[i];
                if (!slot)
                        continue;
@@ -1059,7 +1062,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
        }
 
        chip->pdev = pdev;
-       chip->fixes = (const struct sdhci_pci_fixes*)ent->driver_data;
+       chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
        if (chip->fixes)
                chip->quirks = chip->fixes->quirks;
        chip->num_slots = slots;
@@ -1074,10 +1077,10 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
 
        slots = chip->num_slots;        /* Quirk may have changed this */
 
-       for (i = 0;i < slots;i++) {
+       for (i = 0; i < slots; i++) {
                slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
                if (IS_ERR(slot)) {
-                       for (i--;i >= 0;i--)
+                       for (i--; i >= 0; i--)
                                sdhci_pci_remove_slot(chip->slots[i]);
                        ret = PTR_ERR(slot);
                        goto free;
@@ -1105,7 +1108,7 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
        chip = pci_get_drvdata(pdev);
 
        if (chip) {
-               for (i = 0;i < chip->num_slots; i++)
+               for (i = 0; i < chip->num_slots; i++)
                        sdhci_pci_remove_slot(chip->slots[i]);
 
                pci_set_drvdata(pdev, NULL);
@@ -1116,9 +1119,9 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
 }
 
 static struct pci_driver sdhci_driver = {
-       .name =         "sdhci-pci",
+       .name =         "sdhci-pci",
        .id_table =     pci_ids,
-       .probe =        sdhci_pci_probe,
+       .probe =        sdhci_pci_probe,
        .remove =       __devexit_p(sdhci_pci_remove),
        .suspend =      sdhci_pci_suspend,
        .resume =       sdhci_pci_resume,
index 5a61208cbc66c8f41f2f760b7321f07f1cd8e131..089c9a68b7b1df68d1cd6a06267aa985664ecfd7 100644 (file)
@@ -69,7 +69,45 @@ static void set_clock(struct sdhci_host *host, unsigned int clock)
        }
 }
 
+static int set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+{
+       u16 ctrl_2;
+
+       /*
+        * Set V18_EN -- UHS modes do not work without this.
+        * does not change signaling voltage
+        */
+       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+       /* Select Bus Speed Mode for host */
+       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+       switch (uhs) {
+       case MMC_TIMING_UHS_SDR12:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+               break;
+       case MMC_TIMING_UHS_SDR25:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+               break;
+       case MMC_TIMING_UHS_SDR50:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;
+               break;
+       case MMC_TIMING_UHS_SDR104:
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
+               break;
+       case MMC_TIMING_UHS_DDR50:
+               ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
+               break;
+       }
+
+       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+       pr_debug("%s:%s uhs = %d, ctrl_2 = %04X\n",
+               __func__, mmc_hostname(host->mmc), uhs, ctrl_2);
+
+       return 0;
+}
+
 static struct sdhci_ops sdhci_pxa_ops = {
+       .set_uhs_signaling = set_uhs_signaling,
        .set_clock = set_clock,
 };
 
@@ -136,11 +174,19 @@ static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
        host->hw_name = "MMC";
        host->ops = &sdhci_pxa_ops;
        host->irq = irq;
-       host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+       host->quirks = SDHCI_QUIRK_BROKEN_ADMA
+               | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
+               | SDHCI_QUIRK_32BIT_DMA_ADDR
+               | SDHCI_QUIRK_32BIT_DMA_SIZE
+               | SDHCI_QUIRK_32BIT_ADMA_SIZE
+               | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
 
        if (pdata->quirks)
                host->quirks |= pdata->quirks;
 
+       /* enable 1/8V DDR capable */
+       host->mmc->caps |= MMC_CAP_1_8V_DDR;
+
        /* If slot design supports 8 bit data, indicate this to MMC. */
        if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
                host->mmc->caps |= MMC_CAP_8_BIT_DATA;
index f7e1f964395fd5bb46264e98c0e474046204293b..343c97edba32bfc780295784cc25869699b734d5 100644 (file)
@@ -184,6 +184,8 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
        clk_enable(clk);
        pltfm_host->clk = clk;
 
+       host->mmc->pm_caps = plat->pm_flags;
+
        if (plat->is_8bit)
                host->mmc->caps |= MMC_CAP_8_BIT_DATA;
 
index 5d20661bc357ba387601b6b2089185bceb144aac..58d5436ff649fb7b0319657464344be692a583c8 100644 (file)
 #define SDHCI_USE_LEDS_CLASS
 #endif
 
+#define MAX_TUNING_LOOP 40
+
 static unsigned int debug_quirks = 0;
 
-static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
 static void sdhci_finish_data(struct sdhci_host *);
 
 static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
 static void sdhci_finish_command(struct sdhci_host *);
+static int sdhci_execute_tuning(struct mmc_host *mmc);
+static void sdhci_tuning_timer(unsigned long data);
 
 static void sdhci_dumpregs(struct sdhci_host *host)
 {
@@ -84,6 +87,8 @@ static void sdhci_dumpregs(struct sdhci_host *host)
        printk(KERN_DEBUG DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
                sdhci_readw(host, SDHCI_COMMAND),
                sdhci_readl(host, SDHCI_MAX_CURRENT));
+       printk(KERN_DEBUG DRIVER_NAME ": Host ctl2: 0x%08x\n",
+               sdhci_readw(host, SDHCI_HOST_CONTROL2));
 
        if (host->flags & SDHCI_USE_ADMA)
                printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
@@ -157,6 +162,9 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
        if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
                ier = sdhci_readl(host, SDHCI_INT_ENABLE);
 
+       if (host->ops->platform_reset_enter)
+               host->ops->platform_reset_enter(host, mask);
+
        sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
 
        if (mask & SDHCI_RESET_ALL)
@@ -177,6 +185,9 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
                mdelay(1);
        }
 
+       if (host->ops->platform_reset_exit)
+               host->ops->platform_reset_exit(host, mask);
+
        if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
                sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
 }
@@ -591,9 +602,10 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
                data->sg_len, direction);
 }
 
-static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
+static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 {
        u8 count;
+       struct mmc_data *data = cmd->data;
        unsigned target_timeout, current_timeout;
 
        /*
@@ -605,9 +617,16 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
        if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
                return 0xE;
 
+       /* Unspecified timeout, assume max */
+       if (!data && !cmd->cmd_timeout_ms)
+               return 0xE;
+
        /* timeout in us */
-       target_timeout = data->timeout_ns / 1000 +
-               data->timeout_clks / host->clock;
+       if (!data)
+               target_timeout = cmd->cmd_timeout_ms * 1000;
+       else
+               target_timeout = data->timeout_ns / 1000 +
+                       data->timeout_clks / host->clock;
 
        if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
                host->timeout_clk = host->clock / 1000;
@@ -622,6 +641,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
         *     =>
         *     (1) / (2) > 2^6
         */
+       BUG_ON(!host->timeout_clk);
        count = 0;
        current_timeout = (1 << 13) * 1000 / host->timeout_clk;
        while (current_timeout < target_timeout) {
@@ -632,8 +652,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
        }
 
        if (count >= 0xF) {
-               printk(KERN_WARNING "%s: Too large timeout requested!\n",
-                       mmc_hostname(host->mmc));
+               printk(KERN_WARNING "%s: Too large timeout requested for CMD%d!\n",
+                      mmc_hostname(host->mmc), cmd->opcode);
                count = 0xE;
        }
 
@@ -651,15 +671,21 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
                sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
 }
 
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
 {
        u8 count;
        u8 ctrl;
+       struct mmc_data *data = cmd->data;
        int ret;
 
        WARN_ON(host->data);
 
-       if (data == NULL)
+       if (data || (cmd->flags & MMC_RSP_BUSY)) {
+               count = sdhci_calc_timeout(host, cmd);
+               sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+       }
+
+       if (!data)
                return;
 
        /* Sanity checks */
@@ -669,9 +695,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 
        host->data = data;
        host->data_early = 0;
-
-       count = sdhci_calc_timeout(host, data);
-       sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+       host->data->bytes_xfered = 0;
 
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
                host->flags |= SDHCI_REQ_USE_DMA;
@@ -807,15 +831,17 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 
        sdhci_set_transfer_irqs(host);
 
-       /* We do not handle DMA boundaries, so set it to max (512 KiB) */
-       sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE);
+       /* Set the DMA boundary value and block size */
+       sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
+               data->blksz), SDHCI_BLOCK_SIZE);
        sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
 }
 
 static void sdhci_set_transfer_mode(struct sdhci_host *host,
-       struct mmc_data *data)
+       struct mmc_command *cmd)
 {
        u16 mode;
+       struct mmc_data *data = cmd->data;
 
        if (data == NULL)
                return;
@@ -823,12 +849,20 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
        WARN_ON(!host->data);
 
        mode = SDHCI_TRNS_BLK_CNT_EN;
-       if (data->blocks > 1) {
-               if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
-                       mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12;
-               else
-                       mode |= SDHCI_TRNS_MULTI;
+       if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
+               mode |= SDHCI_TRNS_MULTI;
+               /*
+                * If we are sending CMD23, CMD12 never gets sent
+                * on successful completion (so no Auto-CMD12).
+                */
+               if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
+                       mode |= SDHCI_TRNS_AUTO_CMD12;
+               else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
+                       mode |= SDHCI_TRNS_AUTO_CMD23;
+                       sdhci_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2);
+               }
        }
+
        if (data->flags & MMC_DATA_READ)
                mode |= SDHCI_TRNS_READ;
        if (host->flags & SDHCI_REQ_USE_DMA)
@@ -868,7 +902,15 @@ static void sdhci_finish_data(struct sdhci_host *host)
        else
                data->bytes_xfered = data->blksz * data->blocks;
 
-       if (data->stop) {
+       /*
+        * Need to send CMD12 if -
+        * a) open-ended multiblock transfer (no CMD23)
+        * b) error in multiblock transfer
+        */
+       if (data->stop &&
+           (data->error ||
+            !host->mrq->sbc)) {
+
                /*
                 * The controller needs a reset of internal state machines
                 * upon error conditions.
@@ -920,11 +962,11 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 
        host->cmd = cmd;
 
-       sdhci_prepare_data(host, cmd->data);
+       sdhci_prepare_data(host, cmd);
 
        sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
 
-       sdhci_set_transfer_mode(host, cmd->data);
+       sdhci_set_transfer_mode(host, cmd);
 
        if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
                printk(KERN_ERR "%s: Unsupported response type!\n",
@@ -947,7 +989,9 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                flags |= SDHCI_CMD_CRC;
        if (cmd->flags & MMC_RSP_OPCODE)
                flags |= SDHCI_CMD_INDEX;
-       if (cmd->data)
+
+       /* CMD19 is special in that the Data Present Select should be set */
+       if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK))
                flags |= SDHCI_CMD_DATA;
 
        sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
@@ -977,19 +1021,27 @@ static void sdhci_finish_command(struct sdhci_host *host)
 
        host->cmd->error = 0;
 
-       if (host->data && host->data_early)
-               sdhci_finish_data(host);
+       /* Finished CMD23, now send actual command. */
+       if (host->cmd == host->mrq->sbc) {
+               host->cmd = NULL;
+               sdhci_send_command(host, host->mrq->cmd);
+       } else {
 
-       if (!host->cmd->data)
-               tasklet_schedule(&host->finish_tasklet);
+               /* Processed actual command. */
+               if (host->data && host->data_early)
+                       sdhci_finish_data(host);
 
-       host->cmd = NULL;
+               if (!host->cmd->data)
+                       tasklet_schedule(&host->finish_tasklet);
+
+               host->cmd = NULL;
+       }
 }
 
 static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
-       int div;
-       u16 clk;
+       int div = 0; /* Initialized for compiler warning */
+       u16 clk = 0;
        unsigned long timeout;
 
        if (clock == host->clock)
@@ -1007,14 +1059,45 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                goto out;
 
        if (host->version >= SDHCI_SPEC_300) {
-               /* Version 3.00 divisors must be a multiple of 2. */
-               if (host->max_clk <= clock)
-                       div = 1;
-               else {
-                       for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
-                               if ((host->max_clk / div) <= clock)
-                                       break;
+               /*
+                * Check if the Host Controller supports Programmable Clock
+                * Mode.
+                */
+               if (host->clk_mul) {
+                       u16 ctrl;
+
+                       /*
+                        * We need to figure out whether the Host Driver needs
+                        * to select Programmable Clock Mode, or the value can
+                        * be set automatically by the Host Controller based on
+                        * the Preset Value registers.
+                        */
+                       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       if (!(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+                               for (div = 1; div <= 1024; div++) {
+                                       if (((host->max_clk * host->clk_mul) /
+                                             div) <= clock)
+                                               break;
+                               }
+                               /*
+                                * Set Programmable Clock Mode in the Clock
+                                * Control register.
+                                */
+                               clk = SDHCI_PROG_CLOCK_MODE;
+                               div--;
                        }
+               } else {
+                       /* Version 3.00 divisors must be a multiple of 2. */
+                       if (host->max_clk <= clock)
+                               div = 1;
+                       else {
+                               for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
+                                    div += 2) {
+                                       if ((host->max_clk / div) <= clock)
+                                               break;
+                               }
+                       }
+                       div >>= 1;
                }
        } else {
                /* Version 2.00 divisors must be a power of 2. */
@@ -1022,10 +1105,10 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                        if ((host->max_clk / div) <= clock)
                                break;
                }
+               div >>= 1;
        }
-       div >>= 1;
 
-       clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+       clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
        clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
                << SDHCI_DIVIDER_HI_SHIFT;
        clk |= SDHCI_CLOCK_INT_EN;
@@ -1131,7 +1214,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 #ifndef SDHCI_USE_LEDS_CLASS
        sdhci_activate_led(host);
 #endif
-       if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) {
+
+       /*
+        * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
+        * requests if Auto-CMD12 is enabled.
+        */
+       if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
                if (mrq->stop) {
                        mrq->data->stop = NULL;
                        mrq->stop = NULL;
@@ -1150,8 +1238,30 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        if (!present || host->flags & SDHCI_DEVICE_DEAD) {
                host->mrq->cmd->error = -ENOMEDIUM;
                tasklet_schedule(&host->finish_tasklet);
-       } else
-               sdhci_send_command(host, mrq->cmd);
+       } else {
+               u32 present_state;
+
+               present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+               /*
+                * Check if the re-tuning timer has already expired and there
+                * is no on-going data transfer. If so, we need to execute
+                * tuning procedure before sending command.
+                */
+               if ((host->flags & SDHCI_NEEDS_RETUNING) &&
+                   !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       sdhci_execute_tuning(mmc);
+                       spin_lock_irqsave(&host->lock, flags);
+
+                       /* Restore original mmc_request structure */
+                       host->mrq = mrq;
+               }
+
+               if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
+                       sdhci_send_command(host, mrq->sbc);
+               else
+                       sdhci_send_command(host, mrq->cmd);
+       }
 
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
@@ -1222,7 +1332,84 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        else
                ctrl &= ~SDHCI_CTRL_HISPD;
 
-       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+       if (host->version >= SDHCI_SPEC_300) {
+               u16 clk, ctrl_2;
+               unsigned int clock;
+
+               /* In case of UHS-I modes, set High Speed Enable */
+               if ((ios->timing == MMC_TIMING_UHS_SDR50) ||
+                   (ios->timing == MMC_TIMING_UHS_SDR104) ||
+                   (ios->timing == MMC_TIMING_UHS_DDR50) ||
+                   (ios->timing == MMC_TIMING_UHS_SDR25) ||
+                   (ios->timing == MMC_TIMING_UHS_SDR12))
+                       ctrl |= SDHCI_CTRL_HISPD;
+
+               ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+               if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+                       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+                       /*
+                        * We only need to set Driver Strength if the
+                        * preset value enable is not set.
+                        */
+                       ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
+                       if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
+                               ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
+                       else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
+                               ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
+
+                       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+               } else {
+                       /*
+                        * According to SDHC Spec v3.00, if the Preset Value
+                        * Enable in the Host Control 2 register is set, we
+                        * need to reset SD Clock Enable before changing High
+                        * Speed Enable to avoid generating clock gliches.
+                        */
+
+                       /* Reset SD Clock Enable */
+                       clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+                       clk &= ~SDHCI_CLOCK_CARD_EN;
+                       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+                       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+                       /* Re-enable SD Clock */
+                       clock = host->clock;
+                       host->clock = 0;
+                       sdhci_set_clock(host, clock);
+               }
+
+
+               /* Reset SD Clock Enable */
+               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+               clk &= ~SDHCI_CLOCK_CARD_EN;
+               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+               if (host->ops->set_uhs_signaling)
+                       host->ops->set_uhs_signaling(host, ios->timing);
+               else {
+                       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       /* Select Bus Speed Mode for host */
+                       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+                       if (ios->timing == MMC_TIMING_UHS_SDR12)
+                               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+                       else if (ios->timing == MMC_TIMING_UHS_SDR25)
+                               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+                       else if (ios->timing == MMC_TIMING_UHS_SDR50)
+                               ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+                       else if (ios->timing == MMC_TIMING_UHS_SDR104)
+                               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+                       else if (ios->timing == MMC_TIMING_UHS_DDR50)
+                               ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+                       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+               }
+
+               /* Re-enable SD Clock */
+               clock = host->clock;
+               host->clock = 0;
+               sdhci_set_clock(host, clock);
+       } else
+               sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
        /*
         * Some (ENE) controllers go apeshit on some ios operation,
@@ -1237,14 +1424,11 @@ out:
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_get_ro(struct mmc_host *mmc)
+static int check_ro(struct sdhci_host *host)
 {
-       struct sdhci_host *host;
        unsigned long flags;
        int is_readonly;
 
-       host = mmc_priv(mmc);
-
        spin_lock_irqsave(&host->lock, flags);
 
        if (host->flags & SDHCI_DEVICE_DEAD)
@@ -1262,6 +1446,29 @@ static int sdhci_get_ro(struct mmc_host *mmc)
                !is_readonly : is_readonly;
 }
 
+#define SAMPLE_COUNT   5
+
+static int sdhci_get_ro(struct mmc_host *mmc)
+{
+       struct sdhci_host *host;
+       int i, ro_count;
+
+       host = mmc_priv(mmc);
+
+       if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
+               return check_ro(host);
+
+       ro_count = 0;
+       for (i = 0; i < SAMPLE_COUNT; i++) {
+               if (check_ro(host)) {
+                       if (++ro_count > SAMPLE_COUNT / 2)
+                               return 1;
+               }
+               msleep(30);
+       }
+       return 0;
+}
+
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 {
        struct sdhci_host *host;
@@ -1284,11 +1491,322 @@ out:
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+       struct mmc_ios *ios)
+{
+       struct sdhci_host *host;
+       u8 pwr;
+       u16 clk, ctrl;
+       u32 present_state;
+
+       host = mmc_priv(mmc);
+
+       /*
+        * Signal Voltage Switching is only applicable for Host Controllers
+        * v3.00 and above.
+        */
+       if (host->version < SDHCI_SPEC_300)
+               return 0;
+
+       /*
+        * We first check whether the request is to set signalling voltage
+        * to 3.3V. If so, we change the voltage to 3.3V and return quickly.
+        */
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+               /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
+               ctrl &= ~SDHCI_CTRL_VDD_180;
+               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+               /* Wait for 5ms */
+               usleep_range(5000, 5500);
+
+               /* 3.3V regulator output should be stable within 5 ms */
+               ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+               if (!(ctrl & SDHCI_CTRL_VDD_180))
+                       return 0;
+               else {
+                       printk(KERN_INFO DRIVER_NAME ": Switching to 3.3V "
+                               "signalling voltage failed\n");
+                       return -EIO;
+               }
+       } else if (!(ctrl & SDHCI_CTRL_VDD_180) &&
+                 (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) {
+               /* Stop SDCLK */
+               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+               clk &= ~SDHCI_CLOCK_CARD_EN;
+               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+               /* Check whether DAT[3:0] is 0000 */
+               present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+               if (!((present_state & SDHCI_DATA_LVL_MASK) >>
+                      SDHCI_DATA_LVL_SHIFT)) {
+                       /*
+                        * Enable 1.8V Signal Enable in the Host Control2
+                        * register
+                        */
+                       ctrl |= SDHCI_CTRL_VDD_180;
+                       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+                       /* Wait for 5ms */
+                       usleep_range(5000, 5500);
+
+                       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       if (ctrl & SDHCI_CTRL_VDD_180) {
+                               /* Provide SDCLK again and wait for 1ms*/
+                               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+                               clk |= SDHCI_CLOCK_CARD_EN;
+                               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+                               usleep_range(1000, 1500);
+
+                               /*
+                                * If DAT[3:0] level is 1111b, then the card
+                                * was successfully switched to 1.8V signaling.
+                                */
+                               present_state = sdhci_readl(host,
+                                                       SDHCI_PRESENT_STATE);
+                               if ((present_state & SDHCI_DATA_LVL_MASK) ==
+                                    SDHCI_DATA_LVL_MASK)
+                                       return 0;
+                       }
+               }
+
+               /*
+                * If we are here, that means the switch to 1.8V signaling
+                * failed. We power cycle the card, and retry initialization
+                * sequence by setting S18R to 0.
+                */
+               pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
+               pwr &= ~SDHCI_POWER_ON;
+               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+               /* Wait for 1ms as per the spec */
+               usleep_range(1000, 1500);
+               pwr |= SDHCI_POWER_ON;
+               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+               printk(KERN_INFO DRIVER_NAME ": Switching to 1.8V signalling "
+                       "voltage failed, retrying with S18R set to 0\n");
+               return -EAGAIN;
+       } else
+               /* No signal voltage switch required */
+               return 0;
+}
+
+static int sdhci_execute_tuning(struct mmc_host *mmc)
+{
+       struct sdhci_host *host;
+       u16 ctrl;
+       u32 ier;
+       int tuning_loop_counter = MAX_TUNING_LOOP;
+       unsigned long timeout;
+       int err = 0;
+
+       host = mmc_priv(mmc);
+
+       disable_irq(host->irq);
+       spin_lock(&host->lock);
+
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+       /*
+        * Host Controller needs tuning only in case of SDR104 mode
+        * and for SDR50 mode when Use Tuning for SDR50 is set in
+        * Capabilities register.
+        */
+       if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
+           (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
+           (host->flags & SDHCI_SDR50_NEEDS_TUNING)))
+               ctrl |= SDHCI_CTRL_EXEC_TUNING;
+       else {
+               spin_unlock(&host->lock);
+               enable_irq(host->irq);
+               return 0;
+       }
+
+       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+       /*
+        * As per the Host Controller spec v3.00, tuning command
+        * generates Buffer Read Ready interrupt, so enable that.
+        *
+        * Note: The spec clearly says that when tuning sequence
+        * is being performed, the controller does not generate
+        * interrupts other than Buffer Read Ready interrupt. But
+        * to make sure we don't hit a controller bug, we _only_
+        * enable Buffer Read Ready interrupt here.
+        */
+       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+       sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
+
+       /*
+        * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
+        * of loops reaches 40 times or a timeout of 150ms occurs.
+        */
+       timeout = 150;
+       do {
+               struct mmc_command cmd = {0};
+               struct mmc_request mrq = {0};
+
+               if (!tuning_loop_counter && !timeout)
+                       break;
+
+               cmd.opcode = MMC_SEND_TUNING_BLOCK;
+               cmd.arg = 0;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+               cmd.retries = 0;
+               cmd.data = NULL;
+               cmd.error = 0;
+
+               mrq.cmd = &cmd;
+               host->mrq = &mrq;
+
+               /*
+                * In response to CMD19, the card sends 64 bytes of tuning
+                * block to the Host Controller. So we set the block size
+                * to 64 here.
+                */
+               sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
+
+               /*
+                * The tuning block is sent by the card to the host controller.
+                * So we set the TRNS_READ bit in the Transfer Mode register.
+                * This also takes care of setting DMA Enable and Multi Block
+                * Select in the same register to 0.
+                */
+               sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+               sdhci_send_command(host, &cmd);
+
+               host->cmd = NULL;
+               host->mrq = NULL;
+
+               spin_unlock(&host->lock);
+               enable_irq(host->irq);
+
+               /* Wait for Buffer Read Ready interrupt */
+               wait_event_interruptible_timeout(host->buf_ready_int,
+                                       (host->tuning_done == 1),
+                                       msecs_to_jiffies(50));
+               disable_irq(host->irq);
+               spin_lock(&host->lock);
+
+               if (!host->tuning_done) {
+                       printk(KERN_INFO DRIVER_NAME ": Timeout waiting for "
+                               "Buffer Read Ready interrupt during tuning "
+                               "procedure, falling back to fixed sampling "
+                               "clock\n");
+                       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+                       ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+                       ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
+                       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+                       err = -EIO;
+                       goto out;
+               }
+
+               host->tuning_done = 0;
+
+               ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+               tuning_loop_counter--;
+               timeout--;
+               mdelay(1);
+       } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
+
+       /*
+        * The Host Driver has exhausted the maximum number of loops allowed,
+        * so use fixed sampling frequency.
+        */
+       if (!tuning_loop_counter || !timeout) {
+               ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+       } else {
+               if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
+                       printk(KERN_INFO DRIVER_NAME ": Tuning procedure"
+                               " failed, falling back to fixed sampling"
+                               " clock\n");
+                       err = -EIO;
+               }
+       }
+
+out:
+       /*
+        * If this is the very first time we are here, we start the retuning
+        * timer. Since only during the first time, SDHCI_NEEDS_RETUNING
+        * flag won't be set, we check this condition before actually starting
+        * the timer.
+        */
+       if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count &&
+           (host->tuning_mode == SDHCI_TUNING_MODE_1)) {
+               mod_timer(&host->tuning_timer, jiffies +
+                       host->tuning_count * HZ);
+               /* Tuning mode 1 limits the maximum data length to 4MB */
+               mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
+       } else {
+               host->flags &= ~SDHCI_NEEDS_RETUNING;
+               /* Reload the new initial value for timer */
+               if (host->tuning_mode == SDHCI_TUNING_MODE_1)
+                       mod_timer(&host->tuning_timer, jiffies +
+                               host->tuning_count * HZ);
+       }
+
+       /*
+        * In case tuning fails, host controllers which support re-tuning can
+        * try tuning again at a later time, when the re-tuning timer expires.
+        * So for these controllers, we return 0. Since there might be other
+        * controllers who do not have this capability, we return error for
+        * them.
+        */
+       if (err && host->tuning_count &&
+           host->tuning_mode == SDHCI_TUNING_MODE_1)
+               err = 0;
+
+       sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
+       spin_unlock(&host->lock);
+       enable_irq(host->irq);
+
+       return err;
+}
+
+static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
+{
+       struct sdhci_host *host;
+       u16 ctrl;
+       unsigned long flags;
+
+       host = mmc_priv(mmc);
+
+       /* Host Controller v3.00 defines preset value registers */
+       if (host->version < SDHCI_SPEC_300)
+               return;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+       /*
+        * We only enable or disable Preset Value if they are not already
+        * enabled or disabled respectively. Otherwise, we bail out.
+        */
+       if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+               ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
+               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+       } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+               ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
 static const struct mmc_host_ops sdhci_ops = {
        .request        = sdhci_request,
        .set_ios        = sdhci_set_ios,
        .get_ro         = sdhci_get_ro,
        .enable_sdio_irq = sdhci_enable_sdio_irq,
+       .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
+       .execute_tuning                 = sdhci_execute_tuning,
+       .enable_preset_value            = sdhci_enable_preset_value,
 };
 
 /*****************************************************************************\
@@ -1345,6 +1863,9 @@ static void sdhci_tasklet_finish(unsigned long param)
 
        del_timer(&host->timer);
 
+       if (host->version >= SDHCI_SPEC_300)
+               del_timer(&host->tuning_timer);
+
        mrq = host->mrq;
 
        /*
@@ -1418,6 +1939,20 @@ static void sdhci_timeout_timer(unsigned long data)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static void sdhci_tuning_timer(unsigned long data)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+
+       host = (struct sdhci_host *)data;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       host->flags |= SDHCI_NEEDS_RETUNING;
+
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Interrupt handling                                                        *
@@ -1506,6 +2041,16 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 {
        BUG_ON(intmask == 0);
 
+       /* CMD19 generates _only_ Buffer Read Ready interrupt */
+       if (intmask & SDHCI_INT_DATA_AVAIL) {
+               if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) ==
+                   MMC_SEND_TUNING_BLOCK) {
+                       host->tuning_done = 1;
+                       wake_up(&host->buf_ready_int);
+                       return;
+               }
+       }
+
        if (!host->data) {
                /*
                 * The "data complete" interrupt is also used to
@@ -1551,10 +2096,28 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                 * We currently don't do anything fancy with DMA
                 * boundaries, but as we can't disable the feature
                 * we need to at least restart the transfer.
+                *
+                * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
+                * should return a valid address to continue from, but as
+                * some controllers are faulty, don't trust them.
                 */
-               if (intmask & SDHCI_INT_DMA_END)
-                       sdhci_writel(host, sdhci_readl(host, SDHCI_DMA_ADDRESS),
-                               SDHCI_DMA_ADDRESS);
+               if (intmask & SDHCI_INT_DMA_END) {
+                       u32 dmastart, dmanow;
+                       dmastart = sg_dma_address(host->data->sg);
+                       dmanow = dmastart + host->data->bytes_xfered;
+                       /*
+                        * Force update to the next DMA block boundary.
+                        */
+                       dmanow = (dmanow &
+                               ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
+                               SDHCI_DEFAULT_BOUNDARY_SIZE;
+                       host->data->bytes_xfered = dmanow - dmastart;
+                       DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes,"
+                               " next 0x%08x\n",
+                               mmc_hostname(host->mmc), dmastart,
+                               host->data->bytes_xfered, dmanow);
+                       sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
+               }
 
                if (intmask & SDHCI_INT_DATA_END) {
                        if (host->cmd) {
@@ -1664,6 +2227,14 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
 
        sdhci_disable_card_detection(host);
 
+       /* Disable tuning since we are suspending */
+       if (host->version >= SDHCI_SPEC_300 && host->tuning_count &&
+           host->tuning_mode == SDHCI_TUNING_MODE_1) {
+               host->flags &= ~SDHCI_NEEDS_RETUNING;
+               mod_timer(&host->tuning_timer, jiffies +
+                       host->tuning_count * HZ);
+       }
+
        ret = mmc_suspend_host(host->mmc);
        if (ret)
                return ret;
@@ -1705,6 +2276,11 @@ int sdhci_resume_host(struct sdhci_host *host)
        ret = mmc_resume_host(host->mmc);
        sdhci_enable_card_detection(host);
 
+       /* Set the re-tuning expiration flag */
+       if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
+           (host->tuning_mode == SDHCI_TUNING_MODE_1))
+               host->flags |= SDHCI_NEEDS_RETUNING;
+
        return ret;
 }
 
@@ -1751,7 +2327,9 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
 int sdhci_add_host(struct sdhci_host *host)
 {
        struct mmc_host *mmc;
-       unsigned int caps, ocr_avail;
+       u32 caps[2];
+       u32 max_current_caps;
+       unsigned int ocr_avail;
        int ret;
 
        WARN_ON(host == NULL);
@@ -1774,12 +2352,15 @@ int sdhci_add_host(struct sdhci_host *host)
                        host->version);
        }
 
-       caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
+       caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
                sdhci_readl(host, SDHCI_CAPABILITIES);
 
+       caps[1] = (host->version >= SDHCI_SPEC_300) ?
+               sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0;
+
        if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
                host->flags |= SDHCI_USE_SDMA;
-       else if (!(caps & SDHCI_CAN_DO_SDMA))
+       else if (!(caps[0] & SDHCI_CAN_DO_SDMA))
                DBG("Controller doesn't have SDMA capability\n");
        else
                host->flags |= SDHCI_USE_SDMA;
@@ -1790,7 +2371,8 @@ int sdhci_add_host(struct sdhci_host *host)
                host->flags &= ~SDHCI_USE_SDMA;
        }
 
-       if ((host->version >= SDHCI_SPEC_200) && (caps & SDHCI_CAN_DO_ADMA2))
+       if ((host->version >= SDHCI_SPEC_200) &&
+               (caps[0] & SDHCI_CAN_DO_ADMA2))
                host->flags |= SDHCI_USE_ADMA;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
@@ -1840,10 +2422,10 @@ int sdhci_add_host(struct sdhci_host *host)
        }
 
        if (host->version >= SDHCI_SPEC_300)
-               host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK)
+               host->max_clk = (caps[0] & SDHCI_CLOCK_V3_BASE_MASK)
                        >> SDHCI_CLOCK_BASE_SHIFT;
        else
-               host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK)
+               host->max_clk = (caps[0] & SDHCI_CLOCK_BASE_MASK)
                        >> SDHCI_CLOCK_BASE_SHIFT;
 
        host->max_clk *= 1000000;
@@ -1859,7 +2441,7 @@ int sdhci_add_host(struct sdhci_host *host)
        }
 
        host->timeout_clk =
-               (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+               (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
        if (host->timeout_clk == 0) {
                if (host->ops->get_timeout_clock) {
                        host->timeout_clk = host->ops->get_timeout_clock(host);
@@ -1871,22 +2453,55 @@ int sdhci_add_host(struct sdhci_host *host)
                        return -ENODEV;
                }
        }
-       if (caps & SDHCI_TIMEOUT_CLK_UNIT)
+       if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
                host->timeout_clk *= 1000;
 
+       /*
+        * In case of Host Controller v3.00, find out whether clock
+        * multiplier is supported.
+        */
+       host->clk_mul = (caps[1] & SDHCI_CLOCK_MUL_MASK) >>
+                       SDHCI_CLOCK_MUL_SHIFT;
+
+       /*
+        * In case the value in Clock Multiplier is 0, then programmable
+        * clock mode is not supported, otherwise the actual clock
+        * multiplier is one more than the value of Clock Multiplier
+        * in the Capabilities Register.
+        */
+       if (host->clk_mul)
+               host->clk_mul += 1;
+
        /*
         * Set host parameters.
         */
        mmc->ops = &sdhci_ops;
+       mmc->f_max = host->max_clk;
        if (host->ops->get_min_clock)
                mmc->f_min = host->ops->get_min_clock(host);
-       else if (host->version >= SDHCI_SPEC_300)
-               mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
-       else
+       else if (host->version >= SDHCI_SPEC_300) {
+               if (host->clk_mul) {
+                       mmc->f_min = (host->max_clk * host->clk_mul) / 1024;
+                       mmc->f_max = host->max_clk * host->clk_mul;
+               } else
+                       mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
+       } else
                mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
 
-       mmc->f_max = host->max_clk;
-       mmc->caps |= MMC_CAP_SDIO_IRQ;
+       mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
+
+       if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
+               host->flags |= SDHCI_AUTO_CMD12;
+
+       /* Auto-CMD23 stuff only works in ADMA or PIO. */
+       if ((host->version >= SDHCI_SPEC_300) &&
+           ((host->flags & SDHCI_USE_ADMA) ||
+            !(host->flags & SDHCI_USE_SDMA))) {
+               host->flags |= SDHCI_AUTO_CMD23;
+               DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
+       } else {
+               DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc));
+       }
 
        /*
         * A controller may support 8-bit width, but the board itself
@@ -1898,21 +2513,113 @@ int sdhci_add_host(struct sdhci_host *host)
        if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
-       if (caps & SDHCI_CAN_DO_HISPD)
+       if (caps[0] & SDHCI_CAN_DO_HISPD)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
            mmc_card_is_removable(mmc))
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
+       /* UHS-I mode(s) supported by the host controller. */
+       if (host->version >= SDHCI_SPEC_300)
+               mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
+
+       /* SDR104 supports also implies SDR50 support */
+       if (caps[1] & SDHCI_SUPPORT_SDR104)
+               mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
+       else if (caps[1] & SDHCI_SUPPORT_SDR50)
+               mmc->caps |= MMC_CAP_UHS_SDR50;
+
+       if (caps[1] & SDHCI_SUPPORT_DDR50)
+               mmc->caps |= MMC_CAP_UHS_DDR50;
+
+       /* Does the host needs tuning for SDR50? */
+       if (caps[1] & SDHCI_USE_SDR50_TUNING)
+               host->flags |= SDHCI_SDR50_NEEDS_TUNING;
+
+       /* Driver Type(s) (A, C, D) supported by the host */
+       if (caps[1] & SDHCI_DRIVER_TYPE_A)
+               mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
+       if (caps[1] & SDHCI_DRIVER_TYPE_C)
+               mmc->caps |= MMC_CAP_DRIVER_TYPE_C;
+       if (caps[1] & SDHCI_DRIVER_TYPE_D)
+               mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
+
+       /* Initial value for re-tuning timer count */
+       host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
+                             SDHCI_RETUNING_TIMER_COUNT_SHIFT;
+
+       /*
+        * In case Re-tuning Timer is not disabled, the actual value of
+        * re-tuning timer will be 2 ^ (n - 1).
+        */
+       if (host->tuning_count)
+               host->tuning_count = 1 << (host->tuning_count - 1);
+
+       /* Re-tuning mode supported by the Host Controller */
+       host->tuning_mode = (caps[1] & SDHCI_RETUNING_MODE_MASK) >>
+                            SDHCI_RETUNING_MODE_SHIFT;
+
        ocr_avail = 0;
-       if (caps & SDHCI_CAN_VDD_330)
+       /*
+        * According to SD Host Controller spec v3.00, if the Host System
+        * can afford more than 150mA, Host Driver should set XPC to 1. Also
+        * the value is meaningful only if Voltage Support in the Capabilities
+        * register is set. The actual current value is 4 times the register
+        * value.
+        */
+       max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
+
+       if (caps[0] & SDHCI_CAN_VDD_330) {
+               int max_current_330;
+
                ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
-       if (caps & SDHCI_CAN_VDD_300)
+
+               max_current_330 = ((max_current_caps &
+                                  SDHCI_MAX_CURRENT_330_MASK) >>
+                                  SDHCI_MAX_CURRENT_330_SHIFT) *
+                                  SDHCI_MAX_CURRENT_MULTIPLIER;
+
+               if (max_current_330 > 150)
+                       mmc->caps |= MMC_CAP_SET_XPC_330;
+       }
+       if (caps[0] & SDHCI_CAN_VDD_300) {
+               int max_current_300;
+
                ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
-       if (caps & SDHCI_CAN_VDD_180)
+
+               max_current_300 = ((max_current_caps &
+                                  SDHCI_MAX_CURRENT_300_MASK) >>
+                                  SDHCI_MAX_CURRENT_300_SHIFT) *
+                                  SDHCI_MAX_CURRENT_MULTIPLIER;
+
+               if (max_current_300 > 150)
+                       mmc->caps |= MMC_CAP_SET_XPC_300;
+       }
+       if (caps[0] & SDHCI_CAN_VDD_180) {
+               int max_current_180;
+
                ocr_avail |= MMC_VDD_165_195;
 
+               max_current_180 = ((max_current_caps &
+                                  SDHCI_MAX_CURRENT_180_MASK) >>
+                                  SDHCI_MAX_CURRENT_180_SHIFT) *
+                                  SDHCI_MAX_CURRENT_MULTIPLIER;
+
+               if (max_current_180 > 150)
+                       mmc->caps |= MMC_CAP_SET_XPC_180;
+
+               /* Maximum current capabilities of the host at 1.8V */
+               if (max_current_180 >= 800)
+                       mmc->caps |= MMC_CAP_MAX_CURRENT_800;
+               else if (max_current_180 >= 600)
+                       mmc->caps |= MMC_CAP_MAX_CURRENT_600;
+               else if (max_current_180 >= 400)
+                       mmc->caps |= MMC_CAP_MAX_CURRENT_400;
+               else
+                       mmc->caps |= MMC_CAP_MAX_CURRENT_200;
+       }
+
        mmc->ocr_avail = ocr_avail;
        mmc->ocr_avail_sdio = ocr_avail;
        if (host->ocr_avail_sdio)
@@ -1972,7 +2679,7 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
                mmc->max_blk_size = 2;
        } else {
-               mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >>
+               mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >>
                                SDHCI_MAX_BLOCK_SHIFT;
                if (mmc->max_blk_size >= 3) {
                        printk(KERN_WARNING "%s: Invalid maximum block size, "
@@ -1998,6 +2705,15 @@ int sdhci_add_host(struct sdhci_host *host)
 
        setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
 
+       if (host->version >= SDHCI_SPEC_300) {
+               init_waitqueue_head(&host->buf_ready_int);
+
+               /* Initialize re-tuning timer */
+               init_timer(&host->tuning_timer);
+               host->tuning_timer.data = (unsigned long)host;
+               host->tuning_timer.function = sdhci_tuning_timer;
+       }
+
        ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
                mmc_hostname(mmc), host);
        if (ret)
@@ -2091,6 +2807,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
        free_irq(host->irq, host);
 
        del_timer_sync(&host->timer);
+       if (host->version >= SDHCI_SPEC_300)
+               del_timer_sync(&host->tuning_timer);
 
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
index 25e8bde600d1e839a3b44caf77558ec8a52d381c..745c42fa41ed5fb85cfc45ff9238e37b222ae2b1 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #define SDHCI_DMA_ADDRESS      0x00
+#define SDHCI_ARGUMENT2                SDHCI_DMA_ADDRESS
 
 #define SDHCI_BLOCK_SIZE       0x04
 #define  SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
@@ -36,7 +37,8 @@
 #define SDHCI_TRANSFER_MODE    0x0C
 #define  SDHCI_TRNS_DMA                0x01
 #define  SDHCI_TRNS_BLK_CNT_EN 0x02
-#define  SDHCI_TRNS_ACMD12     0x04
+#define  SDHCI_TRNS_AUTO_CMD12 0x04
+#define  SDHCI_TRNS_AUTO_CMD23 0x08
 #define  SDHCI_TRNS_READ       0x10
 #define  SDHCI_TRNS_MULTI      0x20
 
 #define  SDHCI_DATA_AVAILABLE  0x00000800
 #define  SDHCI_CARD_PRESENT    0x00010000
 #define  SDHCI_WRITE_PROTECT   0x00080000
+#define  SDHCI_DATA_LVL_MASK   0x00F00000
+#define   SDHCI_DATA_LVL_SHIFT 20
 
-#define SDHCI_HOST_CONTROL     0x28
+#define SDHCI_HOST_CONTROL     0x28
 #define  SDHCI_CTRL_LED                0x01
 #define  SDHCI_CTRL_4BITBUS    0x02
 #define  SDHCI_CTRL_HISPD      0x04
 #define  SDHCI_DIV_MASK        0xFF
 #define  SDHCI_DIV_MASK_LEN    8
 #define  SDHCI_DIV_HI_MASK     0x300
+#define  SDHCI_PROG_CLOCK_MODE 0x0020
 #define  SDHCI_CLOCK_CARD_EN   0x0004
 #define  SDHCI_CLOCK_INT_STABLE        0x0002
 #define  SDHCI_CLOCK_INT_EN    0x0001
 
 #define SDHCI_ACMD12_ERR       0x3C
 
-/* 3E-3F reserved */
+#define SDHCI_HOST_CONTROL2            0x3E
+#define  SDHCI_CTRL_UHS_MASK           0x0007
+#define   SDHCI_CTRL_UHS_SDR12         0x0000
+#define   SDHCI_CTRL_UHS_SDR25         0x0001
+#define   SDHCI_CTRL_UHS_SDR50         0x0002
+#define   SDHCI_CTRL_UHS_SDR104                0x0003
+#define   SDHCI_CTRL_UHS_DDR50         0x0004
+#define  SDHCI_CTRL_VDD_180            0x0008
+#define  SDHCI_CTRL_DRV_TYPE_MASK      0x0030
+#define   SDHCI_CTRL_DRV_TYPE_B                0x0000
+#define   SDHCI_CTRL_DRV_TYPE_A                0x0010
+#define   SDHCI_CTRL_DRV_TYPE_C                0x0020
+#define   SDHCI_CTRL_DRV_TYPE_D                0x0030
+#define  SDHCI_CTRL_EXEC_TUNING                0x0040
+#define  SDHCI_CTRL_TUNED_CLK          0x0080
+#define  SDHCI_CTRL_PRESET_VAL_ENABLE  0x8000
 
 #define SDHCI_CAPABILITIES     0x40
 #define  SDHCI_TIMEOUT_CLK_MASK        0x0000003F
 #define  SDHCI_CAN_VDD_180     0x04000000
 #define  SDHCI_CAN_64BIT       0x10000000
 
+#define  SDHCI_SUPPORT_SDR50   0x00000001
+#define  SDHCI_SUPPORT_SDR104  0x00000002
+#define  SDHCI_SUPPORT_DDR50   0x00000004
+#define  SDHCI_DRIVER_TYPE_A   0x00000010
+#define  SDHCI_DRIVER_TYPE_C   0x00000020
+#define  SDHCI_DRIVER_TYPE_D   0x00000040
+#define  SDHCI_RETUNING_TIMER_COUNT_MASK       0x00000F00
+#define  SDHCI_RETUNING_TIMER_COUNT_SHIFT      8
+#define  SDHCI_USE_SDR50_TUNING                        0x00002000
+#define  SDHCI_RETUNING_MODE_MASK              0x0000C000
+#define  SDHCI_RETUNING_MODE_SHIFT             14
+#define  SDHCI_CLOCK_MUL_MASK  0x00FF0000
+#define  SDHCI_CLOCK_MUL_SHIFT 16
+
 #define SDHCI_CAPABILITIES_1   0x44
 
-#define SDHCI_MAX_CURRENT      0x48
+#define SDHCI_MAX_CURRENT              0x48
+#define  SDHCI_MAX_CURRENT_330_MASK    0x0000FF
+#define  SDHCI_MAX_CURRENT_330_SHIFT   0
+#define  SDHCI_MAX_CURRENT_300_MASK    0x00FF00
+#define  SDHCI_MAX_CURRENT_300_SHIFT   8
+#define  SDHCI_MAX_CURRENT_180_MASK    0xFF0000
+#define  SDHCI_MAX_CURRENT_180_SHIFT   16
+#define   SDHCI_MAX_CURRENT_MULTIPLIER 4
 
 /* 4C-4F reserved for more max current */
 
 #define SDHCI_MAX_DIV_SPEC_200 256
 #define SDHCI_MAX_DIV_SPEC_300 2046
 
+/*
+ * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2.
+ */
+#define SDHCI_DEFAULT_BOUNDARY_SIZE  (512 * 1024)
+#define SDHCI_DEFAULT_BOUNDARY_ARG   (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
+
 struct sdhci_ops {
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
        u32             (*read_l)(struct sdhci_host *host, int reg);
@@ -223,6 +270,10 @@ struct sdhci_ops {
        void (*platform_send_init_74_clocks)(struct sdhci_host *host,
                                             u8 power_mode);
        unsigned int    (*get_ro)(struct sdhci_host *host);
+       void    (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
+       void    (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
+       int     (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
+
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
index af97015a2fc7f57b216992a2032869f40cbf5e59..14f8edbaa19551d3d4c72abae3e2cb4f51e24c3f 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/mmc/sh_mmcif.h>
 #include <linux/pagemap.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
 
 #define DRIVER_NAME    "sh_mmcif"
 #define DRIVER_VERSION "2010-04-28"
 #define CLKDEV_MMC_DATA                20000000 /* 20MHz */
 #define CLKDEV_INIT            400000   /* 400 KHz */
 
+enum mmcif_state {
+       STATE_IDLE,
+       STATE_REQUEST,
+       STATE_IOS,
+};
+
 struct sh_mmcif_host {
        struct mmc_host *mmc;
        struct mmc_data *data;
@@ -164,6 +172,9 @@ struct sh_mmcif_host {
        long timeout;
        void __iomem *addr;
        struct completion intr_wait;
+       enum mmcif_state state;
+       spinlock_t lock;
+       bool power;
 
        /* DMA support */
        struct dma_chan         *chan_rx;
@@ -798,17 +809,31 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
 static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct sh_mmcif_host *host = mmc_priv(mmc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (host->state != STATE_IDLE) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               mrq->cmd->error = -EAGAIN;
+               mmc_request_done(mmc, mrq);
+               return;
+       }
+
+       host->state = STATE_REQUEST;
+       spin_unlock_irqrestore(&host->lock, flags);
 
        switch (mrq->cmd->opcode) {
        /* MMCIF does not support SD/SDIO command */
        case SD_IO_SEND_OP_COND:
        case MMC_APP_CMD:
+               host->state = STATE_IDLE;
                mrq->cmd->error = -ETIMEDOUT;
                mmc_request_done(mmc, mrq);
                return;
        case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
                if (!mrq->data) {
                        /* send_if_cond cmd (not support) */
+                       host->state = STATE_IDLE;
                        mrq->cmd->error = -ETIMEDOUT;
                        mmc_request_done(mmc, mrq);
                        return;
@@ -830,12 +855,9 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
        sh_mmcif_start_cmd(host, mrq, mrq->cmd);
        host->data = NULL;
 
-       if (mrq->cmd->error != 0) {
-               mmc_request_done(mmc, mrq);
-               return;
-       }
-       if (mrq->stop)
+       if (!mrq->cmd->error && mrq->stop)
                sh_mmcif_stop_cmd(host, mrq, mrq->stop);
+       host->state = STATE_IDLE;
        mmc_request_done(mmc, mrq);
 }
 
@@ -843,15 +865,39 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct sh_mmcif_host *host = mmc_priv(mmc);
        struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (host->state != STATE_IDLE) {
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+       host->state = STATE_IOS;
+       spin_unlock_irqrestore(&host->lock, flags);
 
        if (ios->power_mode == MMC_POWER_UP) {
                if (p->set_pwr)
                        p->set_pwr(host->pd, ios->power_mode);
+               if (!host->power) {
+                       /* See if we also get DMA */
+                       sh_mmcif_request_dma(host, host->pd->dev.platform_data);
+                       pm_runtime_get_sync(&host->pd->dev);
+                       host->power = true;
+               }
        } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
                /* clock stop */
                sh_mmcif_clock_control(host, 0);
-               if (ios->power_mode == MMC_POWER_OFF && p->down_pwr)
-                       p->down_pwr(host->pd);
+               if (ios->power_mode == MMC_POWER_OFF) {
+                       if (host->power) {
+                               pm_runtime_put(&host->pd->dev);
+                               sh_mmcif_release_dma(host);
+                               host->power = false;
+                       }
+                       if (p->down_pwr)
+                               p->down_pwr(host->pd);
+               }
+               host->state = STATE_IDLE;
                return;
        }
 
@@ -859,6 +905,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                sh_mmcif_clock_control(host, ios->clock);
 
        host->bus_width = ios->bus_width;
+       host->state = STATE_IDLE;
 }
 
 static int sh_mmcif_get_cd(struct mmc_host *mmc)
@@ -925,7 +972,7 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
                err = 1;
        } else {
-               dev_dbg(&host->pd->dev, "Not support int\n");
+               dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state);
                sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
                sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
                err = 1;
@@ -996,6 +1043,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        host->pd = pdev;
 
        init_completion(&host->intr_wait);
+       spin_lock_init(&host->lock);
 
        mmc->ops = &sh_mmcif_ops;
        mmc->f_max = host->clk;
@@ -1020,24 +1068,29 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        sh_mmcif_sync_reset(host);
        platform_set_drvdata(pdev, host);
 
-       /* See if we also get DMA */
-       sh_mmcif_request_dma(host, pd);
+       pm_runtime_enable(&pdev->dev);
+       host->power = false;
+
+       ret = pm_runtime_resume(&pdev->dev);
+       if (ret < 0)
+               goto clean_up2;
 
        mmc_add_host(mmc);
 
+       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+
        ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
        if (ret) {
                dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
-               goto clean_up2;
+               goto clean_up3;
        }
        ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
        if (ret) {
                free_irq(irq[0], host);
                dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
-               goto clean_up2;
+               goto clean_up3;
        }
 
-       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
        sh_mmcif_detect(host->mmc);
 
        dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
@@ -1045,7 +1098,11 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
                sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
        return ret;
 
+clean_up3:
+       mmc_remove_host(mmc);
+       pm_runtime_suspend(&pdev->dev);
 clean_up2:
+       pm_runtime_disable(&pdev->dev);
        clk_disable(host->hclk);
 clean_up1:
        mmc_free_host(mmc);
@@ -1060,14 +1117,14 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
        struct sh_mmcif_host *host = platform_get_drvdata(pdev);
        int irq[2];
 
+       pm_runtime_get_sync(&pdev->dev);
+
        mmc_remove_host(host->mmc);
-       sh_mmcif_release_dma(host);
+       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
 
        if (host->addr)
                iounmap(host->addr);
 
-       sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
-
        irq[0] = platform_get_irq(pdev, 0);
        irq[1] = platform_get_irq(pdev, 1);
 
@@ -1078,15 +1135,52 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
 
        clk_disable(host->hclk);
        mmc_free_host(host->mmc);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int sh_mmcif_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_mmcif_host *host = platform_get_drvdata(pdev);
+       int ret = mmc_suspend_host(host->mmc);
+
+       if (!ret) {
+               sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+               clk_disable(host->hclk);
+       }
+
+       return ret;
+}
+
+static int sh_mmcif_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct sh_mmcif_host *host = platform_get_drvdata(pdev);
+
+       clk_enable(host->hclk);
+
+       return mmc_resume_host(host->mmc);
+}
+#else
+#define sh_mmcif_suspend       NULL
+#define sh_mmcif_resume                NULL
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
+       .suspend = sh_mmcif_suspend,
+       .resume = sh_mmcif_resume,
+};
+
 static struct platform_driver sh_mmcif_driver = {
        .probe          = sh_mmcif_probe,
        .remove         = sh_mmcif_remove,
        .driver         = {
                .name   = DRIVER_NAME,
+               .pm     = &sh_mmcif_dev_pm_ops,
        },
 };
 
index cc701236d16f126895c72d360c4e836582d536fa..b3654293017bca33d4de5b77d0f654e07fb92031 100644 (file)
@@ -62,7 +62,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
        struct tmio_mmc_host *host;
        char clk_name[8];
-       int ret;
+       int i, irq, ret;
 
        priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
        if (priv == NULL) {
@@ -71,6 +71,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        }
 
        mmc_data = &priv->mmc_data;
+       p->pdata = mmc_data;
 
        snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
        priv->clk = clk_get(&pdev->dev, clk_name);
@@ -116,11 +117,36 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        if (ret < 0)
                goto eprobe;
 
-       pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
-               (unsigned long)host->ctl, host->irq);
+       for (i = 0; i < 3; i++) {
+               irq = platform_get_irq(pdev, i);
+               if (irq < 0) {
+                       if (i) {
+                               continue;
+                       } else {
+                               ret = irq;
+                               goto eirq;
+                       }
+               }
+               ret = request_irq(irq, tmio_mmc_irq, 0,
+                                 dev_name(&pdev->dev), host);
+               if (ret) {
+                       while (i--) {
+                               irq = platform_get_irq(pdev, i);
+                               if (irq >= 0)
+                                       free_irq(irq, host);
+                       }
+                       goto eirq;
+               }
+       }
+       dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
+                mmc_hostname(host->mmc), (unsigned long)
+                (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start),
+                mmc_data->hclk / 1000000);
 
        return ret;
 
+eirq:
+       tmio_mmc_host_remove(host);
 eprobe:
        clk_disable(priv->clk);
        clk_put(priv->clk);
@@ -134,6 +160,16 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
        struct mmc_host *mmc = platform_get_drvdata(pdev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
        struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+       struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
+       int i, irq;
+
+       p->pdata = NULL;
+
+       for (i = 0; i < 3; i++) {
+               irq = platform_get_irq(pdev, i);
+               if (irq >= 0)
+                       free_irq(irq, host);
+       }
 
        tmio_mmc_host_remove(host);
        clk_disable(priv->clk);
@@ -143,10 +179,18 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
+       .suspend = tmio_mmc_host_suspend,
+       .resume = tmio_mmc_host_resume,
+       .runtime_suspend = tmio_mmc_host_runtime_suspend,
+       .runtime_resume = tmio_mmc_host_runtime_resume,
+};
+
 static struct platform_driver sh_mobile_sdhi_driver = {
        .driver         = {
                .name   = "sh_mobile_sdhi",
                .owner  = THIS_MODULE,
+               .pm     = &tmio_mmc_dev_pm_ops,
        },
        .probe          = sh_mobile_sdhi_probe,
        .remove         = __devexit_p(sh_mobile_sdhi_remove),
index 79c568461d59565b587627237ba6bb6de8950005..14479f9ef53f93cb514e54974650af5a901f3996 100644 (file)
@@ -30,7 +30,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
        struct mmc_host *mmc = platform_get_drvdata(dev);
        int ret;
 
-       ret = mmc_suspend_host(mmc);
+       ret = tmio_mmc_host_suspend(&dev->dev);
 
        /* Tell MFD core it can disable us now.*/
        if (!ret && cell->disable)
@@ -46,15 +46,12 @@ static int tmio_mmc_resume(struct platform_device *dev)
        int ret = 0;
 
        /* Tell the MFD core we are ready to be enabled */
-       if (cell->resume) {
+       if (cell->resume)
                ret = cell->resume(dev);
-               if (ret)
-                       goto out;
-       }
 
-       mmc_resume_host(mmc);
+       if (!ret)
+               ret = tmio_mmc_host_resume(&dev->dev);
 
-out:
        return ret;
 }
 #else
@@ -67,7 +64,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev)
        const struct mfd_cell *cell = mfd_get_cell(pdev);
        struct tmio_mmc_data *pdata;
        struct tmio_mmc_host *host;
-       int ret = -EINVAL;
+       int ret = -EINVAL, irq;
 
        if (pdev->num_resources != 2)
                goto out;
@@ -76,6 +73,12 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev)
        if (!pdata || !pdata->hclk)
                goto out;
 
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
+               goto out;
+       }
+
        /* Tell the MFD core we are ready to be enabled */
        if (cell->enable) {
                ret = cell->enable(pdev);
@@ -87,11 +90,18 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev)
        if (ret)
                goto cell_disable;
 
+       ret = request_irq(irq, tmio_mmc_irq, IRQF_DISABLED |
+                         IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host);
+       if (ret)
+               goto host_remove;
+
        pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
-               (unsigned long)host->ctl, host->irq);
+               (unsigned long)host->ctl, irq);
 
        return 0;
 
+host_remove:
+       tmio_mmc_host_remove(host);
 cell_disable:
        if (cell->disable)
                cell->disable(pdev);
@@ -107,7 +117,9 @@ static int __devexit tmio_mmc_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
 
        if (mmc) {
-               tmio_mmc_host_remove(mmc_priv(mmc));
+               struct tmio_mmc_host *host = mmc_priv(mmc);
+               free_irq(platform_get_irq(pdev, 0), host);
+               tmio_mmc_host_remove(host);
                if (cell->disable)
                        cell->disable(pdev);
        }
index 099ed49a259b17971dcecf72b5db6d03f28e9de3..8260bc2c34e38ee325b1a864c6ad7f6f756a3bcf 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/highmem.h>
 #include <linux/mmc/tmio.h>
 #include <linux/pagemap.h>
+#include <linux/spinlock.h>
 
 /* Definitions for values the CTRL_SDIO_STATUS register can take. */
 #define TMIO_SDIO_STAT_IOIRQ   0x0001
@@ -44,13 +45,14 @@ struct tmio_mmc_host {
        struct mmc_request      *mrq;
        struct mmc_data         *data;
        struct mmc_host         *mmc;
-       int                     irq;
        unsigned int            sdio_irq_enabled;
 
        /* Callbacks for clock / power control */
        void (*set_pwr)(struct platform_device *host, int state);
        void (*set_clk_div)(struct platform_device *host, int state);
 
+       int                     pm_error;
+
        /* pio related stuff */
        struct scatterlist      *sg_ptr;
        struct scatterlist      *sg_orig;
@@ -83,6 +85,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
 
 void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
 void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
+irqreturn_t tmio_mmc_irq(int irq, void *devid);
 
 static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
                                         unsigned long *flags)
@@ -120,4 +123,15 @@ static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
 }
 #endif
 
+#ifdef CONFIG_PM
+int tmio_mmc_host_suspend(struct device *dev);
+int tmio_mmc_host_resume(struct device *dev);
+#else
+#define tmio_mmc_host_suspend NULL
+#define tmio_mmc_host_resume NULL
+#endif
+
+int tmio_mmc_host_runtime_suspend(struct device *dev);
+int tmio_mmc_host_runtime_resume(struct device *dev);
+
 #endif
index d3de74ab633e73fe9146eb5ceddf14bd08b78b69..25f1ad6cbe098a9d4cd2b270423eade6d6cb4326 100644 (file)
@@ -256,7 +256,10 @@ static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
 void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
 {
        /* We can only either use DMA for both Tx and Rx or not use it at all */
-       if (pdata->dma) {
+       if (!pdata->dma)
+               return;
+
+       if (!host->chan_tx && !host->chan_rx) {
                dma_cap_mask_t mask;
 
                dma_cap_zero(mask);
@@ -284,18 +287,18 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
 
                tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host);
                tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
+       }
 
-               tmio_mmc_enable_dma(host, true);
+       tmio_mmc_enable_dma(host, true);
+
+       return;
 
-               return;
 ebouncebuf:
-               dma_release_channel(host->chan_rx);
-               host->chan_rx = NULL;
+       dma_release_channel(host->chan_rx);
+       host->chan_rx = NULL;
 ereqrx:
-               dma_release_channel(host->chan_tx);
-               host->chan_tx = NULL;
-               return;
-       }
+       dma_release_channel(host->chan_tx);
+       host->chan_tx = NULL;
 }
 
 void tmio_mmc_release_dma(struct tmio_mmc_host *host)
index 710339a85c84676d9c72e2105f24108344248da2..ad6347bb02ddd9ee20a6085185fb6ca03924d666 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/module.h>
 #include <linux/pagemap.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/scatterlist.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
@@ -243,8 +244,12 @@ static void tmio_mmc_reset_work(struct work_struct *work)
        spin_lock_irqsave(&host->lock, flags);
        mrq = host->mrq;
 
-       /* request already finished */
-       if (!mrq
+       /*
+        * is request already finished? Since we use a non-blocking
+        * cancel_delayed_work(), it can happen, that a .set_ios() call preempts
+        * us, so, have to check for IS_ERR(host->mrq)
+        */
+       if (IS_ERR_OR_NULL(mrq)
            || time_is_after_jiffies(host->last_req_ts +
                msecs_to_jiffies(2000))) {
                spin_unlock_irqrestore(&host->lock, flags);
@@ -264,16 +269,19 @@ static void tmio_mmc_reset_work(struct work_struct *work)
 
        host->cmd = NULL;
        host->data = NULL;
-       host->mrq = NULL;
        host->force_pio = false;
 
        spin_unlock_irqrestore(&host->lock, flags);
 
        tmio_mmc_reset(host);
 
+       /* Ready for new calls */
+       host->mrq = NULL;
+
        mmc_request_done(host->mmc, mrq);
 }
 
+/* called with host->lock held, interrupts disabled */
 static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
 {
        struct mmc_request *mrq = host->mrq;
@@ -281,13 +289,15 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
        if (!mrq)
                return;
 
-       host->mrq = NULL;
        host->cmd = NULL;
        host->data = NULL;
        host->force_pio = false;
 
        cancel_delayed_work(&host->delayed_reset_work);
 
+       host->mrq = NULL;
+
+       /* FIXME: mmc_request_done() can schedule! */
        mmc_request_done(host->mmc, mrq);
 }
 
@@ -554,7 +564,7 @@ out:
        spin_unlock(&host->lock);
 }
 
-static irqreturn_t tmio_mmc_irq(int irq, void *devid)
+irqreturn_t tmio_mmc_irq(int irq, void *devid)
 {
        struct tmio_mmc_host *host = devid;
        struct tmio_mmc_data *pdata = host->pdata;
@@ -649,6 +659,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
 out:
        return IRQ_HANDLED;
 }
+EXPORT_SYMBOL(tmio_mmc_irq);
 
 static int tmio_mmc_start_data(struct tmio_mmc_host *host,
        struct mmc_data *data)
@@ -685,15 +696,27 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
 static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
+       unsigned long flags;
        int ret;
 
-       if (host->mrq)
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (host->mrq) {
                pr_debug("request not null\n");
+               if (IS_ERR(host->mrq)) {
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       mrq->cmd->error = -EAGAIN;
+                       mmc_request_done(mmc, mrq);
+                       return;
+               }
+       }
 
        host->last_req_ts = jiffies;
        wmb();
        host->mrq = mrq;
 
+       spin_unlock_irqrestore(&host->lock, flags);
+
        if (mrq->data) {
                ret = tmio_mmc_start_data(host, mrq->data);
                if (ret)
@@ -708,8 +731,8 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        }
 
 fail:
-       host->mrq = NULL;
        host->force_pio = false;
+       host->mrq = NULL;
        mrq->cmd->error = ret;
        mmc_request_done(mmc, mrq);
 }
@@ -723,19 +746,54 @@ fail:
 static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct tmio_mmc_data *pdata = host->pdata;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (host->mrq) {
+               if (IS_ERR(host->mrq)) {
+                       dev_dbg(&host->pdev->dev,
+                               "%s.%d: concurrent .set_ios(), clk %u, mode %u\n",
+                               current->comm, task_pid_nr(current),
+                               ios->clock, ios->power_mode);
+                       host->mrq = ERR_PTR(-EINTR);
+               } else {
+                       dev_dbg(&host->pdev->dev,
+                               "%s.%d: CMD%u active since %lu, now %lu!\n",
+                               current->comm, task_pid_nr(current),
+                               host->mrq->cmd->opcode, host->last_req_ts, jiffies);
+               }
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+       host->mrq = ERR_PTR(-EBUSY);
+
+       spin_unlock_irqrestore(&host->lock, flags);
 
        if (ios->clock)
                tmio_mmc_set_clock(host, ios->clock);
 
        /* Power sequence - OFF -> UP -> ON */
        if (ios->power_mode == MMC_POWER_UP) {
+               if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && !pdata->power) {
+                       pm_runtime_get_sync(&host->pdev->dev);
+                       pdata->power = true;
+               }
                /* power up SD bus */
                if (host->set_pwr)
                        host->set_pwr(host->pdev, 1);
        } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
                /* power down SD bus */
-               if (ios->power_mode == MMC_POWER_OFF && host->set_pwr)
-                       host->set_pwr(host->pdev, 0);
+               if (ios->power_mode == MMC_POWER_OFF) {
+                       if (host->set_pwr)
+                               host->set_pwr(host->pdev, 0);
+                       if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) &&
+                           pdata->power) {
+                               pdata->power = false;
+                               pm_runtime_put(&host->pdev->dev);
+                       }
+               }
                tmio_mmc_clk_stop(host);
        } else {
                /* start bus clock */
@@ -753,6 +811,12 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
        /* Let things settle. delay taken from winCE driver */
        udelay(140);
+       if (PTR_ERR(host->mrq) == -EINTR)
+               dev_dbg(&host->pdev->dev,
+                       "%s.%d: IOS interrupted: clk %u, mode %u",
+                       current->comm, task_pid_nr(current),
+                       ios->clock, ios->power_mode);
+       host->mrq = NULL;
 }
 
 static int tmio_mmc_get_ro(struct mmc_host *mmc)
@@ -801,6 +865,7 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        if (!mmc)
                return -ENOMEM;
 
+       pdata->dev = &pdev->dev;
        _host = mmc_priv(mmc);
        _host->pdata = pdata;
        _host->mmc = mmc;
@@ -834,24 +899,19 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        else
                mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
-       tmio_mmc_clk_stop(_host);
-       tmio_mmc_reset(_host);
-
-       ret = platform_get_irq(pdev, 0);
+       pdata->power = false;
+       pm_runtime_enable(&pdev->dev);
+       ret = pm_runtime_resume(&pdev->dev);
        if (ret < 0)
-               goto unmap_ctl;
+               goto pm_disable;
 
-       _host->irq = ret;
+       tmio_mmc_clk_stop(_host);
+       tmio_mmc_reset(_host);
 
        tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
        if (pdata->flags & TMIO_MMC_SDIO_IRQ)
                tmio_mmc_enable_sdio_irq(mmc, 0);
 
-       ret = request_irq(_host->irq, tmio_mmc_irq, IRQF_DISABLED |
-               IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), _host);
-       if (ret)
-               goto unmap_ctl;
-
        spin_lock_init(&_host->lock);
 
        /* Init delayed work for request timeouts */
@@ -860,6 +920,10 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        /* See if we also get DMA */
        tmio_mmc_request_dma(_host, pdata);
 
+       /* We have to keep the device powered for its card detection to work */
+       if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD))
+               pm_runtime_get_noresume(&pdev->dev);
+
        mmc_add_host(mmc);
 
        /* Unmask the IRQs we want to know about */
@@ -874,7 +938,8 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 
        return 0;
 
-unmap_ctl:
+pm_disable:
+       pm_runtime_disable(&pdev->dev);
        iounmap(_host->ctl);
 host_free:
        mmc_free_host(mmc);
@@ -885,13 +950,88 @@ EXPORT_SYMBOL(tmio_mmc_host_probe);
 
 void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 {
+       struct platform_device *pdev = host->pdev;
+
+       /*
+        * We don't have to manipulate pdata->power here: if there is a card in
+        * the slot, the runtime PM is active and our .runtime_resume() will not
+        * be run. If there is no card in the slot and the platform can suspend
+        * the controller, the runtime PM is suspended and pdata->power == false,
+        * so, our .runtime_resume() will not try to detect a card in the slot.
+        */
+       if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD)
+               pm_runtime_get_sync(&pdev->dev);
+
        mmc_remove_host(host->mmc);
        cancel_delayed_work_sync(&host->delayed_reset_work);
        tmio_mmc_release_dma(host);
-       free_irq(host->irq, host);
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
        iounmap(host->ctl);
        mmc_free_host(host->mmc);
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
+#ifdef CONFIG_PM
+int tmio_mmc_host_suspend(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+       int ret = mmc_suspend_host(mmc);
+
+       if (!ret)
+               tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
+
+       host->pm_error = pm_runtime_put_sync(dev);
+
+       return ret;
+}
+EXPORT_SYMBOL(tmio_mmc_host_suspend);
+
+int tmio_mmc_host_resume(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+
+       /* The MMC core will perform the complete set up */
+       host->pdata->power = false;
+
+       if (!host->pm_error)
+               pm_runtime_get_sync(dev);
+
+       tmio_mmc_reset(mmc_priv(mmc));
+       tmio_mmc_request_dma(host, host->pdata);
+
+       return mmc_resume_host(mmc);
+}
+EXPORT_SYMBOL(tmio_mmc_host_resume);
+
+#endif /* CONFIG_PM */
+
+int tmio_mmc_host_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+EXPORT_SYMBOL(tmio_mmc_host_runtime_suspend);
+
+int tmio_mmc_host_runtime_resume(struct device *dev)
+{
+       struct mmc_host *mmc = dev_get_drvdata(dev);
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct tmio_mmc_data *pdata = host->pdata;
+
+       tmio_mmc_reset(host);
+
+       if (pdata->power) {
+               /* Only entered after a card-insert interrupt */
+               tmio_mmc_set_ios(mmc, &mmc->ios);
+               mmc_detect_change(mmc, msecs_to_jiffies(100));
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
+
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
new file mode 100644 (file)
index 0000000..cbb0330
--- /dev/null
@@ -0,0 +1,2506 @@
+/*
+ * Remote VUB300 SDIO/SDmem Host Controller Driver
+ *
+ * Copyright (C) 2010 Elan Digital Systems Limited
+ *
+ * based on USB Skeleton driver - 2.2
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.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
+ *
+ * VUB300: is a USB 2.0 client device with a single SDIO/SDmem/MMC slot
+ *         Any SDIO/SDmem/MMC device plugged into the VUB300 will appear,
+ *         by virtue of this driver, to have been plugged into a local
+ *         SDIO host controller, similar to, say, a PCI Ricoh controller
+ *         This is because this kernel device driver is both a USB 2.0
+ *         client device driver AND an MMC host controller driver. Thus
+ *         if there is an existing driver for the inserted SDIO/SDmem/MMC
+ *         device then that driver will be used by the kernel to manage
+ *         the device in exactly the same fashion as if it had been
+ *         directly plugged into, say, a local pci bus Ricoh controller
+ *
+ * RANT: this driver was written using a display 128x48 - converting it
+ *       to a line width of 80 makes it very difficult to support. In
+ *       particular functions have been broken down into sub functions
+ *       and the original meaningful names have been shortened into
+ *       cryptic ones.
+ *       The problem is that executing a fragment of code subject to
+ *       two conditions means an indentation of 24, thus leaving only
+ *       56 characters for a C statement. And that is quite ridiculous!
+ *
+ * Data types: data passed to/from the VUB300 is fixed to a number of
+ *             bits and driver data fields reflect that limit by using
+ *             u8, u16, u32
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/workqueue.h>
+#include <linux/ctype.h>
+#include <linux/firmware.h>
+#include <linux/scatterlist.h>
+
+struct host_controller_info {
+       u8 info_size;
+       u16 firmware_version;
+       u8 number_of_ports;
+} __packed;
+
+#define FIRMWARE_BLOCK_BOUNDARY 1024
+struct sd_command_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 command_type; /* Bit7 - Rd/Wr */
+       u8 command_index;
+       u8 transfer_size[4]; /* ReadSize + ReadSize */
+       u8 response_type;
+       u8 arguments[4];
+       u8 block_count[2];
+       u8 block_size[2];
+       u8 block_boundary[2];
+       u8 reserved[44]; /* to pad out to 64 bytes */
+} __packed;
+
+struct sd_irqpoll_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 command_type; /* Bit7 - Rd/Wr */
+       u8 padding[16]; /* don't ask why !! */
+       u8 poll_timeout_msb;
+       u8 poll_timeout_lsb;
+       u8 reserved[42]; /* to pad out to 64 bytes */
+} __packed;
+
+struct sd_common_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+} __packed;
+
+struct sd_response_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 command_type;
+       u8 command_index;
+       u8 command_response[0];
+} __packed;
+
+struct sd_status_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u16 port_flags;
+       u32 sdio_clock;
+       u16 host_header_size;
+       u16 func_header_size;
+       u16 ctrl_header_size;
+} __packed;
+
+struct sd_error_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 error_code;
+} __packed;
+
+struct sd_interrupt_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+} __packed;
+
+struct offload_registers_access {
+       u8 command_byte[4];
+       u8 Respond_Byte[4];
+} __packed;
+
+#define INTERRUPT_REGISTER_ACCESSES 15
+struct sd_offloaded_interrupt {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       struct offload_registers_access reg[INTERRUPT_REGISTER_ACCESSES];
+} __packed;
+
+struct sd_register_header {
+       u8 header_size;
+       u8 header_type;
+       u8 port_number;
+       u8 command_type;
+       u8 command_index;
+       u8 command_response[6];
+} __packed;
+
+#define PIGGYBACK_REGISTER_ACCESSES 14
+struct sd_offloaded_piggyback {
+       struct sd_register_header sdio;
+       struct offload_registers_access reg[PIGGYBACK_REGISTER_ACCESSES];
+} __packed;
+
+union sd_response {
+       struct sd_common_header common;
+       struct sd_status_header status;
+       struct sd_error_header error;
+       struct sd_interrupt_header interrupt;
+       struct sd_response_header response;
+       struct sd_offloaded_interrupt irq;
+       struct sd_offloaded_piggyback pig;
+} __packed;
+
+union sd_command {
+       struct sd_command_header head;
+       struct sd_irqpoll_header poll;
+} __packed;
+
+enum SD_RESPONSE_TYPE {
+       SDRT_UNSPECIFIED = 0,
+       SDRT_NONE,
+       SDRT_1,
+       SDRT_1B,
+       SDRT_2,
+       SDRT_3,
+       SDRT_4,
+       SDRT_5,
+       SDRT_5B,
+       SDRT_6,
+       SDRT_7,
+};
+
+#define RESPONSE_INTERRUPT                     0x01
+#define RESPONSE_ERROR                         0x02
+#define RESPONSE_STATUS                                0x03
+#define RESPONSE_IRQ_DISABLED                  0x05
+#define RESPONSE_IRQ_ENABLED                   0x06
+#define RESPONSE_PIGGYBACKED                   0x07
+#define RESPONSE_NO_INTERRUPT                  0x08
+#define RESPONSE_PIG_DISABLED                  0x09
+#define RESPONSE_PIG_ENABLED                   0x0A
+#define SD_ERROR_1BIT_TIMEOUT                  0x01
+#define SD_ERROR_4BIT_TIMEOUT                  0x02
+#define SD_ERROR_1BIT_CRC_WRONG                        0x03
+#define SD_ERROR_4BIT_CRC_WRONG                        0x04
+#define SD_ERROR_1BIT_CRC_ERROR                        0x05
+#define SD_ERROR_4BIT_CRC_ERROR                        0x06
+#define SD_ERROR_NO_CMD_ENDBIT                 0x07
+#define SD_ERROR_NO_1BIT_DATEND                        0x08
+#define SD_ERROR_NO_4BIT_DATEND                        0x09
+#define SD_ERROR_1BIT_UNEXPECTED_TIMEOUT       0x0A
+#define SD_ERROR_4BIT_UNEXPECTED_TIMEOUT       0x0B
+#define SD_ERROR_ILLEGAL_COMMAND               0x0C
+#define SD_ERROR_NO_DEVICE                     0x0D
+#define SD_ERROR_TRANSFER_LENGTH               0x0E
+#define SD_ERROR_1BIT_DATA_TIMEOUT             0x0F
+#define SD_ERROR_4BIT_DATA_TIMEOUT             0x10
+#define SD_ERROR_ILLEGAL_STATE                 0x11
+#define SD_ERROR_UNKNOWN_ERROR                 0x12
+#define SD_ERROR_RESERVED_ERROR                        0x13
+#define SD_ERROR_INVALID_FUNCTION              0x14
+#define SD_ERROR_OUT_OF_RANGE                  0x15
+#define SD_ERROR_STAT_CMD                      0x16
+#define SD_ERROR_STAT_DATA                     0x17
+#define SD_ERROR_STAT_CMD_TIMEOUT              0x18
+#define SD_ERROR_SDCRDY_STUCK                  0x19
+#define SD_ERROR_UNHANDLED                     0x1A
+#define SD_ERROR_OVERRUN                       0x1B
+#define SD_ERROR_PIO_TIMEOUT                   0x1C
+
+#define FUN(c) (0x000007 & (c->arg>>28))
+#define REG(c) (0x01FFFF & (c->arg>>9))
+
+static int limit_speed_to_24_MHz;
+module_param(limit_speed_to_24_MHz, bool, 0644);
+MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz");
+
+static int pad_input_to_usb_pkt;
+module_param(pad_input_to_usb_pkt, bool, 0644);
+MODULE_PARM_DESC(pad_input_to_usb_pkt,
+                "Pad USB data input transfers to whole USB Packet");
+
+static int disable_offload_processing;
+module_param(disable_offload_processing, bool, 0644);
+MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing");
+
+static int force_1_bit_data_xfers;
+module_param(force_1_bit_data_xfers, bool, 0644);
+MODULE_PARM_DESC(force_1_bit_data_xfers,
+                "Force SDIO Data Transfers to 1-bit Mode");
+
+static int force_polling_for_irqs;
+module_param(force_polling_for_irqs, bool, 0644);
+MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts");
+
+static int firmware_irqpoll_timeout = 1024;
+module_param(firmware_irqpoll_timeout, int, 0644);
+MODULE_PARM_DESC(firmware_irqpoll_timeout, "VUB300 firmware irqpoll timeout");
+
+static int force_max_req_size = 128;
+module_param(force_max_req_size, int, 0644);
+MODULE_PARM_DESC(force_max_req_size, "set max request size in kBytes");
+
+#ifdef SMSC_DEVELOPMENT_BOARD
+static int firmware_rom_wait_states = 0x04;
+#else
+static int firmware_rom_wait_states = 0x1C;
+#endif
+
+module_param(firmware_rom_wait_states, bool, 0644);
+MODULE_PARM_DESC(firmware_rom_wait_states,
+                "ROM wait states byte=RRRIIEEE (Reserved Internal External)");
+
+#define ELAN_VENDOR_ID         0x2201
+#define VUB300_VENDOR_ID       0x0424
+#define VUB300_PRODUCT_ID      0x012C
+static struct usb_device_id vub300_table[] = {
+       {USB_DEVICE(ELAN_VENDOR_ID, VUB300_PRODUCT_ID)},
+       {USB_DEVICE(VUB300_VENDOR_ID, VUB300_PRODUCT_ID)},
+       {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, vub300_table);
+
+static struct workqueue_struct *cmndworkqueue;
+static struct workqueue_struct *pollworkqueue;
+static struct workqueue_struct *deadworkqueue;
+
+static inline int interface_to_InterfaceNumber(struct usb_interface *interface)
+{
+       if (!interface)
+               return -1;
+       if (!interface->cur_altsetting)
+               return -1;
+       return interface->cur_altsetting->desc.bInterfaceNumber;
+}
+
+struct sdio_register {
+       unsigned func_num:3;
+       unsigned sdio_reg:17;
+       unsigned activate:1;
+       unsigned prepared:1;
+       unsigned regvalue:8;
+       unsigned response:8;
+       unsigned sparebit:26;
+};
+
+struct vub300_mmc_host {
+       struct usb_device *udev;
+       struct usb_interface *interface;
+       struct kref kref;
+       struct mutex cmd_mutex;
+       struct mutex irq_mutex;
+       char vub_name[3 + (9 * 8) + 4 + 1]; /* max of 7 sdio fn's */
+       u8 cmnd_out_ep; /* EndPoint for commands */
+       u8 cmnd_res_ep; /* EndPoint for responses */
+       u8 data_out_ep; /* EndPoint for out data */
+       u8 data_inp_ep; /* EndPoint for inp data */
+       bool card_powered;
+       bool card_present;
+       bool read_only;
+       bool large_usb_packets;
+       bool app_spec; /* ApplicationSpecific */
+       bool irq_enabled; /* by the MMC CORE */
+       bool irq_disabled; /* in the firmware */
+       unsigned bus_width:4;
+       u8 total_offload_count;
+       u8 dynamic_register_count;
+       u8 resp_len;
+       u32 datasize;
+       int errors;
+       int usb_transport_fail;
+       int usb_timed_out;
+       int irqs_queued;
+       struct sdio_register sdio_register[16];
+       struct offload_interrupt_function_register {
+#define MAXREGBITS 4
+#define MAXREGS (1<<MAXREGBITS)
+#define MAXREGMASK (MAXREGS-1)
+               u8 offload_count;
+               u32 offload_point;
+               struct offload_registers_access reg[MAXREGS];
+       } fn[8];
+       u16 fbs[8]; /* Function Block Size */
+       struct mmc_command *cmd;
+       struct mmc_request *req;
+       struct mmc_data *data;
+       struct mmc_host *mmc;
+       struct urb *urb;
+       struct urb *command_out_urb;
+       struct urb *command_res_urb;
+       struct completion command_complete;
+       struct completion irqpoll_complete;
+       union sd_command cmnd;
+       union sd_response resp;
+       struct timer_list sg_transfer_timer;
+       struct usb_sg_request sg_request;
+       struct timer_list inactivity_timer;
+       struct work_struct deadwork;
+       struct work_struct cmndwork;
+       struct delayed_work pollwork;
+       struct host_controller_info hc_info;
+       struct sd_status_header system_port_status;
+       u8 padded_buffer[64];
+};
+
+#define kref_to_vub300_mmc_host(d) container_of(d, struct vub300_mmc_host, kref)
+#define SET_TRANSFER_PSEUDOCODE                21
+#define SET_INTERRUPT_PSEUDOCODE       20
+#define SET_FAILURE_MODE               18
+#define SET_ROM_WAIT_STATES            16
+#define SET_IRQ_ENABLE                 13
+#define SET_CLOCK_SPEED                        11
+#define SET_FUNCTION_BLOCK_SIZE                9
+#define SET_SD_DATA_MODE               6
+#define SET_SD_POWER                   4
+#define ENTER_DFU_MODE                 3
+#define GET_HC_INF0                    1
+#define GET_SYSTEM_PORT_STATUS         0
+
+static void vub300_delete(struct kref *kref)
+{                              /* kref callback - softirq */
+       struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
+       struct mmc_host *mmc = vub300->mmc;
+       usb_free_urb(vub300->command_out_urb);
+       vub300->command_out_urb = NULL;
+       usb_free_urb(vub300->command_res_urb);
+       vub300->command_res_urb = NULL;
+       usb_put_dev(vub300->udev);
+       mmc_free_host(mmc);
+       /*
+        * and hence also frees vub300
+        * which is contained at the end of struct mmc
+        */
+}
+
+static void vub300_queue_cmnd_work(struct vub300_mmc_host *vub300)
+{
+       kref_get(&vub300->kref);
+       if (queue_work(cmndworkqueue, &vub300->cmndwork)) {
+               /*
+                * then the cmndworkqueue was not previously
+                * running and the above get ref is obvious
+                * required and will be put when the thread
+                * terminates by a specific call
+                */
+       } else {
+               /*
+                * the cmndworkqueue was already running from
+                * a previous invocation and thus to keep the
+                * kref counts correct we must undo the get
+                */
+               kref_put(&vub300->kref, vub300_delete);
+       }
+}
+
+static void vub300_queue_poll_work(struct vub300_mmc_host *vub300, int delay)
+{
+       kref_get(&vub300->kref);
+       if (queue_delayed_work(pollworkqueue, &vub300->pollwork, delay)) {
+               /*
+                * then the pollworkqueue was not previously
+                * running and the above get ref is obvious
+                * required and will be put when the thread
+                * terminates by a specific call
+                */
+       } else {
+               /*
+                * the pollworkqueue was already running from
+                * a previous invocation and thus to keep the
+                * kref counts correct we must undo the get
+                */
+               kref_put(&vub300->kref, vub300_delete);
+       }
+}
+
+static void vub300_queue_dead_work(struct vub300_mmc_host *vub300)
+{
+       kref_get(&vub300->kref);
+       if (queue_work(deadworkqueue, &vub300->deadwork)) {
+               /*
+                * then the deadworkqueue was not previously
+                * running and the above get ref is obvious
+                * required and will be put when the thread
+                * terminates by a specific call
+                */
+       } else {
+               /*
+                * the deadworkqueue was already running from
+                * a previous invocation and thus to keep the
+                * kref counts correct we must undo the get
+                */
+               kref_put(&vub300->kref, vub300_delete);
+       }
+}
+
+static void irqpoll_res_completed(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+       if (urb->status)
+               vub300->usb_transport_fail = urb->status;
+       complete(&vub300->irqpoll_complete);
+}
+
+static void irqpoll_out_completed(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+       if (urb->status) {
+               vub300->usb_transport_fail = urb->status;
+               complete(&vub300->irqpoll_complete);
+               return;
+       } else {
+               int ret;
+               unsigned int pipe =
+                       usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
+               usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
+                                 &vub300->resp, sizeof(vub300->resp),
+                                 irqpoll_res_completed, vub300);
+               vub300->command_res_urb->actual_length = 0;
+               ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
+               if (ret) {
+                       vub300->usb_transport_fail = ret;
+                       complete(&vub300->irqpoll_complete);
+               }
+               return;
+       }
+}
+
+static void send_irqpoll(struct vub300_mmc_host *vub300)
+{
+       /* cmd_mutex is held by vub300_pollwork_thread */
+       int retval;
+       int timeout = 0xFFFF & (0x0001FFFF - firmware_irqpoll_timeout);
+       vub300->cmnd.poll.header_size = 22;
+       vub300->cmnd.poll.header_type = 1;
+       vub300->cmnd.poll.port_number = 0;
+       vub300->cmnd.poll.command_type = 2;
+       vub300->cmnd.poll.poll_timeout_lsb = 0xFF & (unsigned)timeout;
+       vub300->cmnd.poll.poll_timeout_msb = 0xFF & (unsigned)(timeout >> 8);
+       usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
+                         usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep)
+                         , &vub300->cmnd, sizeof(vub300->cmnd)
+                         , irqpoll_out_completed, vub300);
+       retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
+       if (0 > retval) {
+               vub300->usb_transport_fail = retval;
+               vub300_queue_poll_work(vub300, 1);
+               complete(&vub300->irqpoll_complete);
+               return;
+       } else {
+               return;
+       }
+}
+
+static void new_system_port_status(struct vub300_mmc_host *vub300)
+{
+       int old_card_present = vub300->card_present;
+       int new_card_present =
+               (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
+       vub300->read_only =
+               (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
+       if (new_card_present && !old_card_present) {
+               dev_info(&vub300->udev->dev, "card just inserted\n");
+               vub300->card_present = 1;
+               vub300->bus_width = 0;
+               if (disable_offload_processing)
+                       strncpy(vub300->vub_name, "EMPTY Processing Disabled",
+                               sizeof(vub300->vub_name));
+               else
+                       vub300->vub_name[0] = 0;
+               mmc_detect_change(vub300->mmc, 1);
+       } else if (!new_card_present && old_card_present) {
+               dev_info(&vub300->udev->dev, "card just ejected\n");
+               vub300->card_present = 0;
+               mmc_detect_change(vub300->mmc, 0);
+       } else {
+               /* no change */
+       }
+}
+
+static void __add_offloaded_reg_to_fifo(struct vub300_mmc_host *vub300,
+                                       struct offload_registers_access
+                                       *register_access, u8 func)
+{
+       u8 r = vub300->fn[func].offload_point + vub300->fn[func].offload_count;
+       memcpy(&vub300->fn[func].reg[MAXREGMASK & r], register_access,
+              sizeof(struct offload_registers_access));
+       vub300->fn[func].offload_count += 1;
+       vub300->total_offload_count += 1;
+}
+
+static void add_offloaded_reg(struct vub300_mmc_host *vub300,
+                             struct offload_registers_access *register_access)
+{
+       u32 Register = ((0x03 & register_access->command_byte[0]) << 15)
+                       | ((0xFF & register_access->command_byte[1]) << 7)
+                       | ((0xFE & register_access->command_byte[2]) >> 1);
+       u8 func = ((0x70 & register_access->command_byte[0]) >> 4);
+       u8 regs = vub300->dynamic_register_count;
+       u8 i = 0;
+       while (0 < regs-- && 1 == vub300->sdio_register[i].activate) {
+               if (vub300->sdio_register[i].func_num == func &&
+                   vub300->sdio_register[i].sdio_reg == Register) {
+                       if (vub300->sdio_register[i].prepared == 0)
+                               vub300->sdio_register[i].prepared = 1;
+                       vub300->sdio_register[i].response =
+                               register_access->Respond_Byte[2];
+                       vub300->sdio_register[i].regvalue =
+                               register_access->Respond_Byte[3];
+                       return;
+               } else {
+                       i += 1;
+                       continue;
+               }
+       };
+       __add_offloaded_reg_to_fifo(vub300, register_access, func);
+}
+
+static void check_vub300_port_status(struct vub300_mmc_host *vub300)
+{
+       /*
+        * cmd_mutex is held by vub300_pollwork_thread,
+        * vub300_deadwork_thread or vub300_cmndwork_thread
+        */
+       int retval;
+       retval =
+               usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+                               GET_SYSTEM_PORT_STATUS,
+                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0000, 0x0000, &vub300->system_port_status,
+                               sizeof(vub300->system_port_status), HZ);
+       if (sizeof(vub300->system_port_status) == retval)
+               new_system_port_status(vub300);
+}
+
+static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300)
+{
+       /* cmd_mutex is held by vub300_pollwork_thread */
+       if (vub300->command_res_urb->actual_length == 0)
+               return;
+
+       switch (vub300->resp.common.header_type) {
+       case RESPONSE_INTERRUPT:
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irq_enabled)
+                       mmc_signal_sdio_irq(vub300->mmc);
+               else
+                       vub300->irqs_queued += 1;
+               vub300->irq_disabled = 1;
+               mutex_unlock(&vub300->irq_mutex);
+               break;
+       case RESPONSE_ERROR:
+               if (vub300->resp.error.error_code == SD_ERROR_NO_DEVICE)
+                       check_vub300_port_status(vub300);
+               break;
+       case RESPONSE_STATUS:
+               vub300->system_port_status = vub300->resp.status;
+               new_system_port_status(vub300);
+               if (!vub300->card_present)
+                       vub300_queue_poll_work(vub300, HZ / 5);
+               break;
+       case RESPONSE_IRQ_DISABLED:
+       {
+               int offloaded_data_length = vub300->resp.common.header_size - 3;
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
+                       ri += 1;
+               }
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irq_enabled)
+                       mmc_signal_sdio_irq(vub300->mmc);
+               else
+                       vub300->irqs_queued += 1;
+               vub300->irq_disabled = 1;
+               mutex_unlock(&vub300->irq_mutex);
+               break;
+       }
+       case RESPONSE_IRQ_ENABLED:
+       {
+               int offloaded_data_length = vub300->resp.common.header_size - 3;
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
+                       ri += 1;
+               }
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irq_enabled)
+                       mmc_signal_sdio_irq(vub300->mmc);
+               else if (vub300->irqs_queued)
+                       vub300->irqs_queued += 1;
+               else
+                       vub300->irqs_queued += 1;
+               vub300->irq_disabled = 0;
+               mutex_unlock(&vub300->irq_mutex);
+               break;
+       }
+       case RESPONSE_NO_INTERRUPT:
+               vub300_queue_poll_work(vub300, 1);
+               break;
+       default:
+               break;
+       }
+}
+
+static void __do_poll(struct vub300_mmc_host *vub300)
+{
+       /* cmd_mutex is held by vub300_pollwork_thread */
+       long commretval;
+       mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+       init_completion(&vub300->irqpoll_complete);
+       send_irqpoll(vub300);
+       commretval = wait_for_completion_timeout(&vub300->irqpoll_complete,
+                                                msecs_to_jiffies(500));
+       if (vub300->usb_transport_fail) {
+               /* no need to do anything */
+       } else if (commretval == 0) {
+               vub300->usb_timed_out = 1;
+               usb_kill_urb(vub300->command_out_urb);
+               usb_kill_urb(vub300->command_res_urb);
+       } else if (commretval < 0) {
+               vub300_queue_poll_work(vub300, 1);
+       } else { /* commretval > 0 */
+               __vub300_irqpoll_response(vub300);
+       }
+}
+
+/* this thread runs only when the driver
+ * is trying to poll the device for an IRQ
+ */
+static void vub300_pollwork_thread(struct work_struct *work)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = container_of(work,
+                             struct vub300_mmc_host, pollwork.work);
+       if (!vub300->interface) {
+               kref_put(&vub300->kref, vub300_delete);
+               return;
+       }
+       mutex_lock(&vub300->cmd_mutex);
+       if (vub300->cmd) {
+               vub300_queue_poll_work(vub300, 1);
+       } else if (!vub300->card_present) {
+               /* no need to do anything */
+       } else { /* vub300->card_present */
+               mutex_lock(&vub300->irq_mutex);
+               if (!vub300->irq_enabled) {
+                       mutex_unlock(&vub300->irq_mutex);
+               } else if (vub300->irqs_queued) {
+                       vub300->irqs_queued -= 1;
+                       mmc_signal_sdio_irq(vub300->mmc);
+                       mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+                       mutex_unlock(&vub300->irq_mutex);
+               } else { /* NOT vub300->irqs_queued */
+                       mutex_unlock(&vub300->irq_mutex);
+                       __do_poll(vub300);
+               }
+       }
+       mutex_unlock(&vub300->cmd_mutex);
+       kref_put(&vub300->kref, vub300_delete);
+}
+
+static void vub300_deadwork_thread(struct work_struct *work)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 =
+               container_of(work, struct vub300_mmc_host, deadwork);
+       if (!vub300->interface) {
+               kref_put(&vub300->kref, vub300_delete);
+               return;
+       }
+       mutex_lock(&vub300->cmd_mutex);
+       if (vub300->cmd) {
+               /*
+                * a command got in as the inactivity
+                * timer expired - so we just let the
+                * processing of the command show if
+                * the device is dead
+                */
+       } else if (vub300->card_present) {
+               check_vub300_port_status(vub300);
+       } else if (vub300->mmc && vub300->mmc->card &&
+                  mmc_card_present(vub300->mmc->card)) {
+               /*
+                * the MMC core must not have responded
+                * to the previous indication - lets
+                * hope that it eventually does so we
+                * will just ignore this for now
+                */
+       } else {
+               check_vub300_port_status(vub300);
+       }
+       mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+       mutex_unlock(&vub300->cmd_mutex);
+       kref_put(&vub300->kref, vub300_delete);
+}
+
+static void vub300_inactivity_timer_expired(unsigned long data)
+{                              /* softirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
+       if (!vub300->interface) {
+               kref_put(&vub300->kref, vub300_delete);
+       } else if (vub300->cmd) {
+               mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+       } else {
+               vub300_queue_dead_work(vub300);
+               mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+       }
+}
+
+static int vub300_response_error(u8 error_code)
+{
+       switch (error_code) {
+       case SD_ERROR_PIO_TIMEOUT:
+       case SD_ERROR_1BIT_TIMEOUT:
+       case SD_ERROR_4BIT_TIMEOUT:
+               return -ETIMEDOUT;
+       case SD_ERROR_STAT_DATA:
+       case SD_ERROR_OVERRUN:
+       case SD_ERROR_STAT_CMD:
+       case SD_ERROR_STAT_CMD_TIMEOUT:
+       case SD_ERROR_SDCRDY_STUCK:
+       case SD_ERROR_UNHANDLED:
+       case SD_ERROR_1BIT_CRC_WRONG:
+       case SD_ERROR_4BIT_CRC_WRONG:
+       case SD_ERROR_1BIT_CRC_ERROR:
+       case SD_ERROR_4BIT_CRC_ERROR:
+       case SD_ERROR_NO_CMD_ENDBIT:
+       case SD_ERROR_NO_1BIT_DATEND:
+       case SD_ERROR_NO_4BIT_DATEND:
+       case SD_ERROR_1BIT_DATA_TIMEOUT:
+       case SD_ERROR_4BIT_DATA_TIMEOUT:
+       case SD_ERROR_1BIT_UNEXPECTED_TIMEOUT:
+       case SD_ERROR_4BIT_UNEXPECTED_TIMEOUT:
+               return -EILSEQ;
+       case 33:
+               return -EILSEQ;
+       case SD_ERROR_ILLEGAL_COMMAND:
+               return -EINVAL;
+       case SD_ERROR_NO_DEVICE:
+               return -ENOMEDIUM;
+       default:
+               return -ENODEV;
+       }
+}
+
+static void command_res_completed(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+       if (urb->status) {
+               /* we have to let the initiator handle the error */
+       } else if (vub300->command_res_urb->actual_length == 0) {
+               /*
+                * we have seen this happen once or twice and
+                * we suspect a buggy USB host controller
+                */
+       } else if (!vub300->data) {
+               /* this means that the command (typically CMD52) suceeded */
+       } else if (vub300->resp.common.header_type != 0x02) {
+               /*
+                * this is an error response from the VUB300 chip
+                * and we let the initiator handle it
+                */
+       } else if (vub300->urb) {
+               vub300->cmd->error =
+                       vub300_response_error(vub300->resp.error.error_code);
+               usb_unlink_urb(vub300->urb);
+       } else {
+               vub300->cmd->error =
+                       vub300_response_error(vub300->resp.error.error_code);
+               usb_sg_cancel(&vub300->sg_request);
+       }
+       complete(&vub300->command_complete);    /* got_response_in */
+}
+
+static void command_out_completed(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+       if (urb->status) {
+               complete(&vub300->command_complete);
+       } else {
+               int ret;
+               unsigned int pipe =
+                       usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
+               usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
+                                 &vub300->resp, sizeof(vub300->resp),
+                                 command_res_completed, vub300);
+               vub300->command_res_urb->actual_length = 0;
+               ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
+               if (ret == 0) {
+                       /*
+                        * the urb completion handler will call
+                        * our completion handler
+                        */
+               } else {
+                       /*
+                        * and thus we only call it directly
+                        * when it will not be called
+                        */
+                       complete(&vub300->command_complete);
+               }
+       }
+}
+
+/*
+ * the STUFF bits are masked out for the comparisons
+ */
+static void snoop_block_size_and_bus_width(struct vub300_mmc_host *vub300,
+                                          u32 cmd_arg)
+{
+       if ((0xFBFFFE00 & cmd_arg) == 0x80022200)
+               vub300->fbs[1] = (cmd_arg << 8) | (0x00FF & vub300->fbs[1]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80022000)
+               vub300->fbs[1] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[1]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80042200)
+               vub300->fbs[2] = (cmd_arg << 8) | (0x00FF & vub300->fbs[2]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80042000)
+               vub300->fbs[2] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[2]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80062200)
+               vub300->fbs[3] = (cmd_arg << 8) | (0x00FF & vub300->fbs[3]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80062000)
+               vub300->fbs[3] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[3]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80082200)
+               vub300->fbs[4] = (cmd_arg << 8) | (0x00FF & vub300->fbs[4]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x80082000)
+               vub300->fbs[4] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[4]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800A2200)
+               vub300->fbs[5] = (cmd_arg << 8) | (0x00FF & vub300->fbs[5]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800A2000)
+               vub300->fbs[5] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[5]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800C2200)
+               vub300->fbs[6] = (cmd_arg << 8) | (0x00FF & vub300->fbs[6]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800C2000)
+               vub300->fbs[6] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[6]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800E2200)
+               vub300->fbs[7] = (cmd_arg << 8) | (0x00FF & vub300->fbs[7]);
+       else if ((0xFBFFFE00 & cmd_arg) == 0x800E2000)
+               vub300->fbs[7] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[7]);
+       else if ((0xFBFFFE03 & cmd_arg) == 0x80000E00)
+               vub300->bus_width = 1;
+       else if ((0xFBFFFE03 & cmd_arg) == 0x80000E02)
+               vub300->bus_width = 4;
+}
+
+static void send_command(struct vub300_mmc_host *vub300)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       struct mmc_command *cmd = vub300->cmd;
+       struct mmc_data *data = vub300->data;
+       int retval;
+       int i;
+       u8 response_type;
+       if (vub300->app_spec) {
+               switch (cmd->opcode) {
+               case 6:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       if (0x00000000 == (0x00000003 & cmd->arg))
+                               vub300->bus_width = 1;
+                       else if (0x00000002 == (0x00000003 & cmd->arg))
+                               vub300->bus_width = 4;
+                       else
+                               dev_err(&vub300->udev->dev,
+                                       "unexpected ACMD6 bus_width=%d\n",
+                                       0x00000003 & cmd->arg);
+                       break;
+               case 13:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 22:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 23:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 41:
+                       response_type = SDRT_3;
+                       vub300->resp_len = 6;
+                       break;
+               case 42:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 51:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 55:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               default:
+                       vub300->resp_len = 0;
+                       cmd->error = -EINVAL;
+                       complete(&vub300->command_complete);
+                       return;
+               }
+               vub300->app_spec = 0;
+       } else {
+               switch (cmd->opcode) {
+               case 0:
+                       response_type = SDRT_NONE;
+                       vub300->resp_len = 0;
+                       break;
+               case 1:
+                       response_type = SDRT_3;
+                       vub300->resp_len = 6;
+                       break;
+               case 2:
+                       response_type = SDRT_2;
+                       vub300->resp_len = 17;
+                       break;
+               case 3:
+                       response_type = SDRT_6;
+                       vub300->resp_len = 6;
+                       break;
+               case 4:
+                       response_type = SDRT_NONE;
+                       vub300->resp_len = 0;
+                       break;
+               case 5:
+                       response_type = SDRT_4;
+                       vub300->resp_len = 6;
+                       break;
+               case 6:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 7:
+                       response_type = SDRT_1B;
+                       vub300->resp_len = 6;
+                       break;
+               case 8:
+                       response_type = SDRT_7;
+                       vub300->resp_len = 6;
+                       break;
+               case 9:
+                       response_type = SDRT_2;
+                       vub300->resp_len = 17;
+                       break;
+               case 10:
+                       response_type = SDRT_2;
+                       vub300->resp_len = 17;
+                       break;
+               case 12:
+                       response_type = SDRT_1B;
+                       vub300->resp_len = 6;
+                       break;
+               case 13:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 15:
+                       response_type = SDRT_NONE;
+                       vub300->resp_len = 0;
+                       break;
+               case 16:
+                       for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
+                               vub300->fbs[i] = 0xFFFF & cmd->arg;
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 17:
+               case 18:
+               case 24:
+               case 25:
+               case 27:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 28:
+               case 29:
+                       response_type = SDRT_1B;
+                       vub300->resp_len = 6;
+                       break;
+               case 30:
+               case 32:
+               case 33:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 38:
+                       response_type = SDRT_1B;
+                       vub300->resp_len = 6;
+                       break;
+               case 42:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               case 52:
+                       response_type = SDRT_5;
+                       vub300->resp_len = 6;
+                       snoop_block_size_and_bus_width(vub300, cmd->arg);
+                       break;
+               case 53:
+                       response_type = SDRT_5;
+                       vub300->resp_len = 6;
+                       break;
+               case 55:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       vub300->app_spec = 1;
+                       break;
+               case 56:
+                       response_type = SDRT_1;
+                       vub300->resp_len = 6;
+                       break;
+               default:
+                       vub300->resp_len = 0;
+                       cmd->error = -EINVAL;
+                       complete(&vub300->command_complete);
+                       return;
+               }
+       }
+       /*
+        * it is a shame that we can not use "sizeof(struct sd_command_header)"
+        * this is because the packet _must_ be padded to 64 bytes
+        */
+       vub300->cmnd.head.header_size = 20;
+       vub300->cmnd.head.header_type = 0x00;
+       vub300->cmnd.head.port_number = 0; /* "0" means port 1 */
+       vub300->cmnd.head.command_type = 0x00; /* standard read command */
+       vub300->cmnd.head.response_type = response_type;
+       vub300->cmnd.head.command_index = cmd->opcode;
+       vub300->cmnd.head.arguments[0] = cmd->arg >> 24;
+       vub300->cmnd.head.arguments[1] = cmd->arg >> 16;
+       vub300->cmnd.head.arguments[2] = cmd->arg >> 8;
+       vub300->cmnd.head.arguments[3] = cmd->arg >> 0;
+       if (cmd->opcode == 52) {
+               int fn = 0x7 & (cmd->arg >> 28);
+               vub300->cmnd.head.block_count[0] = 0;
+               vub300->cmnd.head.block_count[1] = 0;
+               vub300->cmnd.head.block_size[0] = (vub300->fbs[fn] >> 8) & 0xFF;
+               vub300->cmnd.head.block_size[1] = (vub300->fbs[fn] >> 0) & 0xFF;
+               vub300->cmnd.head.command_type = 0x00;
+               vub300->cmnd.head.transfer_size[0] = 0;
+               vub300->cmnd.head.transfer_size[1] = 0;
+               vub300->cmnd.head.transfer_size[2] = 0;
+               vub300->cmnd.head.transfer_size[3] = 0;
+       } else if (!data) {
+               vub300->cmnd.head.block_count[0] = 0;
+               vub300->cmnd.head.block_count[1] = 0;
+               vub300->cmnd.head.block_size[0] = (vub300->fbs[0] >> 8) & 0xFF;
+               vub300->cmnd.head.block_size[1] = (vub300->fbs[0] >> 0) & 0xFF;
+               vub300->cmnd.head.command_type = 0x00;
+               vub300->cmnd.head.transfer_size[0] = 0;
+               vub300->cmnd.head.transfer_size[1] = 0;
+               vub300->cmnd.head.transfer_size[2] = 0;
+               vub300->cmnd.head.transfer_size[3] = 0;
+       } else if (cmd->opcode == 53) {
+               int fn = 0x7 & (cmd->arg >> 28);
+               if (0x08 & vub300->cmnd.head.arguments[0]) { /* BLOCK MODE */
+                       vub300->cmnd.head.block_count[0] =
+                               (data->blocks >> 8) & 0xFF;
+                       vub300->cmnd.head.block_count[1] =
+                               (data->blocks >> 0) & 0xFF;
+                       vub300->cmnd.head.block_size[0] =
+                               (data->blksz >> 8) & 0xFF;
+                       vub300->cmnd.head.block_size[1] =
+                               (data->blksz >> 0) & 0xFF;
+               } else {        /* BYTE MODE */
+                       vub300->cmnd.head.block_count[0] = 0;
+                       vub300->cmnd.head.block_count[1] = 0;
+                       vub300->cmnd.head.block_size[0] =
+                               (vub300->datasize >> 8) & 0xFF;
+                       vub300->cmnd.head.block_size[1] =
+                               (vub300->datasize >> 0) & 0xFF;
+               }
+               vub300->cmnd.head.command_type =
+                       (MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
+               vub300->cmnd.head.transfer_size[0] =
+                       (vub300->datasize >> 24) & 0xFF;
+               vub300->cmnd.head.transfer_size[1] =
+                       (vub300->datasize >> 16) & 0xFF;
+               vub300->cmnd.head.transfer_size[2] =
+                       (vub300->datasize >> 8) & 0xFF;
+               vub300->cmnd.head.transfer_size[3] =
+                       (vub300->datasize >> 0) & 0xFF;
+               if (vub300->datasize < vub300->fbs[fn]) {
+                       vub300->cmnd.head.block_count[0] = 0;
+                       vub300->cmnd.head.block_count[1] = 0;
+               }
+       } else {
+               vub300->cmnd.head.block_count[0] = (data->blocks >> 8) & 0xFF;
+               vub300->cmnd.head.block_count[1] = (data->blocks >> 0) & 0xFF;
+               vub300->cmnd.head.block_size[0] = (data->blksz >> 8) & 0xFF;
+               vub300->cmnd.head.block_size[1] = (data->blksz >> 0) & 0xFF;
+               vub300->cmnd.head.command_type =
+                       (MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
+               vub300->cmnd.head.transfer_size[0] =
+                       (vub300->datasize >> 24) & 0xFF;
+               vub300->cmnd.head.transfer_size[1] =
+                       (vub300->datasize >> 16) & 0xFF;
+               vub300->cmnd.head.transfer_size[2] =
+                       (vub300->datasize >> 8) & 0xFF;
+               vub300->cmnd.head.transfer_size[3] =
+                       (vub300->datasize >> 0) & 0xFF;
+               if (vub300->datasize < vub300->fbs[0]) {
+                       vub300->cmnd.head.block_count[0] = 0;
+                       vub300->cmnd.head.block_count[1] = 0;
+               }
+       }
+       if (vub300->cmnd.head.block_size[0] || vub300->cmnd.head.block_size[1]) {
+               u16 block_size = vub300->cmnd.head.block_size[1] |
+                       (vub300->cmnd.head.block_size[0] << 8);
+               u16 block_boundary = FIRMWARE_BLOCK_BOUNDARY -
+                       (FIRMWARE_BLOCK_BOUNDARY % block_size);
+               vub300->cmnd.head.block_boundary[0] =
+                       (block_boundary >> 8) & 0xFF;
+               vub300->cmnd.head.block_boundary[1] =
+                       (block_boundary >> 0) & 0xFF;
+       } else {
+               vub300->cmnd.head.block_boundary[0] = 0;
+               vub300->cmnd.head.block_boundary[1] = 0;
+       }
+       usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
+                         usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep),
+                         &vub300->cmnd, sizeof(vub300->cmnd),
+                         command_out_completed, vub300);
+       retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
+       if (retval < 0) {
+               cmd->error = retval;
+               complete(&vub300->command_complete);
+               return;
+       } else {
+               return;
+       }
+}
+
+/*
+ * timer callback runs in atomic mode
+ *       so it cannot call usb_kill_urb()
+ */
+static void vub300_sg_timed_out(unsigned long data)
+{
+       struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
+       vub300->usb_timed_out = 1;
+       usb_sg_cancel(&vub300->sg_request);
+       usb_unlink_urb(vub300->command_out_urb);
+       usb_unlink_urb(vub300->command_res_urb);
+}
+
+static u16 roundup_to_multiple_of_64(u16 number)
+{
+       return 0xFFC0 & (0x3F + number);
+}
+
+/*
+ * this is a separate function to solve the 80 column width restriction
+ */
+static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
+                                         const struct firmware *fw)
+{
+       u8 register_count = 0;
+       u16 ts = 0;
+       u16 interrupt_size = 0;
+       const u8 *data = fw->data;
+       int size = fw->size;
+       u8 c;
+       dev_info(&vub300->udev->dev, "using %s for SDIO offload processing\n",
+                vub300->vub_name);
+       do {
+               c = *data++;
+       } while (size-- && c); /* skip comment */
+       dev_info(&vub300->udev->dev, "using offload firmware %s %s\n", fw->data,
+                vub300->vub_name);
+       if (size < 4) {
+               dev_err(&vub300->udev->dev,
+                       "corrupt offload pseudocode in firmware %s\n",
+                       vub300->vub_name);
+               strncpy(vub300->vub_name, "corrupt offload pseudocode",
+                       sizeof(vub300->vub_name));
+               return;
+       }
+       interrupt_size += *data++;
+       size -= 1;
+       interrupt_size <<= 8;
+       interrupt_size += *data++;
+       size -= 1;
+       if (interrupt_size < size) {
+               u16 xfer_length = roundup_to_multiple_of_64(interrupt_size);
+               u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
+               if (xfer_buffer) {
+                       int retval;
+                       memcpy(xfer_buffer, data, interrupt_size);
+                       memset(xfer_buffer + interrupt_size, 0,
+                              xfer_length - interrupt_size);
+                       size -= interrupt_size;
+                       data += interrupt_size;
+                       retval =
+                               usb_control_msg(vub300->udev,
+                                               usb_sndctrlpipe(vub300->udev, 0),
+                                               SET_INTERRUPT_PSEUDOCODE,
+                                               USB_DIR_OUT | USB_TYPE_VENDOR |
+                                               USB_RECIP_DEVICE, 0x0000, 0x0000,
+                                               xfer_buffer, xfer_length, HZ);
+                       kfree(xfer_buffer);
+                       if (retval < 0) {
+                               strncpy(vub300->vub_name,
+                                       "SDIO pseudocode download failed",
+                                       sizeof(vub300->vub_name));
+                               return;
+                       }
+               } else {
+                       dev_err(&vub300->udev->dev,
+                               "not enough memory for xfer buffer to send"
+                               " INTERRUPT_PSEUDOCODE for %s %s\n", fw->data,
+                               vub300->vub_name);
+                       strncpy(vub300->vub_name,
+                               "SDIO interrupt pseudocode download failed",
+                               sizeof(vub300->vub_name));
+                       return;
+               }
+       } else {
+               dev_err(&vub300->udev->dev,
+                       "corrupt interrupt pseudocode in firmware %s %s\n",
+                       fw->data, vub300->vub_name);
+               strncpy(vub300->vub_name, "corrupt interrupt pseudocode",
+                       sizeof(vub300->vub_name));
+               return;
+       }
+       ts += *data++;
+       size -= 1;
+       ts <<= 8;
+       ts += *data++;
+       size -= 1;
+       if (ts < size) {
+               u16 xfer_length = roundup_to_multiple_of_64(ts);
+               u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
+               if (xfer_buffer) {
+                       int retval;
+                       memcpy(xfer_buffer, data, ts);
+                       memset(xfer_buffer + ts, 0,
+                              xfer_length - ts);
+                       size -= ts;
+                       data += ts;
+                       retval =
+                               usb_control_msg(vub300->udev,
+                                               usb_sndctrlpipe(vub300->udev, 0),
+                                               SET_TRANSFER_PSEUDOCODE,
+                                               USB_DIR_OUT | USB_TYPE_VENDOR |
+                                               USB_RECIP_DEVICE, 0x0000, 0x0000,
+                                               xfer_buffer, xfer_length, HZ);
+                       kfree(xfer_buffer);
+                       if (retval < 0) {
+                               strncpy(vub300->vub_name,
+                                       "SDIO pseudocode download failed",
+                                       sizeof(vub300->vub_name));
+                               return;
+                       }
+               } else {
+                       dev_err(&vub300->udev->dev,
+                               "not enough memory for xfer buffer to send"
+                               " TRANSFER_PSEUDOCODE for %s %s\n", fw->data,
+                               vub300->vub_name);
+                       strncpy(vub300->vub_name,
+                               "SDIO transfer pseudocode download failed",
+                               sizeof(vub300->vub_name));
+                       return;
+               }
+       } else {
+               dev_err(&vub300->udev->dev,
+                       "corrupt transfer pseudocode in firmware %s %s\n",
+                       fw->data, vub300->vub_name);
+               strncpy(vub300->vub_name, "corrupt transfer pseudocode",
+                       sizeof(vub300->vub_name));
+               return;
+       }
+       register_count += *data++;
+       size -= 1;
+       if (register_count * 4 == size) {
+               int I = vub300->dynamic_register_count = register_count;
+               int i = 0;
+               while (I--) {
+                       unsigned int func_num = 0;
+                       vub300->sdio_register[i].func_num = *data++;
+                       size -= 1;
+                       func_num += *data++;
+                       size -= 1;
+                       func_num <<= 8;
+                       func_num += *data++;
+                       size -= 1;
+                       func_num <<= 8;
+                       func_num += *data++;
+                       size -= 1;
+                       vub300->sdio_register[i].sdio_reg = func_num;
+                       vub300->sdio_register[i].activate = 1;
+                       vub300->sdio_register[i].prepared = 0;
+                       i += 1;
+               }
+               dev_info(&vub300->udev->dev,
+                        "initialized %d dynamic pseudocode registers\n",
+                        vub300->dynamic_register_count);
+               return;
+       } else {
+               dev_err(&vub300->udev->dev,
+                       "corrupt dynamic registers in firmware %s\n",
+                       vub300->vub_name);
+               strncpy(vub300->vub_name, "corrupt dynamic registers",
+                       sizeof(vub300->vub_name));
+               return;
+       }
+}
+
+/*
+ * if the binary containing the EMPTY PseudoCode can not be found
+ * vub300->vub_name is set anyway in order to prevent an automatic retry
+ */
+static void download_offload_pseudocode(struct vub300_mmc_host *vub300)
+{
+       struct mmc_card *card = vub300->mmc->card;
+       int sdio_funcs = card->sdio_funcs;
+       const struct firmware *fw = NULL;
+       int l = snprintf(vub300->vub_name, sizeof(vub300->vub_name),
+                        "vub_%04X%04X", card->cis.vendor, card->cis.device);
+       int n = 0;
+       int retval;
+       for (n = 0; n < sdio_funcs; n++) {
+               struct sdio_func *sf = card->sdio_func[n];
+               l += snprintf(vub300->vub_name + l,
+                             sizeof(vub300->vub_name) - l, "_%04X%04X",
+                             sf->vendor, sf->device);
+       };
+       snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin");
+       dev_info(&vub300->udev->dev, "requesting offload firmware %s\n",
+                vub300->vub_name);
+       retval = request_firmware(&fw, vub300->vub_name, &card->dev);
+       if (retval < 0) {
+               strncpy(vub300->vub_name, "vub_default.bin",
+                       sizeof(vub300->vub_name));
+               retval = request_firmware(&fw, vub300->vub_name, &card->dev);
+               if (retval < 0) {
+                       strncpy(vub300->vub_name,
+                               "no SDIO offload firmware found",
+                               sizeof(vub300->vub_name));
+               } else {
+                       __download_offload_pseudocode(vub300, fw);
+                       release_firmware(fw);
+               }
+       } else {
+               __download_offload_pseudocode(vub300, fw);
+               release_firmware(fw);
+       }
+}
+
+static void vub300_usb_bulk_msg_completion(struct urb *urb)
+{                              /* urb completion handler - hardirq */
+       complete((struct completion *)urb->context);
+}
+
+static int vub300_usb_bulk_msg(struct vub300_mmc_host *vub300,
+                              unsigned int pipe, void *data, int len,
+                              int *actual_length, int timeout_msecs)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       struct usb_device *usb_dev = vub300->udev;
+       struct completion done;
+       int retval;
+       vub300->urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!vub300->urb)
+               return -ENOMEM;
+       usb_fill_bulk_urb(vub300->urb, usb_dev, pipe, data, len,
+                         vub300_usb_bulk_msg_completion, NULL);
+       init_completion(&done);
+       vub300->urb->context = &done;
+       vub300->urb->actual_length = 0;
+       retval = usb_submit_urb(vub300->urb, GFP_KERNEL);
+       if (unlikely(retval))
+               goto out;
+       if (!wait_for_completion_timeout
+           (&done, msecs_to_jiffies(timeout_msecs))) {
+               retval = -ETIMEDOUT;
+               usb_kill_urb(vub300->urb);
+       } else {
+               retval = vub300->urb->status;
+       }
+out:
+       *actual_length = vub300->urb->actual_length;
+       usb_free_urb(vub300->urb);
+       vub300->urb = NULL;
+       return retval;
+}
+
+static int __command_read_data(struct vub300_mmc_host *vub300,
+                              struct mmc_command *cmd, struct mmc_data *data)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       int linear_length = vub300->datasize;
+       int padded_length = vub300->large_usb_packets ?
+               ((511 + linear_length) >> 9) << 9 :
+               ((63 + linear_length) >> 6) << 6;
+       if ((padded_length == linear_length) || !pad_input_to_usb_pkt) {
+               int result;
+               unsigned pipe;
+               pipe = usb_rcvbulkpipe(vub300->udev, vub300->data_inp_ep);
+               result = usb_sg_init(&vub300->sg_request, vub300->udev,
+                                    pipe, 0, data->sg,
+                                    data->sg_len, 0, GFP_KERNEL);
+               if (result < 0) {
+                       usb_unlink_urb(vub300->command_out_urb);
+                       usb_unlink_urb(vub300->command_res_urb);
+                       cmd->error = result;
+                       data->bytes_xfered = 0;
+                       return 0;
+               } else {
+                       vub300->sg_transfer_timer.expires =
+                               jiffies + msecs_to_jiffies(2000 +
+                                                 (linear_length / 16384));
+                       add_timer(&vub300->sg_transfer_timer);
+                       usb_sg_wait(&vub300->sg_request);
+                       del_timer(&vub300->sg_transfer_timer);
+                       if (vub300->sg_request.status < 0) {
+                               cmd->error = vub300->sg_request.status;
+                               data->bytes_xfered = 0;
+                               return 0;
+                       } else {
+                               data->bytes_xfered = vub300->datasize;
+                               return linear_length;
+                       }
+               }
+       } else {
+               u8 *buf = kmalloc(padded_length, GFP_KERNEL);
+               if (buf) {
+                       int result;
+                       unsigned pipe = usb_rcvbulkpipe(vub300->udev,
+                                                       vub300->data_inp_ep);
+                       int actual_length = 0;
+                       result = vub300_usb_bulk_msg(vub300, pipe, buf,
+                                            padded_length, &actual_length,
+                                            2000 + (padded_length / 16384));
+                       if (result < 0) {
+                               cmd->error = result;
+                               data->bytes_xfered = 0;
+                               kfree(buf);
+                               return 0;
+                       } else if (actual_length < linear_length) {
+                               cmd->error = -EREMOTEIO;
+                               data->bytes_xfered = 0;
+                               kfree(buf);
+                               return 0;
+                       } else {
+                               sg_copy_from_buffer(data->sg, data->sg_len, buf,
+                                                   linear_length);
+                               kfree(buf);
+                               data->bytes_xfered = vub300->datasize;
+                               return linear_length;
+                       }
+               } else {
+                       cmd->error = -ENOMEM;
+                       data->bytes_xfered = 0;
+                       return 0;
+               }
+       }
+}
+
+static int __command_write_data(struct vub300_mmc_host *vub300,
+                               struct mmc_command *cmd, struct mmc_data *data)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       unsigned pipe = usb_sndbulkpipe(vub300->udev, vub300->data_out_ep);
+       int linear_length = vub300->datasize;
+       int modulo_64_length = linear_length & 0x003F;
+       int modulo_512_length = linear_length & 0x01FF;
+       if (linear_length < 64) {
+               int result;
+               int actual_length;
+               sg_copy_to_buffer(data->sg, data->sg_len,
+                                 vub300->padded_buffer,
+                                 sizeof(vub300->padded_buffer));
+               memset(vub300->padded_buffer + linear_length, 0,
+                      sizeof(vub300->padded_buffer) - linear_length);
+               result = vub300_usb_bulk_msg(vub300, pipe, vub300->padded_buffer,
+                                            sizeof(vub300->padded_buffer),
+                                            &actual_length, 2000 +
+                                            (sizeof(vub300->padded_buffer) /
+                                             16384));
+               if (result < 0) {
+                       cmd->error = result;
+                       data->bytes_xfered = 0;
+               } else {
+                       data->bytes_xfered = vub300->datasize;
+               }
+       } else if ((!vub300->large_usb_packets && (0 < modulo_64_length)) ||
+                   (vub300->large_usb_packets && (64 > modulo_512_length))
+               ) {             /* don't you just love these work-rounds */
+               int padded_length = ((63 + linear_length) >> 6) << 6;
+               u8 *buf = kmalloc(padded_length, GFP_KERNEL);
+               if (buf) {
+                       int result;
+                       int actual_length;
+                       sg_copy_to_buffer(data->sg, data->sg_len, buf,
+                                         padded_length);
+                       memset(buf + linear_length, 0,
+                              padded_length - linear_length);
+                       result =
+                               vub300_usb_bulk_msg(vub300, pipe, buf,
+                                                   padded_length, &actual_length,
+                                                   2000 + padded_length / 16384);
+                       kfree(buf);
+                       if (result < 0) {
+                               cmd->error = result;
+                               data->bytes_xfered = 0;
+                       } else {
+                               data->bytes_xfered = vub300->datasize;
+                       }
+               } else {
+                       cmd->error = -ENOMEM;
+                       data->bytes_xfered = 0;
+               }
+       } else {                /* no data padding required */
+               int result;
+               unsigned char buf[64 * 4];
+               sg_copy_to_buffer(data->sg, data->sg_len, buf, sizeof(buf));
+               result = usb_sg_init(&vub300->sg_request, vub300->udev,
+                                    pipe, 0, data->sg,
+                                    data->sg_len, 0, GFP_KERNEL);
+               if (result < 0) {
+                       usb_unlink_urb(vub300->command_out_urb);
+                       usb_unlink_urb(vub300->command_res_urb);
+                       cmd->error = result;
+                       data->bytes_xfered = 0;
+               } else {
+                       vub300->sg_transfer_timer.expires =
+                               jiffies + msecs_to_jiffies(2000 +
+                                                          linear_length / 16384);
+                       add_timer(&vub300->sg_transfer_timer);
+                       usb_sg_wait(&vub300->sg_request);
+                       if (cmd->error) {
+                               data->bytes_xfered = 0;
+                       } else {
+                               del_timer(&vub300->sg_transfer_timer);
+                               if (vub300->sg_request.status < 0) {
+                                       cmd->error = vub300->sg_request.status;
+                                       data->bytes_xfered = 0;
+                               } else {
+                                       data->bytes_xfered = vub300->datasize;
+                               }
+                       }
+               }
+       }
+       return linear_length;
+}
+
+static void __vub300_command_response(struct vub300_mmc_host *vub300,
+                                     struct mmc_command *cmd,
+                                     struct mmc_data *data, int data_length)
+{
+       /* cmd_mutex is held by vub300_cmndwork_thread */
+       long respretval;
+       int msec_timeout = 1000 + data_length / 4;
+       respretval =
+               wait_for_completion_timeout(&vub300->command_complete,
+                                           msecs_to_jiffies(msec_timeout));
+       if (respretval == 0) { /* TIMED OUT */
+               /* we don't know which of "out" and "res" if any failed */
+               int result;
+               vub300->usb_timed_out = 1;
+               usb_kill_urb(vub300->command_out_urb);
+               usb_kill_urb(vub300->command_res_urb);
+               cmd->error = -ETIMEDOUT;
+               result = usb_lock_device_for_reset(vub300->udev,
+                                                  vub300->interface);
+               if (result == 0) {
+                       result = usb_reset_device(vub300->udev);
+                       usb_unlock_device(vub300->udev);
+               }
+       } else if (respretval < 0) {
+               /* we don't know which of "out" and "res" if any failed */
+               usb_kill_urb(vub300->command_out_urb);
+               usb_kill_urb(vub300->command_res_urb);
+               cmd->error = respretval;
+       } else if (cmd->error) {
+               /*
+                * the error occured sending the command
+                * or recieving the response
+                */
+       } else if (vub300->command_out_urb->status) {
+               vub300->usb_transport_fail = vub300->command_out_urb->status;
+               cmd->error = -EPROTO == vub300->command_out_urb->status ?
+                       -ESHUTDOWN : vub300->command_out_urb->status;
+       } else if (vub300->command_res_urb->status) {
+               vub300->usb_transport_fail = vub300->command_res_urb->status;
+               cmd->error = -EPROTO == vub300->command_res_urb->status ?
+                       -ESHUTDOWN : vub300->command_res_urb->status;
+       } else if (vub300->resp.common.header_type == 0x00) {
+               /*
+                * the command completed successfully
+                * and there was no piggybacked data
+                */
+       } else if (vub300->resp.common.header_type == RESPONSE_ERROR) {
+               cmd->error =
+                       vub300_response_error(vub300->resp.error.error_code);
+               if (vub300->data)
+                       usb_sg_cancel(&vub300->sg_request);
+       } else if (vub300->resp.common.header_type == RESPONSE_PIGGYBACKED) {
+               int offloaded_data_length =
+                       vub300->resp.common.header_size -
+                       sizeof(struct sd_register_header);
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
+                       ri += 1;
+               }
+               vub300->resp.common.header_size =
+                       sizeof(struct sd_register_header);
+               vub300->resp.common.header_type = 0x00;
+               cmd->error = 0;
+       } else if (vub300->resp.common.header_type == RESPONSE_PIG_DISABLED) {
+               int offloaded_data_length =
+                       vub300->resp.common.header_size -
+                       sizeof(struct sd_register_header);
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
+                       ri += 1;
+               }
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irqs_queued) {
+                       vub300->irqs_queued += 1;
+               } else if (vub300->irq_enabled) {
+                       vub300->irqs_queued += 1;
+                       vub300_queue_poll_work(vub300, 0);
+               } else {
+                       vub300->irqs_queued += 1;
+               }
+               vub300->irq_disabled = 1;
+               mutex_unlock(&vub300->irq_mutex);
+               vub300->resp.common.header_size =
+                       sizeof(struct sd_register_header);
+               vub300->resp.common.header_type = 0x00;
+               cmd->error = 0;
+       } else if (vub300->resp.common.header_type == RESPONSE_PIG_ENABLED) {
+               int offloaded_data_length =
+                       vub300->resp.common.header_size -
+                       sizeof(struct sd_register_header);
+               int register_count = offloaded_data_length >> 3;
+               int ri = 0;
+               while (register_count--) {
+                       add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
+                       ri += 1;
+               }
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irqs_queued) {
+                       vub300->irqs_queued += 1;
+               } else if (vub300->irq_enabled) {
+                       vub300->irqs_queued += 1;
+                       vub300_queue_poll_work(vub300, 0);
+               } else {
+                       vub300->irqs_queued += 1;
+               }
+               vub300->irq_disabled = 0;
+               mutex_unlock(&vub300->irq_mutex);
+               vub300->resp.common.header_size =
+                       sizeof(struct sd_register_header);
+               vub300->resp.common.header_type = 0x00;
+               cmd->error = 0;
+       } else {
+               cmd->error = -EINVAL;
+       }
+}
+
+static void construct_request_response(struct vub300_mmc_host *vub300,
+                                      struct mmc_command *cmd)
+{
+       int resp_len = vub300->resp_len;
+       int less_cmd = (17 == resp_len) ? resp_len : resp_len - 1;
+       int bytes = 3 & less_cmd;
+       int words = less_cmd >> 2;
+       u8 *r = vub300->resp.response.command_response;
+       if (bytes == 3) {
+               cmd->resp[words] = (r[1 + (words << 2)] << 24)
+                       | (r[2 + (words << 2)] << 16)
+                       | (r[3 + (words << 2)] << 8);
+       } else if (bytes == 2) {
+               cmd->resp[words] = (r[1 + (words << 2)] << 24)
+                       | (r[2 + (words << 2)] << 16);
+       } else if (bytes == 1) {
+               cmd->resp[words] = (r[1 + (words << 2)] << 24);
+       }
+       while (words-- > 0) {
+               cmd->resp[words] = (r[1 + (words << 2)] << 24)
+                       | (r[2 + (words << 2)] << 16)
+                       | (r[3 + (words << 2)] << 8)
+                       | (r[4 + (words << 2)] << 0);
+       }
+       if ((cmd->opcode == 53) && (0x000000FF & cmd->resp[0]))
+               cmd->resp[0] &= 0xFFFFFF00;
+}
+
+/* this thread runs only when there is an upper level command req outstanding */
+static void vub300_cmndwork_thread(struct work_struct *work)
+{
+       struct vub300_mmc_host *vub300 =
+               container_of(work, struct vub300_mmc_host, cmndwork);
+       if (!vub300->interface) {
+               kref_put(&vub300->kref, vub300_delete);
+               return;
+       } else {
+               struct mmc_request *req = vub300->req;
+               struct mmc_command *cmd = vub300->cmd;
+               struct mmc_data *data = vub300->data;
+               int data_length;
+               mutex_lock(&vub300->cmd_mutex);
+               init_completion(&vub300->command_complete);
+               if (likely(vub300->vub_name[0]) || !vub300->mmc->card ||
+                   !mmc_card_present(vub300->mmc->card)) {
+                       /*
+                        * the name of the EMPTY Pseudo firmware file
+                        * is used as a flag to indicate that the file
+                        * has been already downloaded to the VUB300 chip
+                        */
+               } else if (0 == vub300->mmc->card->sdio_funcs) {
+                       strncpy(vub300->vub_name, "SD memory device",
+                               sizeof(vub300->vub_name));
+               } else {
+                       download_offload_pseudocode(vub300);
+               }
+               send_command(vub300);
+               if (!data)
+                       data_length = 0;
+               else if (MMC_DATA_READ & data->flags)
+                       data_length = __command_read_data(vub300, cmd, data);
+               else
+                       data_length = __command_write_data(vub300, cmd, data);
+               __vub300_command_response(vub300, cmd, data, data_length);
+               vub300->req = NULL;
+               vub300->cmd = NULL;
+               vub300->data = NULL;
+               if (cmd->error) {
+                       if (cmd->error == -ENOMEDIUM)
+                               check_vub300_port_status(vub300);
+                       mutex_unlock(&vub300->cmd_mutex);
+                       mmc_request_done(vub300->mmc, req);
+                       kref_put(&vub300->kref, vub300_delete);
+                       return;
+               } else {
+                       construct_request_response(vub300, cmd);
+                       vub300->resp_len = 0;
+                       mutex_unlock(&vub300->cmd_mutex);
+                       kref_put(&vub300->kref, vub300_delete);
+                       mmc_request_done(vub300->mmc, req);
+                       return;
+               }
+       }
+}
+
+static int examine_cyclic_buffer(struct vub300_mmc_host *vub300,
+                                struct mmc_command *cmd, u8 Function)
+{
+       /* cmd_mutex is held by vub300_mmc_request */
+       u8 cmd0 = 0xFF & (cmd->arg >> 24);
+       u8 cmd1 = 0xFF & (cmd->arg >> 16);
+       u8 cmd2 = 0xFF & (cmd->arg >> 8);
+       u8 cmd3 = 0xFF & (cmd->arg >> 0);
+       int first = MAXREGMASK & vub300->fn[Function].offload_point;
+       struct offload_registers_access *rf = &vub300->fn[Function].reg[first];
+       if (cmd0 == rf->command_byte[0] &&
+           cmd1 == rf->command_byte[1] &&
+           cmd2 == rf->command_byte[2] &&
+           cmd3 == rf->command_byte[3]) {
+               u8 checksum = 0x00;
+               cmd->resp[1] = checksum << 24;
+               cmd->resp[0] = (rf->Respond_Byte[0] << 24)
+                       | (rf->Respond_Byte[1] << 16)
+                       | (rf->Respond_Byte[2] << 8)
+                       | (rf->Respond_Byte[3] << 0);
+               vub300->fn[Function].offload_point += 1;
+               vub300->fn[Function].offload_count -= 1;
+               vub300->total_offload_count -= 1;
+               return 1;
+       } else {
+               int delta = 1;  /* because it does not match the first one */
+               u8 register_count = vub300->fn[Function].offload_count - 1;
+               u32 register_point = vub300->fn[Function].offload_point + 1;
+               while (0 < register_count) {
+                       int point = MAXREGMASK & register_point;
+                       struct offload_registers_access *r =
+                               &vub300->fn[Function].reg[point];
+                       if (cmd0 == r->command_byte[0] &&
+                           cmd1 == r->command_byte[1] &&
+                           cmd2 == r->command_byte[2] &&
+                           cmd3 == r->command_byte[3]) {
+                               u8 checksum = 0x00;
+                               cmd->resp[1] = checksum << 24;
+                               cmd->resp[0] = (r->Respond_Byte[0] << 24)
+                                       | (r->Respond_Byte[1] << 16)
+                                       | (r->Respond_Byte[2] << 8)
+                                       | (r->Respond_Byte[3] << 0);
+                               vub300->fn[Function].offload_point += delta;
+                               vub300->fn[Function].offload_count -= delta;
+                               vub300->total_offload_count -= delta;
+                               return 1;
+                       } else {
+                               register_point += 1;
+                               register_count -= 1;
+                               delta += 1;
+                               continue;
+                       }
+               }
+               return 0;
+       }
+}
+
+static int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300,
+                                              struct mmc_command *cmd)
+{
+       /* cmd_mutex is held by vub300_mmc_request */
+       u8 regs = vub300->dynamic_register_count;
+       u8 i = 0;
+       u8 func = FUN(cmd);
+       u32 reg = REG(cmd);
+       while (0 < regs--) {
+               if ((vub300->sdio_register[i].func_num == func) &&
+                   (vub300->sdio_register[i].sdio_reg == reg)) {
+                       if (!vub300->sdio_register[i].prepared) {
+                               return 0;
+                       } else if ((0x80000000 & cmd->arg) == 0x80000000) {
+                               /*
+                                * a write to a dynamic register
+                                * nullifies our offloaded value
+                                */
+                               vub300->sdio_register[i].prepared = 0;
+                               return 0;
+                       } else {
+                               u8 checksum = 0x00;
+                               u8 rsp0 = 0x00;
+                               u8 rsp1 = 0x00;
+                               u8 rsp2 = vub300->sdio_register[i].response;
+                               u8 rsp3 = vub300->sdio_register[i].regvalue;
+                               vub300->sdio_register[i].prepared = 0;
+                               cmd->resp[1] = checksum << 24;
+                               cmd->resp[0] = (rsp0 << 24)
+                                       | (rsp1 << 16)
+                                       | (rsp2 << 8)
+                                       | (rsp3 << 0);
+                               return 1;
+                       }
+               } else {
+                       i += 1;
+                       continue;
+               }
+       };
+       if (vub300->total_offload_count == 0)
+               return 0;
+       else if (vub300->fn[func].offload_count == 0)
+               return 0;
+       else
+               return examine_cyclic_buffer(vub300, cmd, func);
+}
+
+static void vub300_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
+{                              /* NOT irq */
+       struct mmc_command *cmd = req->cmd;
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       if (!vub300->interface) {
+               cmd->error = -ESHUTDOWN;
+               mmc_request_done(mmc, req);
+               return;
+       } else {
+               struct mmc_data *data = req->data;
+               if (!vub300->card_powered) {
+                       cmd->error = -ENOMEDIUM;
+                       mmc_request_done(mmc, req);
+                       return;
+               }
+               if (!vub300->card_present) {
+                       cmd->error = -ENOMEDIUM;
+                       mmc_request_done(mmc, req);
+                       return;
+               }
+               if (vub300->usb_transport_fail) {
+                       cmd->error = vub300->usb_transport_fail;
+                       mmc_request_done(mmc, req);
+                       return;
+               }
+               if (!vub300->interface) {
+                       cmd->error = -ENODEV;
+                       mmc_request_done(mmc, req);
+                       return;
+               }
+               kref_get(&vub300->kref);
+               mutex_lock(&vub300->cmd_mutex);
+               mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+               /*
+                * for performance we have to return immediately
+                * if the requested data has been offloaded
+                */
+               if (cmd->opcode == 52 &&
+                   satisfy_request_from_offloaded_data(vub300, cmd)) {
+                       cmd->error = 0;
+                       mutex_unlock(&vub300->cmd_mutex);
+                       kref_put(&vub300->kref, vub300_delete);
+                       mmc_request_done(mmc, req);
+                       return;
+               } else {
+                       vub300->cmd = cmd;
+                       vub300->req = req;
+                       vub300->data = data;
+                       if (data)
+                               vub300->datasize = data->blksz * data->blocks;
+                       else
+                               vub300->datasize = 0;
+                       vub300_queue_cmnd_work(vub300);
+                       mutex_unlock(&vub300->cmd_mutex);
+                       kref_put(&vub300->kref, vub300_delete);
+                       /*
+                        * the kernel lock diagnostics complain
+                        * if the cmd_mutex * is "passed on"
+                        * to the cmndwork thread,
+                        * so we must release it now
+                        * and re-acquire it in the cmndwork thread
+                        */
+               }
+       }
+}
+
+static void __set_clock_speed(struct vub300_mmc_host *vub300, u8 buf[8],
+                             struct mmc_ios *ios)
+{
+       int buf_array_size = 8; /* ARRAY_SIZE(buf) does not work !!! */
+       int retval;
+       u32 kHzClock;
+       if (ios->clock >= 48000000)
+               kHzClock = 48000;
+       else if (ios->clock >= 24000000)
+               kHzClock = 24000;
+       else if (ios->clock >= 20000000)
+               kHzClock = 20000;
+       else if (ios->clock >= 15000000)
+               kHzClock = 15000;
+       else if (ios->clock >= 200000)
+               kHzClock = 200;
+       else
+               kHzClock = 0;
+       {
+               int i;
+               u64 c = kHzClock;
+               for (i = 0; i < buf_array_size; i++) {
+                       buf[i] = c;
+                       c >>= 8;
+               }
+       }
+       retval =
+               usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
+                               SET_CLOCK_SPEED,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x00, 0x00, buf, buf_array_size, HZ);
+       if (retval != 8) {
+               dev_err(&vub300->udev->dev, "SET_CLOCK_SPEED"
+                       " %dkHz failed with retval=%d\n", kHzClock, retval);
+       } else {
+               dev_dbg(&vub300->udev->dev, "SET_CLOCK_SPEED"
+                       " %dkHz\n", kHzClock);
+       }
+}
+
+static void vub300_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       if (!vub300->interface)
+               return;
+       kref_get(&vub300->kref);
+       mutex_lock(&vub300->cmd_mutex);
+       if ((ios->power_mode == MMC_POWER_OFF) && vub300->card_powered) {
+               vub300->card_powered = 0;
+               usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
+                               SET_SD_POWER,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0000, 0x0000, NULL, 0, HZ);
+               /* must wait for the VUB300 u-proc to boot up */
+               msleep(600);
+       } else if ((ios->power_mode == MMC_POWER_UP) && !vub300->card_powered) {
+               usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
+                               SET_SD_POWER,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0001, 0x0000, NULL, 0, HZ);
+               msleep(600);
+               vub300->card_powered = 1;
+       } else if (ios->power_mode == MMC_POWER_ON) {
+               u8 *buf = kmalloc(8, GFP_KERNEL);
+               if (buf) {
+                       __set_clock_speed(vub300, buf, ios);
+                       kfree(buf);
+               }
+       } else {
+               /* this should mean no change of state */
+       }
+       mutex_unlock(&vub300->cmd_mutex);
+       kref_put(&vub300->kref, vub300_delete);
+}
+
+static int vub300_mmc_get_ro(struct mmc_host *mmc)
+{
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       return vub300->read_only;
+}
+
+static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       if (!vub300->interface)
+               return;
+       kref_get(&vub300->kref);
+       if (enable) {
+               mutex_lock(&vub300->irq_mutex);
+               if (vub300->irqs_queued) {
+                       vub300->irqs_queued -= 1;
+                       mmc_signal_sdio_irq(vub300->mmc);
+               } else if (vub300->irq_disabled) {
+                       vub300->irq_disabled = 0;
+                       vub300->irq_enabled = 1;
+                       vub300_queue_poll_work(vub300, 0);
+               } else if (vub300->irq_enabled) {
+                       /* this should not happen, so we will just ignore it */
+               } else {
+                       vub300->irq_enabled = 1;
+                       vub300_queue_poll_work(vub300, 0);
+               }
+               mutex_unlock(&vub300->irq_mutex);
+       } else {
+               vub300->irq_enabled = 0;
+       }
+       kref_put(&vub300->kref, vub300_delete);
+}
+
+void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+       dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n");
+}
+
+static struct mmc_host_ops vub300_mmc_ops = {
+       .request = vub300_mmc_request,
+       .set_ios = vub300_mmc_set_ios,
+       .get_ro = vub300_mmc_get_ro,
+       .enable_sdio_irq = vub300_enable_sdio_irq,
+       .init_card = vub300_init_card,
+};
+
+static int vub300_probe(struct usb_interface *interface,
+                       const struct usb_device_id *id)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = NULL;
+       struct usb_host_interface *iface_desc;
+       struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
+       int i;
+       int retval = -ENOMEM;
+       struct urb *command_out_urb;
+       struct urb *command_res_urb;
+       struct mmc_host *mmc;
+       char manufacturer[48];
+       char product[32];
+       char serial_number[32];
+       usb_string(udev, udev->descriptor.iManufacturer, manufacturer,
+                  sizeof(manufacturer));
+       usb_string(udev, udev->descriptor.iProduct, product, sizeof(product));
+       usb_string(udev, udev->descriptor.iSerialNumber, serial_number,
+                  sizeof(serial_number));
+       dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n",
+                udev->descriptor.idVendor, udev->descriptor.idProduct,
+                manufacturer, product, serial_number);
+       command_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!command_out_urb) {
+               retval = -ENOMEM;
+               dev_err(&vub300->udev->dev,
+                       "not enough memory for the command_out_urb\n");
+               goto error0;
+       }
+       command_res_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!command_res_urb) {
+               retval = -ENOMEM;
+               dev_err(&vub300->udev->dev,
+                       "not enough memory for the command_res_urb\n");
+               goto error1;
+       }
+       /* this also allocates memory for our VUB300 mmc host device */
+       mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev);
+       if (!mmc) {
+               retval = -ENOMEM;
+               dev_err(&vub300->udev->dev,
+                       "not enough memory for the mmc_host\n");
+               goto error4;
+       }
+       /* MMC core transfer sizes tunable parameters */
+       mmc->caps = 0;
+       if (!force_1_bit_data_xfers)
+               mmc->caps |= MMC_CAP_4_BIT_DATA;
+       if (!force_polling_for_irqs)
+               mmc->caps |= MMC_CAP_SDIO_IRQ;
+       mmc->caps &= ~MMC_CAP_NEEDS_POLL;
+       /*
+        * MMC_CAP_NEEDS_POLL causes core.c:mmc_rescan() to poll
+        * for devices which results in spurious CMD7's being
+        * issued which stops some SDIO cards from working
+        */
+       if (limit_speed_to_24_MHz) {
+               mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+               mmc->f_max = 24000000;
+               dev_info(&udev->dev, "limiting SDIO speed to 24_MHz\n");
+       } else {
+               mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+               mmc->f_max = 48000000;
+       }
+       mmc->f_min = 200000;
+       mmc->max_blk_count = 511;
+       mmc->max_blk_size = 512;
+       mmc->max_segs = 128;
+       if (force_max_req_size)
+               mmc->max_req_size = force_max_req_size * 1024;
+       else
+               mmc->max_req_size = 64 * 1024;
+       mmc->max_seg_size = mmc->max_req_size;
+       mmc->ocr_avail = 0;
+       mmc->ocr_avail |= MMC_VDD_165_195;
+       mmc->ocr_avail |= MMC_VDD_20_21;
+       mmc->ocr_avail |= MMC_VDD_21_22;
+       mmc->ocr_avail |= MMC_VDD_22_23;
+       mmc->ocr_avail |= MMC_VDD_23_24;
+       mmc->ocr_avail |= MMC_VDD_24_25;
+       mmc->ocr_avail |= MMC_VDD_25_26;
+       mmc->ocr_avail |= MMC_VDD_26_27;
+       mmc->ocr_avail |= MMC_VDD_27_28;
+       mmc->ocr_avail |= MMC_VDD_28_29;
+       mmc->ocr_avail |= MMC_VDD_29_30;
+       mmc->ocr_avail |= MMC_VDD_30_31;
+       mmc->ocr_avail |= MMC_VDD_31_32;
+       mmc->ocr_avail |= MMC_VDD_32_33;
+       mmc->ocr_avail |= MMC_VDD_33_34;
+       mmc->ocr_avail |= MMC_VDD_34_35;
+       mmc->ocr_avail |= MMC_VDD_35_36;
+       mmc->ops = &vub300_mmc_ops;
+       vub300 = mmc_priv(mmc);
+       vub300->mmc = mmc;
+       vub300->card_powered = 0;
+       vub300->bus_width = 0;
+       vub300->cmnd.head.block_size[0] = 0x00;
+       vub300->cmnd.head.block_size[1] = 0x00;
+       vub300->app_spec = 0;
+       mutex_init(&vub300->cmd_mutex);
+       mutex_init(&vub300->irq_mutex);
+       vub300->command_out_urb = command_out_urb;
+       vub300->command_res_urb = command_res_urb;
+       vub300->usb_timed_out = 0;
+       vub300->dynamic_register_count = 0;
+
+       for (i = 0; i < ARRAY_SIZE(vub300->fn); i++) {
+               vub300->fn[i].offload_point = 0;
+               vub300->fn[i].offload_count = 0;
+       }
+
+       vub300->total_offload_count = 0;
+       vub300->irq_enabled = 0;
+       vub300->irq_disabled = 0;
+       vub300->irqs_queued = 0;
+
+       for (i = 0; i < ARRAY_SIZE(vub300->sdio_register); i++)
+               vub300->sdio_register[i++].activate = 0;
+
+       vub300->udev = udev;
+       vub300->interface = interface;
+       vub300->cmnd_res_ep = 0;
+       vub300->cmnd_out_ep = 0;
+       vub300->data_inp_ep = 0;
+       vub300->data_out_ep = 0;
+
+       for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
+               vub300->fbs[i] = 512;
+
+       /*
+        *      set up the endpoint information
+        *
+        * use the first pair of bulk-in and bulk-out
+        *     endpoints for Command/Response+Interrupt
+        *
+        * use the second pair of bulk-in and bulk-out
+        *     endpoints for Data In/Out
+        */
+       vub300->large_usb_packets = 0;
+       iface_desc = interface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               struct usb_endpoint_descriptor *endpoint =
+                       &iface_desc->endpoint[i].desc;
+               dev_info(&vub300->udev->dev,
+                        "vub300 testing %s EndPoint(%d) %02X\n",
+                        usb_endpoint_is_bulk_in(endpoint) ? "BULK IN" :
+                        usb_endpoint_is_bulk_out(endpoint) ? "BULK OUT" :
+                        "UNKNOWN", i, endpoint->bEndpointAddress);
+               if (endpoint->wMaxPacketSize > 64)
+                       vub300->large_usb_packets = 1;
+               if (usb_endpoint_is_bulk_in(endpoint)) {
+                       if (!vub300->cmnd_res_ep) {
+                               vub300->cmnd_res_ep =
+                                       endpoint->bEndpointAddress;
+                       } else if (!vub300->data_inp_ep) {
+                               vub300->data_inp_ep =
+                                       endpoint->bEndpointAddress;
+                       } else {
+                               dev_warn(&vub300->udev->dev,
+                                        "ignoring"
+                                        " unexpected bulk_in endpoint");
+                       }
+               } else if (usb_endpoint_is_bulk_out(endpoint)) {
+                       if (!vub300->cmnd_out_ep) {
+                               vub300->cmnd_out_ep =
+                                       endpoint->bEndpointAddress;
+                       } else if (!vub300->data_out_ep) {
+                               vub300->data_out_ep =
+                                       endpoint->bEndpointAddress;
+                       } else {
+                               dev_warn(&vub300->udev->dev,
+                                        "ignoring"
+                                        " unexpected bulk_out endpoint");
+                       }
+               } else {
+                       dev_warn(&vub300->udev->dev,
+                                "vub300 ignoring EndPoint(%d) %02X", i,
+                                endpoint->bEndpointAddress);
+               }
+       }
+       if (vub300->cmnd_res_ep && vub300->cmnd_out_ep &&
+           vub300->data_inp_ep && vub300->data_out_ep) {
+               dev_info(&vub300->udev->dev,
+                        "vub300 %s packets"
+                        " using EndPoints %02X %02X %02X %02X\n",
+                        vub300->large_usb_packets ? "LARGE" : "SMALL",
+                        vub300->cmnd_out_ep, vub300->cmnd_res_ep,
+                        vub300->data_out_ep, vub300->data_inp_ep);
+               /* we have the expected EndPoints */
+       } else {
+               dev_err(&vub300->udev->dev,
+                   "Could not find two sets of bulk-in/out endpoint pairs\n");
+               retval = -EINVAL;
+               goto error5;
+       }
+       retval =
+               usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+                               GET_HC_INF0,
+                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0000, 0x0000, &vub300->hc_info,
+                               sizeof(vub300->hc_info), HZ);
+       if (retval < 0)
+               goto error5;
+       retval =
+               usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+                               SET_ROM_WAIT_STATES,
+                               USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               firmware_rom_wait_states, 0x0000, NULL, 0, HZ);
+       if (retval < 0)
+               goto error5;
+       dev_info(&vub300->udev->dev,
+                "operating_mode = %s %s %d MHz %s %d byte USB packets\n",
+                (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
+                (mmc->caps & MMC_CAP_4_BIT_DATA) ? "4-bit" : "1-bit",
+                mmc->f_max / 1000000,
+                pad_input_to_usb_pkt ? "padding input data to" : "with",
+                vub300->large_usb_packets ? 512 : 64);
+       retval =
+               usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+                               GET_SYSTEM_PORT_STATUS,
+                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0x0000, 0x0000, &vub300->system_port_status,
+                               sizeof(vub300->system_port_status), HZ);
+       if (retval < 0) {
+               goto error4;
+       } else if (sizeof(vub300->system_port_status) == retval) {
+               vub300->card_present =
+                       (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
+               vub300->read_only =
+                       (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
+       } else {
+               goto error4;
+       }
+       usb_set_intfdata(interface, vub300);
+       INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
+       INIT_WORK(&vub300->cmndwork, vub300_cmndwork_thread);
+       INIT_WORK(&vub300->deadwork, vub300_deadwork_thread);
+       kref_init(&vub300->kref);
+       init_timer(&vub300->sg_transfer_timer);
+       vub300->sg_transfer_timer.data = (unsigned long)vub300;
+       vub300->sg_transfer_timer.function = vub300_sg_timed_out;
+       kref_get(&vub300->kref);
+       init_timer(&vub300->inactivity_timer);
+       vub300->inactivity_timer.data = (unsigned long)vub300;
+       vub300->inactivity_timer.function = vub300_inactivity_timer_expired;
+       vub300->inactivity_timer.expires = jiffies + HZ;
+       add_timer(&vub300->inactivity_timer);
+       if (vub300->card_present)
+               dev_info(&vub300->udev->dev,
+                        "USB vub300 remote SDIO host controller[%d]"
+                        "connected with SD/SDIO card inserted\n",
+                        interface_to_InterfaceNumber(interface));
+       else
+               dev_info(&vub300->udev->dev,
+                        "USB vub300 remote SDIO host controller[%d]"
+                        "connected with no SD/SDIO card inserted\n",
+                        interface_to_InterfaceNumber(interface));
+       mmc_add_host(mmc);
+       return 0;
+error5:
+       mmc_free_host(mmc);
+       /*
+        * and hence also frees vub300
+        * which is contained at the end of struct mmc
+        */
+error4:
+       usb_free_urb(command_out_urb);
+error1:
+       usb_free_urb(command_res_urb);
+error0:
+       return retval;
+}
+
+static void vub300_disconnect(struct usb_interface *interface)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(interface);
+       if (!vub300 || !vub300->mmc) {
+               return;
+       } else {
+               struct mmc_host *mmc = vub300->mmc;
+               if (!vub300->mmc) {
+                       return;
+               } else {
+                       int ifnum = interface_to_InterfaceNumber(interface);
+                       usb_set_intfdata(interface, NULL);
+                       /* prevent more I/O from starting */
+                       vub300->interface = NULL;
+                       kref_put(&vub300->kref, vub300_delete);
+                       mmc_remove_host(mmc);
+                       pr_info("USB vub300 remote SDIO host controller[%d]"
+                               " now disconnected", ifnum);
+                       return;
+               }
+       }
+}
+
+#ifdef CONFIG_PM
+static int vub300_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+       if (!vub300 || !vub300->mmc) {
+               return 0;
+       } else {
+               struct mmc_host *mmc = vub300->mmc;
+               mmc_suspend_host(mmc);
+               return 0;
+       }
+}
+
+static int vub300_resume(struct usb_interface *intf)
+{
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+       if (!vub300 || !vub300->mmc) {
+               return 0;
+       } else {
+               struct mmc_host *mmc = vub300->mmc;
+               mmc_resume_host(mmc);
+               return 0;
+       }
+}
+#else
+#define vub300_suspend NULL
+#define vub300_resume NULL
+#endif
+static int vub300_pre_reset(struct usb_interface *intf)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+       mutex_lock(&vub300->cmd_mutex);
+       return 0;
+}
+
+static int vub300_post_reset(struct usb_interface *intf)
+{                              /* NOT irq */
+       struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+       /* we are sure no URBs are active - no locking needed */
+       vub300->errors = -EPIPE;
+       mutex_unlock(&vub300->cmd_mutex);
+       return 0;
+}
+
+static struct usb_driver vub300_driver = {
+       .name = "vub300",
+       .probe = vub300_probe,
+       .disconnect = vub300_disconnect,
+       .suspend = vub300_suspend,
+       .resume = vub300_resume,
+       .pre_reset = vub300_pre_reset,
+       .post_reset = vub300_post_reset,
+       .id_table = vub300_table,
+       .supports_autosuspend = 1,
+};
+
+static int __init vub300_init(void)
+{                              /* NOT irq */
+       int result;
+
+       pr_info("VUB300 Driver rom wait states = %02X irqpoll timeout = %04X",
+               firmware_rom_wait_states, 0x0FFFF & firmware_irqpoll_timeout);
+       cmndworkqueue = create_singlethread_workqueue("kvub300c");
+       if (!cmndworkqueue) {
+               pr_err("not enough memory for the REQUEST workqueue");
+               result = -ENOMEM;
+               goto out1;
+       }
+       pollworkqueue = create_singlethread_workqueue("kvub300p");
+       if (!pollworkqueue) {
+               pr_err("not enough memory for the IRQPOLL workqueue");
+               result = -ENOMEM;
+               goto out2;
+       }
+       deadworkqueue = create_singlethread_workqueue("kvub300d");
+       if (!deadworkqueue) {
+               pr_err("not enough memory for the EXPIRED workqueue");
+               result = -ENOMEM;
+               goto out3;
+       }
+       result = usb_register(&vub300_driver);
+       if (result) {
+               pr_err("usb_register failed. Error number %d", result);
+               goto out4;
+       }
+       return 0;
+out4:
+       destroy_workqueue(deadworkqueue);
+out3:
+       destroy_workqueue(pollworkqueue);
+out2:
+       destroy_workqueue(cmndworkqueue);
+out1:
+       return result;
+}
+
+static void __exit vub300_exit(void)
+{
+       usb_deregister(&vub300_driver);
+       flush_workqueue(cmndworkqueue);
+       flush_workqueue(pollworkqueue);
+       flush_workqueue(deadworkqueue);
+       destroy_workqueue(cmndworkqueue);
+       destroy_workqueue(pollworkqueue);
+       destroy_workqueue(deadworkqueue);
+}
+
+module_init(vub300_init);
+module_exit(vub300_exit);
+
+MODULE_AUTHOR("Tony Olech <tony.olech@elandigitalsystems.com>");
+MODULE_DESCRIPTION("VUB300 USB to SD/MMC/SDIO adapter driver");
+MODULE_LICENSE("GPL");
index 209fbb70619b8be9e5f6d6c871b82a88d86833fa..776a478e6296e3bd92656fcd1bc6729288b5dc77 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_ATL2) += atlx/
 obj-$(CONFIG_ATL1E) += atl1e/
 obj-$(CONFIG_ATL1C) += atl1c/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
+obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o
 obj-$(CONFIG_TEHUTI) += tehuti.o
 obj-$(CONFIG_ENIC) += enic/
 obj-$(CONFIG_JME) += jme.o
index 9eb9b98a7ae3fd81f208b7495857db73ebb1f94d..de51e8453c133700a6c1e06087c7f00625cf1d07 100644 (file)
 #include <linux/etherdevice.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/net_tstamp.h>
 #include <linux/phy.h>
 #include <linux/platform_device.h>
+#include <linux/ptp_classify.h>
 #include <linux/slab.h>
+#include <mach/ixp46x_ts.h>
 #include <mach/npe.h>
 #include <mach/qmgr.h>
 
 #define RXFREE_QUEUE(port_id)  (NPE_ID(port_id) + 26)
 #define TXDONE_QUEUE           31
 
+#define PTP_SLAVE_MODE         1
+#define PTP_MASTER_MODE                2
+#define PORT2CHANNEL(p)                NPE_ID(p->id)
+
 /* TX Control Registers */
 #define TX_CNTRL0_TX_EN                0x01
 #define TX_CNTRL0_HALFDUPLEX   0x02
@@ -171,6 +178,8 @@ struct port {
        int id;                 /* logical port ID */
        int speed, duplex;
        u8 firmware[4];
+       int hwts_tx_en;
+       int hwts_rx_en;
 };
 
 /* NPE message structure */
@@ -246,6 +255,172 @@ static int ports_open;
 static struct port *npe_port_tab[MAX_NPES];
 static struct dma_pool *dma_pool;
 
+static struct sock_filter ptp_filter[] = {
+       PTP_FILTER
+};
+
+static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
+{
+       u8 *data = skb->data;
+       unsigned int offset;
+       u16 *hi, *id;
+       u32 lo;
+
+       if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)
+               return 0;
+
+       offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+
+       if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
+               return 0;
+
+       hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
+       id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+
+       memcpy(&lo, &hi[1], sizeof(lo));
+
+       return (uid_hi == ntohs(*hi) &&
+               uid_lo == ntohl(lo) &&
+               seqid  == ntohs(*id));
+}
+
+static void ixp_rx_timestamp(struct port *port, struct sk_buff *skb)
+{
+       struct skb_shared_hwtstamps *shhwtstamps;
+       struct ixp46x_ts_regs *regs;
+       u64 ns;
+       u32 ch, hi, lo, val;
+       u16 uid, seq;
+
+       if (!port->hwts_rx_en)
+               return;
+
+       ch = PORT2CHANNEL(port);
+
+       regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+       val = __raw_readl(&regs->channel[ch].ch_event);
+
+       if (!(val & RX_SNAPSHOT_LOCKED))
+               return;
+
+       lo = __raw_readl(&regs->channel[ch].src_uuid_lo);
+       hi = __raw_readl(&regs->channel[ch].src_uuid_hi);
+
+       uid = hi & 0xffff;
+       seq = (hi >> 16) & 0xffff;
+
+       if (!ixp_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
+               goto out;
+
+       lo = __raw_readl(&regs->channel[ch].rx_snap_lo);
+       hi = __raw_readl(&regs->channel[ch].rx_snap_hi);
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+       ns <<= TICKS_NS_SHIFT;
+
+       shhwtstamps = skb_hwtstamps(skb);
+       memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+       shhwtstamps->hwtstamp = ns_to_ktime(ns);
+out:
+       __raw_writel(RX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
+}
+
+static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb)
+{
+       struct skb_shared_hwtstamps shhwtstamps;
+       struct ixp46x_ts_regs *regs;
+       struct skb_shared_info *shtx;
+       u64 ns;
+       u32 ch, cnt, hi, lo, val;
+
+       shtx = skb_shinfo(skb);
+       if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && port->hwts_tx_en))
+               shtx->tx_flags |= SKBTX_IN_PROGRESS;
+       else
+               return;
+
+       ch = PORT2CHANNEL(port);
+
+       regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+       /*
+        * This really stinks, but we have to poll for the Tx time stamp.
+        * Usually, the time stamp is ready after 4 to 6 microseconds.
+        */
+       for (cnt = 0; cnt < 100; cnt++) {
+               val = __raw_readl(&regs->channel[ch].ch_event);
+               if (val & TX_SNAPSHOT_LOCKED)
+                       break;
+               udelay(1);
+       }
+       if (!(val & TX_SNAPSHOT_LOCKED)) {
+               shtx->tx_flags &= ~SKBTX_IN_PROGRESS;
+               return;
+       }
+
+       lo = __raw_readl(&regs->channel[ch].tx_snap_lo);
+       hi = __raw_readl(&regs->channel[ch].tx_snap_hi);
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+       ns <<= TICKS_NS_SHIFT;
+
+       memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+       shhwtstamps.hwtstamp = ns_to_ktime(ns);
+       skb_tstamp_tx(skb, &shhwtstamps);
+
+       __raw_writel(TX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
+}
+
+static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       struct hwtstamp_config cfg;
+       struct ixp46x_ts_regs *regs;
+       struct port *port = netdev_priv(netdev);
+       int ch;
+
+       if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+               return -EFAULT;
+
+       if (cfg.flags) /* reserved for future extensions */
+               return -EINVAL;
+
+       ch = PORT2CHANNEL(port);
+       regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+       switch (cfg.tx_type) {
+       case HWTSTAMP_TX_OFF:
+               port->hwts_tx_en = 0;
+               break;
+       case HWTSTAMP_TX_ON:
+               port->hwts_tx_en = 1;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       switch (cfg.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               port->hwts_rx_en = 0;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+               port->hwts_rx_en = PTP_SLAVE_MODE;
+               __raw_writel(0, &regs->channel[ch].ch_control);
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+               port->hwts_rx_en = PTP_MASTER_MODE;
+               __raw_writel(MASTER_MODE, &regs->channel[ch].ch_control);
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       /* Clear out any old time stamps. */
+       __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED,
+                    &regs->channel[ch].ch_event);
+
+       return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
 
 static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location,
                           int write, u16 cmd)
@@ -573,6 +748,7 @@ static int eth_poll(struct napi_struct *napi, int budget)
 
                debug_pkt(dev, "eth_poll", skb->data, skb->len);
 
+               ixp_rx_timestamp(port, skb);
                skb->protocol = eth_type_trans(skb, dev);
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += skb->len;
@@ -679,14 +855,12 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
                return NETDEV_TX_OK;
        }
        memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
-       dev_kfree_skb(skb);
 #endif
 
        phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
        if (dma_mapping_error(&dev->dev, phys)) {
-#ifdef __ARMEB__
                dev_kfree_skb(skb);
-#else
+#ifndef __ARMEB__
                kfree(mem);
 #endif
                dev->stats.tx_dropped++;
@@ -728,6 +902,13 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
 #if DEBUG_TX
        printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name);
 #endif
+
+       ixp_tx_timestamp(port, skb);
+       skb_tx_timestamp(skb);
+
+#ifndef __ARMEB__
+       dev_kfree_skb(skb);
+#endif
        return NETDEV_TX_OK;
 }
 
@@ -783,6 +964,9 @@ static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
        if (!netif_running(dev))
                return -EINVAL;
 
+       if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP)
+               return hwtstamp_ioctl(dev, req, cmd);
+
        return phy_mii_ioctl(port->phydev, req, cmd);
 }
 
@@ -1171,6 +1355,11 @@ static int __devinit eth_init_one(struct platform_device *pdev)
        char phy_id[MII_BUS_ID_SIZE + 3];
        int err;
 
+       if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
+               pr_err("ixp4xx_eth: bad ptp filter\n");
+               return -EINVAL;
+       }
+
        if (!(dev = alloc_etherdev(sizeof(struct port))))
                return -ENOMEM;
 
index 2463b1c979227b5c5320ba3c788728a5325f7c2f..81654ae16c63b99627046b4836e25ab0b1a05115 100644 (file)
@@ -1703,7 +1703,8 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_rss_config *req;
-       u32 myhash[10];
+       u32 myhash[10] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF,
+                       0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF};
        int status;
 
        if (mutex_lock_interruptible(&adapter->mbox_lock))
index d5bd35b7f2e1c9e14925239c94adea1021083680..289044332ed8127f27990341114777dfd1376344 100644 (file)
@@ -2675,7 +2675,7 @@ alloc_mem_err:
         * Min size diferent for TPA and non-TPA queues
         */
        if (ring_size < (fp->disable_tpa ?
-                               MIN_RX_SIZE_TPA : MIN_RX_SIZE_NONTPA)) {
+                               MIN_RX_SIZE_NONTPA : MIN_RX_SIZE_TPA)) {
                        /* release memory allocated for this queue */
                        bnx2x_free_fp_mem_at(bp, index);
                        return -ENOMEM;
index a97d9be331d10e1b4d0b8c3c464e58abfd2b1cc5..4b70311a11ef9f4a3ff5b631585f0d8bded19984 100644 (file)
@@ -2222,12 +2222,13 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
 u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param)
 {
        int mb_idx = BP_FW_MB_IDX(bp);
-       u32 seq = ++bp->fw_seq;
+       u32 seq;
        u32 rc = 0;
        u32 cnt = 1;
        u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
 
        mutex_lock(&bp->fw_mb_mutex);
+       seq = ++bp->fw_seq;
        SHMEM_WR(bp, func_mb[mb_idx].drv_mb_param, param);
        SHMEM_WR(bp, func_mb[mb_idx].drv_mb_header, (command | seq));
 
index 8f2d2e7c70e5d2d24ff36a864f528eb6da5f6bc5..2df9276720a0be47f27f909518fd270e531bd535 100644 (file)
@@ -163,8 +163,6 @@ static int tlb_initialize(struct bonding *bond)
        struct tlb_client_info *new_hashtbl;
        int i;
 
-       spin_lock_init(&(bond_info->tx_hashtbl_lock));
-
        new_hashtbl = kzalloc(size, GFP_KERNEL);
        if (!new_hashtbl) {
                pr_err("%s: Error: Failed to allocate TLB hash table\n",
@@ -747,8 +745,6 @@ static int rlb_initialize(struct bonding *bond)
        int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info);
        int i;
 
-       spin_lock_init(&(bond_info->rx_hashtbl_lock));
-
        new_hashtbl = kmalloc(size, GFP_KERNEL);
        if (!new_hashtbl) {
                pr_err("%s: Error: Failed to allocate RLB hash table\n",
index 6dc4284615419d289a98bd1769108461d0c1ddcd..6141667c5fb76b678619057bf9de5588a8a5b396 100644 (file)
@@ -852,7 +852,7 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
 static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
-                                                       mcast_work.work);
+                                           mcast_work.work);
        bond_resend_igmp_join_requests(bond);
 }
 
@@ -1172,10 +1172,12 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
        }
 
        /* resend IGMP joins since active slave has changed or
-        * all were sent on curr_active_slave */
-       if (((USES_PRIMARY(bond->params.mode) && new_active) ||
-            bond->params.mode == BOND_MODE_ROUNDROBIN) &&
-           netif_running(bond->dev)) {
+        * all were sent on curr_active_slave.
+        * resend only if bond is brought up with the affected
+        * bonding modes and the retransmission is enabled */
+       if (netif_running(bond->dev) && (bond->params.resend_igmp > 0) &&
+           ((USES_PRIMARY(bond->params.mode) && new_active) ||
+            bond->params.mode == BOND_MODE_ROUNDROBIN)) {
                bond->igmp_retrans = bond->params.resend_igmp;
                queue_delayed_work(bond->wq, &bond->mcast_work, 0);
        }
@@ -1542,12 +1544,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                           bond_dev->name, slave_dev->name);
        }
 
-       /* bond must be initialized by bond_open() before enslaving */
-       if (!(bond_dev->flags & IFF_UP)) {
-               pr_warning("%s: master_dev is not up in bond_enslave\n",
-                          bond_dev->name);
-       }
-
        /* already enslaved */
        if (slave_dev->flags & IFF_SLAVE) {
                pr_debug("Error, Device was already enslaved\n");
@@ -4834,9 +4830,19 @@ static int bond_init(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
        struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id);
+       struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 
        pr_debug("Begin bond_init for %s\n", bond_dev->name);
 
+       /*
+        * Initialize locks that may be required during
+        * en/deslave operations.  All of the bond_open work
+        * (of which this is part) should really be moved to
+        * a phase prior to dev_open
+        */
+       spin_lock_init(&(bond_info->tx_hashtbl_lock));
+       spin_lock_init(&(bond_info->rx_hashtbl_lock));
+
        bond->wq = create_singlethread_workqueue(bond_dev->name);
        if (!bond->wq)
                return -ENOMEM;
index 4059bfc73dbf531d3e7c7df946c6615b611c51a5..88fcb25e554a1f92205246771040149e3fce6967 100644 (file)
@@ -227,12 +227,6 @@ static ssize_t bonding_store_slaves(struct device *d,
        struct net_device *dev;
        struct bonding *bond = to_bond(d);
 
-       /* Quick sanity check -- is the bond interface up? */
-       if (!(bond->dev->flags & IFF_UP)) {
-               pr_warning("%s: doing slave updates when interface is down.\n",
-                          bond->dev->name);
-       }
-
        if (!rtnl_trylock())
                return restart_syscall();
 
@@ -1539,8 +1533,8 @@ static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
  * Show and set the number of IGMP membership reports to send on link failure
  */
 static ssize_t bonding_show_resend_igmp(struct device *d,
-                                        struct device_attribute *attr,
-                                        char *buf)
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
        struct bonding *bond = to_bond(d);
 
@@ -1548,8 +1542,8 @@ static ssize_t bonding_show_resend_igmp(struct device *d,
 }
 
 static ssize_t bonding_store_resend_igmp(struct device *d,
-                                         struct device_attribute *attr,
-                                         const char *buf, size_t count)
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
 {
        int new_value, ret = count;
        struct bonding *bond = to_bond(d);
@@ -1561,7 +1555,7 @@ static ssize_t bonding_store_resend_igmp(struct device *d,
                goto out;
        }
 
-       if (new_value < 0) {
+       if (new_value < 0 || new_value > 255) {
                pr_err("%s: Invalid resend_igmp value %d not in range 0-255; rejected.\n",
                       bond->dev->name, new_value);
                ret = -EINVAL;
index 6a0a8fca62bc58aeaa8354abc1f2c6d67175e659..3fd5a240034840d223cf43095bc76599811755e6 100644 (file)
@@ -2083,7 +2083,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
        struct netdev_hw_addr *ha;
        int ret;
 
-       if (dev->flags & IFF_PROMISC) {
+       if (port->promisc) {
                ehea_promiscuous(dev, 1);
                return;
        }
diff --git a/drivers/net/gianfar_ptp.c b/drivers/net/gianfar_ptp.c
new file mode 100644 (file)
index 0000000..d8e1753
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * PTP 1588 clock using the eTSEC
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/device.h>
+#include <linux/hrtimer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/timex.h>
+#include <linux/io.h>
+
+#include <linux/ptp_clock_kernel.h>
+
+#include "gianfar.h"
+
+/*
+ * gianfar ptp registers
+ * Generated by regen.tcl on Thu May 13 01:38:57 PM CEST 2010
+ */
+struct gianfar_ptp_registers {
+       u32 tmr_ctrl;     /* Timer control register */
+       u32 tmr_tevent;   /* Timestamp event register */
+       u32 tmr_temask;   /* Timer event mask register */
+       u32 tmr_pevent;   /* Timestamp event register */
+       u32 tmr_pemask;   /* Timer event mask register */
+       u32 tmr_stat;     /* Timestamp status register */
+       u32 tmr_cnt_h;    /* Timer counter high register */
+       u32 tmr_cnt_l;    /* Timer counter low register */
+       u32 tmr_add;      /* Timer drift compensation addend register */
+       u32 tmr_acc;      /* Timer accumulator register */
+       u32 tmr_prsc;     /* Timer prescale */
+       u8  res1[4];
+       u32 tmroff_h;     /* Timer offset high */
+       u32 tmroff_l;     /* Timer offset low */
+       u8  res2[8];
+       u32 tmr_alarm1_h; /* Timer alarm 1 high register */
+       u32 tmr_alarm1_l; /* Timer alarm 1 high register */
+       u32 tmr_alarm2_h; /* Timer alarm 2 high register */
+       u32 tmr_alarm2_l; /* Timer alarm 2 high register */
+       u8  res3[48];
+       u32 tmr_fiper1;   /* Timer fixed period interval */
+       u32 tmr_fiper2;   /* Timer fixed period interval */
+       u32 tmr_fiper3;   /* Timer fixed period interval */
+       u8  res4[20];
+       u32 tmr_etts1_h;  /* Timestamp of general purpose external trigger */
+       u32 tmr_etts1_l;  /* Timestamp of general purpose external trigger */
+       u32 tmr_etts2_h;  /* Timestamp of general purpose external trigger */
+       u32 tmr_etts2_l;  /* Timestamp of general purpose external trigger */
+};
+
+/* Bit definitions for the TMR_CTRL register */
+#define ALM1P                 (1<<31) /* Alarm1 output polarity */
+#define ALM2P                 (1<<30) /* Alarm2 output polarity */
+#define FS                    (1<<28) /* FIPER start indication */
+#define PP1L                  (1<<27) /* Fiper1 pulse loopback mode enabled. */
+#define PP2L                  (1<<26) /* Fiper2 pulse loopback mode enabled. */
+#define TCLK_PERIOD_SHIFT     (16) /* 1588 timer reference clock period. */
+#define TCLK_PERIOD_MASK      (0x3ff)
+#define RTPE                  (1<<15) /* Record Tx Timestamp to PAL Enable. */
+#define FRD                   (1<<14) /* FIPER Realignment Disable */
+#define ESFDP                 (1<<11) /* External Tx/Rx SFD Polarity. */
+#define ESFDE                 (1<<10) /* External Tx/Rx SFD Enable. */
+#define ETEP2                 (1<<9) /* External trigger 2 edge polarity */
+#define ETEP1                 (1<<8) /* External trigger 1 edge polarity */
+#define COPH                  (1<<7) /* Generated clock output phase. */
+#define CIPH                  (1<<6) /* External oscillator input clock phase */
+#define TMSR                  (1<<5) /* Timer soft reset. */
+#define BYP                   (1<<3) /* Bypass drift compensated clock */
+#define TE                    (1<<2) /* 1588 timer enable. */
+#define CKSEL_SHIFT           (0)    /* 1588 Timer reference clock source */
+#define CKSEL_MASK            (0x3)
+
+/* Bit definitions for the TMR_TEVENT register */
+#define ETS2                  (1<<25) /* External trigger 2 timestamp sampled */
+#define ETS1                  (1<<24) /* External trigger 1 timestamp sampled */
+#define ALM2                  (1<<17) /* Current time = alarm time register 2 */
+#define ALM1                  (1<<16) /* Current time = alarm time register 1 */
+#define PP1                   (1<<7)  /* periodic pulse generated on FIPER1 */
+#define PP2                   (1<<6)  /* periodic pulse generated on FIPER2 */
+#define PP3                   (1<<5)  /* periodic pulse generated on FIPER3 */
+
+/* Bit definitions for the TMR_TEMASK register */
+#define ETS2EN                (1<<25) /* External trigger 2 timestamp enable */
+#define ETS1EN                (1<<24) /* External trigger 1 timestamp enable */
+#define ALM2EN                (1<<17) /* Timer ALM2 event enable */
+#define ALM1EN                (1<<16) /* Timer ALM1 event enable */
+#define PP1EN                 (1<<7) /* Periodic pulse event 1 enable */
+#define PP2EN                 (1<<6) /* Periodic pulse event 2 enable */
+
+/* Bit definitions for the TMR_PEVENT register */
+#define TXP2                  (1<<9) /* PTP transmitted timestamp im TXTS2 */
+#define TXP1                  (1<<8) /* PTP transmitted timestamp in TXTS1 */
+#define RXP                   (1<<0) /* PTP frame has been received */
+
+/* Bit definitions for the TMR_PEMASK register */
+#define TXP2EN                (1<<9) /* Transmit PTP packet event 2 enable */
+#define TXP1EN                (1<<8) /* Transmit PTP packet event 1 enable */
+#define RXPEN                 (1<<0) /* Receive PTP packet event enable */
+
+/* Bit definitions for the TMR_STAT register */
+#define STAT_VEC_SHIFT        (0) /* Timer general purpose status vector */
+#define STAT_VEC_MASK         (0x3f)
+
+/* Bit definitions for the TMR_PRSC register */
+#define PRSC_OCK_SHIFT        (0) /* Output clock division/prescale factor. */
+#define PRSC_OCK_MASK         (0xffff)
+
+
+#define DRIVER         "gianfar_ptp"
+#define DEFAULT_CKSEL  1
+#define N_ALARM                1 /* first alarm is used internally to reset fipers */
+#define N_EXT_TS       2
+#define REG_SIZE       sizeof(struct gianfar_ptp_registers)
+
+struct etsects {
+       struct gianfar_ptp_registers *regs;
+       spinlock_t lock; /* protects regs */
+       struct ptp_clock *clock;
+       struct ptp_clock_info caps;
+       struct resource *rsrc;
+       int irq;
+       u64 alarm_interval; /* for periodic alarm */
+       u64 alarm_value;
+       u32 tclk_period;  /* nanoseconds */
+       u32 tmr_prsc;
+       u32 tmr_add;
+       u32 cksel;
+       u32 tmr_fiper1;
+       u32 tmr_fiper2;
+};
+
+/*
+ * Register access functions
+ */
+
+/* Caller must hold etsects->lock. */
+static u64 tmr_cnt_read(struct etsects *etsects)
+{
+       u64 ns;
+       u32 lo, hi;
+
+       lo = gfar_read(&etsects->regs->tmr_cnt_l);
+       hi = gfar_read(&etsects->regs->tmr_cnt_h);
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+       return ns;
+}
+
+/* Caller must hold etsects->lock. */
+static void tmr_cnt_write(struct etsects *etsects, u64 ns)
+{
+       u32 hi = ns >> 32;
+       u32 lo = ns & 0xffffffff;
+
+       gfar_write(&etsects->regs->tmr_cnt_l, lo);
+       gfar_write(&etsects->regs->tmr_cnt_h, hi);
+}
+
+/* Caller must hold etsects->lock. */
+static void set_alarm(struct etsects *etsects)
+{
+       u64 ns;
+       u32 lo, hi;
+
+       ns = tmr_cnt_read(etsects) + 1500000000ULL;
+       ns = div_u64(ns, 1000000000UL) * 1000000000ULL;
+       ns -= etsects->tclk_period;
+       hi = ns >> 32;
+       lo = ns & 0xffffffff;
+       gfar_write(&etsects->regs->tmr_alarm1_l, lo);
+       gfar_write(&etsects->regs->tmr_alarm1_h, hi);
+}
+
+/* Caller must hold etsects->lock. */
+static void set_fipers(struct etsects *etsects)
+{
+       u32 tmr_ctrl = gfar_read(&etsects->regs->tmr_ctrl);
+
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl & (~TE));
+       gfar_write(&etsects->regs->tmr_prsc,   etsects->tmr_prsc);
+       gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
+       gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
+       set_alarm(etsects);
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|TE);
+}
+
+/*
+ * Interrupt service routine
+ */
+
+static irqreturn_t isr(int irq, void *priv)
+{
+       struct etsects *etsects = priv;
+       struct ptp_clock_event event;
+       u64 ns;
+       u32 ack = 0, lo, hi, mask, val;
+
+       val = gfar_read(&etsects->regs->tmr_tevent);
+
+       if (val & ETS1) {
+               ack |= ETS1;
+               hi = gfar_read(&etsects->regs->tmr_etts1_h);
+               lo = gfar_read(&etsects->regs->tmr_etts1_l);
+               event.type = PTP_CLOCK_EXTTS;
+               event.index = 0;
+               event.timestamp = ((u64) hi) << 32;
+               event.timestamp |= lo;
+               ptp_clock_event(etsects->clock, &event);
+       }
+
+       if (val & ETS2) {
+               ack |= ETS2;
+               hi = gfar_read(&etsects->regs->tmr_etts2_h);
+               lo = gfar_read(&etsects->regs->tmr_etts2_l);
+               event.type = PTP_CLOCK_EXTTS;
+               event.index = 1;
+               event.timestamp = ((u64) hi) << 32;
+               event.timestamp |= lo;
+               ptp_clock_event(etsects->clock, &event);
+       }
+
+       if (val & ALM2) {
+               ack |= ALM2;
+               if (etsects->alarm_value) {
+                       event.type = PTP_CLOCK_ALARM;
+                       event.index = 0;
+                       event.timestamp = etsects->alarm_value;
+                       ptp_clock_event(etsects->clock, &event);
+               }
+               if (etsects->alarm_interval) {
+                       ns = etsects->alarm_value + etsects->alarm_interval;
+                       hi = ns >> 32;
+                       lo = ns & 0xffffffff;
+                       spin_lock(&etsects->lock);
+                       gfar_write(&etsects->regs->tmr_alarm2_l, lo);
+                       gfar_write(&etsects->regs->tmr_alarm2_h, hi);
+                       spin_unlock(&etsects->lock);
+                       etsects->alarm_value = ns;
+               } else {
+                       gfar_write(&etsects->regs->tmr_tevent, ALM2);
+                       spin_lock(&etsects->lock);
+                       mask = gfar_read(&etsects->regs->tmr_temask);
+                       mask &= ~ALM2EN;
+                       gfar_write(&etsects->regs->tmr_temask, mask);
+                       spin_unlock(&etsects->lock);
+                       etsects->alarm_value = 0;
+                       etsects->alarm_interval = 0;
+               }
+       }
+
+       if (val & PP1) {
+               ack |= PP1;
+               event.type = PTP_CLOCK_PPS;
+               ptp_clock_event(etsects->clock, &event);
+       }
+
+       if (ack) {
+               gfar_write(&etsects->regs->tmr_tevent, ack);
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+}
+
+/*
+ * PTP clock operations
+ */
+
+static int ptp_gianfar_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       u64 adj;
+       u32 diff, tmr_add;
+       int neg_adj = 0;
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+       if (ppb < 0) {
+               neg_adj = 1;
+               ppb = -ppb;
+       }
+       tmr_add = etsects->tmr_add;
+       adj = tmr_add;
+       adj *= ppb;
+       diff = div_u64(adj, 1000000000ULL);
+
+       tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
+
+       gfar_write(&etsects->regs->tmr_add, tmr_add);
+
+       return 0;
+}
+
+static int ptp_gianfar_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       s64 now;
+       unsigned long flags;
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+       spin_lock_irqsave(&etsects->lock, flags);
+
+       now = tmr_cnt_read(etsects);
+       now += delta;
+       tmr_cnt_write(etsects, now);
+
+       spin_unlock_irqrestore(&etsects->lock, flags);
+
+       set_fipers(etsects);
+
+       return 0;
+}
+
+static int ptp_gianfar_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       u64 ns;
+       u32 remainder;
+       unsigned long flags;
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+       spin_lock_irqsave(&etsects->lock, flags);
+
+       ns = tmr_cnt_read(etsects);
+
+       spin_unlock_irqrestore(&etsects->lock, flags);
+
+       ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+       ts->tv_nsec = remainder;
+       return 0;
+}
+
+static int ptp_gianfar_settime(struct ptp_clock_info *ptp,
+                              const struct timespec *ts)
+{
+       u64 ns;
+       unsigned long flags;
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+       ns = ts->tv_sec * 1000000000ULL;
+       ns += ts->tv_nsec;
+
+       spin_lock_irqsave(&etsects->lock, flags);
+
+       tmr_cnt_write(etsects, ns);
+       set_fipers(etsects);
+
+       spin_unlock_irqrestore(&etsects->lock, flags);
+
+       return 0;
+}
+
+static int ptp_gianfar_enable(struct ptp_clock_info *ptp,
+                             struct ptp_clock_request *rq, int on)
+{
+       struct etsects *etsects = container_of(ptp, struct etsects, caps);
+       unsigned long flags;
+       u32 bit, mask;
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_EXTTS:
+               switch (rq->extts.index) {
+               case 0:
+                       bit = ETS1EN;
+                       break;
+               case 1:
+                       bit = ETS2EN;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               spin_lock_irqsave(&etsects->lock, flags);
+               mask = gfar_read(&etsects->regs->tmr_temask);
+               if (on)
+                       mask |= bit;
+               else
+                       mask &= ~bit;
+               gfar_write(&etsects->regs->tmr_temask, mask);
+               spin_unlock_irqrestore(&etsects->lock, flags);
+               return 0;
+
+       case PTP_CLK_REQ_PPS:
+               spin_lock_irqsave(&etsects->lock, flags);
+               mask = gfar_read(&etsects->regs->tmr_temask);
+               if (on)
+                       mask |= PP1EN;
+               else
+                       mask &= ~PP1EN;
+               gfar_write(&etsects->regs->tmr_temask, mask);
+               spin_unlock_irqrestore(&etsects->lock, flags);
+               return 0;
+
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info ptp_gianfar_caps = {
+       .owner          = THIS_MODULE,
+       .name           = "gianfar clock",
+       .max_adj        = 512000,
+       .n_alarm        = N_ALARM,
+       .n_ext_ts       = N_EXT_TS,
+       .n_per_out      = 0,
+       .pps            = 1,
+       .adjfreq        = ptp_gianfar_adjfreq,
+       .adjtime        = ptp_gianfar_adjtime,
+       .gettime        = ptp_gianfar_gettime,
+       .settime        = ptp_gianfar_settime,
+       .enable         = ptp_gianfar_enable,
+};
+
+/* OF device tree */
+
+static int get_of_u32(struct device_node *node, char *str, u32 *val)
+{
+       int plen;
+       const u32 *prop = of_get_property(node, str, &plen);
+
+       if (!prop || plen != sizeof(*prop))
+               return -1;
+       *val = *prop;
+       return 0;
+}
+
+static int gianfar_ptp_probe(struct platform_device *dev)
+{
+       struct device_node *node = dev->dev.of_node;
+       struct etsects *etsects;
+       struct timespec now;
+       int err = -ENOMEM;
+       u32 tmr_ctrl;
+       unsigned long flags;
+
+       etsects = kzalloc(sizeof(*etsects), GFP_KERNEL);
+       if (!etsects)
+               goto no_memory;
+
+       err = -ENODEV;
+
+       etsects->caps = ptp_gianfar_caps;
+       etsects->cksel = DEFAULT_CKSEL;
+
+       if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) ||
+           get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) ||
+           get_of_u32(node, "fsl,tmr-add", &etsects->tmr_add) ||
+           get_of_u32(node, "fsl,tmr-fiper1", &etsects->tmr_fiper1) ||
+           get_of_u32(node, "fsl,tmr-fiper2", &etsects->tmr_fiper2) ||
+           get_of_u32(node, "fsl,max-adj", &etsects->caps.max_adj)) {
+               pr_err("device tree node missing required elements\n");
+               goto no_node;
+       }
+
+       etsects->irq = platform_get_irq(dev, 0);
+
+       if (etsects->irq == NO_IRQ) {
+               pr_err("irq not in device tree\n");
+               goto no_node;
+       }
+       if (request_irq(etsects->irq, isr, 0, DRIVER, etsects)) {
+               pr_err("request_irq failed\n");
+               goto no_node;
+       }
+
+       etsects->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!etsects->rsrc) {
+               pr_err("no resource\n");
+               goto no_resource;
+       }
+       if (request_resource(&ioport_resource, etsects->rsrc)) {
+               pr_err("resource busy\n");
+               goto no_resource;
+       }
+
+       spin_lock_init(&etsects->lock);
+
+       etsects->regs = ioremap(etsects->rsrc->start,
+                               1 + etsects->rsrc->end - etsects->rsrc->start);
+       if (!etsects->regs) {
+               pr_err("ioremap ptp registers failed\n");
+               goto no_ioremap;
+       }
+       getnstimeofday(&now);
+       ptp_gianfar_settime(&etsects->caps, &now);
+
+       tmr_ctrl =
+         (etsects->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT |
+         (etsects->cksel & CKSEL_MASK) << CKSEL_SHIFT;
+
+       spin_lock_irqsave(&etsects->lock, flags);
+
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl);
+       gfar_write(&etsects->regs->tmr_add,    etsects->tmr_add);
+       gfar_write(&etsects->regs->tmr_prsc,   etsects->tmr_prsc);
+       gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
+       gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
+       set_alarm(etsects);
+       gfar_write(&etsects->regs->tmr_ctrl,   tmr_ctrl|FS|RTPE|TE);
+
+       spin_unlock_irqrestore(&etsects->lock, flags);
+
+       etsects->clock = ptp_clock_register(&etsects->caps);
+       if (IS_ERR(etsects->clock)) {
+               err = PTR_ERR(etsects->clock);
+               goto no_clock;
+       }
+
+       dev_set_drvdata(&dev->dev, etsects);
+
+       return 0;
+
+no_clock:
+no_ioremap:
+       release_resource(etsects->rsrc);
+no_resource:
+       free_irq(etsects->irq, etsects);
+no_node:
+       kfree(etsects);
+no_memory:
+       return err;
+}
+
+static int gianfar_ptp_remove(struct platform_device *dev)
+{
+       struct etsects *etsects = dev_get_drvdata(&dev->dev);
+
+       gfar_write(&etsects->regs->tmr_temask, 0);
+       gfar_write(&etsects->regs->tmr_ctrl,   0);
+
+       ptp_clock_unregister(etsects->clock);
+       iounmap(etsects->regs);
+       release_resource(etsects->rsrc);
+       free_irq(etsects->irq, etsects);
+       kfree(etsects);
+
+       return 0;
+}
+
+static struct of_device_id match_table[] = {
+       { .compatible = "fsl,etsec-ptp" },
+       {},
+};
+
+static struct platform_driver gianfar_ptp_driver = {
+       .driver = {
+               .name           = "gianfar_ptp",
+               .of_match_table = match_table,
+               .owner          = THIS_MODULE,
+       },
+       .probe       = gianfar_ptp_probe,
+       .remove      = gianfar_ptp_remove,
+};
+
+/* module operations */
+
+static int __init ptp_gianfar_init(void)
+{
+       return platform_driver_register(&gianfar_ptp_driver);
+}
+
+module_init(ptp_gianfar_init);
+
+static void __exit ptp_gianfar_exit(void)
+{
+       platform_driver_unregister(&gianfar_ptp_driver);
+}
+
+module_exit(ptp_gianfar_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clock using the eTSEC");
+MODULE_LICENSE("GPL");
index 96c95617195f6b18baf79c73f0f33beff21e14fd..32f07f868d8914e58020860af796944a00f195b4 100644 (file)
@@ -915,7 +915,7 @@ static void ioc3_alloc_rings(struct net_device *dev)
 
                        skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
                        if (!skb) {
-                               show_free_areas();
+                               show_free_areas(0);
                                continue;
                        }
 
index f940dfa1f7f84e713033057605bfb069618ec0bb..9d4ce1aba10c1fdbc2ae6a8b1a20b40ee2134fb9 100644 (file)
@@ -67,27 +67,27 @@ static void bfin_sir_stop_tx(struct bfin_sir_port *port)
        disable_dma(port->tx_dma_channel);
 #endif
 
-       while (!(SIR_UART_GET_LSR(port) & THRE)) {
+       while (!(UART_GET_LSR(port) & THRE)) {
                cpu_relax();
                continue;
        }
 
-       SIR_UART_STOP_TX(port);
+       UART_CLEAR_IER(port, ETBEI);
 }
 
 static void bfin_sir_enable_tx(struct bfin_sir_port *port)
 {
-       SIR_UART_ENABLE_TX(port);
+       UART_SET_IER(port, ETBEI);
 }
 
 static void bfin_sir_stop_rx(struct bfin_sir_port *port)
 {
-       SIR_UART_STOP_RX(port);
+       UART_CLEAR_IER(port, ERBFI);
 }
 
 static void bfin_sir_enable_rx(struct bfin_sir_port *port)
 {
-       SIR_UART_ENABLE_RX(port);
+       UART_SET_IER(port, ERBFI);
 }
 
 static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
@@ -116,7 +116,7 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
 
                do {
                        udelay(utime);
-                       lsr = SIR_UART_GET_LSR(port);
+                       lsr = UART_GET_LSR(port);
                } while (!(lsr & TEMT) && count--);
 
                /* The useconds for 1 bits to transmit */
@@ -125,27 +125,27 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
                /* Clear UCEN bit to reset the UART state machine
                 * and control registers
                 */
-               val = SIR_UART_GET_GCTL(port);
+               val = UART_GET_GCTL(port);
                val &= ~UCEN;
-               SIR_UART_PUT_GCTL(port, val);
+               UART_PUT_GCTL(port, val);
 
                /* Set DLAB in LCR to Access THR RBR IER */
-               SIR_UART_SET_DLAB(port);
+               UART_SET_DLAB(port);
                SSYNC();
 
-               SIR_UART_PUT_DLL(port, quot & 0xFF);
-               SIR_UART_PUT_DLH(port, (quot >> 8) & 0xFF);
+               UART_PUT_DLL(port, quot & 0xFF);
+               UART_PUT_DLH(port, (quot >> 8) & 0xFF);
                SSYNC();
 
                /* Clear DLAB in LCR */
-               SIR_UART_CLEAR_DLAB(port);
+               UART_CLEAR_DLAB(port);
                SSYNC();
 
-               SIR_UART_PUT_LCR(port, lcr);
+               UART_PUT_LCR(port, lcr);
 
-               val = SIR_UART_GET_GCTL(port);
+               val = UART_GET_GCTL(port);
                val |= UCEN;
-               SIR_UART_PUT_GCTL(port, val);
+               UART_PUT_GCTL(port, val);
 
                ret = 0;
                break;
@@ -154,12 +154,12 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
                break;
        }
 
-       val = SIR_UART_GET_GCTL(port);
+       val = UART_GET_GCTL(port);
        /* If not add the 'RPOLC', we can't catch the receive interrupt.
         * It's related with the HW layout and the IR transiver.
         */
        val |= IREN | RPOLC;
-       SIR_UART_PUT_GCTL(port, val);
+       UART_PUT_GCTL(port, val);
        return ret;
 }
 
@@ -168,7 +168,7 @@ static int bfin_sir_is_receiving(struct net_device *dev)
        struct bfin_sir_self *self = netdev_priv(dev);
        struct bfin_sir_port *port = self->sir_port;
 
-       if (!(SIR_UART_GET_IER(port) & ERBFI))
+       if (!(UART_GET_IER(port) & ERBFI))
                return 0;
        return self->rx_buff.state != OUTSIDE_FRAME;
 }
@@ -182,7 +182,7 @@ static void bfin_sir_tx_chars(struct net_device *dev)
 
        if (self->tx_buff.len != 0) {
                chr = *(self->tx_buff.data);
-               SIR_UART_PUT_CHAR(port, chr);
+               UART_PUT_CHAR(port, chr);
                self->tx_buff.data++;
                self->tx_buff.len--;
        } else {
@@ -206,8 +206,8 @@ static void bfin_sir_rx_chars(struct net_device *dev)
        struct bfin_sir_port *port = self->sir_port;
        unsigned char ch;
 
-       SIR_UART_CLEAR_LSR(port);
-       ch = SIR_UART_GET_CHAR(port);
+       UART_CLEAR_LSR(port);
+       ch = UART_GET_CHAR(port);
        async_unwrap_char(dev, &self->stats, &self->rx_buff, ch);
        dev->last_rx = jiffies;
 }
@@ -219,7 +219,7 @@ static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id)
        struct bfin_sir_port *port = self->sir_port;
 
        spin_lock(&self->lock);
-       while ((SIR_UART_GET_LSR(port) & DR))
+       while ((UART_GET_LSR(port) & DR))
                bfin_sir_rx_chars(dev);
        spin_unlock(&self->lock);
 
@@ -233,7 +233,7 @@ static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id)
        struct bfin_sir_port *port = self->sir_port;
 
        spin_lock(&self->lock);
-       if (SIR_UART_GET_LSR(port) & THRE)
+       if (UART_GET_LSR(port) & THRE)
                bfin_sir_tx_chars(dev);
        spin_unlock(&self->lock);
 
@@ -312,7 +312,7 @@ static void bfin_sir_dma_rx_chars(struct net_device *dev)
        struct bfin_sir_port *port = self->sir_port;
        int i;
 
-       SIR_UART_CLEAR_LSR(port);
+       UART_CLEAR_LSR(port);
 
        for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++)
                async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]);
@@ -430,11 +430,10 @@ static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev
        unsigned short val;
 
        bfin_sir_stop_rx(port);
-       SIR_UART_DISABLE_INTS(port);
 
-       val = SIR_UART_GET_GCTL(port);
+       val = UART_GET_GCTL(port);
        val &= ~(UCEN | IREN | RPOLC);
-       SIR_UART_PUT_GCTL(port, val);
+       UART_PUT_GCTL(port, val);
 
 #ifdef CONFIG_SIR_BFIN_DMA
        disable_dma(port->tx_dma_channel);
@@ -518,12 +517,12 @@ static void bfin_sir_send_work(struct work_struct *work)
         * sending data. We also can set the speed, which will
         * reset all the UART.
         */
-       val = SIR_UART_GET_GCTL(port);
+       val = UART_GET_GCTL(port);
        val &= ~(IREN | RPOLC);
-       SIR_UART_PUT_GCTL(port, val);
+       UART_PUT_GCTL(port, val);
        SSYNC();
        val |= IREN | RPOLC;
-       SIR_UART_PUT_GCTL(port, val);
+       UART_PUT_GCTL(port, val);
        SSYNC();
        /* bfin_sir_set_speed(port, self->speed); */
 
index e3b285a677348f1c39f4f6a4cff0fbe77c3af46b..29cbde8501ed8e09750f771204dfe9fc38503d34 100644 (file)
@@ -26,7 +26,6 @@
 #include <asm/cacheflush.h>
 #include <asm/dma.h>
 #include <asm/portmux.h>
-#include <mach/bfin_serial_5xx.h>
 #undef DRIVER_NAME
 
 #ifdef CONFIG_SIR_BFIN_DMA
@@ -83,64 +82,10 @@ struct bfin_sir_self {
 
 #define DRIVER_NAME "bfin_sir"
 
-#define SIR_UART_GET_CHAR(port)    bfin_read16((port)->membase + OFFSET_RBR)
-#define SIR_UART_GET_DLL(port)     bfin_read16((port)->membase + OFFSET_DLL)
-#define SIR_UART_GET_DLH(port)     bfin_read16((port)->membase + OFFSET_DLH)
-#define SIR_UART_GET_LCR(port)     bfin_read16((port)->membase + OFFSET_LCR)
-#define SIR_UART_GET_GCTL(port)    bfin_read16((port)->membase + OFFSET_GCTL)
-
-#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v)
-#define SIR_UART_PUT_DLL(port, v)  bfin_write16(((port)->membase + OFFSET_DLL), v)
-#define SIR_UART_PUT_DLH(port, v)  bfin_write16(((port)->membase + OFFSET_DLH), v)
-#define SIR_UART_PUT_LCR(port, v)  bfin_write16(((port)->membase + OFFSET_LCR), v)
-#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v)
-
-#ifdef CONFIG_BF54x
-#define SIR_UART_GET_LSR(port)     bfin_read16((port)->membase + OFFSET_LSR)
-#define SIR_UART_GET_IER(port)     bfin_read16((port)->membase + OFFSET_IER_SET)
-#define SIR_UART_SET_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER_SET), v)
-#define SIR_UART_CLEAR_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_CLEAR), v)
-#define SIR_UART_PUT_LSR(port, v)  bfin_write16(((port)->membase + OFFSET_LSR), v)
-#define SIR_UART_CLEAR_LSR(port)   bfin_write16(((port)->membase + OFFSET_LSR), -1)
-
-#define SIR_UART_SET_DLAB(port)
-#define SIR_UART_CLEAR_DLAB(port)
-
-#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_SET_IER(port, v)
-#define SIR_UART_DISABLE_INTS(port)   SIR_UART_CLEAR_IER(port, 0xF)
-#define SIR_UART_STOP_TX(port)     do { SIR_UART_PUT_LSR(port, TFI); SIR_UART_CLEAR_IER(port, ETBEI); } while (0)
-#define SIR_UART_ENABLE_TX(port)   do { SIR_UART_SET_IER(port, ETBEI); } while (0)
-#define SIR_UART_STOP_RX(port)     do { SIR_UART_CLEAR_IER(port, ERBFI); } while (0)
-#define SIR_UART_ENABLE_RX(port)   do { SIR_UART_SET_IER(port, ERBFI); } while (0)
-#else
-
-#define SIR_UART_GET_IIR(port)     bfin_read16((port)->membase + OFFSET_IIR)
-#define SIR_UART_GET_IER(port)     bfin_read16((port)->membase + OFFSET_IER)
-#define SIR_UART_PUT_IER(port, v)  bfin_write16(((port)->membase + OFFSET_IER), v)
-
-#define SIR_UART_SET_DLAB(port)    do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) | DLAB); } while (0)
-#define SIR_UART_CLEAR_DLAB(port)  do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) & ~DLAB); } while (0)
-
-#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_PUT_IER(port, v)
-#define SIR_UART_DISABLE_INTS(port)   SIR_UART_PUT_IER(port, 0)
-#define SIR_UART_STOP_TX(port)     do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ETBEI); } while (0)
-#define SIR_UART_ENABLE_TX(port)   do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ETBEI); } while (0)
-#define SIR_UART_STOP_RX(port)     do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ERBFI); } while (0)
-#define SIR_UART_ENABLE_RX(port)   do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ERBFI); } while (0)
-
-static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port)
-{
-       unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR);
-       port->lsr |= (lsr & (BI|FE|PE|OE));
-       return lsr | port->lsr;
-}
-
-static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port)
-{
-       port->lsr = 0;
-       bfin_read16(port->membase + OFFSET_LSR);
-}
-#endif
+#define port_membase(port)     (((struct bfin_sir_port *)(port))->membase)
+#define get_lsr_cache(port)    (((struct bfin_sir_port *)(port))->lsr)
+#define put_lsr_cache(port, v) (((struct bfin_sir_port *)(port))->lsr = (v))
+#include <asm/bfin_serial.h>
 
 static const unsigned short per[][4] = {
        /* rx pin      tx pin     NULL  uart_number */
index 13bebab65d027c9a9c3c3c6aef2a823d1033859a..2333215bbb322e0ba7bce5705c34cc810f07eb7a 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_FIXED_PHY)               += fixed.o
 obj-$(CONFIG_MDIO_BITBANG)     += mdio-bitbang.o
 obj-$(CONFIG_MDIO_GPIO)                += mdio-gpio.o
 obj-$(CONFIG_NATIONAL_PHY)     += national.o
+obj-$(CONFIG_DP83640_PHY)      += dp83640.o
 obj-$(CONFIG_STE10XP)          += ste10Xp.o
 obj-$(CONFIG_MICREL_PHY)       += micrel.o
 obj-$(CONFIG_MDIO_OCTEON)      += mdio-octeon.o
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
new file mode 100644 (file)
index 0000000..b0c9522
--- /dev/null
@@ -0,0 +1,1100 @@
+/*
+ * Driver for the National Semiconductor DP83640 PHYTER
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/net_tstamp.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+
+#include "dp83640_reg.h"
+
+#define DP83640_PHY_ID 0x20005ce1
+#define PAGESEL                0x13
+#define LAYER4         0x02
+#define LAYER2         0x01
+#define MAX_RXTS       4
+#define MAX_TXTS       4
+#define N_EXT_TS       1
+#define PSF_PTPVER     2
+#define PSF_EVNT       0x4000
+#define PSF_RX         0x2000
+#define PSF_TX         0x1000
+#define EXT_EVENT      1
+#define EXT_GPIO       1
+#define CAL_EVENT      2
+#define CAL_GPIO       9
+#define CAL_TRIGGER    2
+
+/* phyter seems to miss the mark by 16 ns */
+#define ADJTIME_FIX    16
+
+#if defined(__BIG_ENDIAN)
+#define ENDIAN_FLAG    0
+#elif defined(__LITTLE_ENDIAN)
+#define ENDIAN_FLAG    PSF_ENDIAN
+#endif
+
+#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb))
+
+struct phy_rxts {
+       u16 ns_lo;   /* ns[15:0] */
+       u16 ns_hi;   /* overflow[1:0], ns[29:16] */
+       u16 sec_lo;  /* sec[15:0] */
+       u16 sec_hi;  /* sec[31:16] */
+       u16 seqid;   /* sequenceId[15:0] */
+       u16 msgtype; /* messageType[3:0], hash[11:0] */
+};
+
+struct phy_txts {
+       u16 ns_lo;   /* ns[15:0] */
+       u16 ns_hi;   /* overflow[1:0], ns[29:16] */
+       u16 sec_lo;  /* sec[15:0] */
+       u16 sec_hi;  /* sec[31:16] */
+};
+
+struct rxts {
+       struct list_head list;
+       unsigned long tmo;
+       u64 ns;
+       u16 seqid;
+       u8  msgtype;
+       u16 hash;
+};
+
+struct dp83640_clock;
+
+struct dp83640_private {
+       struct list_head list;
+       struct dp83640_clock *clock;
+       struct phy_device *phydev;
+       struct work_struct ts_work;
+       int hwts_tx_en;
+       int hwts_rx_en;
+       int layer;
+       int version;
+       /* remember state of cfg0 during calibration */
+       int cfg0;
+       /* remember the last event time stamp */
+       struct phy_txts edata;
+       /* list of rx timestamps */
+       struct list_head rxts;
+       struct list_head rxpool;
+       struct rxts rx_pool_data[MAX_RXTS];
+       /* protects above three fields from concurrent access */
+       spinlock_t rx_lock;
+       /* queues of incoming and outgoing packets */
+       struct sk_buff_head rx_queue;
+       struct sk_buff_head tx_queue;
+};
+
+struct dp83640_clock {
+       /* keeps the instance in the 'phyter_clocks' list */
+       struct list_head list;
+       /* we create one clock instance per MII bus */
+       struct mii_bus *bus;
+       /* protects extended registers from concurrent access */
+       struct mutex extreg_lock;
+       /* remembers which page was last selected */
+       int page;
+       /* our advertised capabilities */
+       struct ptp_clock_info caps;
+       /* protects the three fields below from concurrent access */
+       struct mutex clock_lock;
+       /* the one phyter from which we shall read */
+       struct dp83640_private *chosen;
+       /* list of the other attached phyters, not chosen */
+       struct list_head phylist;
+       /* reference to our PTP hardware clock */
+       struct ptp_clock *ptp_clock;
+};
+
+/* globals */
+
+static int chosen_phy = -1;
+static ushort cal_gpio = 4;
+
+module_param(chosen_phy, int, 0444);
+module_param(cal_gpio, ushort, 0444);
+
+MODULE_PARM_DESC(chosen_phy, \
+       "The address of the PHY to use for the ancillary clock features");
+MODULE_PARM_DESC(cal_gpio, \
+       "Which GPIO line to use for synchronizing multiple PHYs");
+
+/* a list of clocks and a mutex to protect it */
+static LIST_HEAD(phyter_clocks);
+static DEFINE_MUTEX(phyter_clocks_lock);
+
+static void rx_timestamp_work(struct work_struct *work);
+
+/* extended register access functions */
+
+#define BROADCAST_ADDR 31
+
+static inline int broadcast_write(struct mii_bus *bus, u32 regnum, u16 val)
+{
+       return mdiobus_write(bus, BROADCAST_ADDR, regnum, val);
+}
+
+/* Caller must hold extreg_lock. */
+static int ext_read(struct phy_device *phydev, int page, u32 regnum)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+       int val;
+
+       if (dp83640->clock->page != page) {
+               broadcast_write(phydev->bus, PAGESEL, page);
+               dp83640->clock->page = page;
+       }
+       val = phy_read(phydev, regnum);
+
+       return val;
+}
+
+/* Caller must hold extreg_lock. */
+static void ext_write(int broadcast, struct phy_device *phydev,
+                     int page, u32 regnum, u16 val)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+
+       if (dp83640->clock->page != page) {
+               broadcast_write(phydev->bus, PAGESEL, page);
+               dp83640->clock->page = page;
+       }
+       if (broadcast)
+               broadcast_write(phydev->bus, regnum, val);
+       else
+               phy_write(phydev, regnum, val);
+}
+
+/* Caller must hold extreg_lock. */
+static int tdr_write(int bc, struct phy_device *dev,
+                    const struct timespec *ts, u16 cmd)
+{
+       ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec & 0xffff);/* ns[15:0]  */
+       ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec >> 16);   /* ns[31:16] */
+       ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec & 0xffff); /* sec[15:0] */
+       ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec >> 16);    /* sec[31:16]*/
+
+       ext_write(bc, dev, PAGE4, PTP_CTL, cmd);
+
+       return 0;
+}
+
+/* convert phy timestamps into driver timestamps */
+
+static void phy2rxts(struct phy_rxts *p, struct rxts *rxts)
+{
+       u32 sec;
+
+       sec = p->sec_lo;
+       sec |= p->sec_hi << 16;
+
+       rxts->ns = p->ns_lo;
+       rxts->ns |= (p->ns_hi & 0x3fff) << 16;
+       rxts->ns += ((u64)sec) * 1000000000ULL;
+       rxts->seqid = p->seqid;
+       rxts->msgtype = (p->msgtype >> 12) & 0xf;
+       rxts->hash = p->msgtype & 0x0fff;
+       rxts->tmo = jiffies + HZ;
+}
+
+static u64 phy2txts(struct phy_txts *p)
+{
+       u64 ns;
+       u32 sec;
+
+       sec = p->sec_lo;
+       sec |= p->sec_hi << 16;
+
+       ns = p->ns_lo;
+       ns |= (p->ns_hi & 0x3fff) << 16;
+       ns += ((u64)sec) * 1000000000ULL;
+
+       return ns;
+}
+
+/* ptp clock methods */
+
+static int ptp_dp83640_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       u64 rate;
+       int neg_adj = 0;
+       u16 hi, lo;
+
+       if (ppb < 0) {
+               neg_adj = 1;
+               ppb = -ppb;
+       }
+       rate = ppb;
+       rate <<= 26;
+       rate = div_u64(rate, 1953125);
+
+       hi = (rate >> 16) & PTP_RATE_HI_MASK;
+       if (neg_adj)
+               hi |= PTP_RATE_DIR;
+
+       lo = rate & 0xffff;
+
+       mutex_lock(&clock->extreg_lock);
+
+       ext_write(1, phydev, PAGE4, PTP_RATEH, hi);
+       ext_write(1, phydev, PAGE4, PTP_RATEL, lo);
+
+       mutex_unlock(&clock->extreg_lock);
+
+       return 0;
+}
+
+static int ptp_dp83640_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       struct timespec ts;
+       int err;
+
+       delta += ADJTIME_FIX;
+
+       ts = ns_to_timespec(delta);
+
+       mutex_lock(&clock->extreg_lock);
+
+       err = tdr_write(1, phydev, &ts, PTP_STEP_CLK);
+
+       mutex_unlock(&clock->extreg_lock);
+
+       return err;
+}
+
+static int ptp_dp83640_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       unsigned int val[4];
+
+       mutex_lock(&clock->extreg_lock);
+
+       ext_write(0, phydev, PAGE4, PTP_CTL, PTP_RD_CLK);
+
+       val[0] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[15:0] */
+       val[1] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[31:16] */
+       val[2] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[15:0] */
+       val[3] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[31:16] */
+
+       mutex_unlock(&clock->extreg_lock);
+
+       ts->tv_nsec = val[0] | (val[1] << 16);
+       ts->tv_sec  = val[2] | (val[3] << 16);
+
+       return 0;
+}
+
+static int ptp_dp83640_settime(struct ptp_clock_info *ptp,
+                              const struct timespec *ts)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       int err;
+
+       mutex_lock(&clock->extreg_lock);
+
+       err = tdr_write(1, phydev, ts, PTP_LOAD_CLK);
+
+       mutex_unlock(&clock->extreg_lock);
+
+       return err;
+}
+
+static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
+                             struct ptp_clock_request *rq, int on)
+{
+       struct dp83640_clock *clock =
+               container_of(ptp, struct dp83640_clock, caps);
+       struct phy_device *phydev = clock->chosen->phydev;
+       u16 evnt;
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_EXTTS:
+               if (rq->extts.index != 0)
+                       return -EINVAL;
+               evnt = EVNT_WR | (EXT_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
+               if (on) {
+                       evnt |= (EXT_GPIO & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
+                       evnt |= EVNT_RISE;
+               }
+               ext_write(0, phydev, PAGE5, PTP_EVNT, evnt);
+               return 0;
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static u8 status_frame_dst[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 };
+static u8 status_frame_src[6] = { 0x08, 0x00, 0x17, 0x0B, 0x6B, 0x0F };
+
+static void enable_status_frames(struct phy_device *phydev, bool on)
+{
+       u16 cfg0 = 0, ver;
+
+       if (on)
+               cfg0 = PSF_EVNT_EN | PSF_RXTS_EN | PSF_TXTS_EN | ENDIAN_FLAG;
+
+       ver = (PSF_PTPVER & VERSIONPTP_MASK) << VERSIONPTP_SHIFT;
+
+       ext_write(0, phydev, PAGE5, PSF_CFG0, cfg0);
+       ext_write(0, phydev, PAGE6, PSF_CFG1, ver);
+
+       if (!phydev->attached_dev) {
+               pr_warning("dp83640: expected to find an attached netdevice\n");
+               return;
+       }
+
+       if (on) {
+               if (dev_mc_add(phydev->attached_dev, status_frame_dst))
+                       pr_warning("dp83640: failed to add mc address\n");
+       } else {
+               if (dev_mc_del(phydev->attached_dev, status_frame_dst))
+                       pr_warning("dp83640: failed to delete mc address\n");
+       }
+}
+
+static bool is_status_frame(struct sk_buff *skb, int type)
+{
+       struct ethhdr *h = eth_hdr(skb);
+
+       if (PTP_CLASS_V2_L2 == type &&
+           !memcmp(h->h_source, status_frame_src, sizeof(status_frame_src)))
+               return true;
+       else
+               return false;
+}
+
+static int expired(struct rxts *rxts)
+{
+       return time_after(jiffies, rxts->tmo);
+}
+
+/* Caller must hold rx_lock. */
+static void prune_rx_ts(struct dp83640_private *dp83640)
+{
+       struct list_head *this, *next;
+       struct rxts *rxts;
+
+       list_for_each_safe(this, next, &dp83640->rxts) {
+               rxts = list_entry(this, struct rxts, list);
+               if (expired(rxts)) {
+                       list_del_init(&rxts->list);
+                       list_add(&rxts->list, &dp83640->rxpool);
+               }
+       }
+}
+
+/* synchronize the phyters so they act as one clock */
+
+static void enable_broadcast(struct phy_device *phydev, int init_page, int on)
+{
+       int val;
+       phy_write(phydev, PAGESEL, 0);
+       val = phy_read(phydev, PHYCR2);
+       if (on)
+               val |= BC_WRITE;
+       else
+               val &= ~BC_WRITE;
+       phy_write(phydev, PHYCR2, val);
+       phy_write(phydev, PAGESEL, init_page);
+}
+
+static void recalibrate(struct dp83640_clock *clock)
+{
+       s64 now, diff;
+       struct phy_txts event_ts;
+       struct timespec ts;
+       struct list_head *this;
+       struct dp83640_private *tmp;
+       struct phy_device *master = clock->chosen->phydev;
+       u16 cfg0, evnt, ptp_trig, trigger, val;
+
+       trigger = CAL_TRIGGER;
+
+       mutex_lock(&clock->extreg_lock);
+
+       /*
+        * enable broadcast, disable status frames, enable ptp clock
+        */
+       list_for_each(this, &clock->phylist) {
+               tmp = list_entry(this, struct dp83640_private, list);
+               enable_broadcast(tmp->phydev, clock->page, 1);
+               tmp->cfg0 = ext_read(tmp->phydev, PAGE5, PSF_CFG0);
+               ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, 0);
+               ext_write(0, tmp->phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+       }
+       enable_broadcast(master, clock->page, 1);
+       cfg0 = ext_read(master, PAGE5, PSF_CFG0);
+       ext_write(0, master, PAGE5, PSF_CFG0, 0);
+       ext_write(0, master, PAGE4, PTP_CTL, PTP_ENABLE);
+
+       /*
+        * enable an event timestamp
+        */
+       evnt = EVNT_WR | EVNT_RISE | EVNT_SINGLE;
+       evnt |= (CAL_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
+       evnt |= (cal_gpio & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
+
+       list_for_each(this, &clock->phylist) {
+               tmp = list_entry(this, struct dp83640_private, list);
+               ext_write(0, tmp->phydev, PAGE5, PTP_EVNT, evnt);
+       }
+       ext_write(0, master, PAGE5, PTP_EVNT, evnt);
+
+       /*
+        * configure a trigger
+        */
+       ptp_trig = TRIG_WR | TRIG_IF_LATE | TRIG_PULSE;
+       ptp_trig |= (trigger  & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT;
+       ptp_trig |= (cal_gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT;
+       ext_write(0, master, PAGE5, PTP_TRIG, ptp_trig);
+
+       /* load trigger */
+       val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+       val |= TRIG_LOAD;
+       ext_write(0, master, PAGE4, PTP_CTL, val);
+
+       /* enable trigger */
+       val &= ~TRIG_LOAD;
+       val |= TRIG_EN;
+       ext_write(0, master, PAGE4, PTP_CTL, val);
+
+       /* disable trigger */
+       val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+       val |= TRIG_DIS;
+       ext_write(0, master, PAGE4, PTP_CTL, val);
+
+       /*
+        * read out and correct offsets
+        */
+       val = ext_read(master, PAGE4, PTP_STS);
+       pr_info("master PTP_STS  0x%04hx", val);
+       val = ext_read(master, PAGE4, PTP_ESTS);
+       pr_info("master PTP_ESTS 0x%04hx", val);
+       event_ts.ns_lo  = ext_read(master, PAGE4, PTP_EDATA);
+       event_ts.ns_hi  = ext_read(master, PAGE4, PTP_EDATA);
+       event_ts.sec_lo = ext_read(master, PAGE4, PTP_EDATA);
+       event_ts.sec_hi = ext_read(master, PAGE4, PTP_EDATA);
+       now = phy2txts(&event_ts);
+
+       list_for_each(this, &clock->phylist) {
+               tmp = list_entry(this, struct dp83640_private, list);
+               val = ext_read(tmp->phydev, PAGE4, PTP_STS);
+               pr_info("slave  PTP_STS  0x%04hx", val);
+               val = ext_read(tmp->phydev, PAGE4, PTP_ESTS);
+               pr_info("slave  PTP_ESTS 0x%04hx", val);
+               event_ts.ns_lo  = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+               event_ts.ns_hi  = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+               event_ts.sec_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+               event_ts.sec_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+               diff = now - (s64) phy2txts(&event_ts);
+               pr_info("slave offset %lld nanoseconds\n", diff);
+               diff += ADJTIME_FIX;
+               ts = ns_to_timespec(diff);
+               tdr_write(0, tmp->phydev, &ts, PTP_STEP_CLK);
+       }
+
+       /*
+        * restore status frames
+        */
+       list_for_each(this, &clock->phylist) {
+               tmp = list_entry(this, struct dp83640_private, list);
+               ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, tmp->cfg0);
+       }
+       ext_write(0, master, PAGE5, PSF_CFG0, cfg0);
+
+       mutex_unlock(&clock->extreg_lock);
+}
+
+/* time stamping methods */
+
+static void decode_evnt(struct dp83640_private *dp83640,
+                       struct phy_txts *phy_txts, u16 ests)
+{
+       struct ptp_clock_event event;
+       int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
+
+       switch (words) { /* fall through in every case */
+       case 3:
+               dp83640->edata.sec_hi = phy_txts->sec_hi;
+       case 2:
+               dp83640->edata.sec_lo = phy_txts->sec_lo;
+       case 1:
+               dp83640->edata.ns_hi = phy_txts->ns_hi;
+       case 0:
+               dp83640->edata.ns_lo = phy_txts->ns_lo;
+       }
+
+       event.type = PTP_CLOCK_EXTTS;
+       event.index = 0;
+       event.timestamp = phy2txts(&dp83640->edata);
+
+       ptp_clock_event(dp83640->clock->ptp_clock, &event);
+}
+
+static void decode_rxts(struct dp83640_private *dp83640,
+                       struct phy_rxts *phy_rxts)
+{
+       struct rxts *rxts;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dp83640->rx_lock, flags);
+
+       prune_rx_ts(dp83640);
+
+       if (list_empty(&dp83640->rxpool)) {
+               pr_warning("dp83640: rx timestamp pool is empty\n");
+               goto out;
+       }
+       rxts = list_first_entry(&dp83640->rxpool, struct rxts, list);
+       list_del_init(&rxts->list);
+       phy2rxts(phy_rxts, rxts);
+       list_add_tail(&rxts->list, &dp83640->rxts);
+out:
+       spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+}
+
+static void decode_txts(struct dp83640_private *dp83640,
+                       struct phy_txts *phy_txts)
+{
+       struct skb_shared_hwtstamps shhwtstamps;
+       struct sk_buff *skb;
+       u64 ns;
+
+       /* We must already have the skb that triggered this. */
+
+       skb = skb_dequeue(&dp83640->tx_queue);
+
+       if (!skb) {
+               pr_warning("dp83640: have timestamp but tx_queue empty\n");
+               return;
+       }
+       ns = phy2txts(phy_txts);
+       memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+       shhwtstamps.hwtstamp = ns_to_ktime(ns);
+       skb_complete_tx_timestamp(skb, &shhwtstamps);
+}
+
+static void decode_status_frame(struct dp83640_private *dp83640,
+                               struct sk_buff *skb)
+{
+       struct phy_rxts *phy_rxts;
+       struct phy_txts *phy_txts;
+       u8 *ptr;
+       int len, size;
+       u16 ests, type;
+
+       ptr = skb->data + 2;
+
+       for (len = skb_headlen(skb) - 2; len > sizeof(type); len -= size) {
+
+               type = *(u16 *)ptr;
+               ests = type & 0x0fff;
+               type = type & 0xf000;
+               len -= sizeof(type);
+               ptr += sizeof(type);
+
+               if (PSF_RX == type && len >= sizeof(*phy_rxts)) {
+
+                       phy_rxts = (struct phy_rxts *) ptr;
+                       decode_rxts(dp83640, phy_rxts);
+                       size = sizeof(*phy_rxts);
+
+               } else if (PSF_TX == type && len >= sizeof(*phy_txts)) {
+
+                       phy_txts = (struct phy_txts *) ptr;
+                       decode_txts(dp83640, phy_txts);
+                       size = sizeof(*phy_txts);
+
+               } else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) {
+
+                       phy_txts = (struct phy_txts *) ptr;
+                       decode_evnt(dp83640, phy_txts, ests);
+                       size = sizeof(*phy_txts);
+
+               } else {
+                       size = 0;
+                       break;
+               }
+               ptr += size;
+       }
+}
+
+static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
+{
+       u16 *seqid;
+       unsigned int offset;
+       u8 *msgtype, *data = skb_mac_header(skb);
+
+       /* check sequenceID, messageType, 12 bit hash of offset 20-29 */
+
+       switch (type) {
+       case PTP_CLASS_V1_IPV4:
+       case PTP_CLASS_V2_IPV4:
+               offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+               break;
+       case PTP_CLASS_V1_IPV6:
+       case PTP_CLASS_V2_IPV6:
+               offset = OFF_PTP6;
+               break;
+       case PTP_CLASS_V2_L2:
+               offset = ETH_HLEN;
+               break;
+       case PTP_CLASS_V2_VLAN:
+               offset = ETH_HLEN + VLAN_HLEN;
+               break;
+       default:
+               return 0;
+       }
+
+       if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid))
+               return 0;
+
+       if (unlikely(type & PTP_CLASS_V1))
+               msgtype = data + offset + OFF_PTP_CONTROL;
+       else
+               msgtype = data + offset;
+
+       seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+
+       return (rxts->msgtype == (*msgtype & 0xf) &&
+               rxts->seqid   == ntohs(*seqid));
+}
+
+static void dp83640_free_clocks(void)
+{
+       struct dp83640_clock *clock;
+       struct list_head *this, *next;
+
+       mutex_lock(&phyter_clocks_lock);
+
+       list_for_each_safe(this, next, &phyter_clocks) {
+               clock = list_entry(this, struct dp83640_clock, list);
+               if (!list_empty(&clock->phylist)) {
+                       pr_warning("phy list non-empty while unloading");
+                       BUG();
+               }
+               list_del(&clock->list);
+               mutex_destroy(&clock->extreg_lock);
+               mutex_destroy(&clock->clock_lock);
+               put_device(&clock->bus->dev);
+               kfree(clock);
+       }
+
+       mutex_unlock(&phyter_clocks_lock);
+}
+
+static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus)
+{
+       INIT_LIST_HEAD(&clock->list);
+       clock->bus = bus;
+       mutex_init(&clock->extreg_lock);
+       mutex_init(&clock->clock_lock);
+       INIT_LIST_HEAD(&clock->phylist);
+       clock->caps.owner = THIS_MODULE;
+       sprintf(clock->caps.name, "dp83640 timer");
+       clock->caps.max_adj     = 1953124;
+       clock->caps.n_alarm     = 0;
+       clock->caps.n_ext_ts    = N_EXT_TS;
+       clock->caps.n_per_out   = 0;
+       clock->caps.pps         = 0;
+       clock->caps.adjfreq     = ptp_dp83640_adjfreq;
+       clock->caps.adjtime     = ptp_dp83640_adjtime;
+       clock->caps.gettime     = ptp_dp83640_gettime;
+       clock->caps.settime     = ptp_dp83640_settime;
+       clock->caps.enable      = ptp_dp83640_enable;
+       /*
+        * Get a reference to this bus instance.
+        */
+       get_device(&bus->dev);
+}
+
+static int choose_this_phy(struct dp83640_clock *clock,
+                          struct phy_device *phydev)
+{
+       if (chosen_phy == -1 && !clock->chosen)
+               return 1;
+
+       if (chosen_phy == phydev->addr)
+               return 1;
+
+       return 0;
+}
+
+static struct dp83640_clock *dp83640_clock_get(struct dp83640_clock *clock)
+{
+       if (clock)
+               mutex_lock(&clock->clock_lock);
+       return clock;
+}
+
+/*
+ * Look up and lock a clock by bus instance.
+ * If there is no clock for this bus, then create it first.
+ */
+static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus)
+{
+       struct dp83640_clock *clock = NULL, *tmp;
+       struct list_head *this;
+
+       mutex_lock(&phyter_clocks_lock);
+
+       list_for_each(this, &phyter_clocks) {
+               tmp = list_entry(this, struct dp83640_clock, list);
+               if (tmp->bus == bus) {
+                       clock = tmp;
+                       break;
+               }
+       }
+       if (clock)
+               goto out;
+
+       clock = kzalloc(sizeof(struct dp83640_clock), GFP_KERNEL);
+       if (!clock)
+               goto out;
+
+       dp83640_clock_init(clock, bus);
+       list_add_tail(&phyter_clocks, &clock->list);
+out:
+       mutex_unlock(&phyter_clocks_lock);
+
+       return dp83640_clock_get(clock);
+}
+
+static void dp83640_clock_put(struct dp83640_clock *clock)
+{
+       mutex_unlock(&clock->clock_lock);
+}
+
+static int dp83640_probe(struct phy_device *phydev)
+{
+       struct dp83640_clock *clock;
+       struct dp83640_private *dp83640;
+       int err = -ENOMEM, i;
+
+       if (phydev->addr == BROADCAST_ADDR)
+               return 0;
+
+       clock = dp83640_clock_get_bus(phydev->bus);
+       if (!clock)
+               goto no_clock;
+
+       dp83640 = kzalloc(sizeof(struct dp83640_private), GFP_KERNEL);
+       if (!dp83640)
+               goto no_memory;
+
+       dp83640->phydev = phydev;
+       INIT_WORK(&dp83640->ts_work, rx_timestamp_work);
+
+       INIT_LIST_HEAD(&dp83640->rxts);
+       INIT_LIST_HEAD(&dp83640->rxpool);
+       for (i = 0; i < MAX_RXTS; i++)
+               list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool);
+
+       phydev->priv = dp83640;
+
+       spin_lock_init(&dp83640->rx_lock);
+       skb_queue_head_init(&dp83640->rx_queue);
+       skb_queue_head_init(&dp83640->tx_queue);
+
+       dp83640->clock = clock;
+
+       if (choose_this_phy(clock, phydev)) {
+               clock->chosen = dp83640;
+               clock->ptp_clock = ptp_clock_register(&clock->caps);
+               if (IS_ERR(clock->ptp_clock)) {
+                       err = PTR_ERR(clock->ptp_clock);
+                       goto no_register;
+               }
+       } else
+               list_add_tail(&dp83640->list, &clock->phylist);
+
+       if (clock->chosen && !list_empty(&clock->phylist))
+               recalibrate(clock);
+       else
+               enable_broadcast(dp83640->phydev, clock->page, 1);
+
+       dp83640_clock_put(clock);
+       return 0;
+
+no_register:
+       clock->chosen = NULL;
+       kfree(dp83640);
+no_memory:
+       dp83640_clock_put(clock);
+no_clock:
+       return err;
+}
+
+static void dp83640_remove(struct phy_device *phydev)
+{
+       struct dp83640_clock *clock;
+       struct list_head *this, *next;
+       struct dp83640_private *tmp, *dp83640 = phydev->priv;
+
+       if (phydev->addr == BROADCAST_ADDR)
+               return;
+
+       enable_status_frames(phydev, false);
+       cancel_work_sync(&dp83640->ts_work);
+
+       clock = dp83640_clock_get(dp83640->clock);
+
+       if (dp83640 == clock->chosen) {
+               ptp_clock_unregister(clock->ptp_clock);
+               clock->chosen = NULL;
+       } else {
+               list_for_each_safe(this, next, &clock->phylist) {
+                       tmp = list_entry(this, struct dp83640_private, list);
+                       if (tmp == dp83640) {
+                               list_del_init(&tmp->list);
+                               break;
+                       }
+               }
+       }
+
+       dp83640_clock_put(clock);
+       kfree(dp83640);
+}
+
+static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+       struct hwtstamp_config cfg;
+       u16 txcfg0, rxcfg0;
+
+       if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+               return -EFAULT;
+
+       if (cfg.flags) /* reserved for future extensions */
+               return -EINVAL;
+
+       switch (cfg.tx_type) {
+       case HWTSTAMP_TX_OFF:
+               dp83640->hwts_tx_en = 0;
+               break;
+       case HWTSTAMP_TX_ON:
+               dp83640->hwts_tx_en = 1;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       switch (cfg.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               dp83640->hwts_rx_en = 0;
+               dp83640->layer = 0;
+               dp83640->version = 0;
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+               dp83640->hwts_rx_en = 1;
+               dp83640->layer = LAYER4;
+               dp83640->version = 1;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+               dp83640->hwts_rx_en = 1;
+               dp83640->layer = LAYER4;
+               dp83640->version = 2;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+               dp83640->hwts_rx_en = 1;
+               dp83640->layer = LAYER2;
+               dp83640->version = 2;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               dp83640->hwts_rx_en = 1;
+               dp83640->layer = LAYER4|LAYER2;
+               dp83640->version = 2;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       txcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT;
+       rxcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT;
+
+       if (dp83640->layer & LAYER2) {
+               txcfg0 |= TX_L2_EN;
+               rxcfg0 |= RX_L2_EN;
+       }
+       if (dp83640->layer & LAYER4) {
+               txcfg0 |= TX_IPV6_EN | TX_IPV4_EN;
+               rxcfg0 |= RX_IPV6_EN | RX_IPV4_EN;
+       }
+
+       if (dp83640->hwts_tx_en)
+               txcfg0 |= TX_TS_EN;
+
+       if (dp83640->hwts_rx_en)
+               rxcfg0 |= RX_TS_EN;
+
+       mutex_lock(&dp83640->clock->extreg_lock);
+
+       if (dp83640->hwts_tx_en || dp83640->hwts_rx_en) {
+               enable_status_frames(phydev, true);
+               ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+       }
+
+       ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0);
+       ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0);
+
+       mutex_unlock(&dp83640->clock->extreg_lock);
+
+       return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+
+static void rx_timestamp_work(struct work_struct *work)
+{
+       struct dp83640_private *dp83640 =
+               container_of(work, struct dp83640_private, ts_work);
+       struct list_head *this, *next;
+       struct rxts *rxts;
+       struct skb_shared_hwtstamps *shhwtstamps;
+       struct sk_buff *skb;
+       unsigned int type;
+       unsigned long flags;
+
+       /* Deliver each deferred packet, with or without a time stamp. */
+
+       while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL) {
+               type = SKB_PTP_TYPE(skb);
+               spin_lock_irqsave(&dp83640->rx_lock, flags);
+               list_for_each_safe(this, next, &dp83640->rxts) {
+                       rxts = list_entry(this, struct rxts, list);
+                       if (match(skb, type, rxts)) {
+                               shhwtstamps = skb_hwtstamps(skb);
+                               memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+                               shhwtstamps->hwtstamp = ns_to_ktime(rxts->ns);
+                               list_del_init(&rxts->list);
+                               list_add(&rxts->list, &dp83640->rxpool);
+                               break;
+                       }
+               }
+               spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+               netif_rx(skb);
+       }
+
+       /* Clear out expired time stamps. */
+
+       spin_lock_irqsave(&dp83640->rx_lock, flags);
+       prune_rx_ts(dp83640);
+       spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+}
+
+static bool dp83640_rxtstamp(struct phy_device *phydev,
+                            struct sk_buff *skb, int type)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+
+       if (!dp83640->hwts_rx_en)
+               return false;
+
+       if (is_status_frame(skb, type)) {
+               decode_status_frame(dp83640, skb);
+               /* Let the stack drop this frame. */
+               return false;
+       }
+
+       SKB_PTP_TYPE(skb) = type;
+       skb_queue_tail(&dp83640->rx_queue, skb);
+       schedule_work(&dp83640->ts_work);
+
+       return true;
+}
+
+static void dp83640_txtstamp(struct phy_device *phydev,
+                            struct sk_buff *skb, int type)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+
+       if (!dp83640->hwts_tx_en) {
+               kfree_skb(skb);
+               return;
+       }
+       skb_queue_tail(&dp83640->tx_queue, skb);
+       schedule_work(&dp83640->ts_work);
+}
+
+static struct phy_driver dp83640_driver = {
+       .phy_id         = DP83640_PHY_ID,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "NatSemi DP83640",
+       .features       = PHY_BASIC_FEATURES,
+       .flags          = 0,
+       .probe          = dp83640_probe,
+       .remove         = dp83640_remove,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .hwtstamp       = dp83640_hwtstamp,
+       .rxtstamp       = dp83640_rxtstamp,
+       .txtstamp       = dp83640_txtstamp,
+       .driver         = {.owner = THIS_MODULE,}
+};
+
+static int __init dp83640_init(void)
+{
+       return phy_driver_register(&dp83640_driver);
+}
+
+static void __exit dp83640_exit(void)
+{
+       dp83640_free_clocks();
+       phy_driver_unregister(&dp83640_driver);
+}
+
+MODULE_DESCRIPTION("National Semiconductor DP83640 PHY driver");
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_LICENSE("GPL");
+
+module_init(dp83640_init);
+module_exit(dp83640_exit);
+
+static struct mdio_device_id __maybe_unused dp83640_tbl[] = {
+       { DP83640_PHY_ID, 0xfffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, dp83640_tbl);
diff --git a/drivers/net/phy/dp83640_reg.h b/drivers/net/phy/dp83640_reg.h
new file mode 100644 (file)
index 0000000..e7fe411
--- /dev/null
@@ -0,0 +1,267 @@
+/* dp83640_reg.h
+ * Generated by regen.tcl on Thu Feb 17 10:02:48 AM CET 2011
+ */
+#ifndef HAVE_DP83640_REGISTERS
+#define HAVE_DP83640_REGISTERS
+
+#define PAGE0                     0x0000
+#define PHYCR2                    0x001c /* PHY Control Register 2 */
+
+#define PAGE4                     0x0004
+#define PTP_CTL                   0x0014 /* PTP Control Register */
+#define PTP_TDR                   0x0015 /* PTP Time Data Register */
+#define PTP_STS                   0x0016 /* PTP Status Register */
+#define PTP_TSTS                  0x0017 /* PTP Trigger Status Register */
+#define PTP_RATEL                 0x0018 /* PTP Rate Low Register */
+#define PTP_RATEH                 0x0019 /* PTP Rate High Register */
+#define PTP_RDCKSUM               0x001a /* PTP Read Checksum */
+#define PTP_WRCKSUM               0x001b /* PTP Write Checksum */
+#define PTP_TXTS                  0x001c /* PTP Transmit Timestamp Register, in four 16-bit reads */
+#define PTP_RXTS                  0x001d /* PTP Receive Timestamp Register, in six? 16-bit reads */
+#define PTP_ESTS                  0x001e /* PTP Event Status Register */
+#define PTP_EDATA                 0x001f /* PTP Event Data Register */
+
+#define PAGE5                     0x0005
+#define PTP_TRIG                  0x0014 /* PTP Trigger Configuration Register */
+#define PTP_EVNT                  0x0015 /* PTP Event Configuration Register */
+#define PTP_TXCFG0                0x0016 /* PTP Transmit Configuration Register 0 */
+#define PTP_TXCFG1                0x0017 /* PTP Transmit Configuration Register 1 */
+#define PSF_CFG0                  0x0018 /* PHY Status Frame Configuration Register 0 */
+#define PTP_RXCFG0                0x0019 /* PTP Receive Configuration Register 0 */
+#define PTP_RXCFG1                0x001a /* PTP Receive Configuration Register 1 */
+#define PTP_RXCFG2                0x001b /* PTP Receive Configuration Register 2 */
+#define PTP_RXCFG3                0x001c /* PTP Receive Configuration Register 3 */
+#define PTP_RXCFG4                0x001d /* PTP Receive Configuration Register 4 */
+#define PTP_TRDL                  0x001e /* PTP Temporary Rate Duration Low Register */
+#define PTP_TRDH                  0x001f /* PTP Temporary Rate Duration High Register */
+
+#define PAGE6                     0x0006
+#define PTP_COC                   0x0014 /* PTP Clock Output Control Register */
+#define PSF_CFG1                  0x0015 /* PHY Status Frame Configuration Register 1 */
+#define PSF_CFG2                  0x0016 /* PHY Status Frame Configuration Register 2 */
+#define PSF_CFG3                  0x0017 /* PHY Status Frame Configuration Register 3 */
+#define PSF_CFG4                  0x0018 /* PHY Status Frame Configuration Register 4 */
+#define PTP_SFDCFG                0x0019 /* PTP SFD Configuration Register */
+#define PTP_INTCTL                0x001a /* PTP Interrupt Control Register */
+#define PTP_CLKSRC                0x001b /* PTP Clock Source Register */
+#define PTP_ETR                   0x001c /* PTP Ethernet Type Register */
+#define PTP_OFF                   0x001d /* PTP Offset Register */
+#define PTP_GPIOMON               0x001e /* PTP GPIO Monitor Register */
+#define PTP_RXHASH                0x001f /* PTP Receive Hash Register */
+
+/* Bit definitions for the PHYCR2 register */
+#define BC_WRITE                  (1<<11) /* Broadcast Write Enable */
+
+/* Bit definitions for the PTP_CTL register */
+#define TRIG_SEL_SHIFT            (10)    /* PTP Trigger Select */
+#define TRIG_SEL_MASK             (0x7)
+#define TRIG_DIS                  (1<<9)  /* Disable PTP Trigger */
+#define TRIG_EN                   (1<<8)  /* Enable PTP Trigger */
+#define TRIG_READ                 (1<<7)  /* Read PTP Trigger */
+#define TRIG_LOAD                 (1<<6)  /* Load PTP Trigger */
+#define PTP_RD_CLK                (1<<5)  /* Read PTP Clock */
+#define PTP_LOAD_CLK              (1<<4)  /* Load PTP Clock */
+#define PTP_STEP_CLK              (1<<3)  /* Step PTP Clock */
+#define PTP_ENABLE                (1<<2)  /* Enable PTP Clock */
+#define PTP_DISABLE               (1<<1)  /* Disable PTP Clock */
+#define PTP_RESET                 (1<<0)  /* Reset PTP Clock */
+
+/* Bit definitions for the PTP_STS register */
+#define TXTS_RDY                  (1<<11) /* Transmit Timestamp Ready */
+#define RXTS_RDY                  (1<<10) /* Receive Timestamp Ready */
+#define TRIG_DONE                 (1<<9)  /* PTP Trigger Done */
+#define EVENT_RDY                 (1<<8)  /* PTP Event Timestamp Ready */
+#define TXTS_IE                   (1<<3)  /* Transmit Timestamp Interrupt Enable */
+#define RXTS_IE                   (1<<2)  /* Receive Timestamp Interrupt Enable */
+#define TRIG_IE                   (1<<1)  /* Trigger Interrupt Enable */
+#define EVENT_IE                  (1<<0)  /* Event Interrupt Enable */
+
+/* Bit definitions for the PTP_TSTS register */
+#define TRIG7_ERROR               (1<<15) /* Trigger 7 Error */
+#define TRIG7_ACTIVE              (1<<14) /* Trigger 7 Active */
+#define TRIG6_ERROR               (1<<13) /* Trigger 6 Error */
+#define TRIG6_ACTIVE              (1<<12) /* Trigger 6 Active */
+#define TRIG5_ERROR               (1<<11) /* Trigger 5 Error */
+#define TRIG5_ACTIVE              (1<<10) /* Trigger 5 Active */
+#define TRIG4_ERROR               (1<<9)  /* Trigger 4 Error */
+#define TRIG4_ACTIVE              (1<<8)  /* Trigger 4 Active */
+#define TRIG3_ERROR               (1<<7)  /* Trigger 3 Error */
+#define TRIG3_ACTIVE              (1<<6)  /* Trigger 3 Active */
+#define TRIG2_ERROR               (1<<5)  /* Trigger 2 Error */
+#define TRIG2_ACTIVE              (1<<4)  /* Trigger 2 Active */
+#define TRIG1_ERROR               (1<<3)  /* Trigger 1 Error */
+#define TRIG1_ACTIVE              (1<<2)  /* Trigger 1 Active */
+#define TRIG0_ERROR               (1<<1)  /* Trigger 0 Error */
+#define TRIG0_ACTIVE              (1<<0)  /* Trigger 0 Active */
+
+/* Bit definitions for the PTP_RATEH register */
+#define PTP_RATE_DIR              (1<<15) /* PTP Rate Direction */
+#define PTP_TMP_RATE              (1<<14) /* PTP Temporary Rate */
+#define PTP_RATE_HI_SHIFT         (0)     /* PTP Rate High 10-bits */
+#define PTP_RATE_HI_MASK          (0x3ff)
+
+/* Bit definitions for the PTP_ESTS register */
+#define EVNTS_MISSED_SHIFT        (8)     /* Indicates number of events missed */
+#define EVNTS_MISSED_MASK         (0x7)
+#define EVNT_TS_LEN_SHIFT         (6)     /* Indicates length of the Timestamp field in 16-bit words minus 1 */
+#define EVNT_TS_LEN_MASK          (0x3)
+#define EVNT_RF                   (1<<5)  /* Indicates whether the event is a rise or falling event */
+#define EVNT_NUM_SHIFT            (2)     /* Indicates Event Timestamp Unit which detected an event */
+#define EVNT_NUM_MASK             (0x7)
+#define MULT_EVNT                 (1<<1)  /* Indicates multiple events were detected at the same time */
+#define EVENT_DET                 (1<<0)  /* PTP Event Detected */
+
+/* Bit definitions for the PTP_EDATA register */
+#define E7_RISE                   (1<<15) /* Indicates direction of Event 7 */
+#define E7_DET                    (1<<14) /* Indicates Event 7 detected */
+#define E6_RISE                   (1<<13) /* Indicates direction of Event 6 */
+#define E6_DET                    (1<<12) /* Indicates Event 6 detected */
+#define E5_RISE                   (1<<11) /* Indicates direction of Event 5 */
+#define E5_DET                    (1<<10) /* Indicates Event 5 detected */
+#define E4_RISE                   (1<<9)  /* Indicates direction of Event 4 */
+#define E4_DET                    (1<<8)  /* Indicates Event 4 detected */
+#define E3_RISE                   (1<<7)  /* Indicates direction of Event 3 */
+#define E3_DET                    (1<<6)  /* Indicates Event 3 detected */
+#define E2_RISE                   (1<<5)  /* Indicates direction of Event 2 */
+#define E2_DET                    (1<<4)  /* Indicates Event 2 detected */
+#define E1_RISE                   (1<<3)  /* Indicates direction of Event 1 */
+#define E1_DET                    (1<<2)  /* Indicates Event 1 detected */
+#define E0_RISE                   (1<<1)  /* Indicates direction of Event 0 */
+#define E0_DET                    (1<<0)  /* Indicates Event 0 detected */
+
+/* Bit definitions for the PTP_TRIG register */
+#define TRIG_PULSE                (1<<15) /* generate a Pulse rather than a single edge */
+#define TRIG_PER                  (1<<14) /* generate a periodic signal */
+#define TRIG_IF_LATE              (1<<13) /* trigger immediately if already past */
+#define TRIG_NOTIFY               (1<<12) /* Trigger Notification Enable */
+#define TRIG_GPIO_SHIFT           (8)     /* Trigger GPIO Connection, value 1-12 */
+#define TRIG_GPIO_MASK            (0xf)
+#define TRIG_TOGGLE               (1<<7)  /* Trigger Toggle Mode Enable */
+#define TRIG_CSEL_SHIFT           (1)     /* Trigger Configuration Select */
+#define TRIG_CSEL_MASK            (0x7)
+#define TRIG_WR                   (1<<0)  /* Trigger Configuration Write */
+
+/* Bit definitions for the PTP_EVNT register */
+#define EVNT_RISE                 (1<<14) /* Event Rise Detect Enable */
+#define EVNT_FALL                 (1<<13) /* Event Fall Detect Enable */
+#define EVNT_SINGLE               (1<<12) /* enable single event capture operation */
+#define EVNT_GPIO_SHIFT           (8)     /* Event GPIO Connection, value 1-12 */
+#define EVNT_GPIO_MASK            (0xf)
+#define EVNT_SEL_SHIFT            (1)     /* Event Select */
+#define EVNT_SEL_MASK             (0x7)
+#define EVNT_WR                   (1<<0)  /* Event Configuration Write */
+
+/* Bit definitions for the PTP_TXCFG0 register */
+#define SYNC_1STEP                (1<<15) /* insert timestamp into transmit Sync Messages */
+#define DR_INSERT                 (1<<13) /* Insert Delay_Req Timestamp in Delay_Resp (dangerous) */
+#define NTP_TS_EN                 (1<<12) /* Enable Timestamping of NTP Packets */
+#define IGNORE_2STEP              (1<<11) /* Ignore Two_Step flag for One-Step operation */
+#define CRC_1STEP                 (1<<10) /* Disable checking of CRC for One-Step operation */
+#define CHK_1STEP                 (1<<9)  /* Enable UDP Checksum correction for One-Step Operation */
+#define IP1588_EN                 (1<<8)  /* Enable IEEE 1588 defined IP address filter */
+#define TX_L2_EN                  (1<<7)  /* Layer2 Timestamp Enable */
+#define TX_IPV6_EN                (1<<6)  /* IPv6 Timestamp Enable */
+#define TX_IPV4_EN                (1<<5)  /* IPv4 Timestamp Enable */
+#define TX_PTP_VER_SHIFT          (1)     /* Enable Timestamp capture for IEEE 1588 version X */
+#define TX_PTP_VER_MASK           (0xf)
+#define TX_TS_EN                  (1<<0)  /* Transmit Timestamp Enable */
+
+/* Bit definitions for the PTP_TXCFG1 register */
+#define BYTE0_MASK_SHIFT          (8)     /* Bit mask to be used for matching Byte0 of the PTP Message */
+#define BYTE0_MASK_MASK           (0xff)
+#define BYTE0_DATA_SHIFT          (0)     /* Data to be used for matching Byte0 of the PTP Message */
+#define BYTE0_DATA_MASK           (0xff)
+
+/* Bit definitions for the PSF_CFG0 register */
+#define MAC_SRC_ADD_SHIFT         (11)    /* Status Frame Mac Source Address */
+#define MAC_SRC_ADD_MASK          (0x3)
+#define MIN_PRE_SHIFT             (8)     /* Status Frame Minimum Preamble */
+#define MIN_PRE_MASK              (0x7)
+#define PSF_ENDIAN                (1<<7)  /* Status Frame Endian Control */
+#define PSF_IPV4                  (1<<6)  /* Status Frame IPv4 Enable */
+#define PSF_PCF_RD                (1<<5)  /* Control Frame Read PHY Status Frame Enable */
+#define PSF_ERR_EN                (1<<4)  /* Error PHY Status Frame Enable */
+#define PSF_TXTS_EN               (1<<3)  /* Transmit Timestamp PHY Status Frame Enable */
+#define PSF_RXTS_EN               (1<<2)  /* Receive Timestamp PHY Status Frame Enable */
+#define PSF_TRIG_EN               (1<<1)  /* Trigger PHY Status Frame Enable */
+#define PSF_EVNT_EN               (1<<0)  /* Event PHY Status Frame Enable */
+
+/* Bit definitions for the PTP_RXCFG0 register */
+#define DOMAIN_EN                 (1<<15) /* Domain Match Enable */
+#define ALT_MAST_DIS              (1<<14) /* Alternate Master Timestamp Disable */
+#define USER_IP_SEL               (1<<13) /* Selects portion of IP address accessible thru PTP_RXCFG2 */
+#define USER_IP_EN                (1<<12) /* Enable User-programmed IP address filter */
+#define RX_SLAVE                  (1<<11) /* Receive Slave Only */
+#define IP1588_EN_SHIFT           (8)     /* Enable IEEE 1588 defined IP address filters */
+#define IP1588_EN_MASK            (0xf)
+#define RX_L2_EN                  (1<<7)  /* Layer2 Timestamp Enable */
+#define RX_IPV6_EN                (1<<6)  /* IPv6 Timestamp Enable */
+#define RX_IPV4_EN                (1<<5)  /* IPv4 Timestamp Enable */
+#define RX_PTP_VER_SHIFT          (1)     /* Enable Timestamp capture for IEEE 1588 version X */
+#define RX_PTP_VER_MASK           (0xf)
+#define RX_TS_EN                  (1<<0)  /* Receive Timestamp Enable */
+
+/* Bit definitions for the PTP_RXCFG1 register */
+#define BYTE0_MASK_SHIFT          (8)     /* Bit mask to be used for matching Byte0 of the PTP Message */
+#define BYTE0_MASK_MASK           (0xff)
+#define BYTE0_DATA_SHIFT          (0)     /* Data to be used for matching Byte0 of the PTP Message */
+#define BYTE0_DATA_MASK           (0xff)
+
+/* Bit definitions for the PTP_RXCFG3 register */
+#define TS_MIN_IFG_SHIFT          (12)    /* Minimum Inter-frame Gap */
+#define TS_MIN_IFG_MASK           (0xf)
+#define ACC_UDP                   (1<<11) /* Record Timestamp if UDP Checksum Error */
+#define ACC_CRC                   (1<<10) /* Record Timestamp if CRC Error */
+#define TS_APPEND                 (1<<9)  /* Append Timestamp for L2 */
+#define TS_INSERT                 (1<<8)  /* Enable Timestamp Insertion */
+#define PTP_DOMAIN_SHIFT          (0)     /* PTP Message domainNumber field */
+#define PTP_DOMAIN_MASK           (0xff)
+
+/* Bit definitions for the PTP_RXCFG4 register */
+#define IPV4_UDP_MOD              (1<<15) /* Enable IPV4 UDP Modification */
+#define TS_SEC_EN                 (1<<14) /* Enable Timestamp Seconds */
+#define TS_SEC_LEN_SHIFT          (12)    /* Inserted Timestamp Seconds Length */
+#define TS_SEC_LEN_MASK           (0x3)
+#define RXTS_NS_OFF_SHIFT         (6)     /* Receive Timestamp Nanoseconds offset */
+#define RXTS_NS_OFF_MASK          (0x3f)
+#define RXTS_SEC_OFF_SHIFT        (0)     /* Receive Timestamp Seconds offset */
+#define RXTS_SEC_OFF_MASK         (0x3f)
+
+/* Bit definitions for the PTP_COC register */
+#define PTP_CLKOUT_EN             (1<<15) /* PTP Clock Output Enable */
+#define PTP_CLKOUT_SEL            (1<<14) /* PTP Clock Output Source Select */
+#define PTP_CLKOUT_SPEEDSEL       (1<<13) /* PTP Clock Output I/O Speed Select */
+#define PTP_CLKDIV_SHIFT          (0)     /* PTP Clock Divide-by Value */
+#define PTP_CLKDIV_MASK           (0xff)
+
+/* Bit definitions for the PSF_CFG1 register */
+#define PTPRESERVED_SHIFT         (12)    /* PTP v2 reserved field */
+#define PTPRESERVED_MASK          (0xf)
+#define VERSIONPTP_SHIFT          (8)     /* PTP v2 versionPTP field */
+#define VERSIONPTP_MASK           (0xf)
+#define TRANSPORT_SPECIFIC_SHIFT  (4)     /* PTP v2 Header transportSpecific field */
+#define TRANSPORT_SPECIFIC_MASK   (0xf)
+#define MESSAGETYPE_SHIFT         (0)     /* PTP v2 messageType field */
+#define MESSAGETYPE_MASK          (0xf)
+
+/* Bit definitions for the PTP_SFDCFG register */
+#define TX_SFD_GPIO_SHIFT         (4)     /* TX SFD GPIO Select, value 1-12 */
+#define TX_SFD_GPIO_MASK          (0xf)
+#define RX_SFD_GPIO_SHIFT         (0)     /* RX SFD GPIO Select, value 1-12 */
+#define RX_SFD_GPIO_MASK          (0xf)
+
+/* Bit definitions for the PTP_INTCTL register */
+#define PTP_INT_GPIO_SHIFT        (0)     /* PTP Interrupt GPIO Select */
+#define PTP_INT_GPIO_MASK         (0xf)
+
+/* Bit definitions for the PTP_CLKSRC register */
+#define CLK_SRC_SHIFT             (14)    /* PTP Clock Source Select */
+#define CLK_SRC_MASK              (0x3)
+#define CLK_SRC_PER_SHIFT         (0)     /* PTP Clock Source Period */
+#define CLK_SRC_PER_MASK          (0x7f)
+
+/* Bit definitions for the PTP_OFF register */
+#define PTP_OFFSET_SHIFT          (0)     /* PTP Message offset from preceding header */
+#define PTP_OFFSET_MASK           (0xff)
+
+#endif
index db19332a7d87ae69ef2268b7c25901ec6f3aca5d..f4b01c638a330d969ab32f88178bc51ab7eebf73 100644 (file)
@@ -292,6 +292,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
        {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003)},
        {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100)},
        {PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3)},
+       {PCI_DEVICE(0x10cf, 0x11a2)}, /* Fujitsu 1000base-SX with BCM5703SKHB */
        {}
 };
 
index 1e980fdd9d777a883131689d025eb401187f64fb..1e2af96fc29cf17d640f72d3bbbbd6aebe351647 100644 (file)
@@ -1658,11 +1658,9 @@ static int tile_net_stop(struct net_device *dev)
        while (tile_net_lepp_free_comps(dev, true))
                /* loop */;
 
-       /* Wipe the EPP queue. */
+       /* Wipe the EPP queue, and wait till the stores hit the EPP. */
        memset(priv->eq, 0, sizeof(lepp_queue_t));
-
-       /* Evict the EPP queue. */
-       finv_buffer(priv->eq, EQ_SIZE);
+       mb();
 
        return 0;
 }
@@ -2398,7 +2396,7 @@ static void tile_net_cleanup(void)
                        struct net_device *dev = tile_net_devs[i];
                        struct tile_net_priv *priv = netdev_priv(dev);
                        unregister_netdev(dev);
-                       finv_buffer(priv->eq, EQ_SIZE);
+                       finv_buffer_remote(priv->eq, EQ_SIZE, 0);
                        __free_pages(priv->eq_pages, EQ_ORDER);
                        free_netdev(dev);
                }
index 4ab557d0287de5abd269dc9be29ed6148742d393..cdd3ae486109419949612b0df069be7ac001c0a3 100644 (file)
@@ -54,7 +54,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/usb/cdc.h>
 
-#define        DRIVER_VERSION                          "06-May-2011"
+#define        DRIVER_VERSION                          "24-May-2011"
 
 /* CDC NCM subclass 3.2.1 */
 #define USB_CDC_NCM_NDP16_LENGTH_MIN           0x10
@@ -134,8 +134,6 @@ struct cdc_ncm_ctx {
        u16 tx_ndp_modulus;
        u16 tx_seq;
        u16 connected;
-       u8 data_claimed;
-       u8 control_claimed;
 };
 
 static void cdc_ncm_tx_timeout(unsigned long arg);
@@ -460,17 +458,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
 
        del_timer_sync(&ctx->tx_timer);
 
-       if (ctx->data_claimed) {
-               usb_set_intfdata(ctx->data, NULL);
-               usb_driver_release_interface(driver_of(ctx->intf), ctx->data);
-       }
-
-       if (ctx->control_claimed) {
-               usb_set_intfdata(ctx->control, NULL);
-               usb_driver_release_interface(driver_of(ctx->intf),
-                                                               ctx->control);
-       }
-
        if (ctx->tx_rem_skb != NULL) {
                dev_kfree_skb_any(ctx->tx_rem_skb);
                ctx->tx_rem_skb = NULL;
@@ -495,7 +482,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
 
        ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
        if (ctx == NULL)
-               goto error;
+               return -ENODEV;
 
        memset(ctx, 0, sizeof(*ctx));
 
@@ -568,46 +555,36 @@ advance:
 
        /* check if we got everything */
        if ((ctx->control == NULL) || (ctx->data == NULL) ||
-           (ctx->ether_desc == NULL))
+           (ctx->ether_desc == NULL) || (ctx->control != intf))
                goto error;
 
        /* claim interfaces, if any */
-       if (ctx->data != intf) {
-               temp = usb_driver_claim_interface(driver, ctx->data, dev);
-               if (temp)
-                       goto error;
-               ctx->data_claimed = 1;
-       }
-
-       if (ctx->control != intf) {
-               temp = usb_driver_claim_interface(driver, ctx->control, dev);
-               if (temp)
-                       goto error;
-               ctx->control_claimed = 1;
-       }
+       temp = usb_driver_claim_interface(driver, ctx->data, dev);
+       if (temp)
+               goto error;
 
        iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
 
        /* reset data interface */
        temp = usb_set_interface(dev->udev, iface_no, 0);
        if (temp)
-               goto error;
+               goto error2;
 
        /* initialize data interface */
        if (cdc_ncm_setup(ctx))
-               goto error;
+               goto error2;
 
        /* configure data interface */
        temp = usb_set_interface(dev->udev, iface_no, 1);
        if (temp)
-               goto error;
+               goto error2;
 
        cdc_ncm_find_endpoints(ctx, ctx->data);
        cdc_ncm_find_endpoints(ctx, ctx->control);
 
        if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) ||
            (ctx->status_ep == NULL))
-               goto error;
+               goto error2;
 
        dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
 
@@ -617,7 +594,7 @@ advance:
 
        temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
        if (temp)
-               goto error;
+               goto error2;
 
        dev_info(&dev->udev->dev, "MAC-Address: "
                                "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
@@ -642,38 +619,38 @@ advance:
        ctx->tx_speed = ctx->rx_speed = 0;
        return 0;
 
+error2:
+       usb_set_intfdata(ctx->control, NULL);
+       usb_set_intfdata(ctx->data, NULL);
+       usb_driver_release_interface(driver, ctx->data);
 error:
        cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
        dev->data[0] = 0;
-       dev_info(&dev->udev->dev, "Descriptor failure\n");
+       dev_info(&dev->udev->dev, "bind() failure\n");
        return -ENODEV;
 }
 
 static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
 {
        struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
-       struct usb_driver *driver;
+       struct usb_driver *driver = driver_of(intf);
 
        if (ctx == NULL)
                return;         /* no setup */
 
-       driver = driver_of(intf);
-
-       usb_set_intfdata(ctx->data, NULL);
-       usb_set_intfdata(ctx->control, NULL);
-       usb_set_intfdata(ctx->intf, NULL);
-
-       /* release interfaces, if any */
-       if (ctx->data_claimed) {
+       /* disconnect master --> disconnect slave */
+       if (intf == ctx->control && ctx->data) {
+               usb_set_intfdata(ctx->data, NULL);
                usb_driver_release_interface(driver, ctx->data);
-               ctx->data_claimed = 0;
-       }
+               ctx->data = NULL;
 
-       if (ctx->control_claimed) {
+       } else if (intf == ctx->data && ctx->control) {
+               usb_set_intfdata(ctx->control, NULL);
                usb_driver_release_interface(driver, ctx->control);
-               ctx->control_claimed = 0;
+               ctx->control = NULL;
        }
 
+       usb_set_intfdata(ctx->intf, NULL);
        cdc_ncm_free(ctx);
 }
 
index d7227539484e3d5dae53b4077109d38844d32b00..0f1f05f6c4f8a3e644d8e9dd1c75cb7da4d2c2c1 100644 (file)
@@ -1096,7 +1096,7 @@ struct mac_regs {
 
        volatile __le16 PatternCRC[8];  /* 0xB0 */
        volatile __le32 ByteMask[4][4]; /* 0xC0 */
-} __packed;
+};
 
 
 enum hw_mib {
index a70c512f05d2ef9924298da3b87647a0b13866d0..55cf71fbffe32125d9bdbbbe429b98ed0acea35e 100644 (file)
@@ -4501,17 +4501,15 @@ static int setup_proc_entry( struct net_device *dev,
        struct proc_dir_entry *entry;
        /* First setup the device directory */
        strcpy(apriv->proc_name,dev->name);
-       apriv->proc_entry = create_proc_entry(apriv->proc_name,
-                                             S_IFDIR|airo_perm,
-                                             airo_entry);
+       apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm,
+                                           airo_entry);
        if (!apriv->proc_entry)
                goto fail;
        apriv->proc_entry->uid = proc_uid;
        apriv->proc_entry->gid = proc_gid;
 
        /* Setup the StatsDelta */
-       entry = proc_create_data("StatsDelta",
-                                S_IFREG | (S_IRUGO&proc_perm),
+       entry = proc_create_data("StatsDelta", S_IRUGO & proc_perm,
                                 apriv->proc_entry, &proc_statsdelta_ops, dev);
        if (!entry)
                goto fail_stats_delta;
@@ -4519,8 +4517,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the Stats */
-       entry = proc_create_data("Stats",
-                                S_IFREG | (S_IRUGO&proc_perm),
+       entry = proc_create_data("Stats", S_IRUGO & proc_perm,
                                 apriv->proc_entry, &proc_stats_ops, dev);
        if (!entry)
                goto fail_stats;
@@ -4528,8 +4525,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the Status */
-       entry = proc_create_data("Status",
-                                S_IFREG | (S_IRUGO&proc_perm),
+       entry = proc_create_data("Status", S_IRUGO & proc_perm,
                                 apriv->proc_entry, &proc_status_ops, dev);
        if (!entry)
                goto fail_status;
@@ -4537,8 +4533,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the Config */
-       entry = proc_create_data("Config",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("Config", proc_perm,
                                 apriv->proc_entry, &proc_config_ops, dev);
        if (!entry)
                goto fail_config;
@@ -4546,8 +4541,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the SSID */
-       entry = proc_create_data("SSID",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("SSID", proc_perm,
                                 apriv->proc_entry, &proc_SSID_ops, dev);
        if (!entry)
                goto fail_ssid;
@@ -4555,8 +4549,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the APList */
-       entry = proc_create_data("APList",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("APList", proc_perm,
                                 apriv->proc_entry, &proc_APList_ops, dev);
        if (!entry)
                goto fail_aplist;
@@ -4564,8 +4557,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the BSSList */
-       entry = proc_create_data("BSSList",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("BSSList", proc_perm,
                                 apriv->proc_entry, &proc_BSSList_ops, dev);
        if (!entry)
                goto fail_bsslist;
@@ -4573,8 +4565,7 @@ static int setup_proc_entry( struct net_device *dev,
        entry->gid = proc_gid;
 
        /* Setup the WepKey */
-       entry = proc_create_data("WepKey",
-                                S_IFREG | proc_perm,
+       entry = proc_create_data("WepKey", proc_perm,
                                 apriv->proc_entry, &proc_wepkey_ops, dev);
        if (!entry)
                goto fail_wepkey;
@@ -5706,9 +5697,7 @@ static int __init airo_init_module( void )
 {
        int i;
 
-       airo_entry = create_proc_entry("driver/aironet",
-                                      S_IFDIR | airo_perm,
-                                      NULL);
+       airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL);
 
        if (airo_entry) {
                airo_entry->uid = proc_uid;
index 61956392f2da44c3b8dd86b0f84c5a6e6675c5ed..5b49cd03bfdfcaa09d130c07fed1d0bab0607afe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
  * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
  *
index 5a1f4f511bc152df2e033380e666c45a0bb9cc5b..bfb6481f01f9ba9d06aa92fecf9c6ccd4e9c0757 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 0cd6783de883668d2f433bfb07f5ffe0c47863cb..dbab5b9ce4948a3174a4a6e1bb4c74b800f3eb90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 36f7d0639db333d51e904ab6a2871909d06937d1..234617c948a1d8589e4b1a56f30e758ffb597993 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 4bf9dab4f2b38b776d25d5226222be1f7bd36474..441bb33f17adb705af53f5a04f764a6cfa911f46 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 69a94c7e45cb3df2b9b4ce79d5f89f0bdbe09b9d..6d2e2f3303f9125db9f4b7b3fcf47388b61223c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index cb611b287b35a4459bdce1fa4c179b72b64aef94..015d97439935d05b0deb119471334929b7891f0f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index f44c84ab5dceddae414dfdec5f877e98bc0013e6..f344cc2b3d5966827eb352cb5761d14b13833568 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 6203eed860ddc1c31fd2ba0ed10d4151a7e843b5..7573257731b6d7e865f97f50b2f41adbf860dec5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 7a332f16b79af9b83ad7764b45577342e64384e0..077e8a6983fab5637fb8bdc9a949f38a018d7d09 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index a57e963cf0dc19dd6b7ad51180657f63c65b6b9d..2fe0a34cbabcba3750446f5b33e57d80878c5fbf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 47780ef1c892e56317d48e4fdc500bf34fc7c17f..453af6dc514b5f700a16a615d1f2ea3104191026 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index f915a3dbfcad106737b4fc803c814a6ae63e067f..e8ac70da5ac70d2ec0fc585c556017ce51b6b90e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index f276cb922b4d5d96bf16703bd67b75ac40aecb55..f48051c50092f0d85a5babf97160621862c24b36 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index d985841ff4014ef966acede1906db98e71acaf88..0ca7635d0669c276683762f85cd493b3a21e5b87 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index afb0b5ee1865c3c10481b5d6a8fac4c932f97af2..ab21a49159811c8ccaa587aef294e37dd95e84cd 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
 #ifndef AR9003_EEPROM_H
 #define AR9003_EEPROM_H
 
index a55eddbb258923aaf85a35966fb35a3974fa15f0..392bf0f8ff1687678ff01816a0177a99c303e4c5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index be6adec33ddbb0d9c9d655f8b1ca4b5a3f6fc852..10d71f7d3fc22b7ed71bb8f5ad7f9097d910e82e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 45cc7e80436c067430e140dd5dfb36b671afe62f..c50449387bf163144a0ad8491296ca87cc08dfc8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 356d2fd78822279245b0d4a2669a5d6aa6dd731d..e4d6a87ec53830bf70126f29090a2349dea5cfef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 25f3c2fdf2bcf15010d550cfb167294acc45781f..eee23ecd118a292f35e959018414d6a548ed74d4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index c7505b48e5c0b3ede5ff22de98f0f2edd1afc7b5..443090d278e33234e432085fdb97657ce974afd9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2010 Atheros Communications, Inc.
+ * Copyright (c) 2010-2011 Atheros Communications, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index fbdde29f0ab8d4e9349d3320e923eeef262d4432..611ea6ce8508dfb760a1172ea46793e6716c48e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 03b37d7be1c3bac7cb5276d71fb55019869ac6fe..f75068b4b310e2383c2b30e79a2e88c59c0a0622 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -397,6 +397,9 @@ struct ath_beacon {
        struct ath_descdma bdma;
        struct ath_txq *cabq;
        struct list_head bbuf;
+
+       bool tx_processed;
+       bool tx_last;
 };
 
 void ath_beacon_tasklet(unsigned long data);
index 637dbc5f7b67478e975e81a33a33ab5785fc5d84..d4d8ceced89b754c1babef1ba41d11cfe456efcc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 
 #define FUDGE 2
 
+static void ath9k_reset_beacon_status(struct ath_softc *sc)
+{
+       sc->beacon.tx_processed = false;
+       sc->beacon.tx_last = false;
+}
+
 /*
  *  This function will modify certain transmit queue properties depending on
  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
@@ -72,6 +78,8 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
        struct ieee80211_supported_band *sband;
        u8 rate = 0;
 
+       ath9k_reset_beacon_status(sc);
+
        ds = bf->bf_desc;
        flags = ATH9K_TXDESC_NOACK;
 
@@ -134,6 +142,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
        struct ieee80211_tx_info *info;
        int cabq_depth;
 
+       ath9k_reset_beacon_status(sc);
+
        avp = (void *)vif->drv_priv;
        cabq = sc->beacon.cabq;
 
@@ -351,9 +361,7 @@ void ath_beacon_tasklet(unsigned long data)
        struct ath_buf *bf = NULL;
        struct ieee80211_vif *vif;
        int slot;
-       u32 bfaddr, bc = 0, tsftu;
-       u64 tsf;
-       u16 intval;
+       u32 bfaddr, bc = 0;
 
        /*
         * Check if the previous beacon has gone out.  If
@@ -388,17 +396,27 @@ void ath_beacon_tasklet(unsigned long data)
         * on the tsf to safeguard against missing an swba.
         */
 
-       intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
 
-       tsf = ath9k_hw_gettsf64(ah);
-       tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
-       tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
-       slot = (tsftu % (intval * ATH_BCBUF)) / intval;
-       vif = sc->beacon.bslot[slot];
+       if (ah->opmode == NL80211_IFTYPE_AP) {
+               u16 intval;
+               u32 tsftu;
+               u64 tsf;
+
+               intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
+               tsf = ath9k_hw_gettsf64(ah);
+               tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
+               tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
+               slot = (tsftu % (intval * ATH_BCBUF)) / intval;
+               vif = sc->beacon.bslot[slot];
+
+               ath_dbg(common, ATH_DBG_BEACON,
+                       "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
+                       slot, tsf, tsftu / ATH_BCBUF, intval, vif);
+       } else {
+               slot = 0;
+               vif = sc->beacon.bslot[slot];
+       }
 
-       ath_dbg(common, ATH_DBG_BEACON,
-               "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
-               slot, tsf, tsftu / ATH_BCBUF, intval, vif);
 
        bfaddr = 0;
        if (vif) {
@@ -636,6 +654,8 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
        struct ath_common *common = ath9k_hw_common(ah);
        u32 tsf, delta, intval, nexttbtt;
 
+       ath9k_reset_beacon_status(sc);
+
        tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE);
        intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
 
@@ -646,7 +666,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
                        delta = (tsf - sc->beacon.bc_tstamp);
                else
                        delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp));
-               nexttbtt = tsf + roundup(delta, intval);
+               nexttbtt = tsf + intval - (delta % intval);
        }
 
        ath_dbg(common, ATH_DBG_BEACON,
index 23f15a7ca7f128a364ddc32d4ed5cee3fa66834d..41ce0b1398868eeab8c954af9b493913d05c5772 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index a9efca83d676dc08de3ca884004a886e5ec9824b..234f77689b144715d51372d6da5e1f038b37e78a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 558b228a717fe06c35ac66a4e78962a23be97473..a1250c586e40884989a853845e1c68230434f6c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 4420780fa3b86d2a7fbbfb173e0f2fefc7026e05..1bef41d1b1ffb250d38f490a395d6c79e033b019 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 74535e6dfb82a024538caf059c6545f701ba3606..fa6bd2d189e573516e2ab7cac919ab3109dbe52f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 5124f1420b3ae404cbcc80dfdf7732c3c0a06d91..77ec288b5a70557efc233e53c03b31b95d822bb4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index bad1a87249b6011898027cce7300cea8358dbc49..d55ffd7d4bd28565df7d93b5e1ed65c010b99ba5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -435,6 +435,7 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
                        conf->channel_type,
                        channel_type_str(conf->channel_type));
 
+       ath9k_ps_wakeup(sc);
        put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
        put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
        len += snprintf(buf + len, sizeof(buf) - len,
@@ -444,6 +445,7 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
        len += snprintf(buf + len, sizeof(buf) - len,
                        "addrmask: %pM\n", addr);
        tmp = ath9k_hw_getrxfilter(sc->sc_ah);
+       ath9k_ps_restore(sc);
        len += snprintf(buf + len, sizeof(buf) - len,
                        "rfilt: 0x%x", tmp);
        if (tmp & ATH9K_RX_FILTER_UCAST)
@@ -725,6 +727,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
                break;
        }
 
+       ath9k_ps_wakeup(sc);
        len += snprintf(buf + len, size - len,
                        "curbssid: %pM\n"
                        "OP-Mode: %s(%i)\n"
@@ -734,6 +737,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
                        REG_READ(ah, AR_BEACON_PERIOD));
 
        reg = REG_READ(ah, AR_TIMER_MODE);
+       ath9k_ps_restore(sc);
        len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (",
                        reg);
        if (reg & AR_TBTT_TIMER_EN)
@@ -1050,7 +1054,9 @@ static ssize_t read_file_regval(struct file *file, char __user *user_buf,
        unsigned int len;
        u32 regval;
 
+       ath9k_ps_wakeup(sc);
        regval = REG_READ_D(ah, sc->debug.regidx);
+       ath9k_ps_restore(sc);
        len = sprintf(buf, "0x%08x\n", regval);
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
@@ -1072,7 +1078,9 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
        if (strict_strtoul(buf, 0, &regval))
                return -EINVAL;
 
+       ath9k_ps_wakeup(sc);
        REG_WRITE_D(ah, sc->debug.regidx, regval);
+       ath9k_ps_restore(sc);
        return count;
 }
 
index 5488a324cc100b142ed1871a9ce493f18b893543..8ce6ad80f4e208461469ecbb7b90172ae460a044 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 8c18bed3a55890e3fbc9195bc37802aaab2a9015..e61404dda8c59b36be9766dada75b3c16ae3560e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 3e316133f114c9b6765b9002d168e157fbccdaba..de99c0da52e4e33c412086f346673d1d49211015 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 6f714dd723653032c0622b8821852749b4254f38..5b1e894f3d679aa7d43fe52707d731e7aaec6032 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index b87db4763098bad950f78824102d2626b598aa38..7856f0d4512d6292a1a70ef3f4f98360666f1847 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index c031854b569fe0a5c3c145724ec3373c802b68e2..17f0a6806207bca7936c4bd6fdbe8271d04e54f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 0349b3a1cc58c8dcb29729f0237f9d4137e8de46..bc713fc28191b2baf4e1992365902cfbce25fd07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 2e3a33a53406a85d08c4266d90e33462a1a8208b..260f1f37a60e486446394f71043c9ce5c0255dec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 2bdcdbc14b1ea899c687170522e6c3ced11475e2..794f63094e5d66db28189cc248e106474358497e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -18,7 +18,7 @@
 #define HTC_USB_H
 
 #define MAJOR_VERSION_REQ 1
-#define MINOR_VERSION_REQ 2
+#define MINOR_VERSION_REQ 3
 
 #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB))
 
index dfc7a982fc7eb265e263e524926603ba631574fc..5bc022087e651e8be0a8097ca17af1257c1b4f45 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -46,15 +46,8 @@ extern struct ieee80211_ops ath9k_htc_ops;
 extern int htc_modparam_nohwcrypt;
 
 enum htc_phymode {
-       HTC_MODE_AUTO           = 0,
-       HTC_MODE_11A            = 1,
-       HTC_MODE_11B            = 2,
-       HTC_MODE_11G            = 3,
-       HTC_MODE_FH             = 4,
-       HTC_MODE_TURBO_A        = 5,
-       HTC_MODE_TURBO_G        = 6,
-       HTC_MODE_11NA           = 7,
-       HTC_MODE_11NG           = 8
+       HTC_MODE_11NA           = 0,
+       HTC_MODE_11NG           = 1
 };
 
 enum htc_opmode {
@@ -123,18 +116,13 @@ struct ath9k_htc_target_vif {
        u8 pad;
 } __packed;
 
-#define ATH_HTC_STA_AUTH  0x0001
-#define ATH_HTC_STA_QOS   0x0002
-#define ATH_HTC_STA_ERP   0x0004
-#define ATH_HTC_STA_HT    0x0008
-
 struct ath9k_htc_target_sta {
        u8 macaddr[ETH_ALEN];
        u8 bssid[ETH_ALEN];
        u8 sta_index;
        u8 vif_index;
        u8 is_vif_sta;
-       __be16 flags; /* ATH_HTC_STA_* */
+       __be16 flags;
        __be16 htcap;
        __be16 maxampdu;
        u8 pad;
@@ -285,9 +273,9 @@ struct ath9k_htc_rx {
 };
 
 #define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */
-#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 2500 /* ms */
+#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 3000 /* ms */
 #define ATH9K_HTC_TX_RESERVE 10
-#define ATH9K_HTC_TX_TIMEOUT_COUNT 20
+#define ATH9K_HTC_TX_TIMEOUT_COUNT 40
 #define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE)
 
 #define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0)
@@ -450,6 +438,7 @@ struct ath9k_htc_priv {
        u8 vif_sta_pos[ATH9K_HTC_MAX_VIF];
        u8 num_ibss_vif;
        u8 num_sta_vif;
+       u8 num_sta_assoc_vif;
        u8 num_ap_vif;
 
        u16 op_flags;
index 0ded2c66d5ffdd13fe38607794cf65b291d90f32..aa6a73118706753d6d70ac608f8473f7c218c780 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index af57fe5aab98848f52bcd129184181a84c773033..db2352e5cc0d5e660d005ac09204e7c0cc46e8c3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index bfdc8a8871830b5ccb63aa848d69d8121d3745b0..61e6d39507182feda2bc6d02351803f7c5a51e2a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -258,7 +258,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid,
         */
 
        if (IS_AR7010_DEVICE(drv_info))
-               priv->htc->credits = 48;
+               priv->htc->credits = 45;
        else
                priv->htc->credits = 33;
 
@@ -769,11 +769,6 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
        hw->channel_change_time = 5000;
        hw->max_listen_interval = 10;
 
-       if (AR_SREV_9271(priv->ah))
-               hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_9271;
-       else
-               hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_7010;
-
        hw->vif_data_size = sizeof(struct ath9k_htc_vif);
        hw->sta_data_size = sizeof(struct ath9k_htc_sta);
 
index 5aa104fe7eebf26e44d60eee2efcfc21d5129ed0..7b779689543223cb7c110b64cd9e1fc819a25bf6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -26,7 +26,7 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
 {
        enum htc_phymode mode;
 
-       mode = HTC_MODE_AUTO;
+       mode = -EINVAL;
 
        switch (ichan->chanmode) {
        case CHANNEL_G:
@@ -45,6 +45,8 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
                break;
        }
 
+       WARN_ON(mode < 0);
+
        return mode;
 }
 
@@ -500,9 +502,6 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
                tsta.maxampdu = cpu_to_be16(maxampdu);
        }
 
-       if (sta && sta->ht_cap.ht_supported)
-               tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
-
        WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
        if (ret) {
                if (sta)
@@ -582,7 +581,7 @@ int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
        memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
 
        tcap.ampdu_limit = cpu_to_be32(0xffff);
-       tcap.ampdu_subframes = priv->hw->max_tx_aggregation_subframes;
+       tcap.ampdu_subframes = 0xff;
        tcap.enable_coex = enable_coex;
        tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
 
@@ -1165,6 +1164,8 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
 
        ath9k_htc_set_opmode(priv);
 
+       ath9k_htc_set_bssid_mask(priv, vif);
+
        /*
         * Stop ANI only if there are no associated station interfaces.
         */
@@ -1435,6 +1436,37 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
        return ret;
 }
 
+static void ath9k_htc_set_bssid(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+
+       ath9k_hw_write_associd(priv->ah);
+       ath_dbg(common, ATH_DBG_CONFIG,
+               "BSSID: %pM aid: 0x%x\n",
+               common->curbssid, common->curaid);
+}
+
+static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+       if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) {
+               common->curaid = bss_conf->aid;
+               memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+       }
+}
+
+static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv)
+{
+       if (priv->num_sta_assoc_vif == 1) {
+               ieee80211_iterate_active_interfaces_atomic(priv->hw,
+                                                          ath9k_htc_bss_iter, priv);
+               ath9k_htc_set_bssid(priv);
+       }
+}
+
 static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
                                       struct ieee80211_vif *vif,
                                       struct ieee80211_bss_conf *bss_conf,
@@ -1443,43 +1475,32 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
        struct ath9k_htc_priv *priv = hw->priv;
        struct ath_hw *ah = priv->ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       bool set_assoc;
 
        mutex_lock(&priv->mutex);
        ath9k_htc_ps_wakeup(priv);
 
-       /*
-        * Set the HW AID/BSSID only for the first station interface
-        * or in IBSS mode.
-        */
-       set_assoc = !!((priv->ah->opmode == NL80211_IFTYPE_ADHOC) ||
-                      ((priv->ah->opmode == NL80211_IFTYPE_STATION) &&
-                       (priv->num_sta_vif == 1)));
-
-
        if (changed & BSS_CHANGED_ASSOC) {
-               if (set_assoc) {
-                       ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
-                               bss_conf->assoc);
+               ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
+                       bss_conf->assoc);
 
-                       common->curaid = bss_conf->assoc ?
-                               bss_conf->aid : 0;
+               bss_conf->assoc ?
+                       priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--;
 
-                       if (bss_conf->assoc)
+               if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
+                       if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1))
                                ath9k_htc_start_ani(priv);
-                       else
+                       else if (priv->num_sta_assoc_vif == 0)
                                ath9k_htc_stop_ani(priv);
                }
        }
 
        if (changed & BSS_CHANGED_BSSID) {
-               if (set_assoc) {
+               if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
+                       common->curaid = bss_conf->aid;
                        memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
-                       ath9k_hw_write_associd(ah);
-
-                       ath_dbg(common, ATH_DBG_CONFIG,
-                               "BSSID: %pM aid: 0x%x\n",
-                               common->curbssid, common->curaid);
+                       ath9k_htc_set_bssid(priv);
+               } else if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
+                       ath9k_htc_choose_set_bssid(priv);
                }
        }
 
index a898dac22337e559cf46b7f53d2743f2a1341904..2d81c700e201cd4fa3b87cb1414a0b820785c7fc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -875,6 +875,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
                rfilt |= ATH9K_RX_FILTER_CONTROL;
 
        if ((ah->opmode == NL80211_IFTYPE_STATION) &&
+           (priv->nvifs <= 1) &&
            !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC))
                rfilt |= ATH9K_RX_FILTER_MYBEACON;
        else
@@ -888,6 +889,9 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
        if (priv->rxfilter & FIF_PSPOLL)
                rfilt |= ATH9K_RX_FILTER_PSPOLL;
 
+       if (priv->nvifs > 1)
+               rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
+
        return rfilt;
 
 #undef RX_FILTER_PRESERVE
index cee970fdf65256c5124d358b674b977d9201c9b5..1b90ed8795c345a087d59a88a4715a873c3ebf90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 91a5305db95a317eced836e417c9e601de8abdf8..e1ffbb6bd636049686b3181705b236862004d29f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 8b8f0445aef817fc2395bdb5c33a90847cc3e415..2f3e07263fcbaae598b5be8b6c77760e3c566358 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index b75b5dca4e2905dfc020846d1939a01ff47f3d57..72543ce8f616a23b84d2949117ea65d1bd29982c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 7af2773d2bfc38766ec77480aace1f205cb045d2..57435ce627928adaada552ce1aa5636f140ea8cd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index b172d1509515e97881eb9a14945df7cb1830a207..45c585a337e9885b336f1ae50731170f6f63344c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index bd6d2b9d736fbb7b2649bdc3311971f5c9f1a8e0..c2091f1f409616cf6a3d131a19b2f3c2dd341980 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index b60c130917f7e959a356381757c852934c2ada17..8e848c4d16baf536834231633795e3c1c9382abe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 17ebdf1e8b7bc567c20644eb150eec9058012a72..a198ee374b050b6d331107510be54b0618904ccd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -2332,6 +2332,45 @@ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
        return false;
 }
 
+int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
+{
+       struct ath_softc *sc = hw->priv;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ieee80211_vif *vif;
+       struct ath_vif *avp;
+       struct ath_buf *bf;
+       struct ath_tx_status ts;
+       int status;
+
+       vif = sc->beacon.bslot[0];
+       if (!vif)
+               return 0;
+
+       avp = (void *)vif->drv_priv;
+       if (!avp->is_bslot_active)
+               return 0;
+
+       if (!sc->beacon.tx_processed) {
+               tasklet_disable(&sc->bcon_tasklet);
+
+               bf = avp->av_bcbuf;
+               if (!bf || !bf->bf_mpdu)
+                       goto skip;
+
+               status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts);
+               if (status == -EINPROGRESS)
+                       goto skip;
+
+               sc->beacon.tx_processed = true;
+               sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
+
+skip:
+               tasklet_enable(&sc->bcon_tasklet);
+       }
+
+       return sc->beacon.tx_last;
+}
+
 struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
@@ -2356,4 +2395,5 @@ struct ieee80211_ops ath9k_ops = {
        .set_coverage_class = ath9k_set_coverage_class,
        .flush              = ath9k_flush,
        .tx_frames_pending  = ath9k_tx_frames_pending,
+       .tx_last_beacon = ath9k_tx_last_beacon,
 };
index 9c65459be100585e243bb3a3e65c23dab0c6d556..b8cbfc7072137064f443ad0f137b9ccba99c85f4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 9441bf8ca2fd6cf003331d04898e96551a184d6f..8b380305b0fc1acf8c2593acd474daa52f7eb6c9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 4ccbf2ddb5535c27c0699418f723b9314c5e7191..17542214c93f65bfb1727547258f20e11c8440be 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2004 Video54 Technologies, Inc.
- * Copyright (c) 2004-2009 Atheros Communications, Inc.
+ * Copyright (c) 2004-2011 Atheros Communications, Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 5d984b8acdb12540fc531a74186d6b7021f2759c..c3d850207bee0375c9f806cc37fea898e1985bd1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2004 Sam Leffler, Errno Consulting
  * Copyright (c) 2004 Video54 Technologies, Inc.
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 4f52e0429f996718ad1630a597541f803f256079..07e35e59c9e31fa8d9dbb1c6b086c4027e13e2c6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 456f3ec20fef94235ccb724c66419b6a7012d260..c18ee9921fb19ef9000122c21d1da887c5731094 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index f9b1eb4853c4a93a1f964e239a41349e5e7fa0cf..35422fc1f2ce1a566ce11cb0a0d740880531badd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 6095eeb6e025fdd08f971da826e0a5680b3a2f98..fde6da619f30f96e146c00b017e5f37a9df0e80d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index 97dd1fac98b6390591a3baa89f0943e9e50eb92c..3779b8977d4709a9ce68d85a8b2458d472deaea4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
index bb578690935e7f88327bcedf94231219d27cc973..4da01a9f5680feef4726f9a9fbff56914b396045 100644 (file)
@@ -286,6 +286,10 @@ struct ar9170 {
                unsigned int tx_seq_table;
        } fw;
 
+       /* interface configuration combinations */
+       struct ieee80211_iface_limit if_comb_limits[1];
+       struct ieee80211_iface_combination if_combs[1];
+
        /* reset / stuck frames/queue detection */
        struct work_struct restart_work;
        struct work_struct ping_work;
index 9517ede9e2dfdbb104042c3f520e9cb36a18c778..221957c5d37370830eef6c74ae3aacddcbb62f89 100644 (file)
@@ -151,6 +151,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
        const struct carl9170fw_chk_desc *chk_desc;
        const struct carl9170fw_last_desc *last_desc;
        const struct carl9170fw_txsq_desc *txsq_desc;
+       u16 if_comb_types;
 
        last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC,
                sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER);
@@ -268,6 +269,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
        if (SUPP(CARL9170FW_WOL))
                device_set_wakeup_enable(&ar->udev->dev, true);
 
+       if_comb_types = BIT(NL80211_IFTYPE_STATION) |
+                       BIT(NL80211_IFTYPE_P2P_CLIENT);
+
        ar->fw.vif_num = otus_desc->vif_num;
        ar->fw.cmd_bufs = otus_desc->cmd_bufs;
        ar->fw.address = le32_to_cpu(otus_desc->fw_address);
@@ -294,12 +298,25 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
                ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
 
                if (SUPP(CARL9170FW_WLANTX_CAB)) {
-                       ar->hw->wiphy->interface_modes |=
+                       if_comb_types |=
                                BIT(NL80211_IFTYPE_AP) |
                                BIT(NL80211_IFTYPE_P2P_GO);
                }
        }
 
+       ar->if_comb_limits[0].max = ar->fw.vif_num;
+       ar->if_comb_limits[0].types = if_comb_types;
+
+       ar->if_combs[0].num_different_channels = 1;
+       ar->if_combs[0].max_interfaces = ar->fw.vif_num;
+       ar->if_combs[0].limits = ar->if_comb_limits;
+       ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
+
+       ar->hw->wiphy->iface_combinations = ar->if_combs;
+       ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
+
+       ar->hw->wiphy->interface_modes |= if_comb_types;
+
        txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC,
                sizeof(*txsq_desc), CARL9170FW_TXSQ_DESC_CUR_VER);
 
index 7d5c65ea94e6213723ecb7a98f8222d6fa727daf..54d093c2ab44f956b5988d73ae819ed9b398a58b 100644 (file)
@@ -1570,14 +1570,8 @@ void *carl9170_alloc(size_t priv_size)
        INIT_LIST_HEAD(&ar->vif_list);
        init_completion(&ar->tx_flush);
 
-       /*
-        * Note:
-        * IBSS/ADHOC and AP mode are only enabled, if the firmware
-        * supports these modes. The code which will add the
-        * additional interface_modes is in fw.c.
-        */
-       hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-                                    BIT(NL80211_IFTYPE_P2P_CLIENT);
+       /* firmware decides which modes we support */
+       hw->wiphy->interface_modes = 0;
 
        hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
                     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
index cc11d66f15bcc69fd02110ae5eb87b02f5f3948d..3f508e59f146b412246f34becab5862117bfd765 100644 (file)
@@ -43,7 +43,7 @@
  * set of  ~ ( MAC XOR BSSID ) for all bssids we handle.
  *
  * When you do this you are essentially computing the common bits of all your
- * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
+ * BSSes. Later it is assumed the hardware will "and" (&) the BSSID mask with
  * the MAC address to obtain the relevant bits and compare the result with
  * (frame's BSSID & mask) to see if they match.
  *
@@ -71,8 +71,8 @@
  *             On loop iteration for BSSID-02:
  *             bssid_mask &= ~(0001   ^   1001)
  *             bssid_mask =   (1010)  & ~(0001 ^ 1001)
- *             bssid_mask =   (1010)  & ~(1001)
- *             bssid_mask =   (1010)  &  (0110)
+ *             bssid_mask =   (1010)  & ~(1000)
+ *             bssid_mask =   (1010)  &  (0111)
  *             bssid_mask =   0010
  *
  * A bssid_mask of 0010 means "only pay attention to the second least
  *
  * IFRAME-02:  0001 (we should allow)
  *
- *     allow = (0001 & 1010) == 1010
- *
  *     allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
  *  --> allow = (0001 & 0010) ==  (0010 & 0001) ? 1 :0;
- *  --> allow = (0010) == (0010)
+ *  --> allow = (0000) == (0000)
  *  --> allow = 1
  *
  * Other examples:
index ebc93c1bb5e7819b4a275a0c6b1d2de8300312bb..25a78cfb7d15ebb7119264e2ea05e6afb188f7eb 100644 (file)
@@ -567,6 +567,8 @@ struct b43_dma {
        struct b43_dmaring *tx_ring_mcast; /* Multicast */
 
        struct b43_dmaring *rx_ring;
+
+       u32 translation; /* Routing bits */
 };
 
 struct b43_pio_txqueue;
@@ -705,7 +707,7 @@ enum {
 
 /* Data structure for one wireless device (802.11 core) */
 struct b43_wldev {
-       struct ssb_device *dev;
+       struct ssb_device *sdev;
        struct b43_wl *wl;
 
        /* The device initialization status.
@@ -879,22 +881,34 @@ static inline enum ieee80211_band b43_current_band(struct b43_wl *wl)
 
 static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
 {
-       return ssb_read16(dev->dev, offset);
+       return ssb_read16(dev->sdev, offset);
 }
 
 static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
 {
-       ssb_write16(dev->dev, offset, value);
+       ssb_write16(dev->sdev, offset, value);
 }
 
 static inline u32 b43_read32(struct b43_wldev *dev, u16 offset)
 {
-       return ssb_read32(dev->dev, offset);
+       return ssb_read32(dev->sdev, offset);
 }
 
 static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
 {
-       ssb_write32(dev->dev, offset, value);
+       ssb_write32(dev->sdev, offset, value);
+}
+
+static inline void b43_block_read(struct b43_wldev *dev, void *buffer,
+                                size_t count, u16 offset, u8 reg_width)
+{
+       ssb_block_read(dev->sdev, buffer, count, offset, reg_width);
+}
+
+static inline void b43_block_write(struct b43_wldev *dev, const void *buffer,
+                                  size_t count, u16 offset, u8 reg_width)
+{
+       ssb_block_write(dev->sdev, buffer, count, offset, reg_width);
 }
 
 static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
index ff0f5ba14b2cfb60223a19455772fddca719951b..47d44bcff37dccb73705e4a2575470010650f83b 100644 (file)
@@ -80,7 +80,7 @@ static void op32_fill_descriptor(struct b43_dmaring *ring,
        addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
        addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
            >> SSB_DMA_TRANSLATION_SHIFT;
-       addr |= ssb_dma_translation(ring->dev->dev);
+       addr |= ring->dev->dma.translation;
        ctl = bufsize & B43_DMA32_DCTL_BYTECNT;
        if (slot == ring->nr_slots - 1)
                ctl |= B43_DMA32_DCTL_DTABLEEND;
@@ -174,7 +174,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
        addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
        addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
            >> SSB_DMA_TRANSLATION_SHIFT;
-       addrhi |= (ssb_dma_translation(ring->dev->dev) << 1);
+       addrhi |= (ring->dev->dma.translation << 1);
        if (slot == ring->nr_slots - 1)
                ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
        if (start)
@@ -333,10 +333,10 @@ static inline
        dma_addr_t dmaaddr;
 
        if (tx) {
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+               dmaaddr = dma_map_single(ring->dev->sdev->dma_dev,
                                         buf, len, DMA_TO_DEVICE);
        } else {
-               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+               dmaaddr = dma_map_single(ring->dev->sdev->dma_dev,
                                         buf, len, DMA_FROM_DEVICE);
        }
 
@@ -348,10 +348,10 @@ static inline
                          dma_addr_t addr, size_t len, int tx)
 {
        if (tx) {
-               dma_unmap_single(ring->dev->dev->dma_dev,
+               dma_unmap_single(ring->dev->sdev->dma_dev,
                                 addr, len, DMA_TO_DEVICE);
        } else {
-               dma_unmap_single(ring->dev->dev->dma_dev,
+               dma_unmap_single(ring->dev->sdev->dma_dev,
                                 addr, len, DMA_FROM_DEVICE);
        }
 }
@@ -361,7 +361,7 @@ static inline
                                 dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
+       dma_sync_single_for_cpu(ring->dev->sdev->dma_dev,
                                    addr, len, DMA_FROM_DEVICE);
 }
 
@@ -370,7 +370,7 @@ static inline
                                    dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_device(ring->dev->dev->dma_dev,
+       dma_sync_single_for_device(ring->dev->sdev->dma_dev,
                                   addr, len, DMA_FROM_DEVICE);
 }
 
@@ -401,7 +401,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
         */
        if (ring->type == B43_DMA_64BIT)
                flags |= GFP_DMA;
-       ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
+       ring->descbase = dma_alloc_coherent(ring->dev->sdev->dma_dev,
                                            B43_DMA_RINGMEMSIZE,
                                            &(ring->dmabase), flags);
        if (!ring->descbase) {
@@ -415,7 +415,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
 
 static void free_ringmemory(struct b43_dmaring *ring)
 {
-       dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
+       dma_free_coherent(ring->dev->sdev->dma_dev, B43_DMA_RINGMEMSIZE,
                          ring->descbase, ring->dmabase);
 }
 
@@ -523,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
                                  dma_addr_t addr,
                                  size_t buffersize, bool dma_to_device)
 {
-       if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
+       if (unlikely(dma_mapping_error(ring->dev->sdev->dma_dev, addr)))
                return 1;
 
        switch (ring->type) {
@@ -658,7 +658,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
        int err = 0;
        u32 value;
        u32 addrext;
-       u32 trans = ssb_dma_translation(ring->dev->dev);
+       u32 trans = ring->dev->dma.translation;
 
        if (ring->tx) {
                if (ring->type == B43_DMA_64BIT) {
@@ -869,7 +869,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        goto err_kfree_meta;
 
                /* test for ability to dma to txhdr_cache */
-               dma_test = dma_map_single(dev->dev->dma_dev,
+               dma_test = dma_map_single(dev->sdev->dma_dev,
                                          ring->txhdr_cache,
                                          b43_txhdr_size(dev),
                                          DMA_TO_DEVICE);
@@ -884,7 +884,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        if (!ring->txhdr_cache)
                                goto err_kfree_meta;
 
-                       dma_test = dma_map_single(dev->dev->dma_dev,
+                       dma_test = dma_map_single(dev->sdev->dma_dev,
                                                  ring->txhdr_cache,
                                                  b43_txhdr_size(dev),
                                                  DMA_TO_DEVICE);
@@ -898,7 +898,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        }
                }
 
-               dma_unmap_single(dev->dev->dma_dev,
+               dma_unmap_single(dev->sdev->dma_dev,
                                 dma_test, b43_txhdr_size(dev),
                                 DMA_TO_DEVICE);
        }
@@ -1013,9 +1013,9 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
        /* Try to set the DMA mask. If it fails, try falling back to a
         * lower mask, as we can always also support a lower one. */
        while (1) {
-               err = dma_set_mask(dev->dev->dma_dev, mask);
+               err = dma_set_mask(dev->sdev->dma_dev, mask);
                if (!err) {
-                       err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
+                       err = dma_set_coherent_mask(dev->sdev->dma_dev, mask);
                        if (!err)
                                break;
                }
@@ -1055,6 +1055,7 @@ int b43_dma_init(struct b43_wldev *dev)
        err = b43_dma_set_mask(dev, dmamask);
        if (err)
                return err;
+       dma->translation = ssb_dma_translation(dev->sdev);
 
        err = -ENOMEM;
        /* setup TX DMA channels. */
@@ -1084,7 +1085,7 @@ int b43_dma_init(struct b43_wldev *dev)
                goto err_destroy_mcast;
 
        /* No support for the TX status DMA ring. */
-       B43_WARN_ON(dev->dev->id.revision < 5);
+       B43_WARN_ON(dev->sdev->id.revision < 5);
 
        b43dbg(dev->wl, "%u-bit DMA initialized\n",
               (unsigned int)type);
index c587115dd2b9685175e7449ebb0cd118d870488a..0cafafe368af0467f16fd7eb4072010466ce0184 100644 (file)
@@ -138,7 +138,7 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
        led->led_dev.default_trigger = default_trigger;
        led->led_dev.brightness_set = b43_led_brightness_set;
 
-       err = led_classdev_register(dev->dev->dev, &led->led_dev);
+       err = led_classdev_register(dev->sdev->dev, &led->led_dev);
        if (err) {
                b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
                led->wl = NULL;
@@ -215,7 +215,7 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev,
                                  enum b43_led_behaviour *behaviour,
                                  bool *activelow)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u8 sprom[4];
 
        sprom[0] = bus->sprom.gpio0;
index 94e4f1378fc3c5660bd42b008c3e6384768d798d..2ef7d4b3854021fbfcec018225c309efa3d39daa 100644 (file)
@@ -98,7 +98,7 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev,
                rfover |= pga;
                rfover |= lna;
                rfover |= trsw_rx;
-               if ((dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
+               if ((dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
                    && phy->rev > 6)
                        rfover |= B43_PHY_RFOVERVAL_EXTLNA;
 
@@ -387,7 +387,7 @@ struct lo_g_saved_values {
 static void lo_measure_setup(struct b43_wldev *dev,
                             struct lo_g_saved_values *sav)
 {
-       struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+       struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
        struct b43_txpower_lo_control *lo = gphy->lo_control;
index 5a43984bdcea8e2f63294d3dbdd5690cf83caa5e..eb415968698502c597d866ff5a6e3b4f8e36b761 100644 (file)
@@ -548,7 +548,7 @@ void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
 {
        u32 low, high;
 
-       B43_WARN_ON(dev->dev->id.revision < 3);
+       B43_WARN_ON(dev->sdev->id.revision < 3);
 
        /* The hardware guarantees us an atomic read, if we
         * read the low register first. */
@@ -586,7 +586,7 @@ static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
 {
        u32 low, high;
 
-       B43_WARN_ON(dev->dev->id.revision < 3);
+       B43_WARN_ON(dev->sdev->id.revision < 3);
 
        low = tsf;
        high = (tsf >> 32);
@@ -714,7 +714,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
                b43_ram_write(dev, i * 4, buffer[i]);
 
        b43_write16(dev, 0x0568, 0x0000);
-       if (dev->dev->id.revision < 11)
+       if (dev->sdev->id.revision < 11)
                b43_write16(dev, 0x07C0, 0x0000);
        else
                b43_write16(dev, 0x07C0, 0x0100);
@@ -1132,7 +1132,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
        /* Commit write */
        b43_read32(dev, B43_MMIO_MACCTL);
-       if (awake && dev->dev->id.revision >= 5) {
+       if (awake && dev->sdev->id.revision >= 5) {
                /* Wait for the microcode to wake up. */
                for (i = 0; i < 100; i++) {
                        ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
@@ -1144,29 +1144,35 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        }
 }
 
-void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, u32 flags)
 {
        u32 tmslow;
-       u32 macctl;
 
        flags |= B43_TMSLOW_PHYCLKEN;
        flags |= B43_TMSLOW_PHYRESET;
        if (dev->phy.type == B43_PHYTYPE_N)
                flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */
-       ssb_device_enable(dev->dev, flags);
+       ssb_device_enable(dev->sdev, flags);
        msleep(2);              /* Wait for the PLL to turn on. */
 
        /* Now take the PHY out of Reset again */
-       tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+       tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
        tmslow |= SSB_TMSLOW_FGC;
        tmslow &= ~B43_TMSLOW_PHYRESET;
-       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
-       ssb_read32(dev->dev, SSB_TMSLOW);       /* flush */
+       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+       ssb_read32(dev->sdev, SSB_TMSLOW);      /* flush */
        msleep(1);
        tmslow &= ~SSB_TMSLOW_FGC;
-       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
-       ssb_read32(dev->dev, SSB_TMSLOW);       /* flush */
+       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+       ssb_read32(dev->sdev, SSB_TMSLOW);      /* flush */
        msleep(1);
+}
+
+void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+{
+       u32 macctl;
+
+       b43_ssb_wireless_core_reset(dev, flags);
 
        /* Turn Analog ON, but only if we already know the PHY-type.
         * This protects against very early setup where we don't know the
@@ -1215,7 +1221,7 @@ static void drain_txstatus_queue(struct b43_wldev *dev)
 {
        u32 dummy;
 
-       if (dev->dev->id.revision < 5)
+       if (dev->sdev->id.revision < 5)
                return;
        /* Read all entries from the microcode TXstatus FIFO
         * and throw them away.
@@ -1421,9 +1427,9 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
 
        /* Get the mask of available antennas. */
        if (dev->phy.gmode)
-               antenna_mask = dev->dev->bus->sprom.ant_available_bg;
+               antenna_mask = dev->sdev->bus->sprom.ant_available_bg;
        else
-               antenna_mask = dev->dev->bus->sprom.ant_available_a;
+               antenna_mask = dev->sdev->bus->sprom.ant_available_a;
 
        if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
                /* This antenna is not available. Fall back to default. */
@@ -1638,7 +1644,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
        if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
-               if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+               if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
                        /* wl->mutex is enough. */
                        b43_do_beacon_update_trigger_work(dev);
                        mmiowb();
@@ -1683,7 +1689,7 @@ static void b43_update_templates(struct b43_wl *wl)
 static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 {
        b43_time_lock(dev);
-       if (dev->dev->id.revision >= 3) {
+       if (dev->sdev->id.revision >= 3) {
                b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
                b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
        } else {
@@ -2057,7 +2063,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
                B43_WARN_ON(1);
                return -ENOSYS;
        }
-       err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
+       err = request_firmware(&blob, ctx->fwname, ctx->dev->sdev->dev);
        if (err == -ENOENT) {
                snprintf(ctx->errors[ctx->req_type],
                         sizeof(ctx->errors[ctx->req_type]),
@@ -2107,13 +2113,12 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
 {
        struct b43_wldev *dev = ctx->dev;
        struct b43_firmware *fw = &ctx->dev->fw;
-       const u8 rev = ctx->dev->dev->id.revision;
+       const u8 rev = ctx->dev->sdev->id.revision;
        const char *filename;
        u32 tmshigh;
        int err;
 
        /* Get microcode */
-       tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
        if ((rev >= 5) && (rev <= 10))
                filename = "ucode5";
        else if ((rev >= 11) && (rev <= 12))
@@ -2152,6 +2157,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
                if ((rev >= 5) && (rev <= 10)) {
+                       tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
                        if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
                                filename = "a0g1initvals5";
                        else
@@ -2196,6 +2202,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
                if ((rev >= 5) && (rev <= 10)) {
+                       tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
                        if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
                                filename = "a0g1bsinitvals5";
                        else
@@ -2441,7 +2448,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 
        snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
                        dev->fw.rev, dev->fw.patch);
-       wiphy->hw_version = dev->dev->id.coreid;
+       wiphy->hw_version = dev->sdev->id.coreid;
 
        if (b43_is_old_txhdr_format(dev)) {
                /* We're over the deadline, but we keep support for old fw
@@ -2557,10 +2564,20 @@ out:
 /* Initialize the GPIOs
  * http://bcm-specs.sipsolutions.net/GPIO
  */
+static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev)
+{
+       struct ssb_bus *bus = dev->sdev->bus;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+       return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
+#else
+       return bus->chipco.dev;
+#endif
+}
+
 static int b43_gpio_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
-       struct ssb_device *gpiodev, *pcidev = NULL;
+       struct ssb_device *gpiodev;
        u32 mask, set;
 
        b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
@@ -2571,7 +2588,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
 
        mask = 0x0000001F;
        set = 0x0000000F;
-       if (dev->dev->bus->chip_id == 0x4301) {
+       if (dev->sdev->bus->chip_id == 0x4301) {
                mask |= 0x0060;
                set |= 0x0060;
        }
@@ -2582,25 +2599,21 @@ static int b43_gpio_init(struct b43_wldev *dev)
                mask |= 0x0180;
                set |= 0x0180;
        }
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
+       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0200);
                mask |= 0x0200;
                set |= 0x0200;
        }
-       if (dev->dev->id.revision >= 2)
+       if (dev->sdev->id.revision >= 2)
                mask |= 0x0010; /* FIXME: This is redundant. */
 
-#ifdef CONFIG_SSB_DRIVER_PCICORE
-       pcidev = bus->pcicore.dev;
-#endif
-       gpiodev = bus->chipco.dev ? : pcidev;
-       if (!gpiodev)
-               return 0;
-       ssb_write32(gpiodev, B43_GPIO_CONTROL,
-                   (ssb_read32(gpiodev, B43_GPIO_CONTROL)
-                    & mask) | set);
+       gpiodev = b43_ssb_gpio_dev(dev);
+       if (gpiodev)
+               ssb_write32(gpiodev, B43_GPIO_CONTROL,
+                           (ssb_read32(gpiodev, B43_GPIO_CONTROL)
+                            & mask) | set);
 
        return 0;
 }
@@ -2608,16 +2621,11 @@ static int b43_gpio_init(struct b43_wldev *dev)
 /* Turn off all GPIO stuff. Call this on module unload, for example. */
 static void b43_gpio_cleanup(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
-       struct ssb_device *gpiodev, *pcidev = NULL;
+       struct ssb_device *gpiodev;
 
-#ifdef CONFIG_SSB_DRIVER_PCICORE
-       pcidev = bus->pcicore.dev;
-#endif
-       gpiodev = bus->chipco.dev ? : pcidev;
-       if (!gpiodev)
-               return;
-       ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+       gpiodev = b43_ssb_gpio_dev(dev);
+       if (gpiodev)
+               ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
 }
 
 /* http://bcm-specs.sipsolutions.net/EnableMac */
@@ -2689,12 +2697,12 @@ out:
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
 void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
 {
-       u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+       u32 tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
        if (on)
                tmslow |= B43_TMSLOW_MACPHYCLKEN;
        else
                tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
-       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
 }
 
 static void b43_adjust_opmode(struct b43_wldev *dev)
@@ -2733,15 +2741,15 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
        /* Workaround: On old hardware the HW-MAC-address-filter
         * doesn't work properly, so always run promisc in filter
         * it in software. */
-       if (dev->dev->id.revision <= 4)
+       if (dev->sdev->id.revision <= 4)
                ctl |= B43_MACCTL_PROMISC;
 
        b43_write32(dev, B43_MMIO_MACCTL, ctl);
 
        cfp_pretbtt = 2;
        if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
-               if (dev->dev->bus->chip_id == 0x4306 &&
-                   dev->dev->bus->chip_rev == 3)
+               if (dev->sdev->bus->chip_id == 0x4306 &&
+                   dev->sdev->bus->chip_rev == 3)
                        cfp_pretbtt = 100;
                else
                        cfp_pretbtt = 50;
@@ -2899,7 +2907,7 @@ static int b43_chip_init(struct b43_wldev *dev)
                b43_write16(dev, 0x005E, value16);
        }
        b43_write32(dev, 0x0100, 0x01000000);
-       if (dev->dev->id.revision < 5)
+       if (dev->sdev->id.revision < 5)
                b43_write32(dev, 0x010C, 0x01000000);
 
        b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
@@ -2914,7 +2922,7 @@ static int b43_chip_init(struct b43_wldev *dev)
        /* Initially set the wireless operation mode. */
        b43_adjust_opmode(dev);
 
-       if (dev->dev->id.revision < 3) {
+       if (dev->sdev->id.revision < 3) {
                b43_write16(dev, 0x060E, 0x0000);
                b43_write16(dev, 0x0610, 0x8000);
                b43_write16(dev, 0x0604, 0x0000);
@@ -2934,7 +2942,7 @@ static int b43_chip_init(struct b43_wldev *dev)
        b43_mac_phy_clock_set(dev, true);
 
        b43_write16(dev, B43_MMIO_POWERUP_DELAY,
-                   dev->dev->bus->chipco.fast_pwrup_delay);
+                   dev->sdev->bus->chipco.fast_pwrup_delay);
 
        err = 0;
        b43dbg(dev->wl, "Chip initialized\n");
@@ -3097,7 +3105,7 @@ static int b43_validate_chipaccess(struct b43_wldev *dev)
        b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
        b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
 
-       if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
+       if ((dev->sdev->id.revision >= 3) && (dev->sdev->id.revision <= 10)) {
                /* The 32bit register shadows the two 16bit registers
                 * with update sideeffects. Validate this. */
                b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
@@ -3450,7 +3458,7 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 
 static void b43_put_phy_into_reset(struct b43_wldev *dev)
 {
-       struct ssb_device *sdev = dev->dev;
+       struct ssb_device *sdev = dev->sdev;
        u32 tmslow;
 
        tmslow = ssb_read32(sdev, SSB_TMSLOW);
@@ -3946,7 +3954,7 @@ redo:
 
        /* Disable interrupts on the device. */
        b43_set_status(dev, B43_STAT_INITIALIZED);
-       if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
                /* wl->mutex is locked. That is enough. */
                b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
                b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
@@ -3959,11 +3967,11 @@ redo:
        /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
        orig_dev = dev;
        mutex_unlock(&wl->mutex);
-       if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
                b43_sdio_free_irq(dev);
        } else {
-               synchronize_irq(dev->dev->irq);
-               free_irq(dev->dev->irq, dev);
+               synchronize_irq(dev->sdev->irq);
+               free_irq(dev->sdev->irq, dev);
        }
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
@@ -3996,18 +4004,19 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
        B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
 
        drain_txstatus_queue(dev);
-       if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
                err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
                if (err) {
                        b43err(dev->wl, "Cannot request SDIO IRQ\n");
                        goto out;
                }
        } else {
-               err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
+               err = request_threaded_irq(dev->sdev->irq, b43_interrupt_handler,
                                           b43_interrupt_thread_handler,
                                           IRQF_SHARED, KBUILD_MODNAME, dev);
                if (err) {
-                       b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
+                       b43err(dev->wl, "Cannot request IRQ-%d\n",
+                              dev->sdev->irq);
                        goto out;
                }
        }
@@ -4087,10 +4096,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
               analog_type, phy_type, phy_rev);
 
        /* Get RADIO versioning */
-       if (dev->dev->bus->chip_id == 0x4317) {
-               if (dev->dev->bus->chip_rev == 0)
+       if (dev->sdev->bus->chip_id == 0x4317) {
+               if (dev->sdev->bus->chip_rev == 0)
                        tmp = 0x3205017F;
-               else if (dev->dev->bus->chip_rev == 1)
+               else if (dev->sdev->bus->chip_rev == 1)
                        tmp = 0x4205017F;
                else
                        tmp = 0x5205017F;
@@ -4195,7 +4204,7 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev)
 
 static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
 {
-       struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+       struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
        u64 hf;
 
        if (!modparam_btcoex)
@@ -4222,16 +4231,16 @@ static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
 
 static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u32 tmp;
 
        if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) ||
            (bus->chip_id == 0x4312)) {
-               tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
+               tmp = ssb_read32(dev->sdev, SSB_IMCFGLO);
                tmp &= ~SSB_IMCFGLO_REQTO;
                tmp &= ~SSB_IMCFGLO_SERTO;
                tmp |= 0x3;
-               ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+               ssb_write32(dev->sdev, SSB_IMCFGLO, tmp);
                ssb_commit_settings(bus);
        }
 }
@@ -4301,14 +4310,14 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
                dev->wl->current_beacon = NULL;
        }
 
-       ssb_device_disable(dev->dev, 0);
-       ssb_bus_may_powerdown(dev->dev->bus);
+       ssb_device_disable(dev->sdev, 0);
+       ssb_bus_may_powerdown(dev->sdev->bus);
 }
 
 /* Initialize a wireless core */
 static int b43_wireless_core_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct ssb_sprom *sprom = &bus->sprom;
        struct b43_phy *phy = &dev->phy;
        int err;
@@ -4320,7 +4329,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        err = ssb_bus_powerup(bus, 0);
        if (err)
                goto out;
-       if (!ssb_device_is_enabled(dev->dev)) {
+       if (!ssb_device_is_enabled(dev->sdev)) {
                tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
                b43_wireless_core_reset(dev, tmp);
        }
@@ -4330,7 +4339,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        phy->ops->prepare_structs(dev);
 
        /* Enable IRQ routing to this device. */
-       ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
+       ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->sdev);
 
        b43_imcfglo_timeouts_workaround(dev);
        b43_bluetooth_coext_disable(dev);
@@ -4343,7 +4352,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        if (err)
                goto err_busdown;
        b43_shm_write16(dev, B43_SHM_SHARED,
-                       B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
+                       B43_SHM_SH_WLCOREREV, dev->sdev->id.revision);
        hf = b43_hf_read(dev);
        if (phy->type == B43_PHYTYPE_G) {
                hf |= B43_HF_SYMW;
@@ -4390,8 +4399,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        /* Maximum Contention Window */
        b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-       if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
-           (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
+       if ((dev->sdev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
+           (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) ||
            dev->use_pio) {
                dev->__using_pio_transfers = 1;
                err = b43_pio_init(dev);
@@ -4728,7 +4737,7 @@ static void b43_wireless_core_detach(struct b43_wldev *dev)
 static int b43_wireless_core_attach(struct b43_wldev *dev)
 {
        struct b43_wl *wl = dev->wl;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
        int err;
        bool have_2ghz_phy = 0, have_5ghz_phy = 0;
@@ -4747,10 +4756,10 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                goto out;
        }
        /* Get the PHY type. */
-       if (dev->dev->id.revision >= 5) {
+       if (dev->sdev->id.revision >= 5) {
                u32 tmshigh;
 
-               tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+               tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
                have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
                have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
        } else
@@ -4823,7 +4832,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        INIT_WORK(&dev->restart_work, b43_chip_reset);
 
        dev->phy.ops->switch_analog(dev, 0);
-       ssb_device_disable(dev->dev, 0);
+       ssb_device_disable(dev->sdev, 0);
        ssb_bus_may_powerdown(bus);
 
 out:
@@ -4864,7 +4873,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
                goto out;
 
        wldev->use_pio = b43_modparam_pio;
-       wldev->dev = dev;
+       wldev->sdev = dev;
        wldev->wl = wl;
        b43_set_status(wldev, B43_STAT_UNINIT);
        wldev->bad_frames_preempt = modparam_bad_frames_preempt;
@@ -4925,19 +4934,16 @@ static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
        ieee80211_free_hw(hw);
 }
 
-static int b43_wireless_init(struct ssb_device *dev)
+static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
 {
        struct ssb_sprom *sprom = &dev->bus->sprom;
        struct ieee80211_hw *hw;
        struct b43_wl *wl;
-       int err = -ENOMEM;
-
-       b43_sprom_fixup(dev->bus);
 
        hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
        if (!hw) {
                b43err(NULL, "Could not allocate ieee80211 device\n");
-               goto out;
+               return ERR_PTR(-ENOMEM);
        }
        wl = hw_to_b43_wl(hw);
 
@@ -4971,12 +4977,9 @@ static int b43_wireless_init(struct ssb_device *dev)
        INIT_WORK(&wl->tx_work, b43_tx_work);
        skb_queue_head_init(&wl->tx_queue);
 
-       ssb_set_devtypedata(dev, wl);
        b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
                dev->bus->chip_id, dev->id.revision);
-       err = 0;
-out:
-       return err;
+       return wl;
 }
 
 static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
@@ -4989,11 +4992,14 @@ static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
        if (!wl) {
                /* Probing the first core. Must setup common struct b43_wl */
                first = 1;
-               err = b43_wireless_init(dev);
-               if (err)
+               b43_sprom_fixup(dev->bus);
+               wl = b43_wireless_init(dev);
+               if (IS_ERR(wl)) {
+                       err = PTR_ERR(wl);
                        goto out;
-               wl = ssb_get_devtypedata(dev);
-               B43_WARN_ON(!wl);
+               }
+               ssb_set_devtypedata(dev, wl);
+               B43_WARN_ON(ssb_get_devtypedata(dev) != wl);
        }
        err = b43_one_core_attach(dev, wl);
        if (err)
index b6428ec16dd638faf0fe167616ab2c9efb21d91a..b01c8ced57c3938099990b46220431108f521943 100644 (file)
@@ -265,7 +265,7 @@ static void hardware_pctl_init_aphy(struct b43_wldev *dev)
 
 void b43_phy_inita(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
 
        /* This lowlevel A-PHY init is also called from G-PHY init.
@@ -311,7 +311,7 @@ void b43_phy_inita(struct b43_wldev *dev)
        }
 
        if ((phy->type == B43_PHYTYPE_G) &&
-           (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
+           (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
                b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF);
        }
 }
@@ -323,17 +323,17 @@ static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev)
        struct b43_phy_a *aphy = phy->a;
        s16 pab0, pab1, pab2;
 
-       pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
-       pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
-       pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
+       pab0 = (s16) (dev->sdev->bus->sprom.pa1b0);
+       pab1 = (s16) (dev->sdev->bus->sprom.pa1b1);
+       pab2 = (s16) (dev->sdev->bus->sprom.pa1b2);
 
        if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
            pab0 != -1 && pab1 != -1 && pab2 != -1) {
                /* The pabX values are set in SPROM. Use them. */
-               if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
-                   (s8) dev->dev->bus->sprom.itssi_a != -1)
+               if ((s8) dev->sdev->bus->sprom.itssi_a != 0 &&
+                   (s8) dev->sdev->bus->sprom.itssi_a != -1)
                        aphy->tgt_idle_tssi =
-                           (s8) (dev->dev->bus->sprom.itssi_a);
+                           (s8) (dev->sdev->bus->sprom.itssi_a);
                else
                        aphy->tgt_idle_tssi = 62;
                aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
index b5c5ce94d3fd8607c9d06b20d351cd8345a3c7b0..e46b2f4f0920d0ce202dc2b21678603148a5baa8 100644 (file)
@@ -168,7 +168,7 @@ void b43_phy_lock(struct b43_wldev *dev)
        B43_WARN_ON(dev->phy.phy_locked);
        dev->phy.phy_locked = 1;
 #endif
-       B43_WARN_ON(dev->dev->id.revision < 3);
+       B43_WARN_ON(dev->sdev->id.revision < 3);
 
        if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
                b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
@@ -180,7 +180,7 @@ void b43_phy_unlock(struct b43_wldev *dev)
        B43_WARN_ON(!dev->phy.phy_locked);
        dev->phy.phy_locked = 0;
 #endif
-       B43_WARN_ON(dev->dev->id.revision < 3);
+       B43_WARN_ON(dev->sdev->id.revision < 3);
 
        if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
                b43_power_saving_ctl_bits(dev, 0);
@@ -368,8 +368,8 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
        /* The next check will be needed in two seconds, or later. */
        phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2));
 
-       if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-           (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306))
+       if ((dev->sdev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+           (dev->sdev->bus->boardinfo.type == SSB_BOARD_BU4306))
                return; /* No software txpower adjustment needed */
 
        result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI));
index be4828167012d0703f7ebe60d501e9b0f6fd8b6c..1758a282f913548403ee0a6b55dacac832ac92f5 100644 (file)
@@ -718,7 +718,7 @@ static void b43_calc_nrssi_threshold(struct b43_wldev *dev)
        B43_WARN_ON(phy->type != B43_PHYTYPE_G);
 
        if (!phy->gmode ||
-           !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+           !(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
                tmp16 = b43_nrssi_hw_read(dev, 0x20);
                if (tmp16 >= 0x20)
                        tmp16 -= 0x40;
@@ -1114,7 +1114,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
 {
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
-       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
 
        if (!phy->gmode)
                return 0;
@@ -1491,7 +1491,7 @@ static u16 b43_radio_init2050(struct b43_wldev *dev)
 
 static void b43_phy_initb5(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
        u16 offset, value;
@@ -1620,7 +1620,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x5A, 0x88);
                b43_radio_write16(dev, 0x5B, 0x6B);
                b43_radio_write16(dev, 0x5C, 0x0F);
-               if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
+               if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
                        b43_radio_write16(dev, 0x5D, 0xFA);
                        b43_radio_write16(dev, 0x5E, 0xD8);
                } else {
@@ -1787,7 +1787,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
        b43_phy_set(dev, B43_PHY_RFOVER, 0x0100);
        b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xCFFF);
 
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
+       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
                if (phy->rev >= 7) {
                        b43_phy_set(dev, B43_PHY_RFOVER, 0x0800);
                        b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x8000);
@@ -1922,7 +1922,7 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev)
 /* Initialize B/G PHY power control */
 static void b43_phy_init_pctl(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
        struct b43_rfatt old_rfatt;
@@ -2053,7 +2053,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
        if (phy->rev >= 6) {
                b43_phy_maskset(dev, B43_PHY_CCK(0x36), 0x0FFF, (gphy->lo_control->tx_bias << 12));
        }
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
                b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
        else
                b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
@@ -2066,7 +2066,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
        }
 
-       if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+       if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
                /* The specs state to update the NRSSI LT with
                 * the value 0x7FFFFFFF here. I think that is some weird
                 * compiler optimization in the original driver.
@@ -2088,8 +2088,8 @@ static void b43_phy_initg(struct b43_wldev *dev)
        /* FIXME: The spec says in the following if, the 0 should be replaced
           'if OFDM may not be used in the current locale'
           but OFDM is legal everywhere */
-       if ((dev->dev->bus->chip_id == 0x4306
-            && dev->dev->bus->chip_package == 2) || 0) {
+       if ((dev->sdev->bus->chip_id == 0x4306
+            && dev->sdev->bus->chip_package == 2) || 0) {
                b43_phy_mask(dev, B43_PHY_CRS0, 0xBFFF);
                b43_phy_mask(dev, B43_PHY_OFDM(0xC3), 0x7FFF);
        }
@@ -2105,7 +2105,7 @@ void b43_gphy_channel_switch(struct b43_wldev *dev,
        b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
 
        if (channel == 14) {
-               if (dev->dev->bus->sprom.country_code ==
+               if (dev->sdev->bus->sprom.country_code ==
                    SSB_SPROM1CCODE_JAPAN)
                        b43_hf_write(dev,
                                     b43_hf_read(dev) & ~B43_HF_ACPR);
@@ -2136,7 +2136,7 @@ static void default_baseband_attenuation(struct b43_wldev *dev,
 static void default_radio_attenuation(struct b43_wldev *dev,
                                      struct b43_rfatt *rf)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
 
        rf->with_padmix = 0;
@@ -2384,11 +2384,11 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
        struct b43_phy_g *gphy = phy->g;
        s16 pab0, pab1, pab2;
 
-       pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
-       pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
-       pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
+       pab0 = (s16) (dev->sdev->bus->sprom.pa0b0);
+       pab1 = (s16) (dev->sdev->bus->sprom.pa0b1);
+       pab2 = (s16) (dev->sdev->bus->sprom.pa0b2);
 
-       B43_WARN_ON((dev->dev->bus->chip_id == 0x4301) &&
+       B43_WARN_ON((dev->sdev->bus->chip_id == 0x4301) &&
                    (phy->radio_ver != 0x2050)); /* Not supported anymore */
 
        gphy->dyn_tssi_tbl = 0;
@@ -2396,10 +2396,10 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
        if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
            pab0 != -1 && pab1 != -1 && pab2 != -1) {
                /* The pabX values are set in SPROM. Use them. */
-               if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
-                   (s8) dev->dev->bus->sprom.itssi_bg != -1) {
+               if ((s8) dev->sdev->bus->sprom.itssi_bg != 0 &&
+                   (s8) dev->sdev->bus->sprom.itssi_bg != -1) {
                        gphy->tgt_idle_tssi =
-                               (s8) (dev->dev->bus->sprom.itssi_bg);
+                               (s8) (dev->sdev->bus->sprom.itssi_bg);
                } else
                        gphy->tgt_idle_tssi = 62;
                gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
@@ -2840,7 +2840,7 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
                                    B43_TXCTL_TXMIX;
                                rfatt += 2;
                                bbatt += 2;
-                       } else if (dev->dev->bus->sprom.
+                       } else if (dev->sdev->bus->sprom.
                                   boardflags_lo &
                                   B43_BFL_PACTRL) {
                                bbatt += 4 * (rfatt - 2);
@@ -2914,14 +2914,14 @@ static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
        estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi);
 
        B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-       max_pwr = dev->dev->bus->sprom.maxpwr_bg;
-       if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+       max_pwr = dev->sdev->bus->sprom.maxpwr_bg;
+       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
                max_pwr -= 3; /* minus 0.75 */
        if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) {
                b43warn(dev->wl,
                        "Invalid max-TX-power value in SPROM.\n");
                max_pwr = INT_TO_Q52(20); /* fake it */
-               dev->dev->bus->sprom.maxpwr_bg = max_pwr;
+               dev->sdev->bus->sprom.maxpwr_bg = max_pwr;
        }
 
        /* Get desired power (in Q5.2) */
@@ -3014,7 +3014,7 @@ static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
 
-       if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI))
+       if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI))
                return;
 
        b43_mac_suspend(dev);
index fd50eb116243487f532bca9ac24623cdb1e81c93..012c8da2f9447eec120b5c3bd8d97021f4eb3c01 100644 (file)
@@ -86,7 +86,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
 static void lpphy_read_band_sprom(struct b43_wldev *dev)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u16 cckpo, maxpwr;
        u32 ofdmpo;
        int i;
@@ -214,7 +214,7 @@ static void lpphy_table_init(struct b43_wldev *dev)
 
 static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy_lp *lpphy = dev->phy.lp;
        u16 tmp, tmp2;
 
@@ -412,7 +412,7 @@ static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
 
 static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy_lp *lpphy = dev->phy.lp;
 
        b43_phy_write(dev, B43_LPPHY_AFE_DAC_CTL, 0x50);
@@ -519,7 +519,7 @@ struct b2062_freqdata {
 static void lpphy_2062_init(struct b43_wldev *dev)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u32 crystalfreq, tmp, ref;
        unsigned int i;
        const struct b2062_freqdata *fd = NULL;
@@ -697,7 +697,7 @@ static void lpphy_radio_init(struct b43_wldev *dev)
                lpphy_sync_stx(dev);
                b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
                b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
-               if (dev->dev->bus->chip_id == 0x4325) {
+               if (dev->sdev->bus->chip_id == 0x4325) {
                        // TODO SSB PMU recalibration
                }
        }
@@ -1289,7 +1289,7 @@ finish:
 
 static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
        u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
        int i;
@@ -1840,7 +1840,7 @@ static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains,
 static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct lpphy_tx_gains gains, oldgains;
        int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
 
@@ -1870,7 +1870,7 @@ static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
                            bool rx, bool pa, struct lpphy_tx_gains *gains)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        const struct lpphy_rx_iq_comp *iqcomp = NULL;
        struct lpphy_tx_gains nogains, oldgains;
        u16 tmp;
@@ -2408,7 +2408,7 @@ static const struct b206x_channel b2063_chantbl[] = {
 
 static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
 
        b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
        udelay(20);
@@ -2432,7 +2432,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev,
                            unsigned int channel)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        const struct b206x_channel *chandata = NULL;
        u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
        u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
@@ -2522,7 +2522,7 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
 static int lpphy_b2063_tune(struct b43_wldev *dev,
                            unsigned int channel)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
 
        static const struct b206x_channel *chandata = NULL;
        u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
index b075a3f82a43377e9c22a8f54bd4c43854e0c168..9ed65157bef554bcbcd1e857e3d80177a9af60bd 100644 (file)
@@ -299,7 +299,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
 static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
 
        u8 txpi[2], bbmult, i;
        u16 tmp, radio_gain, dac_gain;
@@ -423,8 +423,8 @@ static void b43_radio_init2055_pre(struct b43_wldev *dev)
 static void b43_radio_init2055_post(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
-       struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
+       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
+       struct ssb_boardinfo *binfo = &(dev->sdev->bus->boardinfo);
        int i;
        u16 val;
        bool workaround = false;
@@ -609,12 +609,12 @@ static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force)
        if (dev->phy.type != B43_PHYTYPE_N)
                return;
 
-       tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+       tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
        if (force)
                tmslow |= SSB_TMSLOW_FGC;
        else
                tmslow &= ~SSB_TMSLOW_FGC;
-       ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
 }
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
@@ -959,7 +959,7 @@ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
                b43_phy_write(dev, B43_NPHY_GPIO_LOOEN, 0);
                b43_phy_write(dev, B43_NPHY_GPIO_HIOEN, 0);
 
-               ssb_chipco_gpio_control(&dev->dev->bus->chipco, 0xFC00,
+               ssb_chipco_gpio_control(&dev->sdev->bus->chipco, 0xFC00,
                                        0xFC00);
                b43_write32(dev, B43_MMIO_MACCTL,
                        b43_read32(dev, B43_MMIO_MACCTL) &
@@ -983,7 +983,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
 {
        u16 tmp;
 
-       if (dev->dev->id.revision == 16)
+       if (dev->sdev->id.revision == 16)
                b43_mac_suspend(dev);
 
        tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL);
@@ -993,7 +993,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
        tmp |= (val & mask);
        b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp);
 
-       if (dev->dev->id.revision == 16)
+       if (dev->sdev->id.revision == 16)
                b43_mac_enable(dev);
 
        return tmp;
@@ -1168,7 +1168,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
 static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
 
        /* PHY rev 0, 1, 2 */
        u8 i, j;
@@ -1373,7 +1373,7 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
 static void b43_nphy_workarounds(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_n *nphy = phy->n;
 
@@ -3586,7 +3586,7 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
  */
 int b43_phy_initn(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_n *nphy = phy->n;
        u8 tx_pwr_state;
@@ -3601,7 +3601,7 @@ int b43_phy_initn(struct b43_wldev *dev)
        if ((dev->phy.rev >= 3) &&
           (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
           (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) {
-               chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
+               chipco_set32(&dev->sdev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
        }
        nphy->deaf_count = 0;
        b43_nphy_tables_init(dev);
index aa12273ae716482544f71f0733beb8d70c45ff84..72ab94df7569e79696e475470a33978c3c49c834 100644 (file)
@@ -111,7 +111,7 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev,
                B43_MMIO_PIO11_BASE5,
        };
 
-       if (dev->dev->id.revision >= 11) {
+       if (dev->sdev->id.revision >= 11) {
                B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11));
                return bases_rev11[index];
        }
@@ -121,14 +121,14 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev,
 
 static u16 pio_txqueue_offset(struct b43_wldev *dev)
 {
-       if (dev->dev->id.revision >= 11)
+       if (dev->sdev->id.revision >= 11)
                return 0x18;
        return 0;
 }
 
 static u16 pio_rxqueue_offset(struct b43_wldev *dev)
 {
-       if (dev->dev->id.revision >= 11)
+       if (dev->sdev->id.revision >= 11)
                return 0x38;
        return 8;
 }
@@ -144,7 +144,7 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev,
        if (!q)
                return NULL;
        q->dev = dev;
-       q->rev = dev->dev->id.revision;
+       q->rev = dev->sdev->id.revision;
        q->mmio_base = index_to_pioqueue_base(dev, index) +
                       pio_txqueue_offset(dev);
        q->index = index;
@@ -178,7 +178,7 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev,
        if (!q)
                return NULL;
        q->dev = dev;
-       q->rev = dev->dev->id.revision;
+       q->rev = dev->sdev->id.revision;
        q->mmio_base = index_to_pioqueue_base(dev, index) +
                       pio_rxqueue_offset(dev);
 
@@ -339,7 +339,7 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
        ctl |= B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI;
        b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
 
-       ssb_block_write(dev->dev, data, (data_len & ~1),
+       b43_block_write(dev, data, (data_len & ~1),
                        q->mmio_base + B43_PIO_TXDATA,
                        sizeof(u16));
        if (data_len & 1) {
@@ -351,7 +351,7 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
                b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
                tail[0] = data[data_len - 1];
                tail[1] = 0;
-               ssb_block_write(dev->dev, tail, 2,
+               b43_block_write(dev, tail, 2,
                                q->mmio_base + B43_PIO_TXDATA,
                                sizeof(u16));
        }
@@ -393,7 +393,7 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
               B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31;
        b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
 
-       ssb_block_write(dev->dev, data, (data_len & ~3),
+       b43_block_write(dev, data, (data_len & ~3),
                        q->mmio_base + B43_PIO8_TXDATA,
                        sizeof(u32));
        if (data_len & 3) {
@@ -421,7 +421,7 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
                        break;
                }
                b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
-               ssb_block_write(dev->dev, tail, 4,
+               b43_block_write(dev, tail, 4,
                                q->mmio_base + B43_PIO8_TXDATA,
                                sizeof(u32));
        }
@@ -657,11 +657,11 @@ data_ready:
 
        /* Get the preamble (RX header) */
        if (q->rev >= 8) {
-               ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
+               b43_block_read(dev, rxhdr, sizeof(*rxhdr),
                               q->mmio_base + B43_PIO8_RXDATA,
                               sizeof(u32));
        } else {
-               ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
+               b43_block_read(dev, rxhdr, sizeof(*rxhdr),
                               q->mmio_base + B43_PIO_RXDATA,
                               sizeof(u16));
        }
@@ -697,7 +697,7 @@ data_ready:
        skb_reserve(skb, 2);
        skb_put(skb, len + padding);
        if (q->rev >= 8) {
-               ssb_block_read(dev->dev, skb->data + padding, (len & ~3),
+               b43_block_read(dev, skb->data + padding, (len & ~3),
                               q->mmio_base + B43_PIO8_RXDATA,
                               sizeof(u32));
                if (len & 3) {
@@ -705,7 +705,7 @@ data_ready:
                        BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
 
                        /* Read the last few bytes. */
-                       ssb_block_read(dev->dev, tail, 4,
+                       b43_block_read(dev, tail, 4,
                                       q->mmio_base + B43_PIO8_RXDATA,
                                       sizeof(u32));
                        switch (len & 3) {
@@ -724,7 +724,7 @@ data_ready:
                        }
                }
        } else {
-               ssb_block_read(dev->dev, skb->data + padding, (len & ~1),
+               b43_block_read(dev, skb->data + padding, (len & ~1),
                               q->mmio_base + B43_PIO_RXDATA,
                               sizeof(u16));
                if (len & 1) {
@@ -732,7 +732,7 @@ data_ready:
                        BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
 
                        /* Read the last byte. */
-                       ssb_block_read(dev->dev, tail, 2,
+                       b43_block_read(dev, tail, 2,
                                       q->mmio_base + B43_PIO_RXDATA,
                                       sizeof(u16));
                        skb->data[len + padding - 1] = tail[0];
index 86bc0a0f735cf63fd0218b3628af061a238b77bc..a617efe38289d1157ccccc78fca85dda73b52e5a 100644 (file)
@@ -37,7 +37,7 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        bool enabled;
        bool brought_up = false;
 
@@ -47,7 +47,7 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
                        mutex_unlock(&wl->mutex);
                        return;
                }
-               ssb_device_enable(dev->dev, 0);
+               ssb_device_enable(dev->sdev, 0);
                brought_up = true;
        }
 
@@ -63,7 +63,7 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
        }
 
        if (brought_up) {
-               ssb_device_disable(dev->dev, 0);
+               ssb_device_disable(dev->sdev, 0);
                ssb_bus_may_powerdown(bus);
        }
 
index 09e2dfd7b175a74534de12fe240761f7a3138302..808e25b79703a0151cab0bd46317523768ca160b 100644 (file)
@@ -66,7 +66,7 @@ static void b43_sdio_interrupt_dispatcher(struct sdio_func *func)
 int b43_sdio_request_irq(struct b43_wldev *dev,
                         void (*handler)(struct b43_wldev *dev))
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct sdio_func *func = bus->host_sdio;
        struct b43_sdio *sdio = sdio_get_drvdata(func);
        int err;
@@ -82,7 +82,7 @@ int b43_sdio_request_irq(struct b43_wldev *dev,
 
 void b43_sdio_free_irq(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct sdio_func *func = bus->host_sdio;
        struct b43_sdio *sdio = sdio_get_drvdata(func);
 
index f1ae4e05a32cf3b77b356dbf2ea97b56b6e72c68..57af619725c3e12c3716cae0e0fd7369ae8bcd8a 100644 (file)
@@ -140,7 +140,7 @@ static DEVICE_ATTR(interference, 0644,
 
 int b43_sysfs_register(struct b43_wldev *wldev)
 {
-       struct device *dev = wldev->dev->dev;
+       struct device *dev = wldev->sdev->dev;
 
        B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
 
@@ -149,7 +149,7 @@ int b43_sysfs_register(struct b43_wldev *wldev)
 
 void b43_sysfs_unregister(struct b43_wldev *wldev)
 {
-       struct device *dev = wldev->dev->dev;
+       struct device *dev = wldev->sdev->dev;
 
        device_remove_file(dev, &dev_attr_interference);
 }
index 61027ee84fb537dd2e0276ef518ac66d180907e1..59df3c64af6339e69684a3f048622abac960472f 100644 (file)
@@ -2304,7 +2304,7 @@ void lpphy_rev0_1_table_init(struct b43_wldev *dev)
 
 void lpphy_rev2plus_table_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        int i;
 
        B43_WARN_ON(dev->phy.rev < 2);
@@ -2416,7 +2416,7 @@ void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count,
 
 void lpphy_init_tx_gain_table(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
 
        switch (dev->phy.rev) {
        case 0:
index 9a335da65b423129c54c8245dcdbf890fd531701..8f4db448ec3308a1e6f2ccad03a1277f59e6f610 100644 (file)
@@ -458,7 +458,7 @@ static void b43_wa_rssi_adc(struct b43_wldev *dev)
 
 static void b43_wa_boards_a(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
 
        if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
            bus->boardinfo.type == SSB_BOARD_BU4306 &&
@@ -486,7 +486,7 @@ static void b43_wa_boards_a(struct b43_wldev *dev)
 
 static void b43_wa_boards_g(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->dev->bus;
+       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
 
        if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM ||
index e5be381c17bce02ff4e43269f56c80feb787a8b4..c8f99aebe01f6565a798ef67952bb7cc9c4722c7 100644 (file)
@@ -547,7 +547,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
                        else
                                tmp -= 3;
                } else {
-                       if (dev->dev->bus->sprom.
+                       if (dev->sdev->bus->sprom.
                            boardflags_lo & B43_BFL_RSSI) {
                                if (in_rssi > 63)
                                        in_rssi = 63;
index b4c81931e136b376c8fa3ec5b1634c719591106e..61d4a11f566b4f9e9864f1109369eade4634c50a 100644 (file)
@@ -171,10 +171,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 
 static struct iwl_lib_ops iwl1000_lib = {
        .set_hw_params = iwl1000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
index 89b8da7a6c8bc9ce2d5811a6dd075448ee1237e6..86feec86d13009c9b6266cd7bf102b8f3195af94 100644 (file)
@@ -195,9 +195,9 @@ static int iwl2030_hw_channel_switch(struct iwl_priv *priv,
        struct ieee80211_vif *vif = ctx->vif;
        struct iwl_host_cmd hcmd = {
                .id = REPLY_CHANNEL_SWITCH,
-               .len = sizeof(cmd),
+               .len = { sizeof(cmd), },
                .flags = CMD_SYNC,
-               .data = &cmd,
+               .data = { &cmd, },
        };
 
        cmd.band = priv->band == IEEE80211_BAND_2GHZ;
@@ -252,10 +252,6 @@ static int iwl2030_hw_channel_switch(struct iwl_priv *priv,
 
 static struct iwl_lib_ops iwl2000_lib = {
        .set_hw_params = iwl2000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_bt_setup_deferred_work,
        .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
index 98f81df166e399ecbf674d53e603c7f00db2fd47..a70b8cfafda195a3b92e1f46d2a7e617c3faba0f 100644 (file)
@@ -282,9 +282,9 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
        struct ieee80211_vif *vif = ctx->vif;
        struct iwl_host_cmd hcmd = {
                .id = REPLY_CHANNEL_SWITCH,
-               .len = sizeof(cmd),
+               .len = { sizeof(cmd), },
                .flags = CMD_SYNC,
-               .data = &cmd,
+               .data = { &cmd, },
        };
 
        cmd.band = priv->band == IEEE80211_BAND_2GHZ;
@@ -339,10 +339,6 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
 
 static struct iwl_lib_ops iwl5000_lib = {
        .set_hw_params = iwl5000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
@@ -374,10 +370,6 @@ static struct iwl_lib_ops iwl5000_lib = {
 
 static struct iwl_lib_ops iwl5150_lib = {
        .set_hw_params = iwl5150_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
index a7921f9a03c62488475ee76234918ced431b01b6..f8c710db6e6f90345a8a1f42e7ce1b2d8a7d85aa 100644 (file)
@@ -221,9 +221,9 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
        struct ieee80211_vif *vif = ctx->vif;
        struct iwl_host_cmd hcmd = {
                .id = REPLY_CHANNEL_SWITCH,
-               .len = sizeof(cmd),
+               .len = { sizeof(cmd), },
                .flags = CMD_SYNC,
-               .data = &cmd,
+               .data = { &cmd, },
        };
 
        cmd.band = priv->band == IEEE80211_BAND_2GHZ;
@@ -278,10 +278,6 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
 
 static struct iwl_lib_ops iwl6000_lib = {
        .set_hw_params = iwl6000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
@@ -314,10 +310,6 @@ static struct iwl_lib_ops iwl6000_lib = {
 
 static struct iwl_lib_ops iwl6030_lib = {
        .set_hw_params = iwl6000_hw_set_hw_params,
-       .txq_set_sched = iwlagn_txq_set_sched,
-       .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
-       .txq_free_tfd = iwl_hw_txq_free_tfd,
-       .txq_init = iwl_hw_tx_queue_init,
        .rx_handler_setup = iwlagn_bt_rx_handler_setup,
        .setup_deferred_work = iwlagn_bt_setup_deferred_work,
        .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
index 39d1e47a0978dc15bcb1687f7b63f9aa0e8e2ed1..c9255def10801ca5c320ec255d296d991ddfa834 100644 (file)
@@ -87,14 +87,14 @@ int iwl_send_calib_results(struct iwl_priv *priv)
 
        struct iwl_host_cmd hcmd = {
                .id = REPLY_PHY_CALIBRATION_CMD,
-               .flags = CMD_SIZE_HUGE,
        };
 
        for (i = 0; i < IWL_CALIB_MAX; i++) {
                if ((BIT(i) & priv->hw_params.calib_init_cfg) &&
                    priv->calib_results[i].buf) {
-                       hcmd.len = priv->calib_results[i].buf_len;
-                       hcmd.data = priv->calib_results[i].buf;
+                       hcmd.len[0] = priv->calib_results[i].buf_len;
+                       hcmd.data[0] = priv->calib_results[i].buf;
+                       hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
                        ret = iwl_send_cmd_sync(priv, &hcmd);
                        if (ret) {
                                IWL_ERR(priv, "Error %d iteration %d\n",
@@ -456,9 +456,9 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
        struct iwl_sensitivity_data *data = NULL;
        struct iwl_host_cmd cmd_out = {
                .id = SENSITIVITY_CMD,
-               .len = sizeof(struct iwl_sensitivity_cmd),
+               .len = { sizeof(struct iwl_sensitivity_cmd), },
                .flags = CMD_ASYNC,
-               .data = &cmd,
+               .data = { &cmd, },
        };
 
        data = &(priv->sensitivity_data);
@@ -491,9 +491,9 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
        struct iwl_sensitivity_data *data = NULL;
        struct iwl_host_cmd cmd_out = {
                .id = SENSITIVITY_CMD,
-               .len = sizeof(struct iwl_enhance_sensitivity_cmd),
+               .len = { sizeof(struct iwl_enhance_sensitivity_cmd), },
                .flags = CMD_ASYNC,
-               .data = &cmd,
+               .data = { &cmd, },
        };
 
        data = &(priv->sensitivity_data);
index 8e79653aed9aa799eb169713d2cde2843e920ec7..f803fb62f8bc0abee7a41d3d09ec3bdd35895cbe 100644 (file)
@@ -1140,8 +1140,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_CMD,
-               .len = sizeof(struct iwl_scan_cmd),
-               .flags = CMD_SIZE_HUGE,
+               .len = { sizeof(struct iwl_scan_cmd), },
        };
        struct iwl_scan_cmd *scan;
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
@@ -1425,10 +1424,11 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                return -EIO;
        }
 
-       cmd.len += le16_to_cpu(scan->tx_cmd.len) +
+       cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
            scan->channel_count * sizeof(struct iwl_scan_channel);
-       cmd.data = scan;
-       scan->len = cpu_to_le16(cmd.len);
+       cmd.data[0] = scan;
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+       scan->len = cpu_to_le16(cmd.len[0]);
 
        /* set scan bit here for PAN params */
        set_bit(STATUS_SCAN_HW, &priv->status);
@@ -1520,9 +1520,9 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
        struct iwl_txfifo_flush_cmd flush_cmd;
        struct iwl_host_cmd cmd = {
                .id = REPLY_TXFIFO_FLUSH,
-               .len = sizeof(struct iwl_txfifo_flush_cmd),
+               .len = { sizeof(struct iwl_txfifo_flush_cmd), },
                .flags = CMD_SYNC,
-               .data = &flush_cmd,
+               .data = { &flush_cmd, },
        };
 
        might_sleep();
index 91f26556ac23880ca98461d5fa9b1975f1688d18..592b0cfcf717a7a9f76af9515ae77481dfda47bb 100644 (file)
@@ -335,6 +335,32 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
        return tid;
 }
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_program_fix_rate(struct iwl_priv *priv,
+                               struct iwl_lq_sta *lq_sta)
+{
+       struct iwl_station_priv *sta_priv =
+               container_of(lq_sta, struct iwl_station_priv, lq_sta);
+       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+
+       lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
+       lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+       lq_sta->active_mimo3_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
+
+       lq_sta->dbg_fixed_rate = priv->dbg_fixed_rate;
+
+       IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
+               lq_sta->lq.sta_id, priv->dbg_fixed_rate);
+
+       if (priv->dbg_fixed_rate) {
+               rs_fill_link_cmd(NULL, lq_sta, priv->dbg_fixed_rate);
+               iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
+                               false);
+       }
+}
+#endif
+
 /*
        get the traffic load value for tid
 */
@@ -1046,7 +1072,10 @@ done:
        /* See if there's a better rate or modulation mode to try. */
        if (sta && sta->supp_rates[sband->band])
                rs_rate_scale_perform(priv, skb, sta, lq_sta);
-
+#ifdef CONFIG_MAC80211_DEBUGFS
+       if (priv->dbg_fixed_rate != lq_sta->dbg_fixed_rate)
+               rs_program_fix_rate(priv, lq_sta);
+#endif
        if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
                rs_bt_update_lq(priv, ctx, lq_sta);
 }
@@ -2170,11 +2199,11 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
  * setup rate table in uCode
  * return rate_n_flags as used in the table
  */
-static u32 rs_update_rate_tbl(struct iwl_priv *priv,
-                             struct iwl_rxon_context *ctx,
-                               struct iwl_lq_sta *lq_sta,
-                               struct iwl_scale_tbl_info *tbl,
-                               int index, u8 is_green)
+static void rs_update_rate_tbl(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx,
+                              struct iwl_lq_sta *lq_sta,
+                              struct iwl_scale_tbl_info *tbl,
+                              int index, u8 is_green)
 {
        u32 rate;
 
@@ -2182,8 +2211,6 @@ static u32 rs_update_rate_tbl(struct iwl_priv *priv,
        rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
        rs_fill_link_cmd(priv, lq_sta, rate);
        iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-
-       return rate;
 }
 
 /*
@@ -2212,7 +2239,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        u8 update_lq = 0;
        struct iwl_scale_tbl_info *tbl, *tbl1;
        u16 rate_scale_index_msk = 0;
-       u32 rate;
        u8 is_green = 0;
        u8 active_tbl = 0;
        u8 done_search = 0;
@@ -2299,8 +2325,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                        tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
                        /* get "active" rate info */
                        index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
-                       rate = rs_update_rate_tbl(priv, ctx, lq_sta,
-                                                 tbl, index, is_green);
+                       rs_update_rate_tbl(priv, ctx, lq_sta, tbl,
+                                          index, is_green);
                }
                return;
        }
@@ -2541,8 +2567,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
 lq_update:
        /* Replace uCode's rate table for the destination station. */
        if (update_lq)
-               rate = rs_update_rate_tbl(priv, ctx, lq_sta,
-                                         tbl, index, is_green);
+               rs_update_rate_tbl(priv, ctx, lq_sta, tbl, index, is_green);
 
        if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
                /* Should we stay with this modulation mode,
@@ -2871,6 +2896,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
                lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
        lq_sta->is_agg = 0;
 
+       priv->dbg_fixed_rate = 0;
 #ifdef CONFIG_MAC80211_DEBUGFS
        lq_sta->dbg_fixed_rate = 0;
 #endif
@@ -3045,7 +3071,6 @@ static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
        IWL_DEBUG_RATE(priv, "leave\n");
 }
 
-
 #ifdef CONFIG_MAC80211_DEBUGFS
 static int open_file_generic(struct inode *inode, struct file *file)
 {
@@ -3070,6 +3095,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
                        IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
                } else {
                        lq_sta->dbg_fixed_rate = 0;
+                       priv->dbg_fixed_rate = 0;
                        IWL_ERR(priv,
                            "Invalid antenna selection 0x%X, Valid is 0x%X\n",
                            ant_sel_tx, valid_tx_ant);
@@ -3088,9 +3114,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
        char buf[64];
        size_t buf_size;
        u32 parsed_rate;
-       struct iwl_station_priv *sta_priv =
-               container_of(lq_sta, struct iwl_station_priv, lq_sta);
-       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+
 
        priv = lq_sta->drv;
        memset(buf, 0, sizeof(buf));
@@ -3099,23 +3123,11 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
                return -EFAULT;
 
        if (sscanf(buf, "%x", &parsed_rate) == 1)
-               lq_sta->dbg_fixed_rate = parsed_rate;
+               priv->dbg_fixed_rate = lq_sta->dbg_fixed_rate = parsed_rate;
        else
-               lq_sta->dbg_fixed_rate = 0;
+               priv->dbg_fixed_rate = lq_sta->dbg_fixed_rate = 0;
 
-       lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
-       lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-       lq_sta->active_mimo2_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-       lq_sta->active_mimo3_rate  = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
-
-       IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
-               lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
-
-       if (lq_sta->dbg_fixed_rate) {
-               rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
-               iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
-                               false);
-       }
+       rs_program_fix_rate(priv, lq_sta);
 
        return count;
 }
@@ -3143,7 +3155,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
                        lq_sta->total_failed, lq_sta->total_success,
                        lq_sta->active_legacy_rate);
        desc += sprintf(buff+desc, "fixed rate 0x%X\n",
-                       lq_sta->dbg_fixed_rate);
+                       priv->dbg_fixed_rate);
        desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
            (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
            (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
@@ -3254,14 +3266,10 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
 static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
                        char __user *user_buf, size_t count, loff_t *ppos)
 {
-       char buff[120];
-       int desc = 0;
-
        struct iwl_lq_sta *lq_sta = file->private_data;
-       struct iwl_priv *priv;
        struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
-
-       priv = lq_sta->drv;
+       char buff[120];
+       int desc = 0;
 
        if (is_Ht(tbl->lq_type))
                desc += sprintf(buff+desc,
index 02387430f7fe0dddae5006aa80e59301c19ecaec..a95ad84c537752c7c2c9491cc29eb8531c841b38 100644 (file)
@@ -289,7 +289,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        /* cast away the const for active_rxon in this function */
        struct iwl_rxon_cmd *active = (void *)&ctx->active;
        bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
-       bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
        int ret;
 
        lockdep_assert_held(&priv->mutex);
@@ -389,11 +388,9 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
         * AP station must be done after the BSSID is set to correctly
         * set up filters in the device.
         */
-       if ((old_assoc && new_assoc) || !new_assoc) {
-               ret = iwlagn_rxon_disconn(priv, ctx);
-               if (ret)
-                       return ret;
-       }
+       ret = iwlagn_rxon_disconn(priv, ctx);
+       if (ret)
+               return ret;
 
        if (new_assoc)
                return iwlagn_rxon_connect(priv, ctx);
index 079275f2c64d919102b40c97ad3900ba79899265..0bd722cee5ae0cf3a3f2c8429fa07aa118bfbacf 100644 (file)
@@ -144,7 +144,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
        size_t cmd_size  = sizeof(struct iwl_wep_cmd);
        struct iwl_host_cmd cmd = {
                .id = ctx->wep_key_cmd,
-               .data = wep_cmd,
+               .data = { wep_cmd, },
                .flags = CMD_SYNC,
        };
 
@@ -172,7 +172,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
 
        cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
 
-       cmd.len = cmd_size;
+       cmd.len[0] = cmd_size;
 
        if (not_empty || send_if_empty)
                return iwl_send_cmd(priv, &cmd);
index 342de780a3661dd08f8c41e79eaacfa0f3dbe356..4974cd7837cbecb92a40f6d757eaa42a75235024 100644 (file)
@@ -755,12 +755,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        spin_unlock(&priv->sta_lock);
 
        /* Attach buffers to TFD */
-       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                  txcmd_phys, firstlen, 1, 0);
+       iwlagn_txq_attach_buf_to_tfd(priv, txq, txcmd_phys, firstlen, 1);
        if (secondlen > 0)
-               priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                          phys_addr, secondlen,
-                                                          0, 0);
+               iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
+                                            secondlen, 0);
 
        scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
                                offsetof(struct iwl_tx_cmd, scratch);
@@ -916,7 +914,7 @@ int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
        spin_lock_irqsave(&priv->lock, flags);
 
        /* Turn off all Tx DMA fifos */
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+       iwlagn_txq_set_sched(priv, 0);
 
        /* Tell NIC where to find the "keep warm" buffer */
        iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
@@ -954,7 +952,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
        spin_lock_irqsave(&priv->lock, flags);
 
        /* Turn off all Tx DMA fifos */
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+       iwlagn_txq_set_sched(priv, 0);
 
        /* Tell NIC where to find the "keep warm" buffer */
        iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
@@ -980,7 +978,7 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
        /* Turn off all Tx DMA fifos */
        spin_lock_irqsave(&priv->lock, flags);
 
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+       iwlagn_txq_set_sched(priv, 0);
 
        /* Stop each Tx DMA channel, and wait for it to be idle */
        for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
@@ -1263,7 +1261,7 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
 
                iwlagn_txq_inval_byte_cnt_tbl(priv, txq);
 
-               priv->cfg->ops->lib->txq_free_tfd(priv, txq);
+               iwlagn_txq_free_tfd(priv, txq);
        }
        return nfreed;
 }
index 8bda0e8d666184ab58322cabef88e8424ec47e12..97de5d9de67b5421582ee9c60f9f555f141f3684 100644 (file)
@@ -217,8 +217,8 @@ static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
        struct iwl_calib_cfg_cmd calib_cfg_cmd;
        struct iwl_host_cmd cmd = {
                .id = CALIBRATION_CFG_CMD,
-               .len = sizeof(struct iwl_calib_cfg_cmd),
-               .data = &calib_cfg_cmd,
+               .len = { sizeof(struct iwl_calib_cfg_cmd), },
+               .data = { &calib_cfg_cmd, },
        };
 
        memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
@@ -440,7 +440,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
                        IWL_MASK(0, priv->hw_params.max_txq_num));
 
        /* Activate all Tx DMA/FIFO channels */
-       priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+       iwlagn_txq_set_sched(priv, IWL_MASK(0, 7));
 
        /* map queues to FIFOs */
        if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
index 08e3cae4fa5a1a128fd15af1d8bddbe15b1338fe..11c6c1169e78ad980df93572feed15184a9f2295 100644 (file)
@@ -134,12 +134,10 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
        struct iwl_tx_beacon_cmd *tx_beacon_cmd;
        struct iwl_host_cmd cmd = {
                .id = REPLY_TX_BEACON,
-               .flags = CMD_SIZE_HUGE,
        };
        u32 frame_size;
        u32 rate_flags;
        u32 rate;
-       int err;
 
        /*
         * We have to set up the TX command, the TX Beacon command, and the
@@ -156,17 +154,15 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
        if (WARN_ON(!priv->beacon_skb))
                return -EINVAL;
 
-       /* Allocate beacon memory */
-       tx_beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd) + priv->beacon_skb->len,
-                               GFP_KERNEL);
+       /* Allocate beacon command */
+       if (!priv->beacon_cmd)
+               priv->beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd), GFP_KERNEL);
+       tx_beacon_cmd = priv->beacon_cmd;
        if (!tx_beacon_cmd)
                return -ENOMEM;
 
        frame_size = priv->beacon_skb->len;
 
-       /* Set up TX beacon contents */
-       memcpy(tx_beacon_cmd->frame, priv->beacon_skb->data, frame_size);
-
        /* Set up TX command fields */
        tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
        tx_beacon_cmd->tx.sta_id = priv->beacon_ctx->bcast_sta_id;
@@ -175,7 +171,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
                TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
 
        /* Set up TX beacon command fields */
-       iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame,
+       iwl_set_beacon_tim(priv, tx_beacon_cmd, priv->beacon_skb->data,
                           frame_size);
 
        /* Set up packet rate and flags */
@@ -189,164 +185,14 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
                        rate_flags);
 
        /* Submit command */
-       cmd.len = sizeof(*tx_beacon_cmd) + frame_size;
-       cmd.data = tx_beacon_cmd;
-
-       err = iwl_send_cmd_sync(priv, &cmd);
-
-       /* Free temporary storage */
-       kfree(tx_beacon_cmd);
-
-       return err;
-}
-
-static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
-{
-       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+       cmd.len[0] = sizeof(*tx_beacon_cmd);
+       cmd.data[0] = tx_beacon_cmd;
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+       cmd.len[1] = frame_size;
+       cmd.data[1] = priv->beacon_skb->data;
+       cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
 
-       dma_addr_t addr = get_unaligned_le32(&tb->lo);
-       if (sizeof(dma_addr_t) > sizeof(u32))
-               addr |=
-               ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
-
-       return addr;
-}
-
-static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
-{
-       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-
-       return le16_to_cpu(tb->hi_n_len) >> 4;
-}
-
-static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
-                                 dma_addr_t addr, u16 len)
-{
-       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-       u16 hi_n_len = len << 4;
-
-       put_unaligned_le32(addr, &tb->lo);
-       if (sizeof(dma_addr_t) > sizeof(u32))
-               hi_n_len |= ((addr >> 16) >> 16) & 0xF;
-
-       tb->hi_n_len = cpu_to_le16(hi_n_len);
-
-       tfd->num_tbs = idx + 1;
-}
-
-static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
-{
-       return tfd->num_tbs & 0x1f;
-}
-
-/**
- * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
- * @priv - driver private data
- * @txq - tx queue
- *
- * Does NOT advance any TFD circular buffer read/write indexes
- * Does NOT free the TFD itself (which is within circular buffer)
- */
-void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
-{
-       struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)txq->tfds;
-       struct iwl_tfd *tfd;
-       struct pci_dev *dev = priv->pci_dev;
-       int index = txq->q.read_ptr;
-       int i;
-       int num_tbs;
-
-       tfd = &tfd_tmp[index];
-
-       /* Sanity check on number of chunks */
-       num_tbs = iwl_tfd_get_num_tbs(tfd);
-
-       if (num_tbs >= IWL_NUM_OF_TBS) {
-               IWL_ERR(priv, "Too many chunks: %i\n", num_tbs);
-               /* @todo issue fatal error, it is quite serious situation */
-               return;
-       }
-
-       /* Unmap tx_cmd */
-       if (num_tbs)
-               pci_unmap_single(dev,
-                               dma_unmap_addr(&txq->meta[index], mapping),
-                               dma_unmap_len(&txq->meta[index], len),
-                               PCI_DMA_BIDIRECTIONAL);
-
-       /* Unmap chunks, if any. */
-       for (i = 1; i < num_tbs; i++)
-               pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
-                               iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
-
-       /* free SKB */
-       if (txq->txb) {
-               struct sk_buff *skb;
-
-               skb = txq->txb[txq->q.read_ptr].skb;
-
-               /* can be called from irqs-disabled context */
-               if (skb) {
-                       dev_kfree_skb_any(skb);
-                       txq->txb[txq->q.read_ptr].skb = NULL;
-               }
-       }
-}
-
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
-                                struct iwl_tx_queue *txq,
-                                dma_addr_t addr, u16 len,
-                                u8 reset, u8 pad)
-{
-       struct iwl_queue *q;
-       struct iwl_tfd *tfd, *tfd_tmp;
-       u32 num_tbs;
-
-       q = &txq->q;
-       tfd_tmp = (struct iwl_tfd *)txq->tfds;
-       tfd = &tfd_tmp[q->write_ptr];
-
-       if (reset)
-               memset(tfd, 0, sizeof(*tfd));
-
-       num_tbs = iwl_tfd_get_num_tbs(tfd);
-
-       /* Each TFD can point to a maximum 20 Tx buffers */
-       if (num_tbs >= IWL_NUM_OF_TBS) {
-               IWL_ERR(priv, "Error can not send more than %d chunks\n",
-                         IWL_NUM_OF_TBS);
-               return -EINVAL;
-       }
-
-       if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
-               return -EINVAL;
-
-       if (unlikely(addr & ~IWL_TX_DMA_MASK))
-               IWL_ERR(priv, "Unaligned address = %llx\n",
-                         (unsigned long long)addr);
-
-       iwl_tfd_set_tb(tfd, num_tbs, addr, len);
-
-       return 0;
-}
-
-/*
- * Tell nic where to find circular buffer of Tx Frame Descriptors for
- * given Tx queue, and enable the DMA channel used for that queue.
- *
- * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
- * channels supported in hardware.
- */
-int iwl_hw_tx_queue_init(struct iwl_priv *priv,
-                        struct iwl_tx_queue *txq)
-{
-       int txq_id = txq->q.id;
-
-       /* Circular buffer (TFD queue in DRAM) physical base address */
-       iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
-                            txq->q.dma_addr >> 8);
-
-       return 0;
+       return iwl_send_cmd_sync(priv, &cmd);
 }
 
 static void iwl_bg_beacon_update(struct work_struct *work)
@@ -1776,10 +1622,7 @@ static const char *desc_lookup(u32 num)
 
 void iwl_dump_nic_error_log(struct iwl_priv *priv)
 {
-       u32 data2, line;
-       u32 desc, time, count, base, data1;
-       u32 blink1, blink2, ilink1, ilink2;
-       u32 pc, hcmd;
+       u32 base;
        struct iwl_error_event_table table;
 
        base = priv->device_pointers.error_event_table;
@@ -1802,37 +1645,40 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
 
        iwl_read_targ_mem_words(priv, base, &table, sizeof(table));
 
-       count = table.valid;
-
-       if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+       if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
                IWL_ERR(priv, "Start IWL Error Log Dump:\n");
                IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
-                       priv->status, count);
-       }
-
-       desc = table.error_id;
-       priv->isr_stats.err_code = desc;
-       pc = table.pc;
-       blink1 = table.blink1;
-       blink2 = table.blink2;
-       ilink1 = table.ilink1;
-       ilink2 = table.ilink2;
-       data1 = table.data1;
-       data2 = table.data2;
-       line = table.line;
-       time = table.tsf_low;
-       hcmd = table.hcmd;
-
-       trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
-                                     blink1, blink2, ilink1, ilink2);
-
-       IWL_ERR(priv, "Desc                                  Time       "
-               "data1      data2      line\n");
-       IWL_ERR(priv, "%-28s (0x%04X) %010u 0x%08X 0x%08X %u\n",
-               desc_lookup(desc), desc, time, data1, data2, line);
-       IWL_ERR(priv, "pc      blink1  blink2  ilink1  ilink2  hcmd\n");
-       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n",
-               pc, blink1, blink2, ilink1, ilink2, hcmd);
+                       priv->status, table.valid);
+       }
+
+       priv->isr_stats.err_code = table.error_id;
+
+       trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low,
+                                     table.data1, table.data2, table.line,
+                                     table.blink1, table.blink2, table.ilink1,
+                                     table.ilink2, table.bcon_time, table.gp1,
+                                     table.gp2, table.gp3, table.ucode_ver,
+                                     table.hw_ver, table.brd_ver);
+       IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
+               desc_lookup(table.error_id));
+       IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
+       IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
+       IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
+       IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
+       IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
+       IWL_ERR(priv, "0x%08X | data1\n", table.data1);
+       IWL_ERR(priv, "0x%08X | data2\n", table.data2);
+       IWL_ERR(priv, "0x%08X | line\n", table.line);
+       IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
+       IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
+       IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
+       IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
+       IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
+       IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
+       IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
+       IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
+       IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
+       IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
 }
 
 #define EVENT_START_OFFSET  (4 * sizeof(u32))
@@ -2114,8 +1960,8 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
        struct iwl_calib_cfg_cmd calib_cfg_cmd;
        struct iwl_host_cmd cmd = {
                .id = CALIBRATION_CFG_CMD,
-               .len = sizeof(struct iwl_calib_cfg_cmd),
-               .data = &calib_cfg_cmd,
+               .len = { sizeof(struct iwl_calib_cfg_cmd), },
+               .data = { &calib_cfg_cmd, },
        };
 
        memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
@@ -3395,6 +3241,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
        iwlcore_free_geos(priv);
        iwl_free_channel_map(priv);
        kfree(priv->scan_cmd);
+       kfree(priv->beacon_cmd);
 }
 
 struct ieee80211_ops iwlagn_hw_ops = {
@@ -3812,6 +3659,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
         */
        set_bit(STATUS_EXIT_PENDING, &priv->status);
 
+       iwl_testmode_cleanup(priv);
        iwl_leds_exit(priv);
 
        if (priv->mac80211_registered) {
index fe33fe8aa4185ed0a47bb668048745df7cd32e0b..2495fe7a58cbb5f7d61399c6dacb8ebf358ede73 100644 (file)
@@ -191,12 +191,10 @@ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
 void iwl_setup_rx_handlers(struct iwl_priv *priv);
 
 /* tx */
-void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
                                 struct iwl_tx_queue *txq,
-                                dma_addr_t addr, u16 len, u8 reset, u8 pad);
-int iwl_hw_tx_queue_init(struct iwl_priv *priv,
-                        struct iwl_tx_queue *txq);
+                                dma_addr_t addr, u16 len, u8 reset);
 void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
                              struct ieee80211_tx_info *info);
 int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
@@ -345,6 +343,7 @@ extern int iwl_alive_start(struct iwl_priv *priv);
 #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
 extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len);
 extern void iwl_testmode_init(struct iwl_priv *priv);
+extern void iwl_testmode_cleanup(struct iwl_priv *priv);
 #else
 static inline
 int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
@@ -355,6 +354,10 @@ static inline
 void iwl_testmode_init(struct iwl_priv *priv)
 {
 }
+static inline
+void iwl_testmode_cleanup(struct iwl_priv *priv)
+{
+}
 #endif
 
 #endif /* __iwl_agn_h__ */
index 5fdad6532118884aebdbf9854597cbf2e0928ad6..6ee5f1aa555ca76af578642459fc178189f62db3 100644 (file)
@@ -205,7 +205,6 @@ enum {
 #define QUEUE_TO_SEQ(q)        (((q) & 0x1f) << 8)
 #define SEQ_TO_INDEX(s)        ((s) & 0xff)
 #define INDEX_TO_SEQ(i)        ((i) & 0xff)
-#define SEQ_HUGE_FRAME cpu_to_le16(0x4000)
 #define SEQ_RX_FRAME   cpu_to_le16(0x8000)
 
 /**
@@ -234,9 +233,7 @@ struct iwl_cmd_header {
         *
         *  0:7         tfd index - position within TX queue
         *  8:12        TX queue id
-        *  13          reserved
-        *  14          huge - driver sets this to indicate command is in the
-        *              'huge' storage at the end of the command buffers
+        *  13:14       reserved
         *  15          unsolicited RX or uCode-originated notification
         */
        __le16 sequence;
index 5b5b0cce4a54e7c85d89fb5e45e4b9c7c2853b97..3bb76f6ea41017448c5cc5ce99851c967d66dafe 100644 (file)
@@ -127,16 +127,6 @@ struct iwl_temp_ops {
 struct iwl_lib_ops {
        /* set hw dependent parameters */
        int (*set_hw_params)(struct iwl_priv *priv);
-       /* Handling TX */
-       void (*txq_set_sched)(struct iwl_priv *priv, u32 mask);
-       int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv,
-                                    struct iwl_tx_queue *txq,
-                                    dma_addr_t addr,
-                                    u16 len, u8 reset, u8 pad);
-       void (*txq_free_tfd)(struct iwl_priv *priv,
-                            struct iwl_tx_queue *txq);
-       int (*txq_init)(struct iwl_priv *priv,
-                       struct iwl_tx_queue *txq);
        /* setup Rx handler */
        void (*rx_handler_setup)(struct iwl_priv *priv);
        /* setup deferred work */
index 214e4658c4951ffaff35ddc379b2dec5ffcb0f3e..22a6e3ec7094e651b6afbe8245b778b25881bd77 100644 (file)
@@ -48,8 +48,6 @@
 #include "iwl-agn-rs.h"
 #include "iwl-agn-tt.h"
 
-#define U32_PAD(n)             ((4-(n))&0x3)
-
 struct iwl_tx_queue;
 
 /* CT-KILL constants */
@@ -83,7 +81,7 @@ struct iwl_tx_queue;
 #define MAX_RTS_THRESHOLD         2347U
 #define MAX_MSDU_SIZE            2304U
 #define MAX_MPDU_SIZE            2346U
-#define DEFAULT_BEACON_INTERVAL   100U
+#define DEFAULT_BEACON_INTERVAL   200U
 #define        DEFAULT_SHORT_RETRY_LIMIT 7U
 #define        DEFAULT_LONG_RETRY_LIMIT  4U
 
@@ -112,8 +110,6 @@ struct iwl_cmd_meta {
                         struct iwl_device_cmd *cmd,
                         struct iwl_rx_packet *pkt);
 
-       /* The CMD_SIZE_HUGE flag bit indicates that the command
-        * structure is stored at the end of the shared queue memory. */
        u32 flags;
 
        DEFINE_DMA_UNMAP_ADDR(mapping);
@@ -123,7 +119,23 @@ struct iwl_cmd_meta {
 /*
  * Generic queue structure
  *
- * Contains common data for Rx and Tx queues
+ * Contains common data for Rx and Tx queues.
+ *
+ * Note the difference between n_bd and n_window: the hardware
+ * always assumes 256 descriptors, so n_bd is always 256 (unless
+ * there might be HW changes in the future). For the normal TX
+ * queues, n_window, which is the size of the software queue data
+ * is also 256; however, for the command queue, n_window is only
+ * 32 since we don't need so many commands pending. Since the HW
+ * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
+ * the software buffers (in the variables @meta, @txb in struct
+ * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
+ * in the same struct) have 256.
+ * This means that we end up with the following:
+ *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
+ *  SW entries:           | 0      | ... | 31          |
+ * where N is a number between 0 and 7. This means that the SW
+ * data is a window overlayed over the HW queue.
  */
 struct iwl_queue {
        int n_bd;              /* number of BDs in this queue */
@@ -165,7 +177,7 @@ struct iwl_tx_info {
 
 struct iwl_tx_queue {
        struct iwl_queue q;
-       void *tfds;
+       struct iwl_tfd *tfds;
        struct iwl_device_cmd **cmd;
        struct iwl_cmd_meta *meta;
        struct iwl_tx_info *txb;
@@ -247,7 +259,6 @@ enum {
        CMD_SYNC = 0,
        CMD_SIZE_NORMAL = 0,
        CMD_NO_SKB = 0,
-       CMD_SIZE_HUGE = (1 << 0),
        CMD_ASYNC = (1 << 1),
        CMD_WANT_SKB = (1 << 2),
        CMD_MAPPED = (1 << 3),
@@ -259,8 +270,8 @@ enum {
  * 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).
+ * size of the largest command we send to uCode, except for commands that
+ * aren't fully copied and use other TFD space.
  */
 struct iwl_device_cmd {
        struct iwl_cmd_header hdr;      /* uCode API */
@@ -277,15 +288,21 @@ struct iwl_device_cmd {
 
 #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
 
+#define IWL_MAX_CMD_TFDS       2
+
+enum iwl_hcmd_dataflag {
+       IWL_HCMD_DFL_NOCOPY     = BIT(0),
+};
 
 struct iwl_host_cmd {
-       const void *data;
+       const void *data[IWL_MAX_CMD_TFDS];
        unsigned long reply_page;
        void (*callback)(struct iwl_priv *priv,
                         struct iwl_device_cmd *cmd,
                         struct iwl_rx_packet *pkt);
        u32 flags;
-       u16 len;
+       u16 len[IWL_MAX_CMD_TFDS];
+       u8 dataflags[IWL_MAX_CMD_TFDS];
        u8 id;
 };
 
@@ -688,17 +705,8 @@ static inline int iwl_queue_used(const struct iwl_queue *q, int i)
 }
 
 
-static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
 {
-       /*
-        * This is for init calibration result and scan command which
-        * required buffer > TFD_MAX_PAYLOAD_SIZE,
-        * the big buffer at end of command array
-        */
-       if (is_huge)
-               return q->n_window;     /* must be power of 2 */
-
-       /* Otherwise, use normal size buffers */
        return index & (q->n_window - 1);
 }
 
@@ -1171,6 +1179,14 @@ enum iwl_scan_type {
        IWL_SCAN_OFFCH_TX,
 };
 
+#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
+struct iwl_testmode_trace {
+       u8 *cpu_addr;
+       u8 *trace_addr;
+       dma_addr_t dma_addr;
+       bool trace_enabled;
+};
+#endif
 struct iwl_priv {
 
        /* ieee device used by generic ieee processing code */
@@ -1452,6 +1468,7 @@ struct iwl_priv {
        struct work_struct beacon_update;
        struct iwl_rxon_context *beacon_ctx;
        struct sk_buff *beacon_skb;
+       void *beacon_cmd;
 
        struct work_struct tt_work;
        struct work_struct ct_enter;
@@ -1501,6 +1518,11 @@ struct iwl_priv {
        struct led_classdev led;
        unsigned long blink_on, blink_off;
        bool led_registered;
+#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
+       struct iwl_testmode_trace testmode_trace;
+#endif
+       u32 dbg_fixed_rate;
+
 }; /*iwl_priv */
 
 static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
index f00172cb8a6dda1bc8975dbb6838954bc3f923d4..2c84ba95afca77f70cbdc9171552dacfa7853fcc 100644 (file)
@@ -137,20 +137,27 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
 #define TRACE_SYSTEM iwlwifi
 
 TRACE_EVENT(iwlwifi_dev_hcmd,
-       TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
-       TP_ARGS(priv, hcmd, len, flags),
+       TP_PROTO(struct iwl_priv *priv, u32 flags,
+                const void *hcmd0, size_t len0,
+                const void *hcmd1, size_t len1,
+                const void *hcmd2, size_t len2),
+       TP_ARGS(priv, flags, hcmd0, len0, hcmd1, len1, hcmd2, len2),
        TP_STRUCT__entry(
                PRIV_ENTRY
-               __dynamic_array(u8, hcmd, len)
+               __dynamic_array(u8, hcmd0, len0)
+               __dynamic_array(u8, hcmd1, len1)
+               __dynamic_array(u8, hcmd2, len2)
                __field(u32, flags)
        ),
        TP_fast_assign(
                PRIV_ASSIGN;
-               memcpy(__get_dynamic_array(hcmd), hcmd, len);
+               memcpy(__get_dynamic_array(hcmd0), hcmd0, len0);
+               memcpy(__get_dynamic_array(hcmd1), hcmd1, len1);
+               memcpy(__get_dynamic_array(hcmd2), hcmd2, len2);
                __entry->flags = flags;
        ),
        TP_printk("[%p] hcmd %#.2x (%ssync)",
-                 __entry->priv, ((u8 *)__get_dynamic_array(hcmd))[0],
+                 __entry->priv, ((u8 *)__get_dynamic_array(hcmd0))[0],
                  __entry->flags & CMD_ASYNC ? "a" : "")
 );
 
@@ -202,15 +209,18 @@ TRACE_EVENT(iwlwifi_dev_tx,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_error,
-       TP_PROTO(struct iwl_priv *priv, u32 desc, u32 time,
+       TP_PROTO(struct iwl_priv *priv, u32 desc, u32 tsf_low,
                 u32 data1, u32 data2, u32 line, u32 blink1,
-                u32 blink2, u32 ilink1, u32 ilink2),
-       TP_ARGS(priv, desc, time, data1, data2, line,
-               blink1, blink2, ilink1, ilink2),
+                u32 blink2, u32 ilink1, u32 ilink2, u32 bcon_time,
+                u32 gp1, u32 gp2, u32 gp3, u32 ucode_ver, u32 hw_ver,
+                u32 brd_ver),
+       TP_ARGS(priv, desc, tsf_low, data1, data2, line,
+               blink1, blink2, ilink1, ilink2, bcon_time, gp1, gp2,
+               gp3, ucode_ver, hw_ver, brd_ver),
        TP_STRUCT__entry(
                PRIV_ENTRY
                __field(u32, desc)
-               __field(u32, time)
+               __field(u32, tsf_low)
                __field(u32, data1)
                __field(u32, data2)
                __field(u32, line)
@@ -218,11 +228,18 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
                __field(u32, blink2)
                __field(u32, ilink1)
                __field(u32, ilink2)
+               __field(u32, bcon_time)
+               __field(u32, gp1)
+               __field(u32, gp2)
+               __field(u32, gp3)
+               __field(u32, ucode_ver)
+               __field(u32, hw_ver)
+               __field(u32, brd_ver)
        ),
        TP_fast_assign(
                PRIV_ASSIGN;
                __entry->desc = desc;
-               __entry->time = time;
+               __entry->tsf_low = tsf_low;
                __entry->data1 = data1;
                __entry->data2 = data2;
                __entry->line = line;
@@ -230,12 +247,25 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
                __entry->blink2 = blink2;
                __entry->ilink1 = ilink1;
                __entry->ilink2 = ilink2;
+               __entry->bcon_time = bcon_time;
+               __entry->gp1 = gp1;
+               __entry->gp2 = gp2;
+               __entry->gp3 = gp3;
+               __entry->ucode_ver = ucode_ver;
+               __entry->hw_ver = hw_ver;
+               __entry->brd_ver = brd_ver;
        ),
        TP_printk("[%p] #%02d %010u data 0x%08X 0x%08X line %u, "
-                 "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X",
-                 __entry->priv, __entry->desc, __entry->time, __entry->data1,
+                 "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X "
+                 "bcon_tm %010u gp 0x%08X 0x%08X 0x%08X uCode 0x%08X "
+                 "hw 0x%08X brd 0x%08X",
+                 __entry->priv, __entry->desc, __entry->tsf_low,
+                 __entry->data1,
                  __entry->data2, __entry->line, __entry->blink1,
-                 __entry->blink2, __entry->ilink1, __entry->ilink2)
+                 __entry->blink2, __entry->ilink1, __entry->ilink2,
+                 __entry->bcon_time, __entry->gp1, __entry->gp2,
+                 __entry->gp3, __entry->ucode_ver, __entry->hw_ver,
+                 __entry->brd_ver)
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_event,
index c8397962632c97f2a830205390a0c7350c54a48e..47a56bc1cd12e063bd556c1f19095cda9fabcfcb 100644 (file)
@@ -216,15 +216,14 @@ static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
 
 static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
 {
-       u32 otpgp;
+       iwl_read32(priv, CSR_OTP_GP_REG);
 
-       otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
        if (mode == IWL_OTP_ACCESS_ABSOLUTE)
                iwl_clear_bit(priv, CSR_OTP_GP_REG,
-                               CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+                             CSR_OTP_GP_REG_OTP_ACCESS_MODE);
        else
                iwl_set_bit(priv, CSR_OTP_GP_REG,
-                               CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+                           CSR_OTP_GP_REG_OTP_ACCESS_MODE);
 }
 
 static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
index 8f0beb992ccfb3f0bcf11baa83d92f7cbcf0d431..76f9966231405bf50a97e89ece9381300e30c4d1 100644 (file)
@@ -188,6 +188,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        cmd_idx = iwl_enqueue_hcmd(priv, cmd);
        if (cmd_idx < 0) {
                ret = cmd_idx;
+               clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
                IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
@@ -264,8 +265,8 @@ int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
 {
        struct iwl_host_cmd cmd = {
                .id = id,
-               .len = len,
-               .data = data,
+               .len = { len, },
+               .data = { data, },
        };
 
        return iwl_send_cmd_sync(priv, &cmd);
@@ -279,8 +280,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
 {
        struct iwl_host_cmd cmd = {
                .id = id,
-               .len = len,
-               .data = data,
+               .len = { len, },
+               .data = { data, },
        };
 
        cmd.flags |= CMD_ASYNC;
index 439187f903c9f10f46c0e9f75bc9083624df0e05..7c23beb49d7cd8ba66ef4e4d767c8e77386758df 100644 (file)
@@ -107,8 +107,8 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
 {
        struct iwl_host_cmd cmd = {
                .id = REPLY_LEDS_CMD,
-               .len = sizeof(struct iwl_led_cmd),
-               .data = led_cmd,
+               .len = { sizeof(struct iwl_led_cmd), },
+               .data = { led_cmd, },
                .flags = CMD_ASYNC,
                .callback = NULL,
        };
index 3c8cebde16cc6608facbf2d28dd0b97100b6b637..7df2814fd4f8cf6724e9282641784f5d46f97241 100644 (file)
@@ -141,7 +141,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
        struct iwl_host_cmd cmd = {
                .id = REPLY_ADD_STA,
                .flags = flags,
-               .data = data,
+               .data = { data, },
        };
        u8 sta_id __maybe_unused = sta->sta.sta_id;
 
@@ -155,7 +155,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
                might_sleep();
        }
 
-       cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
+       cmd.len[0] = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
        ret = iwl_send_cmd(priv, &cmd);
 
        if (ret || (flags & CMD_ASYNC))
@@ -401,9 +401,9 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
 
        struct iwl_host_cmd cmd = {
                .id = REPLY_REMOVE_STA,
-               .len = sizeof(struct iwl_rem_sta_cmd),
+               .len = { sizeof(struct iwl_rem_sta_cmd), },
                .flags = CMD_SYNC,
-               .data = &rm_sta_cmd,
+               .data = { &rm_sta_cmd, },
        };
 
        memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
@@ -760,9 +760,9 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
 
        struct iwl_host_cmd cmd = {
                .id = REPLY_TX_LINK_QUALITY_CMD,
-               .len = sizeof(struct iwl_link_quality_cmd),
+               .len = { sizeof(struct iwl_link_quality_cmd), },
                .flags = flags,
-               .data = lq,
+               .data = { lq, },
        };
 
        if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
index 89b6696622c1883ba12cbbbf70a9965aba59b173..69b7e6bf2d6f40adfd1a1a6ab98795730da338f2 100644 (file)
@@ -97,6 +97,13 @@ struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
 
        [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
        [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
+       [IWL_TM_ATTR_TRACE_DATA] = { .type = NLA_UNSPEC, },
+
+       [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
 };
 
 /*
@@ -167,6 +174,31 @@ nla_put_failure:
 void iwl_testmode_init(struct iwl_priv *priv)
 {
        priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
+       priv->testmode_trace.trace_enabled = false;
+}
+
+static void iwl_trace_cleanup(struct iwl_priv *priv)
+{
+       struct device *dev = &priv->pci_dev->dev;
+
+       if (priv->testmode_trace.trace_enabled) {
+               if (priv->testmode_trace.cpu_addr &&
+                   priv->testmode_trace.dma_addr)
+                       dma_free_coherent(dev,
+                                       TRACE_TOTAL_SIZE,
+                                       priv->testmode_trace.cpu_addr,
+                                       priv->testmode_trace.dma_addr);
+               priv->testmode_trace.trace_enabled = false;
+               priv->testmode_trace.cpu_addr = NULL;
+               priv->testmode_trace.trace_addr = NULL;
+               priv->testmode_trace.dma_addr = 0;
+       }
+}
+
+
+void iwl_testmode_cleanup(struct iwl_priv *priv)
+{
+       iwl_trace_cleanup(priv);
 }
 
 /*
@@ -198,10 +230,11 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
        }
 
        cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
-       cmd.data = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
-       cmd.len = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+       cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+       cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
        IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
-                               " len %d\n", cmd.id, cmd.flags, cmd.len);
+                               " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
        /* ok, let's submit the command to ucode */
        return iwl_send_cmd(priv, &cmd);
 }
@@ -388,6 +421,38 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                                "Error starting the device: %d\n", status);
                break;
 
+       case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+               if (priv->eeprom) {
+                       skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                               priv->cfg->base_params->eeprom_size + 20);
+                       if (!skb) {
+                               IWL_DEBUG_INFO(priv,
+                                      "Error allocating memory\n");
+                               return -ENOMEM;
+                       }
+                       NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
+                               IWL_TM_CMD_DEV2APP_EEPROM_RSP);
+                       NLA_PUT(skb, IWL_TM_ATTR_EEPROM,
+                               priv->cfg->base_params->eeprom_size,
+                               priv->eeprom);
+                       status = cfg80211_testmode_reply(skb);
+                       if (status < 0)
+                               IWL_DEBUG_INFO(priv,
+                                              "Error sending msg : %d\n",
+                                              status);
+               } else
+                       return -EFAULT;
+               break;
+
+       case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
+               if (!tb[IWL_TM_ATTR_FIXRATE]) {
+                       IWL_DEBUG_INFO(priv,
+                                      "Error finding fixrate setting\n");
+                       return -ENOMSG;
+               }
+               priv->dbg_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
+               break;
+
        default:
                IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
                return -ENOSYS;
@@ -399,6 +464,102 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
+
+/*
+ * This function handles the user application commands for uCode trace
+ *
+ * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
+ * handlers respectively.
+ *
+ * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
+ * value of the actual command execution is replied to the user application.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct sk_buff *skb;
+       int status = 0;
+       struct device *dev = &priv->pci_dev->dev;
+
+       switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+       case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+               if (priv->testmode_trace.trace_enabled)
+                       return -EBUSY;
+
+               priv->testmode_trace.cpu_addr =
+                       dma_alloc_coherent(dev,
+                                          TRACE_TOTAL_SIZE,
+                                          &priv->testmode_trace.dma_addr,
+                                          GFP_KERNEL);
+               if (!priv->testmode_trace.cpu_addr)
+                       return -ENOMEM;
+               priv->testmode_trace.trace_enabled = true;
+               priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN(
+                       priv->testmode_trace.cpu_addr, 0x100);
+               memset(priv->testmode_trace.trace_addr, 0x03B,
+                       TRACE_BUFF_SIZE);
+               skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                       sizeof(priv->testmode_trace.dma_addr) + 20);
+               if (!skb) {
+                       IWL_DEBUG_INFO(priv,
+                               "Error allocating memory\n");
+                       iwl_trace_cleanup(priv);
+                       return -ENOMEM;
+               }
+               NLA_PUT(skb, IWL_TM_ATTR_TRACE_ADDR,
+                       sizeof(priv->testmode_trace.dma_addr),
+                       (u64 *)&priv->testmode_trace.dma_addr);
+               status = cfg80211_testmode_reply(skb);
+               if (status < 0) {
+                       IWL_DEBUG_INFO(priv,
+                                      "Error sending msg : %d\n",
+                                      status);
+               }
+               break;
+
+       case IWL_TM_CMD_APP2DEV_END_TRACE:
+               iwl_trace_cleanup(priv);
+               break;
+
+       case IWL_TM_CMD_APP2DEV_READ_TRACE:
+               if (priv->testmode_trace.trace_enabled &&
+                   priv->testmode_trace.trace_addr) {
+                       skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+                               20 + TRACE_BUFF_SIZE);
+                       if (skb == NULL) {
+                               IWL_DEBUG_INFO(priv,
+                                       "Error allocating memory\n");
+                               return -ENOMEM;
+                       }
+                       NLA_PUT(skb, IWL_TM_ATTR_TRACE_DATA,
+                               TRACE_BUFF_SIZE,
+                               priv->testmode_trace.trace_addr);
+                       status = cfg80211_testmode_reply(skb);
+                       if (status < 0) {
+                               IWL_DEBUG_INFO(priv,
+                                      "Error sending msg : %d\n", status);
+                       }
+               } else
+                       return -EFAULT;
+               break;
+
+       default:
+               IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
+               return -ENOSYS;
+       }
+       return status;
+
+nla_put_failure:
+       kfree_skb(skb);
+       if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
+           IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
+               iwl_trace_cleanup(priv);
+       return -EMSGSIZE;
+}
+
 /* The testmode gnl message handler that takes the gnl message from the
  * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
  * invoke the corresponding handlers.
@@ -455,9 +616,19 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
        case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
        case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
        case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+       case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+       case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
                IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
                result = iwl_testmode_driver(hw, tb);
                break;
+
+       case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+       case IWL_TM_CMD_APP2DEV_END_TRACE:
+       case IWL_TM_CMD_APP2DEV_READ_TRACE:
+               IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n");
+               result = iwl_testmode_trace(hw, tb);
+               break;
+
        default:
                IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
                result = -ENOSYS;
index 31f8949f2801b701cf409f93ffd68d726deb4115..a88085e9b3615e9739cb021cdfc85adff5e4aed4 100644 (file)
@@ -88,9 +88,15 @@ enum iwl_tm_cmd_t {
        IWL_TM_CMD_APP2DEV_LOAD_INIT_FW,
        IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB,
        IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW,
+       IWL_TM_CMD_APP2DEV_GET_EEPROM,
+       IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
        /* if there is other new command for the driver layer operation,
         * append them here */
 
+       /* commands fom user space for uCode trace operations */
+       IWL_TM_CMD_APP2DEV_BEGIN_TRACE,
+       IWL_TM_CMD_APP2DEV_END_TRACE,
+       IWL_TM_CMD_APP2DEV_READ_TRACE,
 
        /* commands from kernel space to carry the synchronous response
         * to user application */
@@ -99,6 +105,11 @@ enum iwl_tm_cmd_t {
        /* commands from kernel space to multicast the spontaneous messages
         * to user application */
        IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
+
+       /* commands from kernel space to carry the eeprom response
+        * to user application */
+       IWL_TM_CMD_DEV2APP_EEPROM_RSP,
+
        IWL_TM_CMD_MAX,
 };
 
@@ -144,8 +155,31 @@ enum iwl_tm_attr_t {
         * application */
        IWL_TM_ATTR_UCODE_RX_PKT,
 
+       /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_EEPROM,
+        * The mandatory fields are:
+        * IWL_TM_ATTR_EEPROM for the data content responging to the user
+        * application */
+       IWL_TM_ATTR_EEPROM,
+
+       /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_XXX_TRACE,
+        * The mandatory fields are:
+        * IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address
+        */
+       IWL_TM_ATTR_TRACE_ADDR,
+       IWL_TM_ATTR_TRACE_DATA,
+
+       /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
+        * The mandatory fields are:
+        * IWL_TM_ATTR_FIXRATE for the fixed rate
+        */
+       IWL_TM_ATTR_FIXRATE,
+
        IWL_TM_ATTR_MAX,
 };
 
+/* uCode trace buffer */
+#define TRACE_BUFF_SIZE                0x20000
+#define TRACE_BUFF_PADD                0x2000
+#define TRACE_TOTAL_SIZE       (TRACE_BUFF_SIZE + TRACE_BUFF_PADD)
 
 #endif
index e69597ea43e28e1c6ebde79655557e77c23b92d8..686e176b5ebdeb80c992860b49e2e64150892ca0 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <net/mac80211.h>
 #include "iwl-eeprom.h"
+#include "iwl-agn.h"
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-sta.h"
@@ -85,6 +86,158 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
        txq->need_update = 0;
 }
 
+static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
+{
+       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+       dma_addr_t addr = get_unaligned_le32(&tb->lo);
+       if (sizeof(dma_addr_t) > sizeof(u32))
+               addr |=
+               ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
+
+       return addr;
+}
+
+static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
+{
+       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+       return le16_to_cpu(tb->hi_n_len) >> 4;
+}
+
+static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
+                                 dma_addr_t addr, u16 len)
+{
+       struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+       u16 hi_n_len = len << 4;
+
+       put_unaligned_le32(addr, &tb->lo);
+       if (sizeof(dma_addr_t) > sizeof(u32))
+               hi_n_len |= ((addr >> 16) >> 16) & 0xF;
+
+       tb->hi_n_len = cpu_to_le16(hi_n_len);
+
+       tfd->num_tbs = idx + 1;
+}
+
+static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
+{
+       return tfd->num_tbs & 0x1f;
+}
+
+static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta,
+                            struct iwl_tfd *tfd)
+{
+       struct pci_dev *dev = priv->pci_dev;
+       int i;
+       int num_tbs;
+
+       /* Sanity check on number of chunks */
+       num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+       if (num_tbs >= IWL_NUM_OF_TBS) {
+               IWL_ERR(priv, "Too many chunks: %i\n", num_tbs);
+               /* @todo issue fatal error, it is quite serious situation */
+               return;
+       }
+
+       /* Unmap tx_cmd */
+       if (num_tbs)
+               pci_unmap_single(dev,
+                               dma_unmap_addr(meta, mapping),
+                               dma_unmap_len(meta, len),
+                               PCI_DMA_BIDIRECTIONAL);
+
+       /* Unmap chunks, if any. */
+       for (i = 1; i < num_tbs; i++)
+               pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
+                               iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
+}
+
+/**
+ * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ * @priv - driver private data
+ * @txq - tx queue
+ *
+ * Does NOT advance any TFD circular buffer read/write indexes
+ * Does NOT free the TFD itself (which is within circular buffer)
+ */
+void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+       struct iwl_tfd *tfd_tmp = txq->tfds;
+       int index = txq->q.read_ptr;
+
+       iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index]);
+
+       /* free SKB */
+       if (txq->txb) {
+               struct sk_buff *skb;
+
+               skb = txq->txb[txq->q.read_ptr].skb;
+
+               /* can be called from irqs-disabled context */
+               if (skb) {
+                       dev_kfree_skb_any(skb);
+                       txq->txb[txq->q.read_ptr].skb = NULL;
+               }
+       }
+}
+
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+                                struct iwl_tx_queue *txq,
+                                dma_addr_t addr, u16 len,
+                                u8 reset)
+{
+       struct iwl_queue *q;
+       struct iwl_tfd *tfd, *tfd_tmp;
+       u32 num_tbs;
+
+       q = &txq->q;
+       tfd_tmp = txq->tfds;
+       tfd = &tfd_tmp[q->write_ptr];
+
+       if (reset)
+               memset(tfd, 0, sizeof(*tfd));
+
+       num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+       /* Each TFD can point to a maximum 20 Tx buffers */
+       if (num_tbs >= IWL_NUM_OF_TBS) {
+               IWL_ERR(priv, "Error can not send more than %d chunks\n",
+                         IWL_NUM_OF_TBS);
+               return -EINVAL;
+       }
+
+       if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
+               return -EINVAL;
+
+       if (unlikely(addr & ~IWL_TX_DMA_MASK))
+               IWL_ERR(priv, "Unaligned address = %llx\n",
+                         (unsigned long long)addr);
+
+       iwl_tfd_set_tb(tfd, num_tbs, addr, len);
+
+       return 0;
+}
+
+/*
+ * Tell nic where to find circular buffer of Tx Frame Descriptors for
+ * given Tx queue, and enable the DMA channel used for that queue.
+ *
+ * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
+ * channels supported in hardware.
+ */
+static int iwlagn_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+       int txq_id = txq->q.id;
+
+       /* Circular buffer (TFD queue in DRAM) physical base address */
+       iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
+                            txq->q.dma_addr >> 8);
+
+       return 0;
+}
+
 /**
  * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
  */
@@ -97,7 +250,7 @@ void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
                return;
 
         while (q->write_ptr != q->read_ptr) {
-               priv->cfg->ops->lib->txq_free_tfd(priv, txq);
+               iwlagn_txq_free_tfd(priv, txq);
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
        }
 }
@@ -154,7 +307,7 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv)
                return;
 
        while (q->read_ptr != q->write_ptr) {
-               i = get_cmd_index(q, q->read_ptr, 0);
+               i = get_cmd_index(q, q->read_ptr);
 
                if (txq->meta[i].flags & CMD_MAPPED) {
                        pci_unmap_single(priv->pci_dev,
@@ -166,15 +319,6 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv)
 
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
        }
-
-       i = q->n_window;
-       if (txq->meta[i].flags & CMD_MAPPED) {
-               pci_unmap_single(priv->pci_dev,
-                                dma_unmap_addr(&txq->meta[i], mapping),
-                                dma_unmap_len(&txq->meta[i], len),
-                                PCI_DMA_BIDIRECTIONAL);
-               txq->meta[i].flags = 0;
-       }
 }
 
 /**
@@ -194,7 +338,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
        iwl_cmd_queue_unmap(priv);
 
        /* De-alloc array of command/tx buffers */
-       for (i = 0; i <= TFD_CMD_SLOTS; i++)
+       for (i = 0; i < TFD_CMD_SLOTS; i++)
                kfree(txq->cmd[i]);
 
        /* De-alloc circular buffer of TFDs */
@@ -334,33 +478,17 @@ 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).
-        * For the command queue (#4/#9), allocate command space + one big
-        * command for scan, since scan command is very huge; the system will
-        * not have two scans at the same time, so only one is needed.
-        * For normal Tx queues (all other queues), no super-size command
-        * space is needed.
-        */
-       if (txq_id == priv->cmd_queue)
-               actual_slots++;
 
-       txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
+       txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * slots_num,
                            GFP_KERNEL);
-       txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots,
+       txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * slots_num,
                           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_CMD_SIZE;
-
+       for (i = 0; i < slots_num; i++) {
                txq->cmd[i] = kmalloc(len, GFP_KERNEL);
                if (!txq->cmd[i])
                        goto err;
@@ -391,11 +519,11 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
                return ret;
 
        /* Tell device where to find queue */
-       priv->cfg->ops->lib->txq_init(priv, txq);
+       iwlagn_tx_queue_init(priv, txq);
 
        return 0;
 err:
-       for (i = 0; i < actual_slots; i++)
+       for (i = 0; i < slots_num; i++)
                kfree(txq->cmd[i]);
 out_free_arrays:
        kfree(txq->meta);
@@ -420,7 +548,7 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
        iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
 
        /* Tell device where to find queue */
-       priv->cfg->ops->lib->txq_init(priv, txq);
+       iwlagn_tx_queue_init(priv, txq);
 }
 
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
@@ -443,23 +571,49 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        dma_addr_t phys_addr;
        unsigned long flags;
        u32 idx;
-       u16 fix_size;
+       u16 copy_size, cmd_size;
        bool is_ct_kill = false;
+       bool had_nocopy = false;
+       int i;
+       u8 *cmd_dest;
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
+       int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
+       int trace_idx;
+#endif
+
+       if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+               IWL_WARN(priv, "fw recovery, no hcmd send\n");
+               return -EIO;
+       }
 
-       fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+       copy_size = sizeof(out_cmd->hdr);
+       cmd_size = sizeof(out_cmd->hdr);
+
+       /* need one for the header if the first is NOCOPY */
+       BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
+
+       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               if (!cmd->len[i])
+                       continue;
+               if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
+                       had_nocopy = true;
+               } else {
+                       /* NOCOPY must not be followed by normal! */
+                       if (WARN_ON(had_nocopy))
+                               return -EINVAL;
+                       copy_size += cmd->len[i];
+               }
+               cmd_size += cmd->len[i];
+       }
 
        /*
         * If any of the command structures end up being larger than
-        * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
-        * we will need to increase the size of the TFD entries
-        * Also, check to see if command buffer should not exceed the size
-        * of device_cmd and max_cmd_size.
+        * the TFD_MAX_PAYLOAD_SIZE and they aren't dynamically
+        * allocated into separate TFDs, then we will need to
+        * increase the size of the buffers.
         */
-       if (WARN_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
-                   !(cmd->flags & CMD_SIZE_HUGE)))
-               return -EINVAL;
-
-       if (WARN_ON(fix_size > IWL_MAX_CMD_SIZE))
+       if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
                return -EINVAL;
 
        if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
@@ -468,14 +622,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                return -EIO;
        }
 
-       /*
-        * As we only have a single huge buffer, check that the command
-        * is synchronous (otherwise buffers could end up being reused).
-        */
-
-       if (WARN_ON((cmd->flags & CMD_ASYNC) && (cmd->flags & CMD_SIZE_HUGE)))
-               return -EINVAL;
-
        spin_lock_irqsave(&priv->hcmd_lock, flags);
 
        if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
@@ -490,7 +636,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                return -ENOSPC;
        }
 
-       idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
+       idx = get_cmd_index(q, q->write_ptr);
        out_cmd = txq->cmd[idx];
        out_meta = &txq->meta[idx];
 
@@ -505,57 +651,84 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        if (cmd->flags & CMD_ASYNC)
                out_meta->callback = cmd->callback;
 
-       out_cmd->hdr.cmd = cmd->id;
-       memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
-
-       /* At this point, the out_cmd now has all of the incoming cmd
-        * information */
+       /* set up the header */
 
+       out_cmd->hdr.cmd = cmd->id;
        out_cmd->hdr.flags = 0;
        out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) |
-                       INDEX_TO_SEQ(q->write_ptr));
-       if (cmd->flags & CMD_SIZE_HUGE)
-               out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       switch (out_cmd->hdr.cmd) {
-       case REPLY_TX_LINK_QUALITY_CMD:
-       case SENSITIVITY_CMD:
-               IWL_DEBUG_HC_DUMP(priv, "Sending command %s (#%x), seq: 0x%04X, "
-                               "%d bytes at %d[%d]:%d\n",
-                               get_cmd_string(out_cmd->hdr.cmd),
-                               out_cmd->hdr.cmd,
-                               le16_to_cpu(out_cmd->hdr.sequence), fix_size,
-                               q->write_ptr, idx, priv->cmd_queue);
-               break;
-       default:
-               IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
-                               "%d bytes at %d[%d]:%d\n",
-                               get_cmd_string(out_cmd->hdr.cmd),
-                               out_cmd->hdr.cmd,
-                               le16_to_cpu(out_cmd->hdr.sequence), fix_size,
-                               q->write_ptr, idx, priv->cmd_queue);
+                                           INDEX_TO_SEQ(q->write_ptr));
+
+       /* and copy the data that needs to be copied */
+
+       cmd_dest = &out_cmd->cmd.payload[0];
+       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               if (!cmd->len[i])
+                       continue;
+               if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
+                       break;
+               memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
+               cmd_dest += cmd->len[i];
        }
-#endif
+
+       IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
+                       "%d bytes at %d[%d]:%d\n",
+                       get_cmd_string(out_cmd->hdr.cmd),
+                       out_cmd->hdr.cmd,
+                       le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
+                       q->write_ptr, idx, priv->cmd_queue);
+
        phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
-                                  fix_size, PCI_DMA_BIDIRECTIONAL);
+                                  copy_size, PCI_DMA_BIDIRECTIONAL);
        if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
                idx = -ENOMEM;
                goto out;
        }
 
        dma_unmap_addr_set(out_meta, mapping, phys_addr);
-       dma_unmap_len_set(out_meta, len, fix_size);
+       dma_unmap_len_set(out_meta, len, copy_size);
+
+       iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, copy_size, 1);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       trace_bufs[0] = &out_cmd->hdr;
+       trace_lens[0] = copy_size;
+       trace_idx = 1;
+#endif
+
+       for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               if (!cmd->len[i])
+                       continue;
+               if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
+                       continue;
+               phys_addr = pci_map_single(priv->pci_dev, (void *)cmd->data[i],
+                                          cmd->len[i], PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(priv->pci_dev, phys_addr)) {
+                       iwlagn_unmap_tfd(priv, out_meta,
+                                        &txq->tfds[q->write_ptr]);
+                       idx = -ENOMEM;
+                       goto out;
+               }
+
+               iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
+                                            cmd->len[i], 0);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+               trace_bufs[trace_idx] = cmd->data[i];
+               trace_lens[trace_idx] = cmd->len[i];
+               trace_idx++;
+#endif
+       }
 
        out_meta->flags = cmd->flags | CMD_MAPPED;
 
        txq->need_update = 1;
 
-       trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
-
-       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                  phys_addr, fix_size, 1,
-                                                  U32_PAD(cmd->len));
+       /* check that tracing gets all possible blocks */
+       BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+       trace_iwlwifi_dev_hcmd(priv, cmd->flags,
+                              trace_bufs[0], trace_lens[0],
+                              trace_bufs[1], trace_lens[1],
+                              trace_bufs[2], trace_lens[2]);
+#endif
 
        /* Increment and update queue's write index */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
@@ -573,8 +746,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
  * need to be reclaimed. As result, some free space forms.  If there is
  * enough free space (> low mark), wake the stack that feeds us.
  */
-static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
-                                  int idx, int cmd_idx)
+static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx)
 {
        struct iwl_tx_queue *txq = &priv->txq[txq_id];
        struct iwl_queue *q = &txq->q;
@@ -614,7 +786,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        int txq_id = SEQ_TO_QUEUE(sequence);
        int index = SEQ_TO_INDEX(sequence);
        int cmd_index;
-       bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
        struct iwl_device_cmd *cmd;
        struct iwl_cmd_meta *meta;
        struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
@@ -632,14 +803,11 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
                return;
        }
 
-       cmd_index = get_cmd_index(&txq->q, index, huge);
+       cmd_index = get_cmd_index(&txq->q, index);
        cmd = txq->cmd[cmd_index];
        meta = &txq->meta[cmd_index];
 
-       pci_unmap_single(priv->pci_dev,
-                        dma_unmap_addr(meta, mapping),
-                        dma_unmap_len(meta, len),
-                        PCI_DMA_BIDIRECTIONAL);
+       iwlagn_unmap_tfd(priv, meta, &txq->tfds[index]);
 
        /* Input error checking is done when commands are added to queue. */
        if (meta->flags & CMD_WANT_SKB) {
@@ -650,7 +818,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 
        spin_lock_irqsave(&priv->hcmd_lock, flags);
 
-       iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
+       iwl_hcmd_queue_reclaim(priv, txq_id, index);
 
        if (!(meta->flags & CMD_ASYNC)) {
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
index 5665a1a9b99ef0ac511e5bafe68d3f7d19f1333f..a414768f40f11e7e002beae44d292972547cfbde 100644 (file)
@@ -565,7 +565,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
                    && iwm->conf.mode == UMAC_MODE_BSS) {
                        cancel_delayed_work(&iwm->disconnect);
-                       cfg80211_roamed(iwm_to_ndev(iwm),
+                       cfg80211_roamed(iwm_to_ndev(iwm), NULL,
                                        complete->bssid,
                                        iwm->req_ie, iwm->req_ie_len,
                                        iwm->resp_ie, iwm->resp_ie_len,
@@ -586,7 +586,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                                                WLAN_STATUS_SUCCESS,
                                                GFP_KERNEL);
                else
-                       cfg80211_roamed(iwm_to_ndev(iwm),
+                       cfg80211_roamed(iwm_to_ndev(iwm), NULL,
                                        complete->bssid,
                                        iwm->req_ie, iwm->req_ie_len,
                                        iwm->resp_ie, iwm->resp_ie_len,
index d3d5e0853c45822b8b58fa131732d7aca55d7e7c..f807447e4d993cf1fae0befdd13e57b4aa25f764 100644 (file)
@@ -196,6 +196,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                if (skb_src)
                        pra_list->total_pkts_size -= skb_src->len;
 
+               atomic_dec(&priv->wmm.tx_pkts_queued);
+
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
                mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad);
@@ -257,6 +259,8 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
 
                pra_list->total_pkts_size += skb_aggr->len;
 
+               atomic_inc(&priv->wmm.tx_pkts_queued);
+
                tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
index 672701dc2721b56575dc6ba11e1964c494aebf9a..8316b3cd92cdf421975c96ffd9955cc62ae49483 100644 (file)
@@ -69,7 +69,8 @@ struct mwifiex_drv_mode {
 #define MWIFIEX_TIMER_10S                      10000
 #define MWIFIEX_TIMER_1S                       1000
 
-#define MAX_TX_PENDING      60
+#define MAX_TX_PENDING      100
+#define LOW_TX_PENDING      80
 
 #define MWIFIEX_UPLD_SIZE               (2312)
 
@@ -202,6 +203,7 @@ struct mwifiex_tid_tbl {
 #define WMM_HIGHEST_PRIORITY           7
 #define HIGH_PRIO_TID                          7
 #define LOW_PRIO_TID                           0
+#define NO_PKT_PRIO_TID                                (-1)
 
 struct mwifiex_wmm_desc {
        struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
@@ -213,7 +215,10 @@ struct mwifiex_wmm_desc {
        u32 drv_pkt_delay_max;
        u8 queue_priority[IEEE80211_MAX_QUEUES];
        u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1];     /* UP: 0 to 7 */
-
+       /* Number of transmit packets queued */
+       atomic_t tx_pkts_queued;
+       /* Tracks highest priority with a packet queued */
+       atomic_t highest_queued_prio;
 };
 
 struct mwifiex_802_11_security {
index 210120889dfe446c86b000d8f66e5d6e528a6847..aaa50c0741965c4bd7f3f39748a6ba856b1afb07 100644 (file)
@@ -140,7 +140,9 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
        } else {
                priv->stats.tx_errors++;
        }
-       atomic_dec(&adapter->tx_pending);
+
+       if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
+               goto done;
 
        for (i = 0; i < adapter->priv_num; i++) {
 
index faa09e32902eb140344da184af90a2fdf4e54afe..91634daec306c093928a7718c176d734b7bf07aa 100644 (file)
@@ -177,14 +177,20 @@ static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv)
  * This function map ACs to TIDs.
  */
 static void
-mwifiex_wmm_queue_priorities_tid(u8 queue_priority[])
+mwifiex_wmm_queue_priorities_tid(struct mwifiex_wmm_desc *wmm)
 {
+       u8 *queue_priority = wmm->queue_priority;
        int i;
 
        for (i = 0; i < 4; ++i) {
                tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
                tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
        }
+
+       for (i = 0; i < MAX_NUM_TID; ++i)
+               tos_to_tid_inv[tos_to_tid[i]] = (u8)i;
+
+       atomic_set(&wmm->highest_queued_prio, HIGH_PRIO_TID);
 }
 
 /*
@@ -246,7 +252,7 @@ mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
                }
        }
 
-       mwifiex_wmm_queue_priorities_tid(priv->wmm.queue_priority);
+       mwifiex_wmm_queue_priorities_tid(&priv->wmm);
 }
 
 /*
@@ -399,6 +405,9 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
                priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
                priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
                priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
+
+               atomic_set(&priv->wmm.tx_pkts_queued, 0);
+               atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
        }
 }
 
@@ -408,17 +417,13 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
 int
 mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
 {
-       int i, j;
+       int i;
        struct mwifiex_private *priv;
 
-       for (j = 0; j < adapter->priv_num; ++j) {
-               priv = adapter->priv[j];
-               if (priv) {
-                       for (i = 0; i < MAX_NUM_TID; i++)
-                               if (!mwifiex_wmm_is_ra_list_empty(
-                                            &priv->wmm.tid_tbl_ptr[i].ra_list))
-                                       return false;
-               }
+       for (i = 0; i < adapter->priv_num; ++i) {
+               priv = adapter->priv[i];
+               if (priv && atomic_read(&priv->wmm.tx_pkts_queued))
+                               return false;
        }
 
        return true;
@@ -468,6 +473,9 @@ static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv)
        for (i = 0; i < MAX_NUM_TID; i++)
                mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].
                                                     ra_list);
+
+       atomic_set(&priv->wmm.tx_pkts_queued, 0);
+       atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
 }
 
 /*
@@ -638,6 +646,13 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
 
        ra_list->total_pkts_size += skb->len;
 
+       atomic_inc(&priv->wmm.tx_pkts_queued);
+
+       if (atomic_read(&priv->wmm.highest_queued_prio) <
+                                               tos_to_tid_inv[tid_down])
+               atomic_set(&priv->wmm.highest_queued_prio,
+                                               tos_to_tid_inv[tid_down]);
+
        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
 }
 
@@ -863,9 +878,14 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                }
 
                do {
+                       atomic_t *hqp;
+                       spinlock_t *lock;
+
                        priv_tmp = bssprio_node->priv;
+                       hqp = &priv_tmp->wmm.highest_queued_prio;
+                       lock = &priv_tmp->wmm.ra_list_spinlock;
 
-                       for (i = HIGH_PRIO_TID; i >= LOW_PRIO_TID; --i) {
+                       for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
 
                                tid_ptr = &(priv_tmp)->wmm.
                                        tid_tbl_ptr[tos_to_tid[i]];
@@ -903,6 +923,11 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                                        is_list_empty =
                                                skb_queue_empty(&ptr->skb_head);
                                        if (!is_list_empty) {
+                                               spin_lock_irqsave(lock, flags);
+                                               if (atomic_read(hqp) > i)
+                                                       atomic_set(hqp, i);
+                                               spin_unlock_irqrestore(lock,
+                                                                       flags);
                                                *priv = priv_tmp;
                                                *tid = tos_to_tid[i];
                                                return ptr;
@@ -921,6 +946,12 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
                                } while (ptr != head);
                        }
 
+                       /* No packet at any TID for this priv. Mark as such
+                        * to skip checking TIDs for this priv (until pkt is
+                        * added).
+                        */
+                       atomic_set(hqp, NO_PKT_PRIO_TID);
+
                        /* Get next bss priority node */
                        bssprio_node = list_first_entry(&bssprio_node->list,
                                                struct mwifiex_bss_prio_node,
@@ -1028,6 +1059,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
                                .bss_prio_cur->list,
                                struct mwifiex_bss_prio_node,
                                list);
+               atomic_dec(&priv->wmm.tx_pkts_queued);
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
        }
@@ -1134,6 +1166,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
                                .bss_prio_cur->list,
                                struct mwifiex_bss_prio_node,
                                list);
+               atomic_dec(&priv->wmm.tx_pkts_queued);
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
        }
@@ -1227,5 +1260,5 @@ mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter)
 
                if (mwifiex_dequeue_tx_packet(adapter))
                        break;
-       } while (true);
+       } while (!mwifiex_wmm_lists_empty(adapter));
 }
index e18358725b69813077de8d9e55f8a98d5fa7a021..a8f3bc740dfaf8354abff344f5ab7665bd8faf58 100644 (file)
@@ -82,6 +82,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
        {USB_DEVICE(0x06b9, 0x0121)},   /* Thomson SpeedTouch 121g */
        {USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
        {USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
+       {USB_DEVICE(0x083a, 0xc501)},   /* Zoom Wireless-G 4410 */
        {USB_DEVICE(0x083a, 0xf503)},   /* Accton FD7050E ver 1010ec  */
        {USB_DEVICE(0x0846, 0x4240)},   /* Netgear WG111 (v2) */
        {USB_DEVICE(0x0915, 0x2000)},   /* Cohiba Proto board */
index 518542b4bf9e87a0571431d4374842b72ef62faa..29f938930667d3696efd82f5d45fc9c98c15ac39 100644 (file)
@@ -2830,7 +2830,8 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
                                                req_ie_len, resp_ie,
                                                resp_ie_len, 0, GFP_KERNEL);
                else
-                       cfg80211_roamed(usbdev->net, bssid, req_ie, req_ie_len,
+                       cfg80211_roamed(usbdev->net, NULL, bssid,
+                                       req_ie, req_ie_len,
                                        resp_ie, resp_ie_len, GFP_KERNEL);
        } else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
                cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
index 2bb71195e97658c98a39494d6190e3ce745b6344..39b0297ce925d6625291c91873d2948f42432a4c 100644 (file)
@@ -190,7 +190,7 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
 
        ppsc->swrf_processing = true;
 
-       if (ppsc->inactive_pwrstate == ERFOFF &&
+       if (ppsc->inactive_pwrstate == ERFON &&
            rtlhal->interface == INTF_PCI) {
                if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
                    RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
index c5424cad43cb578ea57d8d095dfba92a4b23c772..d2cc81586a6a9c95a4b1660b0a377a024ac7fee9 100644 (file)
@@ -728,7 +728,7 @@ void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
                return;
        rtlphy->set_bwmode_inprogress = true;
        if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
-               rtlphy->set_bwmode_inprogress = false;
+               rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw);
        } else {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         ("FALSE driver sleep or unload\n"));
index 73ae8a431848693818e55fcd76cceb6717031284..abe0fcc753686fc9ac888bb3b64a176fcd530382 100644 (file)
@@ -366,6 +366,75 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
        return true;
 }
 
+void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u8 reg_bw_opmode;
+       u8 reg_prsr_rsc;
+
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+                ("Switch to %s bandwidth\n",
+                 rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+                 "20MHz" : "40MHz"))
+
+       if (is_hal_stop(rtlhal)) {
+               rtlphy->set_bwmode_inprogress = false;
+               return;
+       }
+
+       reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
+       reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
+
+       switch (rtlphy->current_chan_bw) {
+       case HT_CHANNEL_WIDTH_20:
+               reg_bw_opmode |= BW_OPMODE_20MHZ;
+               rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+               rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+               reg_prsr_rsc =
+                   (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5);
+               rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
+               break;
+       }
+
+       switch (rtlphy->current_chan_bw) {
+       case HT_CHANNEL_WIDTH_20:
+               rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+               rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+               rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+               rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+
+               rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+                             (mac->cur_40_prime_sc >> 1));
+               rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+               rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);
+
+               rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
+                             (mac->cur_40_prime_sc ==
+                              HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
+               break;
+       }
+       rtl92ce_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+       rtlphy->set_bwmode_inprogress = false;
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
+}
+
 void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
 {
        u8 tmpreg;
index ad580852cc76284f28c64d7fbea52c344deaf9fe..be2c92adef33d293e1579a78f57c4eb56e8574de 100644 (file)
@@ -257,5 +257,6 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
                                            u8 configtype);
 bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
                                              u8 configtype);
+void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
 
 #endif
index 390bbb5ee11d425a4da2672e4b0895288c9e2076..373dc78af1dcaef05f5511de4e509a87f06add03 100644 (file)
@@ -232,6 +232,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
        .config_bb_with_headerfile = _rtl92ce_phy_config_bb_with_headerfile,
        .config_bb_with_pgheaderfile = _rtl92ce_phy_config_bb_with_pgheaderfile,
        .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate,
+       .phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback,
        .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower,
 };
 
index db9a763aaa7fd0cbce405c681bd6ad9ac910c558..d29365a232a1e2a9a0a55b1b258eea8d550a8d7e 100644 (file)
@@ -1581,7 +1581,9 @@ static int xennet_connect(struct net_device *dev)
        if (err)
                return err;
 
+       rtnl_lock();
        netdev_update_features(dev);
+       rtnl_unlock();
 
        spin_lock_bh(&np->rx_lock);
        spin_lock_irq(&np->tx_lock);
index 94a114aa8e286fd5fc91f97d8c7b416204c19ea2..b1396e5b295307ac42f89d5d98ef8f6e61015d0f 100644 (file)
@@ -81,6 +81,19 @@ static void __iomem *rtl_cmd_addr;
 static u8 rtl_cmd_type;
 static u8 rtl_cmd_width;
 
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       low = readl(p);
+       high = readl(p + 1);
+
+       return low + ((u64)high << 32);
+}
+#endif
+
 static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
 {
        if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
index 85c8ad43c0c5821f1e38ca2572ff02799324f014..5ffe7c3981482f7076ea95172cd0e960a04e465f 100644 (file)
@@ -344,6 +344,19 @@ struct ips_driver {
 static bool
 ips_gpu_turbo_enabled(struct ips_driver *ips);
 
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       low = readl(p);
+       high = readl(p + 1);
+
+       return low + ((u64)high << 32);
+}
+#endif
+
 /**
  * ips_cpu_busy - is CPU busy?
  * @ips: IPS driver struct
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
new file mode 100644 (file)
index 0000000..68d7201
--- /dev/null
@@ -0,0 +1,75 @@
+#
+# PTP clock support configuration
+#
+
+menu "PTP clock support"
+
+comment "Enable Device Drivers -> PPS to see the PTP clock options."
+       depends on PPS=n
+
+config PTP_1588_CLOCK
+       tristate "PTP clock support"
+       depends on EXPERIMENTAL
+       depends on PPS
+       help
+         The IEEE 1588 standard defines a method to precisely
+         synchronize distributed clocks over Ethernet networks. The
+         standard defines a Precision Time Protocol (PTP), which can
+         be used to achieve synchronization within a few dozen
+         microseconds. In addition, with the help of special hardware
+         time stamping units, it can be possible to achieve
+         synchronization to within a few hundred nanoseconds.
+
+         This driver adds support for PTP clocks as character
+         devices. If you want to use a PTP clock, then you should
+         also enable at least one clock driver as well.
+
+         To compile this driver as a module, choose M here: the module
+         will be called ptp.
+
+config PTP_1588_CLOCK_GIANFAR
+       tristate "Freescale eTSEC as PTP clock"
+       depends on PTP_1588_CLOCK
+       depends on GIANFAR
+       help
+         This driver adds support for using the eTSEC as a PTP
+         clock. This clock is only useful if your PTP programs are
+         getting hardware time stamps on the PTP Ethernet packets
+         using the SO_TIMESTAMPING API.
+
+         To compile this driver as a module, choose M here: the module
+         will be called gianfar_ptp.
+
+config PTP_1588_CLOCK_IXP46X
+       tristate "Intel IXP46x as PTP clock"
+       depends on PTP_1588_CLOCK
+       depends on IXP4XX_ETH
+       help
+         This driver adds support for using the IXP46X as a PTP
+         clock. This clock is only useful if your PTP programs are
+         getting hardware time stamps on the PTP Ethernet packets
+         using the SO_TIMESTAMPING API.
+
+         To compile this driver as a module, choose M here: the module
+         will be called ptp_ixp46x.
+
+comment "Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks."
+       depends on PTP_1588_CLOCK && (PHYLIB=n || NETWORK_PHY_TIMESTAMPING=n)
+
+config DP83640_PHY
+       tristate "Driver for the National Semiconductor DP83640 PHYTER"
+       depends on PTP_1588_CLOCK
+       depends on NETWORK_PHY_TIMESTAMPING
+       depends on PHYLIB
+       ---help---
+         Supports the DP83640 PHYTER with IEEE 1588 features.
+
+         This driver adds support for using the DP83640 as a PTP
+         clock. This clock is only useful if your PTP programs are
+         getting hardware time stamps on the PTP Ethernet packets
+         using the SO_TIMESTAMPING API.
+
+         In order for this to work, your MAC driver must also
+         implement the skb_tx_timetamp() function.
+
+endmenu
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
new file mode 100644 (file)
index 0000000..f6933e8
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for PTP 1588 clock support.
+#
+
+ptp-y                                  := ptp_clock.o ptp_chardev.o ptp_sysfs.o
+obj-$(CONFIG_PTP_1588_CLOCK)           += ptp.o
+obj-$(CONFIG_PTP_1588_CLOCK_IXP46X)    += ptp_ixp46x.o
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
new file mode 100644 (file)
index 0000000..a8d03ae
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * PTP 1588 clock support - character device implementation.
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/module.h>
+#include <linux/posix-clock.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include "ptp_private.h"
+
+int ptp_open(struct posix_clock *pc, fmode_t fmode)
+{
+       return 0;
+}
+
+long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
+{
+       struct ptp_clock_caps caps;
+       struct ptp_clock_request req;
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       struct ptp_clock_info *ops = ptp->info;
+       int enable, err = 0;
+
+       switch (cmd) {
+
+       case PTP_CLOCK_GETCAPS:
+               memset(&caps, 0, sizeof(caps));
+               caps.max_adj = ptp->info->max_adj;
+               caps.n_alarm = ptp->info->n_alarm;
+               caps.n_ext_ts = ptp->info->n_ext_ts;
+               caps.n_per_out = ptp->info->n_per_out;
+               caps.pps = ptp->info->pps;
+               err = copy_to_user((void __user *)arg, &caps, sizeof(caps));
+               break;
+
+       case PTP_EXTTS_REQUEST:
+               if (copy_from_user(&req.extts, (void __user *)arg,
+                                  sizeof(req.extts))) {
+                       err = -EFAULT;
+                       break;
+               }
+               if (req.extts.index >= ops->n_ext_ts) {
+                       err = -EINVAL;
+                       break;
+               }
+               req.type = PTP_CLK_REQ_EXTTS;
+               enable = req.extts.flags & PTP_ENABLE_FEATURE ? 1 : 0;
+               err = ops->enable(ops, &req, enable);
+               break;
+
+       case PTP_PEROUT_REQUEST:
+               if (copy_from_user(&req.perout, (void __user *)arg,
+                                  sizeof(req.perout))) {
+                       err = -EFAULT;
+                       break;
+               }
+               if (req.perout.index >= ops->n_per_out) {
+                       err = -EINVAL;
+                       break;
+               }
+               req.type = PTP_CLK_REQ_PEROUT;
+               enable = req.perout.period.sec || req.perout.period.nsec;
+               err = ops->enable(ops, &req, enable);
+               break;
+
+       case PTP_ENABLE_PPS:
+               if (!capable(CAP_SYS_TIME))
+                       return -EPERM;
+               req.type = PTP_CLK_REQ_PPS;
+               enable = arg ? 1 : 0;
+               err = ops->enable(ops, &req, enable);
+               break;
+
+       default:
+               err = -ENOTTY;
+               break;
+       }
+       return err;
+}
+
+unsigned int ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+
+       poll_wait(fp, &ptp->tsev_wq, wait);
+
+       return queue_cnt(&ptp->tsevq) ? POLLIN : 0;
+}
+
+ssize_t ptp_read(struct posix_clock *pc,
+                uint rdflags, char __user *buf, size_t cnt)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       struct timestamp_event_queue *queue = &ptp->tsevq;
+       struct ptp_extts_event event[PTP_BUF_TIMESTAMPS];
+       unsigned long flags;
+       size_t qcnt, i;
+
+       if (cnt % sizeof(struct ptp_extts_event) != 0)
+               return -EINVAL;
+
+       if (cnt > sizeof(event))
+               cnt = sizeof(event);
+
+       cnt = cnt / sizeof(struct ptp_extts_event);
+
+       if (mutex_lock_interruptible(&ptp->tsevq_mux))
+               return -ERESTARTSYS;
+
+       if (wait_event_interruptible(ptp->tsev_wq,
+                                    ptp->defunct || queue_cnt(queue))) {
+               mutex_unlock(&ptp->tsevq_mux);
+               return -ERESTARTSYS;
+       }
+
+       if (ptp->defunct)
+               return -ENODEV;
+
+       spin_lock_irqsave(&queue->lock, flags);
+
+       qcnt = queue_cnt(queue);
+
+       if (cnt > qcnt)
+               cnt = qcnt;
+
+       for (i = 0; i < cnt; i++) {
+               event[i] = queue->buf[queue->head];
+               queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+       }
+
+       spin_unlock_irqrestore(&queue->lock, flags);
+
+       cnt = cnt * sizeof(struct ptp_extts_event);
+
+       mutex_unlock(&ptp->tsevq_mux);
+
+       if (copy_to_user(buf, event, cnt)) {
+               mutex_unlock(&ptp->tsevq_mux);
+               return -EFAULT;
+       }
+
+       return cnt;
+}
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
new file mode 100644 (file)
index 0000000..cf3f999
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * PTP 1588 clock support
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/posix-clock.h>
+#include <linux/pps_kernel.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+
+#include "ptp_private.h"
+
+#define PTP_MAX_ALARMS 4
+#define PTP_MAX_CLOCKS 8
+#define PTP_PPS_DEFAULTS (PPS_CAPTUREASSERT | PPS_OFFSETASSERT)
+#define PTP_PPS_EVENT PPS_CAPTUREASSERT
+#define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC)
+
+/* private globals */
+
+static dev_t ptp_devt;
+static struct class *ptp_class;
+
+static DECLARE_BITMAP(ptp_clocks_map, PTP_MAX_CLOCKS);
+static DEFINE_MUTEX(ptp_clocks_mutex); /* protects 'ptp_clocks_map' */
+
+/* time stamp event queue operations */
+
+static inline int queue_free(struct timestamp_event_queue *q)
+{
+       return PTP_MAX_TIMESTAMPS - queue_cnt(q) - 1;
+}
+
+static void enqueue_external_timestamp(struct timestamp_event_queue *queue,
+                                      struct ptp_clock_event *src)
+{
+       struct ptp_extts_event *dst;
+       unsigned long flags;
+       s64 seconds;
+       u32 remainder;
+
+       seconds = div_u64_rem(src->timestamp, 1000000000, &remainder);
+
+       spin_lock_irqsave(&queue->lock, flags);
+
+       dst = &queue->buf[queue->tail];
+       dst->index = src->index;
+       dst->t.sec = seconds;
+       dst->t.nsec = remainder;
+
+       if (!queue_free(queue))
+               queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+
+       queue->tail = (queue->tail + 1) % PTP_MAX_TIMESTAMPS;
+
+       spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static s32 scaled_ppm_to_ppb(long ppm)
+{
+       /*
+        * The 'freq' field in the 'struct timex' is in parts per
+        * million, but with a 16 bit binary fractional field.
+        *
+        * We want to calculate
+        *
+        *    ppb = scaled_ppm * 1000 / 2^16
+        *
+        * which simplifies to
+        *
+        *    ppb = scaled_ppm * 125 / 2^13
+        */
+       s64 ppb = 1 + ppm;
+       ppb *= 125;
+       ppb >>= 13;
+       return (s32) ppb;
+}
+
+/* posix clock implementation */
+
+static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp)
+{
+       return 1; /* always round timer functions to one nanosecond */
+}
+
+static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       return ptp->info->settime(ptp->info, tp);
+}
+
+static int ptp_clock_gettime(struct posix_clock *pc, struct timespec *tp)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       return ptp->info->gettime(ptp->info, tp);
+}
+
+static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+       struct ptp_clock_info *ops;
+       int err = -EOPNOTSUPP;
+
+       ops = ptp->info;
+
+       if (tx->modes & ADJ_SETOFFSET) {
+               struct timespec ts;
+               ktime_t kt;
+               s64 delta;
+
+               ts.tv_sec  = tx->time.tv_sec;
+               ts.tv_nsec = tx->time.tv_usec;
+
+               if (!(tx->modes & ADJ_NANO))
+                       ts.tv_nsec *= 1000;
+
+               if ((unsigned long) ts.tv_nsec >= NSEC_PER_SEC)
+                       return -EINVAL;
+
+               kt = timespec_to_ktime(ts);
+               delta = ktime_to_ns(kt);
+               err = ops->adjtime(ops, delta);
+
+       } else if (tx->modes & ADJ_FREQUENCY) {
+
+               err = ops->adjfreq(ops, scaled_ppm_to_ppb(tx->freq));
+       }
+
+       return err;
+}
+
+static struct posix_clock_operations ptp_clock_ops = {
+       .owner          = THIS_MODULE,
+       .clock_adjtime  = ptp_clock_adjtime,
+       .clock_gettime  = ptp_clock_gettime,
+       .clock_getres   = ptp_clock_getres,
+       .clock_settime  = ptp_clock_settime,
+       .ioctl          = ptp_ioctl,
+       .open           = ptp_open,
+       .poll           = ptp_poll,
+       .read           = ptp_read,
+};
+
+static void delete_ptp_clock(struct posix_clock *pc)
+{
+       struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+
+       mutex_destroy(&ptp->tsevq_mux);
+
+       /* Remove the clock from the bit map. */
+       mutex_lock(&ptp_clocks_mutex);
+       clear_bit(ptp->index, ptp_clocks_map);
+       mutex_unlock(&ptp_clocks_mutex);
+
+       kfree(ptp);
+}
+
+/* public interface */
+
+struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info)
+{
+       struct ptp_clock *ptp;
+       int err = 0, index, major = MAJOR(ptp_devt);
+
+       if (info->n_alarm > PTP_MAX_ALARMS)
+               return ERR_PTR(-EINVAL);
+
+       /* Find a free clock slot and reserve it. */
+       err = -EBUSY;
+       mutex_lock(&ptp_clocks_mutex);
+       index = find_first_zero_bit(ptp_clocks_map, PTP_MAX_CLOCKS);
+       if (index < PTP_MAX_CLOCKS)
+               set_bit(index, ptp_clocks_map);
+       else
+               goto no_slot;
+
+       /* Initialize a clock structure. */
+       err = -ENOMEM;
+       ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL);
+       if (ptp == NULL)
+               goto no_memory;
+
+       ptp->clock.ops = ptp_clock_ops;
+       ptp->clock.release = delete_ptp_clock;
+       ptp->info = info;
+       ptp->devid = MKDEV(major, index);
+       ptp->index = index;
+       spin_lock_init(&ptp->tsevq.lock);
+       mutex_init(&ptp->tsevq_mux);
+       init_waitqueue_head(&ptp->tsev_wq);
+
+       /* Create a new device in our class. */
+       ptp->dev = device_create(ptp_class, NULL, ptp->devid, ptp,
+                                "ptp%d", ptp->index);
+       if (IS_ERR(ptp->dev))
+               goto no_device;
+
+       dev_set_drvdata(ptp->dev, ptp);
+
+       err = ptp_populate_sysfs(ptp);
+       if (err)
+               goto no_sysfs;
+
+       /* Register a new PPS source. */
+       if (info->pps) {
+               struct pps_source_info pps;
+               memset(&pps, 0, sizeof(pps));
+               snprintf(pps.name, PPS_MAX_NAME_LEN, "ptp%d", index);
+               pps.mode = PTP_PPS_MODE;
+               pps.owner = info->owner;
+               ptp->pps_source = pps_register_source(&pps, PTP_PPS_DEFAULTS);
+               if (!ptp->pps_source) {
+                       pr_err("failed to register pps source\n");
+                       goto no_pps;
+               }
+       }
+
+       /* Create a posix clock. */
+       err = posix_clock_register(&ptp->clock, ptp->devid);
+       if (err) {
+               pr_err("failed to create posix clock\n");
+               goto no_clock;
+       }
+
+       mutex_unlock(&ptp_clocks_mutex);
+       return ptp;
+
+no_clock:
+       if (ptp->pps_source)
+               pps_unregister_source(ptp->pps_source);
+no_pps:
+       ptp_cleanup_sysfs(ptp);
+no_sysfs:
+       device_destroy(ptp_class, ptp->devid);
+no_device:
+       mutex_destroy(&ptp->tsevq_mux);
+       kfree(ptp);
+no_memory:
+       clear_bit(index, ptp_clocks_map);
+no_slot:
+       mutex_unlock(&ptp_clocks_mutex);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL(ptp_clock_register);
+
+int ptp_clock_unregister(struct ptp_clock *ptp)
+{
+       ptp->defunct = 1;
+       wake_up_interruptible(&ptp->tsev_wq);
+
+       /* Release the clock's resources. */
+       if (ptp->pps_source)
+               pps_unregister_source(ptp->pps_source);
+       ptp_cleanup_sysfs(ptp);
+       device_destroy(ptp_class, ptp->devid);
+
+       posix_clock_unregister(&ptp->clock);
+       return 0;
+}
+EXPORT_SYMBOL(ptp_clock_unregister);
+
+void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
+{
+       struct pps_event_time evt;
+
+       switch (event->type) {
+
+       case PTP_CLOCK_ALARM:
+               break;
+
+       case PTP_CLOCK_EXTTS:
+               enqueue_external_timestamp(&ptp->tsevq, event);
+               wake_up_interruptible(&ptp->tsev_wq);
+               break;
+
+       case PTP_CLOCK_PPS:
+               pps_get_ts(&evt);
+               pps_event(ptp->pps_source, &evt, PTP_PPS_EVENT, NULL);
+               break;
+       }
+}
+EXPORT_SYMBOL(ptp_clock_event);
+
+/* module operations */
+
+static void __exit ptp_exit(void)
+{
+       class_destroy(ptp_class);
+       unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS);
+}
+
+static int __init ptp_init(void)
+{
+       int err;
+
+       ptp_class = class_create(THIS_MODULE, "ptp");
+       if (IS_ERR(ptp_class)) {
+               pr_err("ptp: failed to allocate class\n");
+               return PTR_ERR(ptp_class);
+       }
+
+       err = alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "ptp");
+       if (err < 0) {
+               pr_err("ptp: failed to allocate device region\n");
+               goto no_region;
+       }
+
+       ptp_class->dev_attrs = ptp_dev_attrs;
+       pr_info("PTP clock support registered\n");
+       return 0;
+
+no_region:
+       class_destroy(ptp_class);
+       return err;
+}
+
+subsys_initcall(ptp_init);
+module_exit(ptp_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clocks support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ptp/ptp_ixp46x.c b/drivers/ptp/ptp_ixp46x.c
new file mode 100644 (file)
index 0000000..803d665
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * PTP 1588 clock using the IXP46X
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/ptp_clock_kernel.h>
+#include <mach/ixp46x_ts.h>
+
+#define DRIVER         "ptp_ixp46x"
+#define N_EXT_TS       2
+#define MASTER_GPIO    8
+#define MASTER_IRQ     25
+#define SLAVE_GPIO     7
+#define SLAVE_IRQ      24
+
+struct ixp_clock {
+       struct ixp46x_ts_regs *regs;
+       struct ptp_clock *ptp_clock;
+       struct ptp_clock_info caps;
+       int exts0_enabled;
+       int exts1_enabled;
+};
+
+DEFINE_SPINLOCK(register_lock);
+
+/*
+ * Register access functions
+ */
+
+static u64 ixp_systime_read(struct ixp46x_ts_regs *regs)
+{
+       u64 ns;
+       u32 lo, hi;
+
+       lo = __raw_readl(&regs->systime_lo);
+       hi = __raw_readl(&regs->systime_hi);
+
+       ns = ((u64) hi) << 32;
+       ns |= lo;
+       ns <<= TICKS_NS_SHIFT;
+
+       return ns;
+}
+
+static void ixp_systime_write(struct ixp46x_ts_regs *regs, u64 ns)
+{
+       u32 hi, lo;
+
+       ns >>= TICKS_NS_SHIFT;
+       hi = ns >> 32;
+       lo = ns & 0xffffffff;
+
+       __raw_writel(lo, &regs->systime_lo);
+       __raw_writel(hi, &regs->systime_hi);
+}
+
+/*
+ * Interrupt service routine
+ */
+
+static irqreturn_t isr(int irq, void *priv)
+{
+       struct ixp_clock *ixp_clock = priv;
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+       struct ptp_clock_event event;
+       u32 ack = 0, lo, hi, val;
+
+       val = __raw_readl(&regs->event);
+
+       if (val & TSER_SNS) {
+               ack |= TSER_SNS;
+               if (ixp_clock->exts0_enabled) {
+                       hi = __raw_readl(&regs->asms_hi);
+                       lo = __raw_readl(&regs->asms_lo);
+                       event.type = PTP_CLOCK_EXTTS;
+                       event.index = 0;
+                       event.timestamp = ((u64) hi) << 32;
+                       event.timestamp |= lo;
+                       event.timestamp <<= TICKS_NS_SHIFT;
+                       ptp_clock_event(ixp_clock->ptp_clock, &event);
+               }
+       }
+
+       if (val & TSER_SNM) {
+               ack |= TSER_SNM;
+               if (ixp_clock->exts1_enabled) {
+                       hi = __raw_readl(&regs->amms_hi);
+                       lo = __raw_readl(&regs->amms_lo);
+                       event.type = PTP_CLOCK_EXTTS;
+                       event.index = 1;
+                       event.timestamp = ((u64) hi) << 32;
+                       event.timestamp |= lo;
+                       event.timestamp <<= TICKS_NS_SHIFT;
+                       ptp_clock_event(ixp_clock->ptp_clock, &event);
+               }
+       }
+
+       if (val & TTIPEND)
+               ack |= TTIPEND; /* this bit seems to be always set */
+
+       if (ack) {
+               __raw_writel(ack, &regs->event);
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+}
+
+/*
+ * PTP clock operations
+ */
+
+static int ptp_ixp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+       u64 adj;
+       u32 diff, addend;
+       int neg_adj = 0;
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+       if (ppb < 0) {
+               neg_adj = 1;
+               ppb = -ppb;
+       }
+       addend = DEFAULT_ADDEND;
+       adj = addend;
+       adj *= ppb;
+       diff = div_u64(adj, 1000000000ULL);
+
+       addend = neg_adj ? addend - diff : addend + diff;
+
+       __raw_writel(addend, &regs->addend);
+
+       return 0;
+}
+
+static int ptp_ixp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+       s64 now;
+       unsigned long flags;
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+       spin_lock_irqsave(&register_lock, flags);
+
+       now = ixp_systime_read(regs);
+       now += delta;
+       ixp_systime_write(regs, now);
+
+       spin_unlock_irqrestore(&register_lock, flags);
+
+       return 0;
+}
+
+static int ptp_ixp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+       u64 ns;
+       u32 remainder;
+       unsigned long flags;
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+       spin_lock_irqsave(&register_lock, flags);
+
+       ns = ixp_systime_read(regs);
+
+       spin_unlock_irqrestore(&register_lock, flags);
+
+       ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+       ts->tv_nsec = remainder;
+       return 0;
+}
+
+static int ptp_ixp_settime(struct ptp_clock_info *ptp,
+                          const struct timespec *ts)
+{
+       u64 ns;
+       unsigned long flags;
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+       struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+       ns = ts->tv_sec * 1000000000ULL;
+       ns += ts->tv_nsec;
+
+       spin_lock_irqsave(&register_lock, flags);
+
+       ixp_systime_write(regs, ns);
+
+       spin_unlock_irqrestore(&register_lock, flags);
+
+       return 0;
+}
+
+static int ptp_ixp_enable(struct ptp_clock_info *ptp,
+                         struct ptp_clock_request *rq, int on)
+{
+       struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+
+       switch (rq->type) {
+       case PTP_CLK_REQ_EXTTS:
+               switch (rq->extts.index) {
+               case 0:
+                       ixp_clock->exts0_enabled = on ? 1 : 0;
+                       break;
+               case 1:
+                       ixp_clock->exts1_enabled = on ? 1 : 0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               return 0;
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info ptp_ixp_caps = {
+       .owner          = THIS_MODULE,
+       .name           = "IXP46X timer",
+       .max_adj        = 66666655,
+       .n_ext_ts       = N_EXT_TS,
+       .pps            = 0,
+       .adjfreq        = ptp_ixp_adjfreq,
+       .adjtime        = ptp_ixp_adjtime,
+       .gettime        = ptp_ixp_gettime,
+       .settime        = ptp_ixp_settime,
+       .enable         = ptp_ixp_enable,
+};
+
+/* module operations */
+
+static struct ixp_clock ixp_clock;
+
+static int setup_interrupt(int gpio)
+{
+       int irq;
+
+       gpio_line_config(gpio, IXP4XX_GPIO_IN);
+
+       irq = gpio_to_irq(gpio);
+
+       if (NO_IRQ == irq)
+               return NO_IRQ;
+
+       if (irq_set_irq_type(irq, IRQF_TRIGGER_FALLING)) {
+               pr_err("cannot set trigger type for irq %d\n", irq);
+               return NO_IRQ;
+       }
+
+       if (request_irq(irq, isr, 0, DRIVER, &ixp_clock)) {
+               pr_err("request_irq failed for irq %d\n", irq);
+               return NO_IRQ;
+       }
+
+       return irq;
+}
+
+static void __exit ptp_ixp_exit(void)
+{
+       free_irq(MASTER_IRQ, &ixp_clock);
+       free_irq(SLAVE_IRQ, &ixp_clock);
+       ptp_clock_unregister(ixp_clock.ptp_clock);
+}
+
+static int __init ptp_ixp_init(void)
+{
+       if (!cpu_is_ixp46x())
+               return -ENODEV;
+
+       ixp_clock.regs =
+               (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+       ixp_clock.caps = ptp_ixp_caps;
+
+       ixp_clock.ptp_clock = ptp_clock_register(&ixp_clock.caps);
+
+       if (IS_ERR(ixp_clock.ptp_clock))
+               return PTR_ERR(ixp_clock.ptp_clock);
+
+       __raw_writel(DEFAULT_ADDEND, &ixp_clock.regs->addend);
+       __raw_writel(1, &ixp_clock.regs->trgt_lo);
+       __raw_writel(0, &ixp_clock.regs->trgt_hi);
+       __raw_writel(TTIPEND, &ixp_clock.regs->event);
+
+       if (MASTER_IRQ != setup_interrupt(MASTER_GPIO)) {
+               pr_err("failed to setup gpio %d as irq\n", MASTER_GPIO);
+               goto no_master;
+       }
+       if (SLAVE_IRQ != setup_interrupt(SLAVE_GPIO)) {
+               pr_err("failed to setup gpio %d as irq\n", SLAVE_GPIO);
+               goto no_slave;
+       }
+
+       return 0;
+no_slave:
+       free_irq(MASTER_IRQ, &ixp_clock);
+no_master:
+       ptp_clock_unregister(ixp_clock.ptp_clock);
+       return -ENODEV;
+}
+
+module_init(ptp_ixp_init);
+module_exit(ptp_ixp_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clock using the IXP46X timer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
new file mode 100644 (file)
index 0000000..4d5b508
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * PTP 1588 clock support - private declarations for the core module.
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _PTP_PRIVATE_H_
+#define _PTP_PRIVATE_H_
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/posix-clock.h>
+#include <linux/ptp_clock.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/time.h>
+
+#define PTP_MAX_TIMESTAMPS 128
+#define PTP_BUF_TIMESTAMPS 30
+
+struct timestamp_event_queue {
+       struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS];
+       int head;
+       int tail;
+       spinlock_t lock;
+};
+
+struct ptp_clock {
+       struct posix_clock clock;
+       struct device *dev;
+       struct ptp_clock_info *info;
+       dev_t devid;
+       int index; /* index into clocks.map */
+       struct pps_device *pps_source;
+       struct timestamp_event_queue tsevq; /* simple fifo for time stamps */
+       struct mutex tsevq_mux; /* one process at a time reading the fifo */
+       wait_queue_head_t tsev_wq;
+       int defunct; /* tells readers to go away when clock is being removed */
+};
+
+/*
+ * The function queue_cnt() is safe for readers to call without
+ * holding q->lock. Readers use this function to verify that the queue
+ * is nonempty before proceeding with a dequeue operation. The fact
+ * that a writer might concurrently increment the tail does not
+ * matter, since the queue remains nonempty nonetheless.
+ */
+static inline int queue_cnt(struct timestamp_event_queue *q)
+{
+       int cnt = q->tail - q->head;
+       return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt;
+}
+
+/*
+ * see ptp_chardev.c
+ */
+
+long ptp_ioctl(struct posix_clock *pc,
+              unsigned int cmd, unsigned long arg);
+
+int ptp_open(struct posix_clock *pc, fmode_t fmode);
+
+ssize_t ptp_read(struct posix_clock *pc,
+                uint flags, char __user *buf, size_t cnt);
+
+uint ptp_poll(struct posix_clock *pc,
+             struct file *fp, poll_table *wait);
+
+/*
+ * see ptp_sysfs.c
+ */
+
+extern struct device_attribute ptp_dev_attrs[];
+
+int ptp_cleanup_sysfs(struct ptp_clock *ptp);
+
+int ptp_populate_sysfs(struct ptp_clock *ptp);
+
+#endif
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
new file mode 100644 (file)
index 0000000..2f93926
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * PTP 1588 clock support - sysfs interface.
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/capability.h>
+
+#include "ptp_private.h"
+
+static ssize_t clock_name_show(struct device *dev,
+                              struct device_attribute *attr, char *page)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name);
+}
+
+#define PTP_SHOW_INT(name)                                             \
+static ssize_t name##_show(struct device *dev,                         \
+                          struct device_attribute *attr, char *page)   \
+{                                                                      \
+       struct ptp_clock *ptp = dev_get_drvdata(dev);                   \
+       return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->name);    \
+}
+
+PTP_SHOW_INT(max_adj);
+PTP_SHOW_INT(n_alarm);
+PTP_SHOW_INT(n_ext_ts);
+PTP_SHOW_INT(n_per_out);
+PTP_SHOW_INT(pps);
+
+#define PTP_RO_ATTR(_var, _name) {                             \
+       .attr   = { .name = __stringify(_name), .mode = 0444 }, \
+       .show   = _var##_show,                                  \
+}
+
+struct device_attribute ptp_dev_attrs[] = {
+       PTP_RO_ATTR(clock_name, clock_name),
+       PTP_RO_ATTR(max_adj,    max_adjustment),
+       PTP_RO_ATTR(n_alarm,    n_alarms),
+       PTP_RO_ATTR(n_ext_ts,   n_external_timestamps),
+       PTP_RO_ATTR(n_per_out,  n_periodic_outputs),
+       PTP_RO_ATTR(pps,        pps_available),
+       __ATTR_NULL,
+};
+
+static ssize_t extts_enable_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       struct ptp_clock_info *ops = ptp->info;
+       struct ptp_clock_request req = { .type = PTP_CLK_REQ_EXTTS };
+       int cnt, enable;
+       int err = -EINVAL;
+
+       cnt = sscanf(buf, "%u %d", &req.extts.index, &enable);
+       if (cnt != 2)
+               goto out;
+       if (req.extts.index >= ops->n_ext_ts)
+               goto out;
+
+       err = ops->enable(ops, &req, enable ? 1 : 0);
+       if (err)
+               goto out;
+
+       return count;
+out:
+       return err;
+}
+
+static ssize_t extts_fifo_show(struct device *dev,
+                              struct device_attribute *attr, char *page)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       struct timestamp_event_queue *queue = &ptp->tsevq;
+       struct ptp_extts_event event;
+       unsigned long flags;
+       size_t qcnt;
+       int cnt = 0;
+
+       memset(&event, 0, sizeof(event));
+
+       if (mutex_lock_interruptible(&ptp->tsevq_mux))
+               return -ERESTARTSYS;
+
+       spin_lock_irqsave(&queue->lock, flags);
+       qcnt = queue_cnt(queue);
+       if (qcnt) {
+               event = queue->buf[queue->head];
+               queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+       }
+       spin_unlock_irqrestore(&queue->lock, flags);
+
+       if (!qcnt)
+               goto out;
+
+       cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n",
+                      event.index, event.t.sec, event.t.nsec);
+out:
+       mutex_unlock(&ptp->tsevq_mux);
+       return cnt;
+}
+
+static ssize_t period_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       struct ptp_clock_info *ops = ptp->info;
+       struct ptp_clock_request req = { .type = PTP_CLK_REQ_PEROUT };
+       int cnt, enable, err = -EINVAL;
+
+       cnt = sscanf(buf, "%u %lld %u %lld %u", &req.perout.index,
+                    &req.perout.start.sec, &req.perout.start.nsec,
+                    &req.perout.period.sec, &req.perout.period.nsec);
+       if (cnt != 5)
+               goto out;
+       if (req.perout.index >= ops->n_per_out)
+               goto out;
+
+       enable = req.perout.period.sec || req.perout.period.nsec;
+       err = ops->enable(ops, &req, enable);
+       if (err)
+               goto out;
+
+       return count;
+out:
+       return err;
+}
+
+static ssize_t pps_enable_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       struct ptp_clock_info *ops = ptp->info;
+       struct ptp_clock_request req = { .type = PTP_CLK_REQ_PPS };
+       int cnt, enable;
+       int err = -EINVAL;
+
+       if (!capable(CAP_SYS_TIME))
+               return -EPERM;
+
+       cnt = sscanf(buf, "%d", &enable);
+       if (cnt != 1)
+               goto out;
+
+       err = ops->enable(ops, &req, enable ? 1 : 0);
+       if (err)
+               goto out;
+
+       return count;
+out:
+       return err;
+}
+
+static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
+static DEVICE_ATTR(fifo,         0444, extts_fifo_show, NULL);
+static DEVICE_ATTR(period,       0220, NULL, period_store);
+static DEVICE_ATTR(pps_enable,   0220, NULL, pps_enable_store);
+
+int ptp_cleanup_sysfs(struct ptp_clock *ptp)
+{
+       struct device *dev = ptp->dev;
+       struct ptp_clock_info *info = ptp->info;
+
+       if (info->n_ext_ts) {
+               device_remove_file(dev, &dev_attr_extts_enable);
+               device_remove_file(dev, &dev_attr_fifo);
+       }
+       if (info->n_per_out)
+               device_remove_file(dev, &dev_attr_period);
+
+       if (info->pps)
+               device_remove_file(dev, &dev_attr_pps_enable);
+
+       return 0;
+}
+
+int ptp_populate_sysfs(struct ptp_clock *ptp)
+{
+       struct device *dev = ptp->dev;
+       struct ptp_clock_info *info = ptp->info;
+       int err;
+
+       if (info->n_ext_ts) {
+               err = device_create_file(dev, &dev_attr_extts_enable);
+               if (err)
+                       goto out1;
+               err = device_create_file(dev, &dev_attr_fifo);
+               if (err)
+                       goto out2;
+       }
+       if (info->n_per_out) {
+               err = device_create_file(dev, &dev_attr_period);
+               if (err)
+                       goto out3;
+       }
+       if (info->pps) {
+               err = device_create_file(dev, &dev_attr_pps_enable);
+               if (err)
+                       goto out4;
+       }
+       return 0;
+out4:
+       if (info->n_per_out)
+               device_remove_file(dev, &dev_attr_period);
+out3:
+       if (info->n_ext_ts)
+               device_remove_file(dev, &dev_attr_fifo);
+out2:
+       if (info->n_ext_ts)
+               device_remove_file(dev, &dev_attr_extts_enable);
+out1:
+       return err;
+}
index b9f29e0d4295b0f1031b151a8e03efde7e974a40..f0b13a0d1851542ca4ca05157fff2981799fe482 100644 (file)
@@ -274,6 +274,13 @@ config REGULATOR_AB8500
          This driver supports the regulators found on the ST-Ericsson mixed
          signal AB8500 PMIC
 
+config REGULATOR_DB8500_PRCMU
+       bool "ST-Ericsson DB8500 Voltage Domain Regulators"
+       depends on MFD_DB8500_PRCMU
+       help
+         This driver supports the voltage domain regulators controlled by the
+         DB8500 PRCMU
+
 config REGULATOR_TPS6586X
        tristate "TI TPS6586X Power regulators"
        depends on MFD_TPS6586X
index d72a427567786eade1a87fb05c2a83284757ba01..165ff5371e9e0ab78615763abbcf026001fd4e24 100644 (file)
@@ -41,5 +41,6 @@ obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
+obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
new file mode 100644 (file)
index 0000000..1089a96
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ *          Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Power domain regulators on DB8500
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/db8500-prcmu.h>
+
+/*
+ * power state reference count
+ */
+static int power_state_active_cnt; /* will initialize to zero */
+static DEFINE_SPINLOCK(power_state_active_lock);
+
+static void power_state_active_enable(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&power_state_active_lock, flags);
+       power_state_active_cnt++;
+       spin_unlock_irqrestore(&power_state_active_lock, flags);
+}
+
+static int power_state_active_disable(void)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&power_state_active_lock, flags);
+       if (power_state_active_cnt <= 0) {
+               pr_err("power state: unbalanced enable/disable calls\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       power_state_active_cnt--;
+out:
+       spin_unlock_irqrestore(&power_state_active_lock, flags);
+       return ret;
+}
+
+/*
+ * Exported interface for CPUIdle only. This function is called when interrupts
+ * are turned off. Hence, no locking.
+ */
+int power_state_active_is_enabled(void)
+{
+       return (power_state_active_cnt > 0);
+}
+
+/**
+ * struct db8500_regulator_info - db8500 regulator information
+ * @dev: device pointer
+ * @desc: regulator description
+ * @rdev: regulator device pointer
+ * @is_enabled: status of the regulator
+ * @epod_id: id for EPOD (power domain)
+ * @is_ramret: RAM retention switch for EPOD (power domain)
+ * @operating_point: operating point (only for vape, to be removed)
+ *
+ */
+struct db8500_regulator_info {
+       struct device *dev;
+       struct regulator_desc desc;
+       struct regulator_dev *rdev;
+       bool is_enabled;
+       u16 epod_id;
+       bool is_ramret;
+       bool exclude_from_power_state;
+       unsigned int operating_point;
+};
+
+static int db8500_regulator_enable(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n",
+               info->desc.name);
+
+       info->is_enabled = true;
+       if (!info->exclude_from_power_state)
+               power_state_active_enable();
+
+       return 0;
+}
+
+static int db8500_regulator_disable(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret = 0;
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n",
+               info->desc.name);
+
+       info->is_enabled = false;
+       if (!info->exclude_from_power_state)
+               ret = power_state_active_disable();
+
+       return ret;
+}
+
+static int db8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):"
+               " %i\n", info->desc.name, info->is_enabled);
+
+       return info->is_enabled;
+}
+
+/* db8500 regulator operations */
+static struct regulator_ops db8500_regulator_ops = {
+       .enable                 = db8500_regulator_enable,
+       .disable                = db8500_regulator_disable,
+       .is_enabled             = db8500_regulator_is_enabled,
+};
+
+/*
+ * EPOD control
+ */
+static bool epod_on[NUM_EPOD_ID];
+static bool epod_ramret[NUM_EPOD_ID];
+
+static int enable_epod(u16 epod_id, bool ramret)
+{
+       int ret;
+
+       if (ramret) {
+               if (!epod_on[epod_id]) {
+                       ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+                       if (ret < 0)
+                               return ret;
+               }
+               epod_ramret[epod_id] = true;
+       } else {
+               ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
+               if (ret < 0)
+                       return ret;
+               epod_on[epod_id] = true;
+       }
+
+       return 0;
+}
+
+static int disable_epod(u16 epod_id, bool ramret)
+{
+       int ret;
+
+       if (ramret) {
+               if (!epod_on[epod_id]) {
+                       ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+                       if (ret < 0)
+                               return ret;
+               }
+               epod_ramret[epod_id] = false;
+       } else {
+               if (epod_ramret[epod_id]) {
+                       ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+                       if (ret < 0)
+                               return ret;
+               } else {
+                       ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+                       if (ret < 0)
+                               return ret;
+               }
+               epod_on[epod_id] = false;
+       }
+
+       return 0;
+}
+
+/*
+ * Regulator switch
+ */
+static int db8500_regulator_switch_enable(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n",
+               info->desc.name);
+
+       ret = enable_epod(info->epod_id, info->is_ramret);
+       if (ret < 0) {
+               dev_err(rdev_get_dev(rdev),
+                       "regulator-switch-%s-enable: prcmu call failed\n",
+                       info->desc.name);
+               goto out;
+       }
+
+       info->is_enabled = true;
+out:
+       return ret;
+}
+
+static int db8500_regulator_switch_disable(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+       int ret;
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n",
+               info->desc.name);
+
+       ret = disable_epod(info->epod_id, info->is_ramret);
+       if (ret < 0) {
+               dev_err(rdev_get_dev(rdev),
+                       "regulator_switch-%s-disable: prcmu call failed\n",
+                       info->desc.name);
+               goto out;
+       }
+
+       info->is_enabled = 0;
+out:
+       return ret;
+}
+
+static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev)
+{
+       struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+       if (info == NULL)
+               return -EINVAL;
+
+       dev_vdbg(rdev_get_dev(rdev),
+               "regulator-switch-%s-is_enabled (is_enabled): %i\n",
+               info->desc.name, info->is_enabled);
+
+       return info->is_enabled;
+}
+
+static struct regulator_ops db8500_regulator_switch_ops = {
+       .enable                 = db8500_regulator_switch_enable,
+       .disable                = db8500_regulator_switch_disable,
+       .is_enabled             = db8500_regulator_switch_is_enabled,
+};
+
+/*
+ * Regulator information
+ */
+static struct db8500_regulator_info
+               db8500_regulator_info[DB8500_NUM_REGULATORS] = {
+       [DB8500_REGULATOR_VAPE] = {
+               .desc = {
+                       .name   = "db8500-vape",
+                       .id     = DB8500_REGULATOR_VAPE,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VARM] = {
+               .desc = {
+                       .name   = "db8500-varm",
+                       .id     = DB8500_REGULATOR_VARM,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VMODEM] = {
+               .desc = {
+                       .name   = "db8500-vmodem",
+                       .id     = DB8500_REGULATOR_VMODEM,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VPLL] = {
+               .desc = {
+                       .name   = "db8500-vpll",
+                       .id     = DB8500_REGULATOR_VPLL,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VSMPS1] = {
+               .desc = {
+                       .name   = "db8500-vsmps1",
+                       .id     = DB8500_REGULATOR_VSMPS1,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VSMPS2] = {
+               .desc = {
+                       .name   = "db8500-vsmps2",
+                       .id     = DB8500_REGULATOR_VSMPS2,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .exclude_from_power_state = true,
+       },
+       [DB8500_REGULATOR_VSMPS3] = {
+               .desc = {
+                       .name   = "db8500-vsmps3",
+                       .id     = DB8500_REGULATOR_VSMPS3,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_VRF1] = {
+               .desc = {
+                       .name   = "db8500-vrf1",
+                       .id     = DB8500_REGULATOR_VRF1,
+                       .ops    = &db8500_regulator_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+       },
+       [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
+               .desc = {
+                       .name   = "db8500-sva-mmdsp",
+                       .id     = DB8500_REGULATOR_SWITCH_SVAMMDSP,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SVAMMDSP,
+       },
+       [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
+               .desc = {
+                       .name   = "db8500-sva-mmdsp-ret",
+                       .id     = DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SVAMMDSP,
+               .is_ramret = true,
+       },
+       [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
+               .desc = {
+                       .name   = "db8500-sva-pipe",
+                       .id     = DB8500_REGULATOR_SWITCH_SVAPIPE,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SVAPIPE,
+       },
+       [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
+               .desc = {
+                       .name   = "db8500-sia-mmdsp",
+                       .id     = DB8500_REGULATOR_SWITCH_SIAMMDSP,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SIAMMDSP,
+       },
+       [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
+               .desc = {
+                       .name   = "db8500-sia-mmdsp-ret",
+                       .id     = DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SIAMMDSP,
+               .is_ramret = true,
+       },
+       [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
+               .desc = {
+                       .name   = "db8500-sia-pipe",
+                       .id     = DB8500_REGULATOR_SWITCH_SIAPIPE,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SIAPIPE,
+       },
+       [DB8500_REGULATOR_SWITCH_SGA] = {
+               .desc = {
+                       .name   = "db8500-sga",
+                       .id     = DB8500_REGULATOR_SWITCH_SGA,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_SGA,
+       },
+       [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
+               .desc = {
+                       .name   = "db8500-b2r2-mcde",
+                       .id     = DB8500_REGULATOR_SWITCH_B2R2_MCDE,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_B2R2_MCDE,
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM12] = {
+               .desc = {
+                       .name   = "db8500-esram12",
+                       .id     = DB8500_REGULATOR_SWITCH_ESRAM12,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id        = EPOD_ID_ESRAM12,
+               .is_enabled     = true,
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
+               .desc = {
+                       .name   = "db8500-esram12-ret",
+                       .id     = DB8500_REGULATOR_SWITCH_ESRAM12RET,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_ESRAM12,
+               .is_ramret = true,
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM34] = {
+               .desc = {
+                       .name   = "db8500-esram34",
+                       .id     = DB8500_REGULATOR_SWITCH_ESRAM34,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id        = EPOD_ID_ESRAM34,
+               .is_enabled     = true,
+       },
+       [DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
+               .desc = {
+                       .name   = "db8500-esram34-ret",
+                       .id     = DB8500_REGULATOR_SWITCH_ESRAM34RET,
+                       .ops    = &db8500_regulator_switch_ops,
+                       .type   = REGULATOR_VOLTAGE,
+                       .owner  = THIS_MODULE,
+               },
+               .epod_id = EPOD_ID_ESRAM34,
+               .is_ramret = true,
+       },
+};
+
+static int __devinit db8500_regulator_probe(struct platform_device *pdev)
+{
+       struct regulator_init_data *db8500_init_data = mfd_get_data(pdev);
+       int i, err;
+
+       /* register all regulators */
+       for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
+               struct db8500_regulator_info *info;
+               struct regulator_init_data *init_data = &db8500_init_data[i];
+
+               /* assign per-regulator data */
+               info = &db8500_regulator_info[i];
+               info->dev = &pdev->dev;
+
+               /* register with the regulator framework */
+               info->rdev = regulator_register(&info->desc, &pdev->dev,
+                               init_data, info);
+               if (IS_ERR(info->rdev)) {
+                       err = PTR_ERR(info->rdev);
+                       dev_err(&pdev->dev, "failed to register %s: err %i\n",
+                               info->desc.name, err);
+
+                       /* if failing, unregister all earlier regulators */
+                       i--;
+                       while (i >= 0) {
+                               info = &db8500_regulator_info[i];
+                               regulator_unregister(info->rdev);
+                               i--;
+                       }
+                       return err;
+               }
+
+               dev_dbg(rdev_get_dev(info->rdev),
+                       "regulator-%s-probed\n", info->desc.name);
+       }
+
+       return 0;
+}
+
+static int __exit db8500_regulator_remove(struct platform_device *pdev)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
+               struct db8500_regulator_info *info;
+               info = &db8500_regulator_info[i];
+
+               dev_vdbg(rdev_get_dev(info->rdev),
+                       "regulator-%s-remove\n", info->desc.name);
+
+               regulator_unregister(info->rdev);
+       }
+
+       return 0;
+}
+
+static struct platform_driver db8500_regulator_driver = {
+       .driver = {
+               .name = "db8500-prcmu-regulators",
+               .owner = THIS_MODULE,
+       },
+       .probe = db8500_regulator_probe,
+       .remove = __exit_p(db8500_regulator_remove),
+};
+
+static int __init db8500_regulator_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&db8500_regulator_driver);
+       if (ret < 0)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit db8500_regulator_exit(void)
+{
+       platform_driver_unregister(&db8500_regulator_driver);
+}
+
+arch_initcall(db8500_regulator_init);
+module_exit(db8500_regulator_exit);
+
+MODULE_AUTHOR("STMicroelectronics/ST-Ericsson");
+MODULE_DESCRIPTION("DB8500 regulator driver");
+MODULE_LICENSE("GPL v2");
index 42891726ea7296ef867453e4423b9d4f0909fdad..b8f4e9e66cd516c3987ba1983da791bc3d059d70 100644 (file)
@@ -992,4 +992,11 @@ config RTC_DRV_TEGRA
          This drive can also be built as a module. If so, the module
          will be called rtc-tegra.
 
+config RTC_DRV_TILE
+       tristate "Tilera hypervisor RTC support"
+       depends on TILE
+       help
+         Enable support for the Linux driver side of the Tilera
+         hypervisor's real-time clock interface.
+
 endif # RTC_CLASS
index ca91c3c42e98f6f7effa5ce95463f26e11d34a74..9574748d1c7312ba50af8485a9f37f0e1c31afd6 100644 (file)
@@ -93,6 +93,7 @@ obj-$(CONFIG_RTC_DRV_STMP)    += rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
 obj-$(CONFIG_RTC_DRV_TEGRA)    += rtc-tegra.o
 obj-$(CONFIG_RTC_DRV_TEST)     += rtc-test.o
+obj-$(CONFIG_RTC_DRV_TILE)     += rtc-tile.o
 obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl.o
 obj-$(CONFIG_RTC_DRV_TX4939)   += rtc-tx4939.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c
new file mode 100644 (file)
index 0000000..eb65daf
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ *
+ * Tilera-specific RTC driver.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+/* Platform device pointer. */
+static struct platform_device *tile_rtc_platform_device;
+
+/*
+ * RTC read routine.  Gets time info from RTC chip via hypervisor syscall.
+ */
+static int read_rtc_time(struct device *dev, struct rtc_time *tm)
+{
+       HV_RTCTime hvtm = hv_get_rtc();
+
+       tm->tm_sec = hvtm.tm_sec;
+       tm->tm_min = hvtm.tm_min;
+       tm->tm_hour = hvtm.tm_hour;
+       tm->tm_mday = hvtm.tm_mday;
+       tm->tm_mon = hvtm.tm_mon;
+       tm->tm_year = hvtm.tm_year;
+       tm->tm_wday = 0;
+       tm->tm_yday = 0;
+       tm->tm_isdst = 0;
+
+       if (rtc_valid_tm(tm) < 0)
+               dev_warn(dev, "Read invalid date/time from RTC\n");
+
+       return 0;
+}
+
+/*
+ * RTC write routine.  Sends time info to hypervisor via syscall, to be
+ * written to RTC chip.
+ */
+static int set_rtc_time(struct device *dev, struct rtc_time *tm)
+{
+       HV_RTCTime hvtm;
+
+       hvtm.tm_sec = tm->tm_sec;
+       hvtm.tm_min = tm->tm_min;
+       hvtm.tm_hour = tm->tm_hour;
+       hvtm.tm_mday = tm->tm_mday;
+       hvtm.tm_mon = tm->tm_mon;
+       hvtm.tm_year = tm->tm_year;
+
+       hv_set_rtc(hvtm);
+
+       return 0;
+}
+
+/*
+ * RTC read/write ops.
+ */
+static const struct rtc_class_ops tile_rtc_ops = {
+       .read_time      = read_rtc_time,
+       .set_time       = set_rtc_time,
+};
+
+/*
+ * Device probe routine.
+ */
+static int __devinit tile_rtc_probe(struct platform_device *dev)
+{
+       struct rtc_device *rtc;
+
+       rtc = rtc_device_register("tile",
+                                 &dev->dev, &tile_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       platform_set_drvdata(dev, rtc);
+
+       return 0;
+}
+
+/*
+ * Device cleanup routine.
+ */
+static int __devexit tile_rtc_remove(struct platform_device *dev)
+{
+       struct rtc_device *rtc = platform_get_drvdata(dev);
+
+       if (rtc)
+               rtc_device_unregister(rtc);
+
+       platform_set_drvdata(dev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver tile_rtc_platform_driver = {
+       .driver         = {
+               .name   = "rtc-tile",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = tile_rtc_probe,
+       .remove         = __devexit_p(tile_rtc_remove),
+};
+
+/*
+ * Driver init routine.
+ */
+static int __init tile_rtc_driver_init(void)
+{
+       int err;
+
+       err = platform_driver_register(&tile_rtc_platform_driver);
+       if (err)
+               return err;
+
+       tile_rtc_platform_device = platform_device_alloc("rtc-tile", 0);
+       if (tile_rtc_platform_device == NULL) {
+               err = -ENOMEM;
+               goto exit_driver_unregister;
+       }
+
+       err = platform_device_add(tile_rtc_platform_device);
+       if (err)
+               goto exit_device_put;
+
+       return 0;
+
+exit_device_put:
+       platform_device_put(tile_rtc_platform_device);
+
+exit_driver_unregister:
+       platform_driver_unregister(&tile_rtc_platform_driver);
+       return err;
+}
+
+/*
+ * Driver cleanup routine.
+ */
+static void __exit tile_rtc_driver_exit(void)
+{
+       platform_driver_unregister(&tile_rtc_platform_driver);
+}
+
+module_init(tile_rtc_driver_init);
+module_exit(tile_rtc_driver_exit);
+
+MODULE_DESCRIPTION("Tilera-specific Real Time Clock Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rtc-tile");
index 35381cb0936e751775f2e9e770f399577d810361..03e522b2fe0be6f70f9bc4838ff109a789e1c0c1 100644 (file)
@@ -655,6 +655,27 @@ static int qla4_8xxx_pci_is_same_window(struct scsi_qla_host *ha,
        return 0;
 }
 
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+       const volatile u32 __iomem *p = addr;
+       u32 low, high;
+
+       low = readl(p);
+       high = readl(p + 1);
+
+       return low + ((u64)high << 32);
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(__u64 val, volatile void __iomem *addr)
+{
+       writel(val, addr);
+       writel(val >> 32, addr+4);
+}
+#endif
+
 static int qla4_8xxx_pci_mem_read_direct(struct scsi_qla_host *ha,
                u64 off, void *data, int size)
 {
index 95019c747cc17cad69ed22c9091c2228b914c23b..4778e27071689593ec4fdffdd1107018c2f7ebe6 100644 (file)
@@ -636,7 +636,7 @@ static int sr_probe(struct device *dev)
        disk->first_minor = minor;
        sprintf(disk->disk_name, "sr%d", minor);
        disk->fops = &sr_bdops;
-       disk->flags = GENHD_FL_CD;
+       disk->flags = GENHD_FL_CD | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
        disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST;
 
        blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT);
index 31d7ba8299e7ab2df701d2d5d04c646140e6ce53..77dfb4070c1d11f470457d89c149345ddf524212 100644 (file)
@@ -587,7 +587,7 @@ ar6k_cfg80211_connect_event(struct ar6_softc *ar, u16 channel,
                                 WLAN_STATUS_SUCCESS, GFP_KERNEL);
     } else {
         /* inform roam event to cfg80211 */
-        cfg80211_roamed(ar->arNetDev, bssid,
+       cfg80211_roamed(ar->arNetDev, ibss_channel, bssid,
                         assocReqIe, assocReqLen,
                         assocRespIe, assocRespLen,
                         GFP_KERNEL);
index e3b409bb9847b708444ae03e88beda648630b5f4..1827b0bf9201e1b868f404172d4cf71ed1b93b59 100644 (file)
@@ -2869,7 +2869,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
        wl_update_prof(wl, NULL, &e->addr, WL_PROF_BSSID);
        wl_update_bss_info(wl);
 
-       cfg80211_roamed(ndev,
+       cfg80211_roamed(ndev, NULL,
                        (u8 *)wl_read_prof(wl, WL_PROF_BSSID),
                        conn_info->req_ie, conn_info->req_ie_len,
                        conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
index 76378397b763355c059ace7b5fe6bdd09abaf80c..fb466f4c92e00794085a6e628bb66a44b1ecf133 100644 (file)
@@ -695,7 +695,7 @@ void prism2_disconnected(wlandevice_t *wlandev)
 
 void prism2_roamed(wlandevice_t *wlandev)
 {
-       cfg80211_roamed(wlandev->netdev, wlandev->bssid,
+       cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid,
                NULL, 0, NULL, 0, GFP_KERNEL);
 }
 
index b8a2b30a157216f63506c4fbbd2cda539bd186f3..77ac2d4d3ef17dc72e9d2633f8f9846ff766c2c8 100644 (file)
@@ -1181,9 +1181,12 @@ static bool zcache_freeze;
 /*
  * zcache shrinker interface (only useful for ephemeral pages, so zbud only)
  */
-static int shrink_zcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int shrink_zcache_memory(struct shrinker *shrink,
+                               struct shrink_control *sc)
 {
        int ret = -1;
+       int nr = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        if (nr >= 0) {
                if (!(gfp_mask & __GFP_FS))
index d5bfd41707e754c0c5803eb8d30c751927052c65..e0a77540b8ca39bbed2d4e771e18f443b1be8492 100644 (file)
@@ -281,7 +281,7 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
 #ifdef CONFIG_MAGIC_SYSRQ
                        } else if (ch == 0x10) { /* ^P */
                                show_state();
-                               show_free_areas();
+                               show_free_areas(0);
                                show_buffers();
 /*                             show_net_buffers(); */
                                return;
index c63d0d152af675fa15e78dee69844640309eabc8..f2cb7503fcb213115b3b15722495c335a0aad984 100644 (file)
@@ -15,6 +15,7 @@
  *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  */
 #include <linux/serial_reg.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/serial_core.h>
index f9916ca5ca4d44a7fcac405f8329678526445164..549b960667c81b5bcbff1145550a28630038c374 100644 (file)
@@ -1460,6 +1460,14 @@ config FB_S3
        ---help---
          Driver for graphics boards with S3 Trio / S3 Virge chip.
 
+config FB_S3_DDC
+       bool "DDC for S3 support"
+       depends on FB_S3
+       select FB_DDC
+       default y
+       help
+         Say Y here if you want DDC support for your S3 graphics card.
+
 config FB_SAVAGE
        tristate "S3 Savage support"
        depends on FB && PCI && EXPERIMENTAL
@@ -1983,6 +1991,18 @@ config FB_SH_MOBILE_HDMI
        ---help---
          Driver for the on-chip SH-Mobile HDMI controller.
 
+config FB_SH_MOBILE_MERAM
+       tristate "SuperH Mobile MERAM read ahead support for LCDC"
+       depends on FB_SH_MOBILE_LCDC
+       default y
+       ---help---
+         Enable MERAM support for the SH-Mobile LCD controller.
+
+         This will allow for caching of the framebuffer to provide more
+         reliable access under heavy main memory bus traffic situations.
+         Up to 4 memory channels can be configured, allowing 4 RGB or
+         2 YCbCr framebuffers to be configured.
+
 config FB_TMIO
        tristate "Toshiba Mobile IO FrameBuffer support"
        depends on FB && MFD_CORE
@@ -2246,29 +2266,43 @@ config FB_METRONOME
 config FB_MB862XX
        tristate "Fujitsu MB862xx GDC support"
        depends on FB
+       depends on PCI || (OF && PPC)
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        ---help---
          Frame buffer driver for Fujitsu Carmine/Coral-P(A)/Lime controllers.
 
+choice
+       prompt "GDC variant"
+       depends on FB_MB862XX
+
 config FB_MB862XX_PCI_GDC
        bool "Carmine/Coral-P(A) GDC"
-       depends on PCI && FB_MB862XX
+       depends on PCI
        ---help---
          This enables framebuffer support for Fujitsu Carmine/Coral-P(A)
          PCI graphics controller devices.
 
 config FB_MB862XX_LIME
        bool "Lime GDC"
-       depends on FB_MB862XX
-       depends on OF && !FB_MB862XX_PCI_GDC
-       depends on PPC
+       depends on OF && PPC
        select FB_FOREIGN_ENDIAN
        select FB_LITTLE_ENDIAN
        ---help---
          Framebuffer support for Fujitsu Lime GDC on host CPU bus.
 
+endchoice
+
+config FB_MB862XX_I2C
+       bool "Support I2C bus on MB862XX GDC"
+       depends on FB_MB862XX && I2C
+       default y
+       help
+         Selecting this option adds Coral-P(A)/Lime GDC I2C bus adapter
+         driver to support accessing I2C devices on controller's I2C bus.
+         These are usually some video decoder chips.
+
 config FB_EP93XX
        tristate "EP93XX frame buffer support"
        depends on FB && ARCH_EP93XX
index 2ea44b6625fef806296ee3a2c551b2cb58af730a..8b83129e209ca0f943a3d624e29930a679aec110 100644 (file)
@@ -130,6 +130,7 @@ obj-$(CONFIG_FB_UDL)                  += udlfb.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 obj-$(CONFIG_SH_MIPI_DSI)        += sh_mipi_dsi.o
 obj-$(CONFIG_FB_SH_MOBILE_HDMI)          += sh_mobile_hdmi.o
+obj-$(CONFIG_FB_SH_MOBILE_MERAM)  += sh_mobile_meram.o
 obj-$(CONFIG_FB_SH_MOBILE_LCDC)          += sh_mobile_lcdcfb.o
 obj-$(CONFIG_FB_OMAP)             += omap/
 obj-y                             += omap2/
index e5d6b56d4447e274d0db3f8eedf68cda99bfb53e..5ea6596dd824084971b49bdf2e9364df7832746c 100644 (file)
@@ -2224,22 +2224,23 @@ static int amifb_ioctl(struct fb_info *info,
         * Allocate, Clear and Align a Block of Chip Memory
         */
 
-static u_long unaligned_chipptr = 0;
+static void *aligned_chipptr;
 
 static inline u_long __init chipalloc(u_long size)
 {
-       size += PAGE_SIZE-1;
-       if (!(unaligned_chipptr = (u_long)amiga_chip_alloc(size,
-                                                          "amifb [RAM]")))
-               panic("No Chip RAM for frame buffer");
-       memset((void *)unaligned_chipptr, 0, size);
-       return PAGE_ALIGN(unaligned_chipptr);
+       aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]");
+       if (!aligned_chipptr) {
+               pr_err("amifb: No Chip RAM for frame buffer");
+               return 0;
+       }
+       memset(aligned_chipptr, 0, size);
+       return (u_long)aligned_chipptr;
 }
 
 static inline void chipfree(void)
 {
-       if (unaligned_chipptr)
-               amiga_chip_free((void *)unaligned_chipptr);
+       if (aligned_chipptr)
+               amiga_chip_free(aligned_chipptr);
 }
 
 
@@ -2295,7 +2296,7 @@ default_chipset:
                            defmode = amiga_vblank == 50 ? DEFMODE_PAL
                                                         : DEFMODE_NTSC;
                        if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-                           VIDEOMEMSIZE_ECS_1M)
+                           VIDEOMEMSIZE_ECS_2M)
                                fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
                        else
                                fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
@@ -2312,7 +2313,7 @@ default_chipset:
                        maxfmode = TAG_FMODE_4;
                        defmode = DEFMODE_AGA;
                        if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
-                           VIDEOMEMSIZE_AGA_1M)
+                           VIDEOMEMSIZE_AGA_2M)
                                fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
                        else
                                fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
@@ -2385,6 +2386,10 @@ default_chipset:
                            DUMMYSPRITEMEMSIZE+
                            COPINITSIZE+
                            4*COPLISTSIZE);
+       if (!chipptr) {
+               err = -ENOMEM;
+               goto amifb_error;
+       }
 
        assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
        assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
index af3119707dbfe2a65b4f9a9da2e9eadee6e5360d..d1aee730d7d80e7dd674dce346e27c812cc3e8d3 100644 (file)
@@ -211,8 +211,12 @@ static ssize_t adp5520_bl_daylight_max_store(struct device *dev,
                        const char *buf, size_t count)
 {
        struct adp5520_bl *data = dev_get_drvdata(dev);
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data->cached_daylight_max);
+       if (ret < 0)
+               return ret;
 
-       strict_strtoul(buf, 10, &data->cached_daylight_max);
        return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_MAX);
 }
 static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
index 8b7d47386f3983d883e04bb26be5837a23c65437..fcdac872522d66702e0035bfda682ae189547eec 100644 (file)
@@ -899,7 +899,7 @@ static struct fb_ops da8xx_fb_ops = {
        .fb_blank = cfb_blank,
 };
 
-static int __init fb_probe(struct platform_device *device)
+static int __devinit fb_probe(struct platform_device *device)
 {
        struct da8xx_lcdc_platform_data *fb_pdata =
                                                device->dev.platform_data;
@@ -1165,7 +1165,7 @@ static int fb_resume(struct platform_device *dev)
 
 static struct platform_driver da8xx_fb_driver = {
        .probe = fb_probe,
-       .remove = fb_remove,
+       .remove = __devexit_p(fb_remove),
        .suspend = fb_suspend,
        .resume = fb_resume,
        .driver = {
index 4eb38db36e4b4a3c9d50e6a169cd71fd088ba8cb..fb205843c2c726da59b7f5f20c0c338ddba005d6 100644 (file)
@@ -242,9 +242,9 @@ static int set_system(const struct dmi_system_id *id)
                return 0;
        }
 
-       printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
+       printk(KERN_INFO "efifb: dmi detected %s - framebuffer at 0x%08x "
                         "(%dx%d, stride %d)\n", id->ident,
-                        (void *)screen_info.lfb_base, screen_info.lfb_width,
+                        screen_info.lfb_base, screen_info.lfb_width,
                         screen_info.lfb_height, screen_info.lfb_linelength);
 
 
index d7777714166b89a5ac24e235d7b53b7bc1a0d81f..5707ed0e31a7378bd98ba8e53df736ce1e19f427 100644 (file)
@@ -2,4 +2,7 @@
 # Makefile for the MB862xx framebuffer driver
 #
 
-obj-$(CONFIG_FB_MB862XX)       := mb862xxfb.o mb862xxfb_accel.o
+obj-$(CONFIG_FB_MB862XX) += mb862xxfb.o
+
+mb862xxfb-y := mb862xxfbdrv.o mb862xxfb_accel.o
+mb862xxfb-$(CONFIG_FB_MB862XX_I2C) += mb862xx-i2c.o
diff --git a/drivers/video/mb862xx/mb862xx-i2c.c b/drivers/video/mb862xx/mb862xx-i2c.c
new file mode 100644 (file)
index 0000000..b953099
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Coral-P(A)/Lime I2C adapter driver
+ *
+ * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.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.
+ *
+ */
+
+#include <linux/fb.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "mb862xxfb.h"
+#include "mb862xx_reg.h"
+
+static int mb862xx_i2c_wait_event(struct i2c_adapter *adap)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+       u32 reg;
+
+       do {
+               udelay(1);
+               reg = inreg(i2c, GC_I2C_BCR);
+               if (reg & (I2C_INT | I2C_BER))
+                       break;
+       } while (1);
+
+       return (reg & I2C_BER) ? 0 : 1;
+}
+
+static int mb862xx_i2c_do_address(struct i2c_adapter *adap, int addr)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+
+       outreg(i2c, GC_I2C_DAR, addr);
+       outreg(i2c, GC_I2C_CCR, I2C_CLOCK_AND_ENABLE);
+       outreg(i2c, GC_I2C_BCR, par->i2c_rs ? I2C_REPEATED_START : I2C_START);
+       if (!mb862xx_i2c_wait_event(adap))
+               return -EIO;
+       par->i2c_rs = !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);
+       return par->i2c_rs;
+}
+
+static int mb862xx_i2c_write_byte(struct i2c_adapter *adap, u8 byte)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+
+       outreg(i2c, GC_I2C_DAR, byte);
+       outreg(i2c, GC_I2C_BCR, I2C_START);
+       if (!mb862xx_i2c_wait_event(adap))
+               return -EIO;
+       return !(inreg(i2c, GC_I2C_BSR) & I2C_LRB);
+}
+
+static int mb862xx_i2c_read_byte(struct i2c_adapter *adap, u8 *byte, int last)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+
+       outreg(i2c, GC_I2C_BCR, I2C_START | (last ? 0 : I2C_ACK));
+       if (!mb862xx_i2c_wait_event(adap))
+               return 0;
+       *byte = inreg(i2c, GC_I2C_DAR);
+       return 1;
+}
+
+void mb862xx_i2c_stop(struct i2c_adapter *adap)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+
+       outreg(i2c, GC_I2C_BCR, I2C_STOP);
+       outreg(i2c, GC_I2C_CCR, I2C_DISABLE);
+       par->i2c_rs = 0;
+}
+
+static int mb862xx_i2c_read(struct i2c_adapter *adap, struct i2c_msg *m)
+{
+       int i, ret = 0;
+       int last = m->len - 1;
+
+       for (i = 0; i < m->len; i++) {
+               if (!mb862xx_i2c_read_byte(adap, &m->buf[i], i == last)) {
+                       ret = -EIO;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int mb862xx_i2c_write(struct i2c_adapter *adap, struct i2c_msg *m)
+{
+       int i, ret = 0;
+
+       for (i = 0; i < m->len; i++) {
+               if (!mb862xx_i2c_write_byte(adap, m->buf[i])) {
+                       ret = -EIO;
+                       break;
+               }
+       }
+       return ret;
+}
+
+static int mb862xx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+                       int num)
+{
+       struct mb862xxfb_par *par = adap->algo_data;
+       struct i2c_msg *m;
+       int addr;
+       int i = 0, err = 0;
+
+       dev_dbg(par->dev, "%s: %d msgs\n", __func__, num);
+
+       for (i = 0; i < num; i++) {
+               m = &msgs[i];
+               if (!m->len) {
+                       dev_dbg(par->dev, "%s: null msgs\n", __func__);
+                       continue;
+               }
+               addr = m->addr;
+               if (m->flags & I2C_M_RD)
+                       addr |= 1;
+
+               err = mb862xx_i2c_do_address(adap, addr);
+               if (err < 0)
+                       break;
+               if (m->flags & I2C_M_RD)
+                       err = mb862xx_i2c_read(adap, m);
+               else
+                       err = mb862xx_i2c_write(adap, m);
+       }
+
+       if (i)
+               mb862xx_i2c_stop(adap);
+
+       return (err < 0) ? err : i;
+}
+
+static u32 mb862xx_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static const struct i2c_algorithm mb862xx_algo = {
+       .master_xfer    = mb862xx_xfer,
+       .functionality  = mb862xx_func,
+};
+
+static struct i2c_adapter mb862xx_i2c_adapter = {
+       .name           = "MB862xx I2C adapter",
+       .algo           = &mb862xx_algo,
+       .owner          = THIS_MODULE,
+};
+
+int mb862xx_i2c_init(struct mb862xxfb_par *par)
+{
+       int ret;
+
+       mb862xx_i2c_adapter.algo_data = par;
+       par->adap = &mb862xx_i2c_adapter;
+
+       ret = i2c_add_adapter(par->adap);
+       if (ret < 0) {
+               dev_err(par->dev, "failed to add %s\n",
+                       mb862xx_i2c_adapter.name);
+       }
+       return ret;
+}
+
+void mb862xx_i2c_exit(struct mb862xxfb_par *par)
+{
+       if (par->adap) {
+               i2c_del_adapter(par->adap);
+               par->adap = NULL;
+       }
+}
index 2ba65e118500e99b1874e47aa94f3ded12dd0493..9df48b8edc94f6e745391a6a8ab9e3f9bb3de764 100644 (file)
@@ -5,11 +5,8 @@
 #ifndef _MB862XX_REG_H
 #define _MB862XX_REG_H
 
-#ifdef MB862XX_MMIO_BOTTOM
-#define MB862XX_MMIO_BASE      0x03fc0000
-#else
 #define MB862XX_MMIO_BASE      0x01fc0000
-#endif
+#define MB862XX_MMIO_HIGH_BASE 0x03fc0000
 #define MB862XX_I2C_BASE       0x0000c000
 #define MB862XX_DISP_BASE      0x00010000
 #define MB862XX_CAP_BASE       0x00018000
@@ -23,6 +20,7 @@
 #define GC_IMASK               0x00000024
 #define GC_SRST                        0x0000002c
 #define GC_CCF                 0x00000038
+#define GC_RSW                 0x0000005c
 #define GC_CID                 0x000000f0
 #define GC_REVISION            0x00000084
 
 #define GC_L0OA0               0x00000024
 #define GC_L0DA0               0x00000028
 #define GC_L0DY_L0DX           0x0000002c
+#define GC_L1M                 0x00000030
+#define GC_L1DA                        0x00000034
 #define GC_DCM1                        0x00000100
 #define GC_L0EM                        0x00000110
 #define GC_L0WY_L0WX           0x00000114
 #define GC_L0WH_L0WW           0x00000118
+#define GC_L1EM                        0x00000120
+#define GC_L1WY_L1WX           0x00000124
+#define GC_L1WH_L1WW           0x00000128
+#define GC_DLS                 0x00000180
 #define GC_DCM2                        0x00000104
 #define GC_DCM3                        0x00000108
 #define GC_CPM_CUTC            0x000000a0
 
 #define GC_CPM_CEN0            0x00100000
 #define GC_CPM_CEN1            0x00200000
+#define GC_DCM1_DEN            0x80000000
+#define GC_DCM1_L1E            0x00020000
+#define GC_L1M_16              0x80000000
+#define GC_L1M_YC              0x40000000
+#define GC_L1M_CS              0x20000000
 
 #define GC_DCM01_ESY           0x00000004
 #define GC_DCM01_SC            0x00003f00
 #define GC_L0M_L0C_16          0x80000000
 #define GC_L0EM_L0EC_24                0x40000000
 #define GC_L0M_L0W_UNIT                64
+#define GC_L1EM_DM             0x02000000
 
 #define GC_DISP_REFCLK_400     400
 
+/* I2C */
+#define GC_I2C_BSR             0x00000000      /* BSR */
+#define GC_I2C_BCR             0x00000004      /* BCR */
+#define GC_I2C_CCR             0x00000008      /* CCR */
+#define GC_I2C_ADR             0x0000000C      /* ADR */
+#define GC_I2C_DAR             0x00000010      /* DAR */
+
+#define I2C_DISABLE            0x00000000
+#define I2C_STOP               0x00000000
+#define I2C_START              0x00000010
+#define I2C_REPEATED_START     0x00000030
+#define I2C_CLOCK_AND_ENABLE   0x0000003f
+#define I2C_READY              0x01
+#define I2C_INT                        0x01
+#define I2C_INTE               0x02
+#define I2C_ACK                        0x08
+#define I2C_BER                        0x80
+#define I2C_BEIE               0x40
+#define I2C_TRX                        0x80
+#define I2C_LRB                        0x10
+
+/* Capture registers and bits */
+#define GC_CAP_VCM             0x00000000
+#define GC_CAP_CSC             0x00000004
+#define GC_CAP_VCS             0x00000008
+#define GC_CAP_CBM             0x00000010
+#define GC_CAP_CBOA            0x00000014
+#define GC_CAP_CBLA            0x00000018
+#define GC_CAP_IMG_START       0x0000001C
+#define GC_CAP_IMG_END         0x00000020
+#define GC_CAP_CMSS            0x00000048
+#define GC_CAP_CMDS            0x0000004C
+
+#define GC_VCM_VIE             0x80000000
+#define GC_VCM_CM              0x03000000
+#define GC_VCM_VS_PAL          0x00000002
+#define GC_CBM_OO              0x80000000
+#define GC_CBM_HRV             0x00000010
+#define GC_CBM_CBST            0x00000001
+
 /* Carmine specific */
 #define MB86297_DRAW_BASE              0x00020000
 #define MB86297_DISP0_BASE             0x00100000
index d7e7cb76bbf2522dd05398cd6442da90e2ae7c56..8550630c1e01dc8ee71d64aee5a43755fef6115a 100644 (file)
@@ -1,6 +1,26 @@
 #ifndef __MB862XX_H__
 #define __MB862XX_H__
 
+struct mb862xx_l1_cfg {
+       unsigned short sx;
+       unsigned short sy;
+       unsigned short sw;
+       unsigned short sh;
+       unsigned short dx;
+       unsigned short dy;
+       unsigned short dw;
+       unsigned short dh;
+       int mirror;
+};
+
+#define MB862XX_BASE           'M'
+#define MB862XX_L1_GET_CFG     _IOR(MB862XX_BASE, 0, struct mb862xx_l1_cfg*)
+#define MB862XX_L1_SET_CFG     _IOW(MB862XX_BASE, 1, struct mb862xx_l1_cfg*)
+#define MB862XX_L1_ENABLE      _IOW(MB862XX_BASE, 2, int)
+#define MB862XX_L1_CAP_CTL     _IOW(MB862XX_BASE, 3, int)
+
+#ifdef __KERNEL__
+
 #define PCI_VENDOR_ID_FUJITSU_LIMITED  0x10cf
 #define PCI_DEVICE_ID_FUJITSU_CORALP   0x2019
 #define PCI_DEVICE_ID_FUJITSU_CORALPA  0x201e
@@ -38,6 +58,8 @@ struct mb862xxfb_par {
        void __iomem            *mmio_base;     /* remapped registers */
        size_t                  mapped_vram;    /* length of remapped vram */
        size_t                  mmio_len;       /* length of register region */
+       unsigned long           cap_buf;        /* capture buffers offset */
+       size_t                  cap_len;        /* length of capture buffers */
 
        void __iomem            *host;          /* relocatable reg. bases */
        void __iomem            *i2c;
@@ -57,11 +79,23 @@ struct mb862xxfb_par {
        unsigned int            refclk;         /* disp. reference clock */
        struct mb862xx_gc_mode  *gc_mode;       /* GDC mode init data */
        int                     pre_init;       /* don't init display if 1 */
+       struct i2c_adapter      *adap;          /* GDC I2C bus adapter */
+       int                     i2c_rs;
+
+       struct mb862xx_l1_cfg   l1_cfg;
+       int                     l1_stride;
 
        u32                     pseudo_palette[16];
 };
 
 extern void mb862xxfb_init_accel(struct fb_info *info, int xres);
+#ifdef CONFIG_FB_MB862XX_I2C
+extern int mb862xx_i2c_init(struct mb862xxfb_par *par);
+extern void mb862xx_i2c_exit(struct mb862xxfb_par *par);
+#else
+static inline int mb862xx_i2c_init(struct mb862xxfb_par *par) { return 0; }
+static inline void mb862xx_i2c_exit(struct mb862xxfb_par *par) { }
+#endif
 
 #if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC)
 #error "Select Lime GDC or CoralP/Carmine support, but not both together"
@@ -82,4 +116,6 @@ extern void mb862xxfb_init_accel(struct fb_info *info, int xres);
 
 #define pack(a, b)     (((a) << 16) | (b))
 
+#endif /* __KERNEL__ */
+
 #endif
similarity index 86%
rename from drivers/video/mb862xx/mb862xxfb.c
rename to drivers/video/mb862xx/mb862xxfbdrv.c
index c76e663a6cd41a6ab43721174bf5e08b0cb0f095..ea39336addfb791a2f806d4854e70675461a1158 100644 (file)
@@ -27,7 +27,7 @@
 
 #define NR_PALETTE             256
 #define MB862XX_MEM_SIZE       0x1000000
-#define CORALP_MEM_SIZE                0x4000000
+#define CORALP_MEM_SIZE                0x2000000
 #define CARMINE_MEM_SIZE       0x8000000
 #define DRV_NAME               "mb862xxfb"
 
@@ -309,6 +309,97 @@ static int mb862xxfb_blank(int mode, struct fb_info *fbi)
        return 0;
 }
 
+static int mb862xxfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+                          unsigned long arg)
+{
+       struct mb862xxfb_par *par = fbi->par;
+       struct mb862xx_l1_cfg *l1_cfg = &par->l1_cfg;
+       void __user *argp = (void __user *)arg;
+       int *enable;
+       u32 l1em = 0;
+
+       switch (cmd) {
+       case MB862XX_L1_GET_CFG:
+               if (copy_to_user(argp, l1_cfg, sizeof(*l1_cfg)))
+                       return -EFAULT;
+               break;
+       case MB862XX_L1_SET_CFG:
+               if (copy_from_user(l1_cfg, argp, sizeof(*l1_cfg)))
+                       return -EFAULT;
+               if ((l1_cfg->sw >= l1_cfg->dw) && (l1_cfg->sh >= l1_cfg->dh)) {
+                       /* downscaling */
+                       outreg(cap, GC_CAP_CSC,
+                               pack((l1_cfg->sh << 11) / l1_cfg->dh,
+                                    (l1_cfg->sw << 11) / l1_cfg->dw));
+                       l1em = inreg(disp, GC_L1EM);
+                       l1em &= ~GC_L1EM_DM;
+               } else if ((l1_cfg->sw <= l1_cfg->dw) &&
+                          (l1_cfg->sh <= l1_cfg->dh)) {
+                       /* upscaling */
+                       outreg(cap, GC_CAP_CSC,
+                               pack((l1_cfg->sh << 11) / l1_cfg->dh,
+                                    (l1_cfg->sw << 11) / l1_cfg->dw));
+                       outreg(cap, GC_CAP_CMSS,
+                               pack(l1_cfg->sw >> 1, l1_cfg->sh));
+                       outreg(cap, GC_CAP_CMDS,
+                               pack(l1_cfg->dw >> 1, l1_cfg->dh));
+                       l1em = inreg(disp, GC_L1EM);
+                       l1em |= GC_L1EM_DM;
+               }
+
+               if (l1_cfg->mirror) {
+                       outreg(cap, GC_CAP_CBM,
+                               inreg(cap, GC_CAP_CBM) | GC_CBM_HRV);
+                       l1em |= l1_cfg->dw * 2 - 8;
+               } else {
+                       outreg(cap, GC_CAP_CBM,
+                               inreg(cap, GC_CAP_CBM) & ~GC_CBM_HRV);
+                       l1em &= 0xffff0000;
+               }
+               outreg(disp, GC_L1EM, l1em);
+               break;
+       case MB862XX_L1_ENABLE:
+               enable = (int *)arg;
+               if (*enable) {
+                       outreg(disp, GC_L1DA, par->cap_buf);
+                       outreg(cap, GC_CAP_IMG_START,
+                               pack(l1_cfg->sy >> 1, l1_cfg->sx));
+                       outreg(cap, GC_CAP_IMG_END,
+                               pack(l1_cfg->sh, l1_cfg->sw));
+                       outreg(disp, GC_L1M, GC_L1M_16 | GC_L1M_YC | GC_L1M_CS |
+                                            (par->l1_stride << 16));
+                       outreg(disp, GC_L1WY_L1WX,
+                               pack(l1_cfg->dy, l1_cfg->dx));
+                       outreg(disp, GC_L1WH_L1WW,
+                               pack(l1_cfg->dh - 1, l1_cfg->dw));
+                       outreg(disp, GC_DLS, 1);
+                       outreg(cap, GC_CAP_VCM,
+                               GC_VCM_VIE | GC_VCM_CM | GC_VCM_VS_PAL);
+                       outreg(disp, GC_DCM1, inreg(disp, GC_DCM1) |
+                                             GC_DCM1_DEN | GC_DCM1_L1E);
+               } else {
+                       outreg(cap, GC_CAP_VCM,
+                               inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE);
+                       outreg(disp, GC_DCM1,
+                               inreg(disp, GC_DCM1) & ~GC_DCM1_L1E);
+               }
+               break;
+       case MB862XX_L1_CAP_CTL:
+               enable = (int *)arg;
+               if (*enable) {
+                       outreg(cap, GC_CAP_VCM,
+                               inreg(cap, GC_CAP_VCM) | GC_VCM_VIE);
+               } else {
+                       outreg(cap, GC_CAP_VCM,
+                               inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE);
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
 /* framebuffer ops */
 static struct fb_ops mb862xxfb_ops = {
        .owner          = THIS_MODULE,
@@ -320,6 +411,7 @@ static struct fb_ops mb862xxfb_ops = {
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
+       .fb_ioctl       = mb862xxfb_ioctl,
 };
 
 /* initialize fb_info data */
@@ -328,6 +420,7 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
        struct mb862xxfb_par *par = fbi->par;
        struct mb862xx_gc_mode *mode = par->gc_mode;
        unsigned long reg;
+       int stride;
 
        fbi->fbops = &mb862xxfb_ops;
        fbi->pseudo_palette = par->pseudo_palette;
@@ -336,7 +429,6 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
 
        strcpy(fbi->fix.id, DRV_NAME);
        fbi->fix.smem_start = (unsigned long)par->fb_base_phys;
-       fbi->fix.smem_len = par->mapped_vram;
        fbi->fix.mmio_start = (unsigned long)par->mmio_base_phys;
        fbi->fix.mmio_len = par->mmio_len;
        fbi->fix.accel = FB_ACCEL_NONE;
@@ -420,6 +512,28 @@ static int mb862xxfb_init_fbinfo(struct fb_info *fbi)
                         FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
        fbi->fix.line_length = (fbi->var.xres_virtual *
                                fbi->var.bits_per_pixel) / 8;
+       fbi->fix.smem_len = fbi->fix.line_length * fbi->var.yres_virtual;
+
+       /*
+        * reserve space for capture buffers and two cursors
+        * at the end of vram: 720x576 * 2 * 2.2 + 64x64 * 16.
+        */
+       par->cap_buf = par->mapped_vram - 0x1bd800 - 0x10000;
+       par->cap_len = 0x1bd800;
+       par->l1_cfg.sx = 0;
+       par->l1_cfg.sy = 0;
+       par->l1_cfg.sw = 720;
+       par->l1_cfg.sh = 576;
+       par->l1_cfg.dx = 0;
+       par->l1_cfg.dy = 0;
+       par->l1_cfg.dw = 720;
+       par->l1_cfg.dh = 576;
+       stride = par->l1_cfg.sw * (fbi->var.bits_per_pixel / 8);
+       par->l1_stride = stride / 64 + ((stride % 64) ? 1 : 0);
+       outreg(cap, GC_CAP_CBM, GC_CBM_OO | GC_CBM_CBST |
+                               (par->l1_stride << 16));
+       outreg(cap, GC_CAP_CBOA, par->cap_buf);
+       outreg(cap, GC_CAP_CBLA, par->cap_buf + par->cap_len);
        return 0;
 }
 
@@ -742,22 +856,38 @@ static int coralp_init(struct mb862xxfb_par *par)
 
        par->refclk = GC_DISP_REFCLK_400;
 
+       if (par->mapped_vram >= 0x2000000) {
+               /* relocate gdc registers space */
+               writel(1, par->fb_base + MB862XX_MMIO_BASE + GC_RSW);
+               udelay(1); /* wait at least 20 bus cycles */
+       }
+
        ver = inreg(host, GC_CID);
        cn = (ver & GC_CID_CNAME_MSK) >> 8;
        ver = ver & GC_CID_VERSION_MSK;
        if (cn == 3) {
+               unsigned long reg;
+
                dev_info(par->dev, "Fujitsu Coral-%s GDC Rev.%d found\n",\
                         (ver == 6) ? "P" : (ver == 8) ? "PA" : "?",
                         par->pdev->revision);
-               outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133);
-               udelay(200);
-               outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL);
-               udelay(10);
+               reg = inreg(disp, GC_DCM1);
+               if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E)
+                       par->pre_init = 1;
+
+               if (!par->pre_init) {
+                       outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133);
+                       udelay(200);
+                       outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL);
+                       udelay(10);
+               }
                /* Clear interrupt status */
                outreg(host, GC_IST, 0);
        } else {
                return -ENODEV;
        }
+
+       mb862xx_i2c_init(par);
        return 0;
 }
 
@@ -899,7 +1029,13 @@ static int __devinit mb862xx_pci_probe(struct pci_dev *pdev,
        case PCI_DEVICE_ID_FUJITSU_CORALPA:
                par->fb_base_phys = pci_resource_start(par->pdev, 0);
                par->mapped_vram = CORALP_MEM_SIZE;
-               par->mmio_base_phys = par->fb_base_phys + MB862XX_MMIO_BASE;
+               if (par->mapped_vram >= 0x2000000) {
+                       par->mmio_base_phys = par->fb_base_phys +
+                                             MB862XX_MMIO_HIGH_BASE;
+               } else {
+                       par->mmio_base_phys = par->fb_base_phys +
+                                             MB862XX_MMIO_BASE;
+               }
                par->mmio_len = MB862XX_MMIO_SIZE;
                par->type = BT_CORALP;
                break;
@@ -1009,6 +1145,8 @@ static void __devexit mb862xx_pci_remove(struct pci_dev *pdev)
                outreg(host, GC_IMASK, 0);
        }
 
+       mb862xx_i2c_exit(par);
+
        device_remove_file(&pdev->dev, &dev_attr_dispregs);
 
        pci_set_drvdata(pdev, NULL);
index 529483467abf0254fbe6da582c938e57c8494e8a..0ccd7adf47bb2db54312287fb5191ac8ed4b2b94 100644 (file)
@@ -922,14 +922,14 @@ static int get_dss_clocks(void)
                return PTR_ERR(dispc.dss_ick);
        }
 
-       dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck");
+       dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "fck");
        if (IS_ERR(dispc.dss1_fck)) {
                dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
                clk_put(dispc.dss_ick);
                return PTR_ERR(dispc.dss1_fck);
        }
 
-       dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_fck");
+       dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_clk");
        if (IS_ERR(dispc.dss_54m_fck)) {
                dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
                clk_put(dispc.dss_ick);
index e264efd0278f24cf2fa9650e4002d25a0c7160c2..b3ddd743d8a6f59e5b7154ff1a6233202440b43d 100644 (file)
@@ -90,7 +90,7 @@ static void omapdss_release(struct device *dev)
 
 /* dummy device for clocks */
 static struct platform_device omapdss_device = {
-       .name           = "omapdss",
+       .name           = "omapdss_dss",
        .id             = -1,
        .dev            = {
                .release = omapdss_release,
index eada9f12efc767908c1c17f401e1ca0b925a1d37..0c6981f1a4a3dd5326a19cfefb9736a9f7c5adff 100644 (file)
@@ -90,7 +90,7 @@ static int rfbi_get_clocks(void)
                return PTR_ERR(rfbi.dss_ick);
        }
 
-       rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "dss1_fck");
+       rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "fck");
        if (IS_ERR(rfbi.dss1_fck)) {
                dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n");
                clk_put(rfbi.dss_ick);
index d853d05dad312361b0d83aa4d4d351d47fd75140..5ddef129f79826e8fadda55cb052204b220cb041 100644 (file)
@@ -1,6 +1,6 @@
 obj-$(CONFIG_OMAP2_VRAM) += vram.o
 obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
 
-obj-y += dss/
-obj-y += omapfb/
+obj-$(CONFIG_OMAP2_DSS) += dss/
+obj-$(CONFIG_FB_OMAP2) += omapfb/
 obj-y += displays/
index d18ad6b2372af818671780c532700422c911f3e8..609a28073178678f87069909d950745a48000a0a 100644 (file)
@@ -3,6 +3,7 @@ menu "OMAP2/3 Display Device Drivers"
 
 config PANEL_GENERIC_DPI
         tristate "Generic DPI Panel"
+       depends on OMAP2_DSS_DPI
         help
          Generic DPI panel driver.
          Supports DVI output for Beagle and OMAP3 SDP.
@@ -11,20 +12,20 @@ config PANEL_GENERIC_DPI
 
 config PANEL_LGPHILIPS_LB035Q02
        tristate "LG.Philips LB035Q02 LCD Panel"
-       depends on OMAP2_DSS && SPI
+       depends on OMAP2_DSS_DPI && SPI
        help
          LCD Panel used on the Gumstix Overo Palo35
 
 config PANEL_SHARP_LS037V7DW01
         tristate "Sharp LS037V7DW01 LCD Panel"
-        depends on OMAP2_DSS
+        depends on OMAP2_DSS_DPI
         select BACKLIGHT_CLASS_DEVICE
         help
           LCD Panel used in TI's SDP3430 and EVM boards
 
 config PANEL_NEC_NL8048HL11_01B
        tristate "NEC NL8048HL11-01B Panel"
-       depends on OMAP2_DSS
+       depends on OMAP2_DSS_DPI
        help
                This NEC NL8048HL11-01B panel is TFT LCD
                used in the Zoom2/3/3630 sdp boards.
@@ -37,7 +38,7 @@ config PANEL_TAAL
 
 config PANEL_TPO_TD043MTEA1
         tristate "TPO TD043MTEA1 LCD Panel"
-        depends on OMAP2_DSS && SPI
+        depends on OMAP2_DSS_DPI && SPI
         help
           LCD Panel used in OMAP3 Pandora
 
index 7e04c921aa2a8585d4cb180776d9469c0b4d44ce..dbd59b8e5b36520e76c472c5621b35bb7c262415 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/backlight.h>
 #include <linux/fb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define MIPID_CMD_READ_DISP_ID         0x04
 #define MIPID_CMD_READ_RED             0x06
index 4a9b9ff59467fa10c3c274432bb6c901334bd560..9c90f75653fb3d262489d3c9e78f04282bd8d7e2 100644 (file)
@@ -33,8 +33,9 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <video/omapdss.h>
 
-#include <plat/panel-generic-dpi.h>
+#include <video/omap-panel-generic-dpi.h>
 
 struct panel_config {
        struct omap_video_timings timings;
@@ -181,6 +182,56 @@ static struct panel_config generic_dpi_panels[] = {
                .power_off_delay        = 0,
                .name                   = "samsung_lte430wq_f0c",
        },
+
+       /* Seiko 70WVW1TZ3Z3 */
+       {
+               {
+                       .x_res          = 800,
+                       .y_res          = 480,
+
+                       .pixel_clock    = 33000,
+
+                       .hsw            = 128,
+                       .hfp            = 10,
+                       .hbp            = 10,
+
+                       .vsw            = 2,
+                       .vfp            = 4,
+                       .vbp            = 11,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x0,
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                               OMAP_DSS_LCD_IHS,
+               .power_on_delay         = 0,
+               .power_off_delay        = 0,
+               .name                   = "seiko_70wvw1tz3",
+       },
+
+       /* Powertip PH480272T */
+       {
+               {
+                       .x_res          = 480,
+                       .y_res          = 272,
+
+                       .pixel_clock    = 9000,
+
+                       .hsw            = 40,
+                       .hfp            = 2,
+                       .hbp            = 2,
+
+                       .vsw            = 10,
+                       .vfp            = 2,
+                       .vbp            = 2,
+               },
+               .acbi                   = 0x0,
+               .acb                    = 0x0,
+               .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+                                         OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
+               .power_on_delay         = 0,
+               .power_off_delay        = 0,
+               .name                   = "powertip_ph480272t",
+       },
 };
 
 struct panel_drv_data {
@@ -285,7 +336,7 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
        return 0;
 }
 
-static void generic_dpi_panel_remove(struct omap_dss_device *dssdev)
+static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
 {
        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 
@@ -358,7 +409,7 @@ static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
 
 static struct omap_dss_driver dpi_driver = {
        .probe          = generic_dpi_panel_probe,
-       .remove         = generic_dpi_panel_remove,
+       .remove         = __exit_p(generic_dpi_panel_remove),
 
        .enable         = generic_dpi_panel_enable,
        .disable        = generic_dpi_panel_disable,
index 271324db24366925ca26a1f89737b3cb4ec2a949..e0eb35be303e580ec2c93fc9cc37df6fed9ea784 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/spi/spi.h>
 #include <linux/mutex.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 struct lb035q02_data {
        struct mutex lock;
index 925e0fadff54130e9745645bd71c13f90f10041f..2ba9d0ca187c866f97ec1c56b725865adecde137 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/backlight.h>
 #include <linux/fb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define LCD_XRES               800
 #define LCD_YRES               480
index d2b35d2df2a60ad03c29b3cf18b0ebae9cce65b7..ba38b3ad17d6d6c8dc8f3e0f2eb33a301f82d3eb 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 struct sharp_data {
        struct backlight_device *bl;
@@ -120,7 +120,7 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
        return 0;
 }
 
-static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
+static void __exit sharp_ls_panel_remove(struct omap_dss_device *dssdev)
 {
        struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
        struct backlight_device *bl = sd->bl;
@@ -205,7 +205,7 @@ static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
 
 static struct omap_dss_driver sharp_ls_driver = {
        .probe          = sharp_ls_panel_probe,
-       .remove         = sharp_ls_panel_remove,
+       .remove         = __exit_p(sharp_ls_panel_remove),
 
        .enable         = sharp_ls_panel_enable,
        .disable        = sharp_ls_panel_disable,
index adc9900458e1cd7b0e627bb9fb4e9bc16f0b7175..fdd5d4ae437df9e3901f3891e07f188e14596e67 100644 (file)
@@ -33,8 +33,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/mutex.h>
 
-#include <plat/display.h>
-#include <plat/nokia-dsi-panel.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-nokia-dsi.h>
 
 /* DSI Virtual channel. Hardcoded for now. */
 #define TCH 0
 #define DCS_GET_ID2            0xdb
 #define DCS_GET_ID3            0xdc
 
-#define TAAL_ESD_CHECK_PERIOD  msecs_to_jiffies(5000)
-
 static irqreturn_t taal_te_isr(int irq, void *data);
 static void taal_te_timeout_work_callback(struct work_struct *work);
 static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
 
+static int taal_panel_reset(struct omap_dss_device *dssdev);
+
 struct panel_regulator {
        struct regulator *regulator;
        const char *name;
@@ -229,8 +229,14 @@ struct taal_data {
 
        bool intro_printed;
 
-       struct workqueue_struct *esd_wq;
+       struct workqueue_struct *workqueue;
+
        struct delayed_work esd_work;
+       unsigned esd_interval;
+
+       bool ulps_enabled;
+       unsigned ulps_timeout;
+       struct delayed_work ulps_work;
 
        struct panel_config *panel_config;
 };
@@ -242,6 +248,7 @@ static inline struct nokia_dsi_panel_data
 }
 
 static void taal_esd_work(struct work_struct *work);
+static void taal_ulps_work(struct work_struct *work);
 
 static void hw_guard_start(struct taal_data *td, int guard_msec)
 {
@@ -264,7 +271,7 @@ static int taal_dcs_read_1(struct taal_data *td, u8 dcs_cmd, u8 *data)
        int r;
        u8 buf[1];
 
-       r = dsi_vc_dcs_read(td->channel, dcs_cmd, buf, 1);
+       r = dsi_vc_dcs_read(td->dssdev, td->channel, dcs_cmd, buf, 1);
 
        if (r < 0)
                return r;
@@ -276,7 +283,7 @@ static int taal_dcs_read_1(struct taal_data *td, u8 dcs_cmd, u8 *data)
 
 static int taal_dcs_write_0(struct taal_data *td, u8 dcs_cmd)
 {
-       return dsi_vc_dcs_write(td->channel, &dcs_cmd, 1);
+       return dsi_vc_dcs_write(td->dssdev, td->channel, &dcs_cmd, 1);
 }
 
 static int taal_dcs_write_1(struct taal_data *td, u8 dcs_cmd, u8 param)
@@ -284,7 +291,7 @@ static int taal_dcs_write_1(struct taal_data *td, u8 dcs_cmd, u8 param)
        u8 buf[2];
        buf[0] = dcs_cmd;
        buf[1] = param;
-       return dsi_vc_dcs_write(td->channel, buf, 2);
+       return dsi_vc_dcs_write(td->dssdev, td->channel, buf, 2);
 }
 
 static int taal_sleep_in(struct taal_data *td)
@@ -296,7 +303,7 @@ static int taal_sleep_in(struct taal_data *td)
        hw_guard_wait(td);
 
        cmd = DCS_SLEEP_IN;
-       r = dsi_vc_dcs_write_nosync(td->channel, &cmd, 1);
+       r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, &cmd, 1);
        if (r)
                return r;
 
@@ -402,7 +409,7 @@ static int taal_set_update_window(struct taal_data *td,
        buf[3] = (x2 >> 8) & 0xff;
        buf[4] = (x2 >> 0) & 0xff;
 
-       r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
+       r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, buf, sizeof(buf));
        if (r)
                return r;
 
@@ -412,15 +419,132 @@ static int taal_set_update_window(struct taal_data *td,
        buf[3] = (y2 >> 8) & 0xff;
        buf[4] = (y2 >> 0) & 0xff;
 
-       r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf));
+       r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, buf, sizeof(buf));
        if (r)
                return r;
 
-       dsi_vc_send_bta_sync(td->channel);
+       dsi_vc_send_bta_sync(td->dssdev, td->channel);
 
        return r;
 }
 
+static void taal_queue_esd_work(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       if (td->esd_interval > 0)
+               queue_delayed_work(td->workqueue, &td->esd_work,
+                               msecs_to_jiffies(td->esd_interval));
+}
+
+static void taal_cancel_esd_work(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       cancel_delayed_work(&td->esd_work);
+}
+
+static void taal_queue_ulps_work(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       if (td->ulps_timeout > 0)
+               queue_delayed_work(td->workqueue, &td->ulps_work,
+                               msecs_to_jiffies(td->ulps_timeout));
+}
+
+static void taal_cancel_ulps_work(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       cancel_delayed_work(&td->ulps_work);
+}
+
+static int taal_enter_ulps(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+       int r;
+
+       if (td->ulps_enabled)
+               return 0;
+
+       taal_cancel_ulps_work(dssdev);
+
+       r = _taal_enable_te(dssdev, false);
+       if (r)
+               goto err;
+
+       disable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+       omapdss_dsi_display_disable(dssdev, false, true);
+
+       td->ulps_enabled = true;
+
+       return 0;
+
+err:
+       dev_err(&dssdev->dev, "enter ULPS failed");
+       taal_panel_reset(dssdev);
+
+       td->ulps_enabled = false;
+
+       taal_queue_ulps_work(dssdev);
+
+       return r;
+}
+
+static int taal_exit_ulps(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
+       int r;
+
+       if (!td->ulps_enabled)
+               return 0;
+
+       r = omapdss_dsi_display_enable(dssdev);
+       if (r)
+               goto err;
+
+       omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
+
+       r = _taal_enable_te(dssdev, true);
+       if (r)
+               goto err;
+
+       enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+
+       taal_queue_ulps_work(dssdev);
+
+       td->ulps_enabled = false;
+
+       return 0;
+
+err:
+       dev_err(&dssdev->dev, "exit ULPS failed");
+       r = taal_panel_reset(dssdev);
+
+       enable_irq(gpio_to_irq(panel_data->ext_te_gpio));
+       td->ulps_enabled = false;
+
+       taal_queue_ulps_work(dssdev);
+
+       return r;
+}
+
+static int taal_wake_up(struct omap_dss_device *dssdev)
+{
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       if (td->ulps_enabled)
+               return taal_exit_ulps(dssdev);
+
+       taal_cancel_ulps_work(dssdev);
+       taal_queue_ulps_work(dssdev);
+       return 0;
+}
+
 static int taal_bl_update_status(struct backlight_device *dev)
 {
        struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
@@ -441,9 +565,13 @@ static int taal_bl_update_status(struct backlight_device *dev)
 
        if (td->use_dsi_bl) {
                if (td->enabled) {
-                       dsi_bus_lock();
-                       r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
-                       dsi_bus_unlock();
+                       dsi_bus_lock(dssdev);
+
+                       r = taal_wake_up(dssdev);
+                       if (!r)
+                               r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level);
+
+                       dsi_bus_unlock(dssdev);
                } else {
                        r = 0;
                }
@@ -504,9 +632,13 @@ static ssize_t taal_num_errors_show(struct device *dev,
        mutex_lock(&td->lock);
 
        if (td->enabled) {
-               dsi_bus_lock();
-               r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
-               dsi_bus_unlock();
+               dsi_bus_lock(dssdev);
+
+               r = taal_wake_up(dssdev);
+               if (!r)
+                       r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors);
+
+               dsi_bus_unlock(dssdev);
        } else {
                r = -ENODEV;
        }
@@ -530,9 +662,13 @@ static ssize_t taal_hw_revision_show(struct device *dev,
        mutex_lock(&td->lock);
 
        if (td->enabled) {
-               dsi_bus_lock();
-               r = taal_get_id(td, &id1, &id2, &id3);
-               dsi_bus_unlock();
+               dsi_bus_lock(dssdev);
+
+               r = taal_wake_up(dssdev);
+               if (!r)
+                       r = taal_get_id(td, &id1, &id2, &id3);
+
+               dsi_bus_unlock(dssdev);
        } else {
                r = -ENODEV;
        }
@@ -579,6 +715,7 @@ static ssize_t store_cabc_mode(struct device *dev,
        struct omap_dss_device *dssdev = to_dss_device(dev);
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
        int i;
+       int r;
 
        for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
                if (sysfs_streq(cabc_modes[i], buf))
@@ -591,10 +728,19 @@ static ssize_t store_cabc_mode(struct device *dev,
        mutex_lock(&td->lock);
 
        if (td->enabled) {
-               dsi_bus_lock();
-               if (!td->cabc_broken)
-                       taal_dcs_write_1(td, DCS_WRITE_CABC, i);
-               dsi_bus_unlock();
+               dsi_bus_lock(dssdev);
+
+               if (!td->cabc_broken) {
+                       r = taal_wake_up(dssdev);
+                       if (r)
+                               goto err;
+
+                       r = taal_dcs_write_1(td, DCS_WRITE_CABC, i);
+                       if (r)
+                               goto err;
+               }
+
+               dsi_bus_unlock(dssdev);
        }
 
        td->cabc_mode = i;
@@ -602,6 +748,10 @@ static ssize_t store_cabc_mode(struct device *dev,
        mutex_unlock(&td->lock);
 
        return count;
+err:
+       dsi_bus_unlock(dssdev);
+       mutex_unlock(&td->lock);
+       return r;
 }
 
 static ssize_t show_cabc_available_modes(struct device *dev,
@@ -620,18 +770,161 @@ static ssize_t show_cabc_available_modes(struct device *dev,
        return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
 }
 
+static ssize_t taal_store_esd_interval(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
+       unsigned long t;
+       int r;
+
+       r = strict_strtoul(buf, 10, &t);
+       if (r)
+               return r;
+
+       mutex_lock(&td->lock);
+       taal_cancel_esd_work(dssdev);
+       td->esd_interval = t;
+       if (td->enabled)
+               taal_queue_esd_work(dssdev);
+       mutex_unlock(&td->lock);
+
+       return count;
+}
+
+static ssize_t taal_show_esd_interval(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned t;
+
+       mutex_lock(&td->lock);
+       t = td->esd_interval;
+       mutex_unlock(&td->lock);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t taal_store_ulps(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned long t;
+       int r;
+
+       r = strict_strtoul(buf, 10, &t);
+       if (r)
+               return r;
+
+       mutex_lock(&td->lock);
+
+       if (td->enabled) {
+               dsi_bus_lock(dssdev);
+
+               if (t)
+                       r = taal_enter_ulps(dssdev);
+               else
+                       r = taal_wake_up(dssdev);
+
+               dsi_bus_unlock(dssdev);
+       }
+
+       mutex_unlock(&td->lock);
+
+       if (r)
+               return r;
+
+       return count;
+}
+
+static ssize_t taal_show_ulps(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned t;
+
+       mutex_lock(&td->lock);
+       t = td->ulps_enabled;
+       mutex_unlock(&td->lock);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
+static ssize_t taal_store_ulps_timeout(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned long t;
+       int r;
+
+       r = strict_strtoul(buf, 10, &t);
+       if (r)
+               return r;
+
+       mutex_lock(&td->lock);
+       td->ulps_timeout = t;
+
+       if (td->enabled) {
+               /* taal_wake_up will restart the timer */
+               dsi_bus_lock(dssdev);
+               r = taal_wake_up(dssdev);
+               dsi_bus_unlock(dssdev);
+       }
+
+       mutex_unlock(&td->lock);
+
+       if (r)
+               return r;
+
+       return count;
+}
+
+static ssize_t taal_show_ulps_timeout(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct omap_dss_device *dssdev = to_dss_device(dev);
+       struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+       unsigned t;
+
+       mutex_lock(&td->lock);
+       t = td->ulps_timeout;
+       mutex_unlock(&td->lock);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", t);
+}
+
 static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
 static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
 static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
                show_cabc_mode, store_cabc_mode);
 static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
                show_cabc_available_modes, NULL);
+static DEVICE_ATTR(esd_interval, S_IRUGO | S_IWUSR,
+               taal_show_esd_interval, taal_store_esd_interval);
+static DEVICE_ATTR(ulps, S_IRUGO | S_IWUSR,
+               taal_show_ulps, taal_store_ulps);
+static DEVICE_ATTR(ulps_timeout, S_IRUGO | S_IWUSR,
+               taal_show_ulps_timeout, taal_store_ulps_timeout);
 
 static struct attribute *taal_attrs[] = {
        &dev_attr_num_dsi_errors.attr,
        &dev_attr_hw_revision.attr,
        &dev_attr_cabc_mode.attr,
        &dev_attr_cabc_available_modes.attr,
+       &dev_attr_esd_interval.attr,
+       &dev_attr_ulps.attr,
+       &dev_attr_ulps_timeout.attr,
        NULL,
 };
 
@@ -700,6 +993,9 @@ static int taal_probe(struct omap_dss_device *dssdev)
        }
        td->dssdev = dssdev;
        td->panel_config = panel_config;
+       td->esd_interval = panel_data->esd_interval;
+       td->ulps_enabled = false;
+       td->ulps_timeout = panel_data->ulps_timeout;
 
        mutex_init(&td->lock);
 
@@ -710,13 +1006,14 @@ static int taal_probe(struct omap_dss_device *dssdev)
        if (r)
                goto err_reg;
 
-       td->esd_wq = create_singlethread_workqueue("taal_esd");
-       if (td->esd_wq == NULL) {
+       td->workqueue = create_singlethread_workqueue("taal_esd");
+       if (td->workqueue == NULL) {
                dev_err(&dssdev->dev, "can't create ESD workqueue\n");
                r = -ENOMEM;
                goto err_wq;
        }
        INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
+       INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work);
 
        dev_set_drvdata(&dssdev->dev, td);
 
@@ -734,8 +1031,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
                props.max_brightness = 127;
 
        props.type = BACKLIGHT_RAW;
-       bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
-                                         &taal_bl_ops, &props);
+       bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev,
+                                       dssdev, &taal_bl_ops, &props);
        if (IS_ERR(bldev)) {
                r = PTR_ERR(bldev);
                goto err_bl;
@@ -810,7 +1107,7 @@ err_irq:
 err_gpio:
        backlight_device_unregister(bldev);
 err_bl:
-       destroy_workqueue(td->esd_wq);
+       destroy_workqueue(td->workqueue);
 err_wq:
        free_regulators(panel_config->regulators, panel_config->num_regulators);
 err_reg:
@@ -819,7 +1116,7 @@ err:
        return r;
 }
 
-static void taal_remove(struct omap_dss_device *dssdev)
+static void __exit taal_remove(struct omap_dss_device *dssdev)
 {
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
        struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
@@ -841,8 +1138,9 @@ static void taal_remove(struct omap_dss_device *dssdev)
        taal_bl_update_status(bldev);
        backlight_device_unregister(bldev);
 
-       cancel_delayed_work(&td->esd_work);
-       destroy_workqueue(td->esd_wq);
+       taal_cancel_ulps_work(dssdev);
+       taal_cancel_esd_work(dssdev);
+       destroy_workqueue(td->workqueue);
 
        /* reset, to be sure that the panel is in a valid state */
        taal_hw_reset(dssdev);
@@ -867,7 +1165,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
 
        taal_hw_reset(dssdev);
 
-       omapdss_dsi_vc_enable_hs(td->channel, false);
+       omapdss_dsi_vc_enable_hs(dssdev, td->channel, false);
 
        r = taal_sleep_out(td);
        if (r)
@@ -924,7 +1222,7 @@ static int taal_power_on(struct omap_dss_device *dssdev)
                td->intro_printed = true;
        }
 
-       omapdss_dsi_vc_enable_hs(td->channel, true);
+       omapdss_dsi_vc_enable_hs(dssdev, td->channel, true);
 
        return 0;
 err:
@@ -932,7 +1230,7 @@ err:
 
        taal_hw_reset(dssdev);
 
-       omapdss_dsi_display_disable(dssdev);
+       omapdss_dsi_display_disable(dssdev, true, false);
 err0:
        return r;
 }
@@ -955,15 +1253,23 @@ static void taal_power_off(struct omap_dss_device *dssdev)
                taal_hw_reset(dssdev);
        }
 
-       omapdss_dsi_display_disable(dssdev);
+       omapdss_dsi_display_disable(dssdev, true, false);
 
        td->enabled = 0;
 }
 
+static int taal_panel_reset(struct omap_dss_device *dssdev)
+{
+       dev_err(&dssdev->dev, "performing LCD reset\n");
+
+       taal_power_off(dssdev);
+       taal_hw_reset(dssdev);
+       return taal_power_on(dssdev);
+}
+
 static int taal_enable(struct omap_dss_device *dssdev)
 {
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-       struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
        int r;
 
        dev_dbg(&dssdev->dev, "enable\n");
@@ -975,18 +1281,16 @@ static int taal_enable(struct omap_dss_device *dssdev)
                goto err;
        }
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
        r = taal_power_on(dssdev);
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
        if (r)
                goto err;
 
-       if (panel_data->use_esd_check)
-               queue_delayed_work(td->esd_wq, &td->esd_work,
-                               TAAL_ESD_CHECK_PERIOD);
+       taal_queue_esd_work(dssdev);
 
        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
@@ -1007,14 +1311,17 @@ static void taal_disable(struct omap_dss_device *dssdev)
 
        mutex_lock(&td->lock);
 
-       cancel_delayed_work(&td->esd_work);
+       taal_cancel_ulps_work(dssdev);
+       taal_cancel_esd_work(dssdev);
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
-       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+       if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+               taal_wake_up(dssdev);
                taal_power_off(dssdev);
+       }
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 
@@ -1035,13 +1342,16 @@ static int taal_suspend(struct omap_dss_device *dssdev)
                goto err;
        }
 
-       cancel_delayed_work(&td->esd_work);
+       taal_cancel_ulps_work(dssdev);
+       taal_cancel_esd_work(dssdev);
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
-       taal_power_off(dssdev);
+       r = taal_wake_up(dssdev);
+       if (!r)
+               taal_power_off(dssdev);
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
        dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
 
@@ -1056,7 +1366,6 @@ err:
 static int taal_resume(struct omap_dss_device *dssdev)
 {
        struct taal_data *td = dev_get_drvdata(&dssdev->dev);
-       struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
        int r;
 
        dev_dbg(&dssdev->dev, "resume\n");
@@ -1068,19 +1377,17 @@ static int taal_resume(struct omap_dss_device *dssdev)
                goto err;
        }
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
        r = taal_power_on(dssdev);
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
        if (r) {
                dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
        } else {
                dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-               if (panel_data->use_esd_check)
-                       queue_delayed_work(td->esd_wq, &td->esd_work,
-                                       TAAL_ESD_CHECK_PERIOD);
+               taal_queue_esd_work(dssdev);
        }
 
        mutex_unlock(&td->lock);
@@ -1095,7 +1402,7 @@ static void taal_framedone_cb(int err, void *data)
 {
        struct omap_dss_device *dssdev = data;
        dev_dbg(&dssdev->dev, "framedone, err %d\n", err);
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 }
 
 static irqreturn_t taal_te_isr(int irq, void *data)
@@ -1123,7 +1430,7 @@ static irqreturn_t taal_te_isr(int irq, void *data)
        return IRQ_HANDLED;
 err:
        dev_err(&dssdev->dev, "start update failed\n");
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        return IRQ_HANDLED;
 }
 
@@ -1136,7 +1443,7 @@ static void taal_te_timeout_work_callback(struct work_struct *work)
        dev_err(&dssdev->dev, "TE not received for 250ms!\n");
 
        atomic_set(&td->do_update, 0);
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 }
 
 static int taal_update(struct omap_dss_device *dssdev,
@@ -1149,7 +1456,11 @@ static int taal_update(struct omap_dss_device *dssdev,
        dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
 
        mutex_lock(&td->lock);
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
+
+       r = taal_wake_up(dssdev);
+       if (r)
+               goto err;
 
        if (!td->enabled) {
                r = 0;
@@ -1184,7 +1495,7 @@ static int taal_update(struct omap_dss_device *dssdev,
        mutex_unlock(&td->lock);
        return 0;
 err:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
        return r;
 }
@@ -1196,8 +1507,8 @@ static int taal_sync(struct omap_dss_device *dssdev)
        dev_dbg(&dssdev->dev, "sync\n");
 
        mutex_lock(&td->lock);
-       dsi_bus_lock();
-       dsi_bus_unlock();
+       dsi_bus_lock(dssdev);
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
 
        dev_dbg(&dssdev->dev, "sync done\n");
@@ -1235,9 +1546,13 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
        if (td->te_enabled == enable)
                goto end;
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
        if (td->enabled) {
+               r = taal_wake_up(dssdev);
+               if (r)
+                       goto err;
+
                r = _taal_enable_te(dssdev, enable);
                if (r)
                        goto err;
@@ -1245,13 +1560,13 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
 
        td->te_enabled = enable;
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 end:
        mutex_unlock(&td->lock);
 
        return 0;
 err:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
 
        return r;
@@ -1281,9 +1596,13 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
        if (td->rotate == rotate)
                goto end;
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
 
        if (td->enabled) {
+               r = taal_wake_up(dssdev);
+               if (r)
+                       goto err;
+
                r = taal_set_addr_mode(td, rotate, td->mirror);
                if (r)
                        goto err;
@@ -1291,12 +1610,12 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
 
        td->rotate = rotate;
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 end:
        mutex_unlock(&td->lock);
        return 0;
 err:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
        return r;
 }
@@ -1325,8 +1644,12 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
        if (td->mirror == enable)
                goto end;
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
        if (td->enabled) {
+               r = taal_wake_up(dssdev);
+               if (r)
+                       goto err;
+
                r = taal_set_addr_mode(td, td->rotate, enable);
                if (r)
                        goto err;
@@ -1334,12 +1657,12 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
 
        td->mirror = enable;
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 end:
        mutex_unlock(&td->lock);
        return 0;
 err:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
        return r;
 }
@@ -1369,7 +1692,11 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
                goto err1;
        }
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
+
+       r = taal_wake_up(dssdev);
+       if (r)
+               goto err2;
 
        r = taal_dcs_read_1(td, DCS_GET_ID1, &id1);
        if (r)
@@ -1381,11 +1708,11 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
        if (r)
                goto err2;
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
        mutex_unlock(&td->lock);
        return 0;
 err2:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 err1:
        mutex_unlock(&td->lock);
        return r;
@@ -1415,7 +1742,11 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
                        dssdev->panel.timings.x_res *
                        dssdev->panel.timings.y_res * 3);
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
+
+       r = taal_wake_up(dssdev);
+       if (r)
+               goto err2;
 
        /* plen 1 or 2 goes into short packet. until checksum error is fixed,
         * use short packets. plen 32 works, but bigger packets seem to cause
@@ -1427,7 +1758,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
 
        taal_set_update_window(td, x, y, w, h);
 
-       r = dsi_vc_set_max_rx_packet_size(td->channel, plen);
+       r = dsi_vc_set_max_rx_packet_size(dssdev, td->channel, plen);
        if (r)
                goto err2;
 
@@ -1435,7 +1766,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
                u8 dcs_cmd = first ? 0x2e : 0x3e;
                first = 0;
 
-               r = dsi_vc_dcs_read(td->channel, dcs_cmd,
+               r = dsi_vc_dcs_read(dssdev, td->channel, dcs_cmd,
                                buf + buf_used, size - buf_used);
 
                if (r < 0) {
@@ -1461,14 +1792,35 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
        r = buf_used;
 
 err3:
-       dsi_vc_set_max_rx_packet_size(td->channel, 1);
+       dsi_vc_set_max_rx_packet_size(dssdev, td->channel, 1);
 err2:
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 err1:
        mutex_unlock(&td->lock);
        return r;
 }
 
+static void taal_ulps_work(struct work_struct *work)
+{
+       struct taal_data *td = container_of(work, struct taal_data,
+                       ulps_work.work);
+       struct omap_dss_device *dssdev = td->dssdev;
+
+       mutex_lock(&td->lock);
+
+       if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || !td->enabled) {
+               mutex_unlock(&td->lock);
+               return;
+       }
+
+       dsi_bus_lock(dssdev);
+
+       taal_enter_ulps(dssdev);
+
+       dsi_bus_unlock(dssdev);
+       mutex_unlock(&td->lock);
+}
+
 static void taal_esd_work(struct work_struct *work)
 {
        struct taal_data *td = container_of(work, struct taal_data,
@@ -1485,7 +1837,13 @@ static void taal_esd_work(struct work_struct *work)
                return;
        }
 
-       dsi_bus_lock();
+       dsi_bus_lock(dssdev);
+
+       r = taal_wake_up(dssdev);
+       if (r) {
+               dev_err(&dssdev->dev, "failed to exit ULPS\n");
+               goto err;
+       }
 
        r = taal_dcs_read_1(td, DCS_RDDSDR, &state1);
        if (r) {
@@ -1521,22 +1879,20 @@ static void taal_esd_work(struct work_struct *work)
                        goto err;
        }
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
-       queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+       taal_queue_esd_work(dssdev);
 
        mutex_unlock(&td->lock);
        return;
 err:
        dev_err(&dssdev->dev, "performing LCD reset\n");
 
-       taal_power_off(dssdev);
-       taal_hw_reset(dssdev);
-       taal_power_on(dssdev);
+       taal_panel_reset(dssdev);
 
-       dsi_bus_unlock();
+       dsi_bus_unlock(dssdev);
 
-       queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+       taal_queue_esd_work(dssdev);
 
        mutex_unlock(&td->lock);
 }
@@ -1557,7 +1913,7 @@ static enum omap_dss_update_mode taal_get_update_mode(
 
 static struct omap_dss_driver taal_driver = {
        .probe          = taal_probe,
-       .remove         = taal_remove,
+       .remove         = __exit_p(taal_remove),
 
        .enable         = taal_enable,
        .disable        = taal_disable,
index dbe9d43b4850d80c7218719528ce3c57c473b944..2462b9ec66623f2fa33d6f0b4852a8938e5ac85a 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define TPO_R02_MODE(x)                ((x) & 7)
 #define TPO_R02_MODE_800x480   7
@@ -144,13 +144,15 @@ static ssize_t tpo_td043_vmirror_store(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
 {
        struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev);
-       long val;
+       int val;
        int ret;
 
-       ret = strict_strtol(buf, 0, &val);
+       ret = kstrtoint(buf, 0, &val);
        if (ret < 0)
                return ret;
 
+       val = !!val;
+
        ret = tpo_td043_write_mirror(tpo_td043->spi, tpo_td043->hmirror, val);
        if (ret < 0)
                return ret;
@@ -175,7 +177,7 @@ static ssize_t tpo_td043_mode_store(struct device *dev,
        long val;
        int ret;
 
-       ret = strict_strtol(buf, 0, &val);
+       ret = kstrtol(buf, 0, &val);
        if (ret != 0 || val & ~7)
                return -EINVAL;
 
index bfc5da0e9700b7dea404085f50ae56cfb774ba42..6b3e2da11419497687b0a4a9449a793aa338a09a 100644 (file)
@@ -80,7 +80,7 @@ config OMAP2_DSS_SDI
 
 config OMAP2_DSS_DSI
        bool "DSI support"
-       depends on ARCH_OMAP3
+       depends on ARCH_OMAP3 || ARCH_OMAP4
         default n
        help
          MIPI DSI (Display Serial Interface) support.
@@ -90,14 +90,6 @@ config OMAP2_DSS_DSI
 
          See http://www.mipi.org/ for DSI spesifications.
 
-config OMAP2_DSS_USE_DSI_PLL
-       bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
-       default n
-       depends on OMAP2_DSS_DSI
-       help
-         Use DSI PLL to generate pixel clock.  Currently only for DPI output.
-         DSI PLL can be used to generate higher and more precise pixel clocks.
-
 config OMAP2_DSS_FAKE_VSYNC
        bool "Fake VSYNC irq from manual update displays"
        default n
@@ -125,4 +117,27 @@ config OMAP2_DSS_MIN_FCK_PER_PCK
          Max FCK is 173MHz, so this doesn't work if your PCK
          is very high.
 
+config OMAP2_DSS_SLEEP_BEFORE_RESET
+       bool "Sleep 50ms before DSS reset"
+       default y
+       help
+         For some unknown reason we may get SYNC_LOST errors from the display
+         subsystem at initialization time if we don't sleep before resetting
+         the DSS. See the source (dss.c) for more comments.
+
+         However, 50ms is quite long time to sleep, and with some
+         configurations the SYNC_LOST may never happen, so the sleep can
+         be disabled here.
+
+config OMAP2_DSS_SLEEP_AFTER_VENC_RESET
+       bool "Sleep 20ms after VENC reset"
+       default y
+       help
+         There is a 20ms sleep after VENC reset which seemed to fix the
+         reset. The reason for the bug is unclear, and it's also unclear
+         on what platforms this happens.
+
+         This option enables the sleep, and is enabled by default. You can
+         disable the sleep if it doesn't cause problems on your platform.
+
 endif
index 1aa2ed1e786e11cb2ae5f9d827d0b3b78791a504..3da426719dd6e50f9451a60d1a592a6ef79ef83d 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/device.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "dss.h"
 #include "dss_features.h"
@@ -54,6 +54,9 @@ unsigned int dss_debug;
 module_param_named(debug, dss_debug, bool, 0644);
 #endif
 
+static int omap_dss_register_device(struct omap_dss_device *);
+static void omap_dss_unregister_device(struct omap_dss_device *);
+
 /* REGULATORS */
 
 struct regulator *dss_get_vdds_dsi(void)
@@ -124,8 +127,7 @@ static int dss_initialize_debugfs(void)
 #endif
 
 #if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS)
-       debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir,
-                       &dsi_dump_irqs, &dss_debug_fops);
+       dsi_create_debugfs_files_irq(dss_debugfs_dir, &dss_debug_fops);
 #endif
 
        debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
@@ -137,8 +139,7 @@ static int dss_initialize_debugfs(void)
                        &rfbi_dump_regs, &dss_debug_fops);
 #endif
 #ifdef CONFIG_OMAP2_DSS_DSI
-       debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
-                       &dsi_dump_regs, &dss_debug_fops);
+       dsi_create_debugfs_files_reg(dss_debugfs_dir, &dss_debug_fops);
 #endif
 #ifdef CONFIG_OMAP2_DSS_VENC
        debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
@@ -480,7 +481,7 @@ static void omap_dss_dev_release(struct device *dev)
        reset_device(dev, 0);
 }
 
-int omap_dss_register_device(struct omap_dss_device *dssdev)
+static int omap_dss_register_device(struct omap_dss_device *dssdev)
 {
        static int dev_num;
 
@@ -494,7 +495,7 @@ int omap_dss_register_device(struct omap_dss_device *dssdev)
        return device_register(&dssdev->dev);
 }
 
-void omap_dss_unregister_device(struct omap_dss_device *dssdev)
+static void omap_dss_unregister_device(struct omap_dss_device *dssdev)
 {
        device_unregister(&dssdev->dev);
 }
index 7804779c9da150bb2ddf431cc9ac1134ef901e89..7a9a2e7d968530f9bac3000d086e4a2eac531d7f 100644 (file)
 #include <plat/sram.h>
 #include <plat/clock.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "dss.h"
 #include "dss_features.h"
+#include "dispc.h"
 
 /* DISPC */
 #define DISPC_SZ_REGS                  SZ_4K
 
-struct dispc_reg { u16 idx; };
-
-#define DISPC_REG(idx)                 ((const struct dispc_reg) { idx })
-
-/*
- * DISPC common registers and
- * DISPC channel registers , ch = 0 for LCD, ch = 1 for
- * DIGIT, and ch = 2 for LCD2
- */
-#define DISPC_REVISION                 DISPC_REG(0x0000)
-#define DISPC_SYSCONFIG                        DISPC_REG(0x0010)
-#define DISPC_SYSSTATUS                        DISPC_REG(0x0014)
-#define DISPC_IRQSTATUS                        DISPC_REG(0x0018)
-#define DISPC_IRQENABLE                        DISPC_REG(0x001C)
-#define DISPC_CONTROL                  DISPC_REG(0x0040)
-#define DISPC_CONTROL2                 DISPC_REG(0x0238)
-#define DISPC_CONFIG                   DISPC_REG(0x0044)
-#define DISPC_CONFIG2                  DISPC_REG(0x0620)
-#define DISPC_CAPABLE                  DISPC_REG(0x0048)
-#define DISPC_DEFAULT_COLOR(ch)                DISPC_REG(ch == 0 ? 0x004C : \
-                                       (ch == 1 ? 0x0050 : 0x03AC))
-#define DISPC_TRANS_COLOR(ch)          DISPC_REG(ch == 0 ? 0x0054 : \
-                                       (ch == 1 ? 0x0058 : 0x03B0))
-#define DISPC_LINE_STATUS              DISPC_REG(0x005C)
-#define DISPC_LINE_NUMBER              DISPC_REG(0x0060)
-#define DISPC_TIMING_H(ch)             DISPC_REG(ch != 2 ? 0x0064 : 0x0400)
-#define DISPC_TIMING_V(ch)             DISPC_REG(ch != 2 ? 0x0068 : 0x0404)
-#define DISPC_POL_FREQ(ch)             DISPC_REG(ch != 2 ? 0x006C : 0x0408)
-#define DISPC_DIVISORo(ch)             DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
-#define DISPC_GLOBAL_ALPHA             DISPC_REG(0x0074)
-#define DISPC_SIZE_DIG                 DISPC_REG(0x0078)
-#define DISPC_SIZE_LCD(ch)             DISPC_REG(ch != 2 ? 0x007C : 0x03CC)
-
-/* DISPC GFX plane */
-#define DISPC_GFX_BA0                  DISPC_REG(0x0080)
-#define DISPC_GFX_BA1                  DISPC_REG(0x0084)
-#define DISPC_GFX_POSITION             DISPC_REG(0x0088)
-#define DISPC_GFX_SIZE                 DISPC_REG(0x008C)
-#define DISPC_GFX_ATTRIBUTES           DISPC_REG(0x00A0)
-#define DISPC_GFX_FIFO_THRESHOLD       DISPC_REG(0x00A4)
-#define DISPC_GFX_FIFO_SIZE_STATUS     DISPC_REG(0x00A8)
-#define DISPC_GFX_ROW_INC              DISPC_REG(0x00AC)
-#define DISPC_GFX_PIXEL_INC            DISPC_REG(0x00B0)
-#define DISPC_GFX_WINDOW_SKIP          DISPC_REG(0x00B4)
-#define DISPC_GFX_TABLE_BA             DISPC_REG(0x00B8)
-
-#define DISPC_DATA_CYCLE1(ch)          DISPC_REG(ch != 2 ? 0x01D4 : 0x03C0)
-#define DISPC_DATA_CYCLE2(ch)          DISPC_REG(ch != 2 ? 0x01D8 : 0x03C4)
-#define DISPC_DATA_CYCLE3(ch)          DISPC_REG(ch != 2 ? 0x01DC : 0x03C8)
-#define DISPC_CPR_COEF_R(ch)           DISPC_REG(ch != 2 ? 0x0220 : 0x03BC)
-#define DISPC_CPR_COEF_G(ch)           DISPC_REG(ch != 2 ? 0x0224 : 0x03B8)
-#define DISPC_CPR_COEF_B(ch)           DISPC_REG(ch != 2 ? 0x0228 : 0x03B4)
-
-#define DISPC_GFX_PRELOAD              DISPC_REG(0x022C)
-
-/* DISPC Video plane, n = 0 for VID1 and n = 1 for VID2 */
-#define DISPC_VID_REG(n, idx)          DISPC_REG(0x00BC + (n)*0x90 + idx)
-
-#define DISPC_VID_BA0(n)               DISPC_VID_REG(n, 0x0000)
-#define DISPC_VID_BA1(n)               DISPC_VID_REG(n, 0x0004)
-#define DISPC_VID_POSITION(n)          DISPC_VID_REG(n, 0x0008)
-#define DISPC_VID_SIZE(n)              DISPC_VID_REG(n, 0x000C)
-#define DISPC_VID_ATTRIBUTES(n)                DISPC_VID_REG(n, 0x0010)
-#define DISPC_VID_FIFO_THRESHOLD(n)    DISPC_VID_REG(n, 0x0014)
-#define DISPC_VID_FIFO_SIZE_STATUS(n)  DISPC_VID_REG(n, 0x0018)
-#define DISPC_VID_ROW_INC(n)           DISPC_VID_REG(n, 0x001C)
-#define DISPC_VID_PIXEL_INC(n)         DISPC_VID_REG(n, 0x0020)
-#define DISPC_VID_FIR(n)               DISPC_VID_REG(n, 0x0024)
-#define DISPC_VID_PICTURE_SIZE(n)      DISPC_VID_REG(n, 0x0028)
-#define DISPC_VID_ACCU0(n)             DISPC_VID_REG(n, 0x002C)
-#define DISPC_VID_ACCU1(n)             DISPC_VID_REG(n, 0x0030)
-
-/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
-#define DISPC_VID_FIR_COEF_H(n, i)     DISPC_REG(0x00F0 + (n)*0x90 + (i)*0x8)
-/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
-#define DISPC_VID_FIR_COEF_HV(n, i)    DISPC_REG(0x00F4 + (n)*0x90 + (i)*0x8)
-/* coef index i = {0, 1, 2, 3, 4} */
-#define DISPC_VID_CONV_COEF(n, i)      DISPC_REG(0x0130 + (n)*0x90 + (i)*0x4)
-/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
-#define DISPC_VID_FIR_COEF_V(n, i)     DISPC_REG(0x01E0 + (n)*0x20 + (i)*0x4)
-
-#define DISPC_VID_PRELOAD(n)           DISPC_REG(0x230 + (n)*0x04)
-
-#define DISPC_DIVISOR                  DISPC_REG(0x0804)
-
 #define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
                                         DISPC_IRQ_OCP_ERR | \
                                         DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
@@ -167,10 +83,6 @@ struct dispc_v_coef {
 #define REG_FLD_MOD(idx, val, start, end)                              \
        dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
 
-static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES,
-       DISPC_VID_ATTRIBUTES(0),
-       DISPC_VID_ATTRIBUTES(1) };
-
 struct dispc_irq_stats {
        unsigned long last_reset;
        unsigned irq_count;
@@ -198,25 +110,38 @@ static struct {
 #endif
 } dispc;
 
+enum omap_color_component {
+       /* used for all color formats for OMAP3 and earlier
+        * and for RGB and Y color component on OMAP4
+        */
+       DISPC_COLOR_COMPONENT_RGB_Y             = 1 << 0,
+       /* used for UV component for
+        * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
+        * color formats on OMAP4
+        */
+       DISPC_COLOR_COMPONENT_UV                = 1 << 1,
+};
+
 static void _omap_dispc_set_irqs(void);
 
-static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
+static inline void dispc_write_reg(const u16 idx, u32 val)
 {
-       __raw_writel(val, dispc.base + idx.idx);
+       __raw_writel(val, dispc.base + idx);
 }
 
-static inline u32 dispc_read_reg(const struct dispc_reg idx)
+static inline u32 dispc_read_reg(const u16 idx)
 {
-       return __raw_readl(dispc.base + idx.idx);
+       return __raw_readl(dispc.base + idx);
 }
 
 #define SR(reg) \
-       dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
+       dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
 #define RR(reg) \
-       dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
+       dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
 
 void dispc_save_context(void)
 {
+       int i;
        if (cpu_is_omap24xx())
                return;
 
@@ -224,157 +149,153 @@ void dispc_save_context(void)
        SR(IRQENABLE);
        SR(CONTROL);
        SR(CONFIG);
-       SR(DEFAULT_COLOR(0));
-       SR(DEFAULT_COLOR(1));
-       SR(TRANS_COLOR(0));
-       SR(TRANS_COLOR(1));
+       SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
+       SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
+       SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
+       SR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
        SR(LINE_NUMBER);
-       SR(TIMING_H(0));
-       SR(TIMING_V(0));
-       SR(POL_FREQ(0));
-       SR(DIVISORo(0));
+       SR(TIMING_H(OMAP_DSS_CHANNEL_LCD));
+       SR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
+       SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
+       SR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
        SR(GLOBAL_ALPHA);
-       SR(SIZE_DIG);
-       SR(SIZE_LCD(0));
+       SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
+       SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                SR(CONTROL2);
-               SR(DEFAULT_COLOR(2));
-               SR(TRANS_COLOR(2));
-               SR(SIZE_LCD(2));
-               SR(TIMING_H(2));
-               SR(TIMING_V(2));
-               SR(POL_FREQ(2));
-               SR(DIVISORo(2));
+               SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
+               SR(TIMING_H(OMAP_DSS_CHANNEL_LCD2));
+               SR(TIMING_V(OMAP_DSS_CHANNEL_LCD2));
+               SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
+               SR(DIVISORo(OMAP_DSS_CHANNEL_LCD2));
                SR(CONFIG2);
        }
 
-       SR(GFX_BA0);
-       SR(GFX_BA1);
-       SR(GFX_POSITION);
-       SR(GFX_SIZE);
-       SR(GFX_ATTRIBUTES);
-       SR(GFX_FIFO_THRESHOLD);
-       SR(GFX_ROW_INC);
-       SR(GFX_PIXEL_INC);
-       SR(GFX_WINDOW_SKIP);
-       SR(GFX_TABLE_BA);
-
-       SR(DATA_CYCLE1(0));
-       SR(DATA_CYCLE2(0));
-       SR(DATA_CYCLE3(0));
-
-       SR(CPR_COEF_R(0));
-       SR(CPR_COEF_G(0));
-       SR(CPR_COEF_B(0));
+       SR(OVL_BA0(OMAP_DSS_GFX));
+       SR(OVL_BA1(OMAP_DSS_GFX));
+       SR(OVL_POSITION(OMAP_DSS_GFX));
+       SR(OVL_SIZE(OMAP_DSS_GFX));
+       SR(OVL_ATTRIBUTES(OMAP_DSS_GFX));
+       SR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
+       SR(OVL_ROW_INC(OMAP_DSS_GFX));
+       SR(OVL_PIXEL_INC(OMAP_DSS_GFX));
+       SR(OVL_WINDOW_SKIP(OMAP_DSS_GFX));
+       SR(OVL_TABLE_BA(OMAP_DSS_GFX));
+
+       SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
+       SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
+       SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
+
+       SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+       SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+       SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               SR(CPR_COEF_B(2));
-               SR(CPR_COEF_G(2));
-               SR(CPR_COEF_R(2));
+               SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+               SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+               SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
 
-               SR(DATA_CYCLE1(2));
-               SR(DATA_CYCLE2(2));
-               SR(DATA_CYCLE3(2));
+               SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
+               SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
+               SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
        }
 
-       SR(GFX_PRELOAD);
+       SR(OVL_PRELOAD(OMAP_DSS_GFX));
 
        /* VID1 */
-       SR(VID_BA0(0));
-       SR(VID_BA1(0));
-       SR(VID_POSITION(0));
-       SR(VID_SIZE(0));
-       SR(VID_ATTRIBUTES(0));
-       SR(VID_FIFO_THRESHOLD(0));
-       SR(VID_ROW_INC(0));
-       SR(VID_PIXEL_INC(0));
-       SR(VID_FIR(0));
-       SR(VID_PICTURE_SIZE(0));
-       SR(VID_ACCU0(0));
-       SR(VID_ACCU1(0));
-
-       SR(VID_FIR_COEF_H(0, 0));
-       SR(VID_FIR_COEF_H(0, 1));
-       SR(VID_FIR_COEF_H(0, 2));
-       SR(VID_FIR_COEF_H(0, 3));
-       SR(VID_FIR_COEF_H(0, 4));
-       SR(VID_FIR_COEF_H(0, 5));
-       SR(VID_FIR_COEF_H(0, 6));
-       SR(VID_FIR_COEF_H(0, 7));
-
-       SR(VID_FIR_COEF_HV(0, 0));
-       SR(VID_FIR_COEF_HV(0, 1));
-       SR(VID_FIR_COEF_HV(0, 2));
-       SR(VID_FIR_COEF_HV(0, 3));
-       SR(VID_FIR_COEF_HV(0, 4));
-       SR(VID_FIR_COEF_HV(0, 5));
-       SR(VID_FIR_COEF_HV(0, 6));
-       SR(VID_FIR_COEF_HV(0, 7));
-
-       SR(VID_CONV_COEF(0, 0));
-       SR(VID_CONV_COEF(0, 1));
-       SR(VID_CONV_COEF(0, 2));
-       SR(VID_CONV_COEF(0, 3));
-       SR(VID_CONV_COEF(0, 4));
-
-       SR(VID_FIR_COEF_V(0, 0));
-       SR(VID_FIR_COEF_V(0, 1));
-       SR(VID_FIR_COEF_V(0, 2));
-       SR(VID_FIR_COEF_V(0, 3));
-       SR(VID_FIR_COEF_V(0, 4));
-       SR(VID_FIR_COEF_V(0, 5));
-       SR(VID_FIR_COEF_V(0, 6));
-       SR(VID_FIR_COEF_V(0, 7));
-
-       SR(VID_PRELOAD(0));
+       SR(OVL_BA0(OMAP_DSS_VIDEO1));
+       SR(OVL_BA1(OMAP_DSS_VIDEO1));
+       SR(OVL_POSITION(OMAP_DSS_VIDEO1));
+       SR(OVL_SIZE(OMAP_DSS_VIDEO1));
+       SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
+       SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
+       SR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
+       SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
+       SR(OVL_FIR(OMAP_DSS_VIDEO1));
+       SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
+       SR(OVL_ACCU0(OMAP_DSS_VIDEO1));
+       SR(OVL_ACCU1(OMAP_DSS_VIDEO1));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 5; i++)
+               SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               SR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
+               SR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
+               SR(OVL_FIR2(OMAP_DSS_VIDEO1));
+               SR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
+               SR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
+
+       SR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
 
        /* VID2 */
-       SR(VID_BA0(1));
-       SR(VID_BA1(1));
-       SR(VID_POSITION(1));
-       SR(VID_SIZE(1));
-       SR(VID_ATTRIBUTES(1));
-       SR(VID_FIFO_THRESHOLD(1));
-       SR(VID_ROW_INC(1));
-       SR(VID_PIXEL_INC(1));
-       SR(VID_FIR(1));
-       SR(VID_PICTURE_SIZE(1));
-       SR(VID_ACCU0(1));
-       SR(VID_ACCU1(1));
-
-       SR(VID_FIR_COEF_H(1, 0));
-       SR(VID_FIR_COEF_H(1, 1));
-       SR(VID_FIR_COEF_H(1, 2));
-       SR(VID_FIR_COEF_H(1, 3));
-       SR(VID_FIR_COEF_H(1, 4));
-       SR(VID_FIR_COEF_H(1, 5));
-       SR(VID_FIR_COEF_H(1, 6));
-       SR(VID_FIR_COEF_H(1, 7));
-
-       SR(VID_FIR_COEF_HV(1, 0));
-       SR(VID_FIR_COEF_HV(1, 1));
-       SR(VID_FIR_COEF_HV(1, 2));
-       SR(VID_FIR_COEF_HV(1, 3));
-       SR(VID_FIR_COEF_HV(1, 4));
-       SR(VID_FIR_COEF_HV(1, 5));
-       SR(VID_FIR_COEF_HV(1, 6));
-       SR(VID_FIR_COEF_HV(1, 7));
-
-       SR(VID_CONV_COEF(1, 0));
-       SR(VID_CONV_COEF(1, 1));
-       SR(VID_CONV_COEF(1, 2));
-       SR(VID_CONV_COEF(1, 3));
-       SR(VID_CONV_COEF(1, 4));
-
-       SR(VID_FIR_COEF_V(1, 0));
-       SR(VID_FIR_COEF_V(1, 1));
-       SR(VID_FIR_COEF_V(1, 2));
-       SR(VID_FIR_COEF_V(1, 3));
-       SR(VID_FIR_COEF_V(1, 4));
-       SR(VID_FIR_COEF_V(1, 5));
-       SR(VID_FIR_COEF_V(1, 6));
-       SR(VID_FIR_COEF_V(1, 7));
-
-       SR(VID_PRELOAD(1));
+       SR(OVL_BA0(OMAP_DSS_VIDEO2));
+       SR(OVL_BA1(OMAP_DSS_VIDEO2));
+       SR(OVL_POSITION(OMAP_DSS_VIDEO2));
+       SR(OVL_SIZE(OMAP_DSS_VIDEO2));
+       SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
+       SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
+       SR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
+       SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
+       SR(OVL_FIR(OMAP_DSS_VIDEO2));
+       SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
+       SR(OVL_ACCU0(OMAP_DSS_VIDEO2));
+       SR(OVL_ACCU1(OMAP_DSS_VIDEO2));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 5; i++)
+               SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 8; i++)
+               SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               SR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
+               SR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
+               SR(OVL_FIR2(OMAP_DSS_VIDEO2));
+               SR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
+               SR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
+
+               for (i = 0; i < 8; i++)
+                       SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
+
+       SR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                SR(DIVISOR);
@@ -382,160 +303,158 @@ void dispc_save_context(void)
 
 void dispc_restore_context(void)
 {
+       int i;
        RR(SYSCONFIG);
        /*RR(IRQENABLE);*/
        /*RR(CONTROL);*/
        RR(CONFIG);
-       RR(DEFAULT_COLOR(0));
-       RR(DEFAULT_COLOR(1));
-       RR(TRANS_COLOR(0));
-       RR(TRANS_COLOR(1));
+       RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
+       RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
+       RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
+       RR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
        RR(LINE_NUMBER);
-       RR(TIMING_H(0));
-       RR(TIMING_V(0));
-       RR(POL_FREQ(0));
-       RR(DIVISORo(0));
+       RR(TIMING_H(OMAP_DSS_CHANNEL_LCD));
+       RR(TIMING_V(OMAP_DSS_CHANNEL_LCD));
+       RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD));
+       RR(DIVISORo(OMAP_DSS_CHANNEL_LCD));
        RR(GLOBAL_ALPHA);
-       RR(SIZE_DIG);
-       RR(SIZE_LCD(0));
+       RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
+       RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               RR(DEFAULT_COLOR(2));
-               RR(TRANS_COLOR(2));
-               RR(SIZE_LCD(2));
-               RR(TIMING_H(2));
-               RR(TIMING_V(2));
-               RR(POL_FREQ(2));
-               RR(DIVISORo(2));
+               RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
+               RR(TIMING_H(OMAP_DSS_CHANNEL_LCD2));
+               RR(TIMING_V(OMAP_DSS_CHANNEL_LCD2));
+               RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
+               RR(DIVISORo(OMAP_DSS_CHANNEL_LCD2));
                RR(CONFIG2);
        }
 
-       RR(GFX_BA0);
-       RR(GFX_BA1);
-       RR(GFX_POSITION);
-       RR(GFX_SIZE);
-       RR(GFX_ATTRIBUTES);
-       RR(GFX_FIFO_THRESHOLD);
-       RR(GFX_ROW_INC);
-       RR(GFX_PIXEL_INC);
-       RR(GFX_WINDOW_SKIP);
-       RR(GFX_TABLE_BA);
-
-       RR(DATA_CYCLE1(0));
-       RR(DATA_CYCLE2(0));
-       RR(DATA_CYCLE3(0));
-
-       RR(CPR_COEF_R(0));
-       RR(CPR_COEF_G(0));
-       RR(CPR_COEF_B(0));
+       RR(OVL_BA0(OMAP_DSS_GFX));
+       RR(OVL_BA1(OMAP_DSS_GFX));
+       RR(OVL_POSITION(OMAP_DSS_GFX));
+       RR(OVL_SIZE(OMAP_DSS_GFX));
+       RR(OVL_ATTRIBUTES(OMAP_DSS_GFX));
+       RR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
+       RR(OVL_ROW_INC(OMAP_DSS_GFX));
+       RR(OVL_PIXEL_INC(OMAP_DSS_GFX));
+       RR(OVL_WINDOW_SKIP(OMAP_DSS_GFX));
+       RR(OVL_TABLE_BA(OMAP_DSS_GFX));
+
+
+       RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
+       RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
+       RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
+
+       RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+       RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+       RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               RR(DATA_CYCLE1(2));
-               RR(DATA_CYCLE2(2));
-               RR(DATA_CYCLE3(2));
+               RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
+               RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
+               RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
 
-               RR(CPR_COEF_B(2));
-               RR(CPR_COEF_G(2));
-               RR(CPR_COEF_R(2));
+               RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+               RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+               RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
        }
 
-       RR(GFX_PRELOAD);
+       RR(OVL_PRELOAD(OMAP_DSS_GFX));
 
        /* VID1 */
-       RR(VID_BA0(0));
-       RR(VID_BA1(0));
-       RR(VID_POSITION(0));
-       RR(VID_SIZE(0));
-       RR(VID_ATTRIBUTES(0));
-       RR(VID_FIFO_THRESHOLD(0));
-       RR(VID_ROW_INC(0));
-       RR(VID_PIXEL_INC(0));
-       RR(VID_FIR(0));
-       RR(VID_PICTURE_SIZE(0));
-       RR(VID_ACCU0(0));
-       RR(VID_ACCU1(0));
-
-       RR(VID_FIR_COEF_H(0, 0));
-       RR(VID_FIR_COEF_H(0, 1));
-       RR(VID_FIR_COEF_H(0, 2));
-       RR(VID_FIR_COEF_H(0, 3));
-       RR(VID_FIR_COEF_H(0, 4));
-       RR(VID_FIR_COEF_H(0, 5));
-       RR(VID_FIR_COEF_H(0, 6));
-       RR(VID_FIR_COEF_H(0, 7));
-
-       RR(VID_FIR_COEF_HV(0, 0));
-       RR(VID_FIR_COEF_HV(0, 1));
-       RR(VID_FIR_COEF_HV(0, 2));
-       RR(VID_FIR_COEF_HV(0, 3));
-       RR(VID_FIR_COEF_HV(0, 4));
-       RR(VID_FIR_COEF_HV(0, 5));
-       RR(VID_FIR_COEF_HV(0, 6));
-       RR(VID_FIR_COEF_HV(0, 7));
-
-       RR(VID_CONV_COEF(0, 0));
-       RR(VID_CONV_COEF(0, 1));
-       RR(VID_CONV_COEF(0, 2));
-       RR(VID_CONV_COEF(0, 3));
-       RR(VID_CONV_COEF(0, 4));
-
-       RR(VID_FIR_COEF_V(0, 0));
-       RR(VID_FIR_COEF_V(0, 1));
-       RR(VID_FIR_COEF_V(0, 2));
-       RR(VID_FIR_COEF_V(0, 3));
-       RR(VID_FIR_COEF_V(0, 4));
-       RR(VID_FIR_COEF_V(0, 5));
-       RR(VID_FIR_COEF_V(0, 6));
-       RR(VID_FIR_COEF_V(0, 7));
-
-       RR(VID_PRELOAD(0));
+       RR(OVL_BA0(OMAP_DSS_VIDEO1));
+       RR(OVL_BA1(OMAP_DSS_VIDEO1));
+       RR(OVL_POSITION(OMAP_DSS_VIDEO1));
+       RR(OVL_SIZE(OMAP_DSS_VIDEO1));
+       RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
+       RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
+       RR(OVL_ROW_INC(OMAP_DSS_VIDEO1));
+       RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
+       RR(OVL_FIR(OMAP_DSS_VIDEO1));
+       RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
+       RR(OVL_ACCU0(OMAP_DSS_VIDEO1));
+       RR(OVL_ACCU1(OMAP_DSS_VIDEO1));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 5; i++)
+               RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               RR(OVL_BA0_UV(OMAP_DSS_VIDEO1));
+               RR(OVL_BA1_UV(OMAP_DSS_VIDEO1));
+               RR(OVL_FIR2(OMAP_DSS_VIDEO1));
+               RR(OVL_ACCU2_0(OMAP_DSS_VIDEO1));
+               RR(OVL_ACCU2_1(OMAP_DSS_VIDEO1));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
+
+       RR(OVL_PRELOAD(OMAP_DSS_VIDEO1));
 
        /* VID2 */
-       RR(VID_BA0(1));
-       RR(VID_BA1(1));
-       RR(VID_POSITION(1));
-       RR(VID_SIZE(1));
-       RR(VID_ATTRIBUTES(1));
-       RR(VID_FIFO_THRESHOLD(1));
-       RR(VID_ROW_INC(1));
-       RR(VID_PIXEL_INC(1));
-       RR(VID_FIR(1));
-       RR(VID_PICTURE_SIZE(1));
-       RR(VID_ACCU0(1));
-       RR(VID_ACCU1(1));
-
-       RR(VID_FIR_COEF_H(1, 0));
-       RR(VID_FIR_COEF_H(1, 1));
-       RR(VID_FIR_COEF_H(1, 2));
-       RR(VID_FIR_COEF_H(1, 3));
-       RR(VID_FIR_COEF_H(1, 4));
-       RR(VID_FIR_COEF_H(1, 5));
-       RR(VID_FIR_COEF_H(1, 6));
-       RR(VID_FIR_COEF_H(1, 7));
-
-       RR(VID_FIR_COEF_HV(1, 0));
-       RR(VID_FIR_COEF_HV(1, 1));
-       RR(VID_FIR_COEF_HV(1, 2));
-       RR(VID_FIR_COEF_HV(1, 3));
-       RR(VID_FIR_COEF_HV(1, 4));
-       RR(VID_FIR_COEF_HV(1, 5));
-       RR(VID_FIR_COEF_HV(1, 6));
-       RR(VID_FIR_COEF_HV(1, 7));
-
-       RR(VID_CONV_COEF(1, 0));
-       RR(VID_CONV_COEF(1, 1));
-       RR(VID_CONV_COEF(1, 2));
-       RR(VID_CONV_COEF(1, 3));
-       RR(VID_CONV_COEF(1, 4));
-
-       RR(VID_FIR_COEF_V(1, 0));
-       RR(VID_FIR_COEF_V(1, 1));
-       RR(VID_FIR_COEF_V(1, 2));
-       RR(VID_FIR_COEF_V(1, 3));
-       RR(VID_FIR_COEF_V(1, 4));
-       RR(VID_FIR_COEF_V(1, 5));
-       RR(VID_FIR_COEF_V(1, 6));
-       RR(VID_FIR_COEF_V(1, 7));
-
-       RR(VID_PRELOAD(1));
+       RR(OVL_BA0(OMAP_DSS_VIDEO2));
+       RR(OVL_BA1(OMAP_DSS_VIDEO2));
+       RR(OVL_POSITION(OMAP_DSS_VIDEO2));
+       RR(OVL_SIZE(OMAP_DSS_VIDEO2));
+       RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
+       RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
+       RR(OVL_ROW_INC(OMAP_DSS_VIDEO2));
+       RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
+       RR(OVL_FIR(OMAP_DSS_VIDEO2));
+       RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
+       RR(OVL_ACCU0(OMAP_DSS_VIDEO2));
+       RR(OVL_ACCU1(OMAP_DSS_VIDEO2));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 5; i++)
+               RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i));
+
+       for (i = 0; i < 8; i++)
+               RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               RR(OVL_BA0_UV(OMAP_DSS_VIDEO2));
+               RR(OVL_BA1_UV(OMAP_DSS_VIDEO2));
+               RR(OVL_FIR2(OMAP_DSS_VIDEO2));
+               RR(OVL_ACCU2_0(OMAP_DSS_VIDEO2));
+               RR(OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i));
+
+               for (i = 0; i < 8; i++)
+                       RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
+
+       RR(OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        if (dss_has_feature(FEAT_CORE_CLK_DIV))
                RR(DIVISOR);
@@ -631,28 +550,44 @@ end:
 }
 
 static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
+{
+       dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
+}
+
+static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
+{
+       dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
+}
+
+static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
+{
+       dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
+}
+
+static void _dispc_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
+       dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
 }
 
-static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
+static void _dispc_write_firhv2_reg(enum omap_plane plane, int reg, u32 value)
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
+       dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
 }
 
-static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
+static void _dispc_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
 {
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
+       dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
 }
 
 static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
-               int vscaleup, int five_taps)
+                                 int vscaleup, int five_taps,
+                                 enum omap_color_component color_comp)
 {
        /* Coefficients for horizontal up-sampling */
        static const struct dispc_h_coef coef_hup[8] = {
@@ -750,8 +685,14 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
                        | FLD_VAL(v_coef[i].vc1, 23, 16)
                        | FLD_VAL(v_coef[i].vc2, 31, 24);
 
-               _dispc_write_firh_reg(plane, i, h);
-               _dispc_write_firhv_reg(plane, i, hv);
+               if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
+                       _dispc_write_firh_reg(plane, i, h);
+                       _dispc_write_firhv_reg(plane, i, hv);
+               } else {
+                       _dispc_write_firh2_reg(plane, i, h);
+                       _dispc_write_firhv2_reg(plane, i, hv);
+               }
+
        }
 
        if (five_taps) {
@@ -759,7 +700,10 @@ static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
                        u32 v;
                        v = FLD_VAL(v_coef[i].vc00, 7, 0)
                                | FLD_VAL(v_coef[i].vc22, 15, 8);
-                       _dispc_write_firv_reg(plane, i, v);
+                       if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
+                               _dispc_write_firv_reg(plane, i, v);
+                       else
+                               _dispc_write_firv2_reg(plane, i, v);
                }
        }
 }
@@ -779,72 +723,83 @@ static void _dispc_setup_color_conv_coef(void)
 
        ct = &ctbl_bt601_5;
 
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry));
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy,  ct->rcb));
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr));
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by));
-       dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0,       ct->bcb));
-
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry));
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy,  ct->rcb));
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
-       dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0,       ct->bcb));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0),
+               CVAL(ct->rcr, ct->ry));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1),
+               CVAL(ct->gy,  ct->rcb));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2),
+               CVAL(ct->gcb, ct->gcr));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3),
+               CVAL(ct->bcr, ct->by));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4),
+               CVAL(0, ct->bcb));
+
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0),
+               CVAL(ct->rcr, ct->ry));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1),
+               CVAL(ct->gy, ct->rcb));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2),
+               CVAL(ct->gcb, ct->gcr));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3),
+               CVAL(ct->bcr, ct->by));
+       dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4),
+               CVAL(0, ct->bcb));
 
 #undef CVAL
 
-       REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11);
-       REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1),
+               ct->full_range, 11, 11);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2),
+               ct->full_range, 11, 11);
 }
 
 
 static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
 {
-       const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
-               DISPC_VID_BA0(0),
-               DISPC_VID_BA0(1) };
-
-       dispc_write_reg(ba0_reg[plane], paddr);
+       dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
 }
 
 static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
 {
-       const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
-                                     DISPC_VID_BA1(0),
-                                     DISPC_VID_BA1(1) };
+       dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
+}
 
-       dispc_write_reg(ba1_reg[plane], paddr);
+static void _dispc_set_plane_ba0_uv(enum omap_plane plane, u32 paddr)
+{
+       dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
 }
 
-static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
+static void _dispc_set_plane_ba1_uv(enum omap_plane plane, u32 paddr)
 {
-       const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
-                                     DISPC_VID_POSITION(0),
-                                     DISPC_VID_POSITION(1) };
+       dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
+}
 
+static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
+{
        u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
-       dispc_write_reg(pos_reg[plane], val);
+
+       dispc_write_reg(DISPC_OVL_POSITION(plane), val);
 }
 
 static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
 {
-       const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
-                                     DISPC_VID_PICTURE_SIZE(0),
-                                     DISPC_VID_PICTURE_SIZE(1) };
        u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       dispc_write_reg(siz_reg[plane], val);
+
+       if (plane == OMAP_DSS_GFX)
+               dispc_write_reg(DISPC_OVL_SIZE(plane), val);
+       else
+               dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
 }
 
 static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
 {
        u32 val;
-       const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
-                                     DISPC_VID_SIZE(1) };
 
        BUG_ON(plane == OMAP_DSS_GFX);
 
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
-       dispc_write_reg(vsi_reg[plane-1], val);
+
+       dispc_write_reg(DISPC_OVL_SIZE(plane), val);
 }
 
 static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable)
@@ -856,7 +811,7 @@ static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable)
                plane == OMAP_DSS_VIDEO1)
                return;
 
-       REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 28, 28);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
 }
 
 static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
@@ -876,61 +831,93 @@ static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
 
 static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
 {
-       const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
-                                    DISPC_VID_PIXEL_INC(0),
-                                    DISPC_VID_PIXEL_INC(1) };
-
-       dispc_write_reg(ri_reg[plane], inc);
+       dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
 }
 
 static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
 {
-       const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
-                                    DISPC_VID_ROW_INC(0),
-                                    DISPC_VID_ROW_INC(1) };
-
-       dispc_write_reg(ri_reg[plane], inc);
+       dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
 }
 
 static void _dispc_set_color_mode(enum omap_plane plane,
                enum omap_color_mode color_mode)
 {
        u32 m = 0;
-
-       switch (color_mode) {
-       case OMAP_DSS_COLOR_CLUT1:
-               m = 0x0; break;
-       case OMAP_DSS_COLOR_CLUT2:
-               m = 0x1; break;
-       case OMAP_DSS_COLOR_CLUT4:
-               m = 0x2; break;
-       case OMAP_DSS_COLOR_CLUT8:
-               m = 0x3; break;
-       case OMAP_DSS_COLOR_RGB12U:
-               m = 0x4; break;
-       case OMAP_DSS_COLOR_ARGB16:
-               m = 0x5; break;
-       case OMAP_DSS_COLOR_RGB16:
-               m = 0x6; break;
-       case OMAP_DSS_COLOR_RGB24U:
-               m = 0x8; break;
-       case OMAP_DSS_COLOR_RGB24P:
-               m = 0x9; break;
-       case OMAP_DSS_COLOR_YUV2:
-               m = 0xa; break;
-       case OMAP_DSS_COLOR_UYVY:
-               m = 0xb; break;
-       case OMAP_DSS_COLOR_ARGB32:
-               m = 0xc; break;
-       case OMAP_DSS_COLOR_RGBA32:
-               m = 0xd; break;
-       case OMAP_DSS_COLOR_RGBX32:
-               m = 0xe; break;
-       default:
-               BUG(); break;
+       if (plane != OMAP_DSS_GFX) {
+               switch (color_mode) {
+               case OMAP_DSS_COLOR_NV12:
+                       m = 0x0; break;
+               case OMAP_DSS_COLOR_RGB12U:
+                       m = 0x1; break;
+               case OMAP_DSS_COLOR_RGBA16:
+                       m = 0x2; break;
+               case OMAP_DSS_COLOR_RGBX16:
+                       m = 0x4; break;
+               case OMAP_DSS_COLOR_ARGB16:
+                       m = 0x5; break;
+               case OMAP_DSS_COLOR_RGB16:
+                       m = 0x6; break;
+               case OMAP_DSS_COLOR_ARGB16_1555:
+                       m = 0x7; break;
+               case OMAP_DSS_COLOR_RGB24U:
+                       m = 0x8; break;
+               case OMAP_DSS_COLOR_RGB24P:
+                       m = 0x9; break;
+               case OMAP_DSS_COLOR_YUV2:
+                       m = 0xa; break;
+               case OMAP_DSS_COLOR_UYVY:
+                       m = 0xb; break;
+               case OMAP_DSS_COLOR_ARGB32:
+                       m = 0xc; break;
+               case OMAP_DSS_COLOR_RGBA32:
+                       m = 0xd; break;
+               case OMAP_DSS_COLOR_RGBX32:
+                       m = 0xe; break;
+               case OMAP_DSS_COLOR_XRGB16_1555:
+                       m = 0xf; break;
+               default:
+                       BUG(); break;
+               }
+       } else {
+               switch (color_mode) {
+               case OMAP_DSS_COLOR_CLUT1:
+                       m = 0x0; break;
+               case OMAP_DSS_COLOR_CLUT2:
+                       m = 0x1; break;
+               case OMAP_DSS_COLOR_CLUT4:
+                       m = 0x2; break;
+               case OMAP_DSS_COLOR_CLUT8:
+                       m = 0x3; break;
+               case OMAP_DSS_COLOR_RGB12U:
+                       m = 0x4; break;
+               case OMAP_DSS_COLOR_ARGB16:
+                       m = 0x5; break;
+               case OMAP_DSS_COLOR_RGB16:
+                       m = 0x6; break;
+               case OMAP_DSS_COLOR_ARGB16_1555:
+                       m = 0x7; break;
+               case OMAP_DSS_COLOR_RGB24U:
+                       m = 0x8; break;
+               case OMAP_DSS_COLOR_RGB24P:
+                       m = 0x9; break;
+               case OMAP_DSS_COLOR_YUV2:
+                       m = 0xa; break;
+               case OMAP_DSS_COLOR_UYVY:
+                       m = 0xb; break;
+               case OMAP_DSS_COLOR_ARGB32:
+                       m = 0xc; break;
+               case OMAP_DSS_COLOR_RGBA32:
+                       m = 0xd; break;
+               case OMAP_DSS_COLOR_RGBX32:
+                       m = 0xe; break;
+               case OMAP_DSS_COLOR_XRGB16_1555:
+                       m = 0xf; break;
+               default:
+                       BUG(); break;
+               }
        }
 
-       REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
 }
 
 static void _dispc_set_channel_out(enum omap_plane plane,
@@ -953,7 +940,7 @@ static void _dispc_set_channel_out(enum omap_plane plane,
                return;
        }
 
-       val = dispc_read_reg(dispc_reg_att[plane]);
+       val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                switch (channel) {
                case OMAP_DSS_CHANNEL_LCD:
@@ -977,7 +964,7 @@ static void _dispc_set_channel_out(enum omap_plane plane,
        } else {
                val = FLD_MOD(val, channel, shift, shift);
        }
-       dispc_write_reg(dispc_reg_att[plane], val);
+       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 }
 
 void dispc_set_burst_size(enum omap_plane plane,
@@ -1001,9 +988,9 @@ void dispc_set_burst_size(enum omap_plane plane,
                return;
        }
 
-       val = dispc_read_reg(dispc_reg_att[plane]);
+       val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
        val = FLD_MOD(val, burst_size, shift+1, shift);
-       dispc_write_reg(dispc_reg_att[plane], val);
+       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 
        enable_clocks(0);
 }
@@ -1028,9 +1015,9 @@ static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
 
        BUG_ON(plane == OMAP_DSS_GFX);
 
-       val = dispc_read_reg(dispc_reg_att[plane]);
+       val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
        val = FLD_MOD(val, enable, 9, 9);
-       dispc_write_reg(dispc_reg_att[plane], val);
+       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
 }
 
 void dispc_enable_replication(enum omap_plane plane, bool enable)
@@ -1043,7 +1030,7 @@ void dispc_enable_replication(enum omap_plane plane, bool enable)
                bit = 10;
 
        enable_clocks(1);
-       REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
        enable_clocks(0);
 }
 
@@ -1053,7 +1040,7 @@ void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height)
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
        enable_clocks(1);
-       dispc_write_reg(DISPC_SIZE_LCD(channel), val);
+       dispc_write_reg(DISPC_SIZE_MGR(channel), val);
        enable_clocks(0);
 }
 
@@ -1063,15 +1050,12 @@ void dispc_set_digit_size(u16 width, u16 height)
        BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
        val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
        enable_clocks(1);
-       dispc_write_reg(DISPC_SIZE_DIG, val);
+       dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val);
        enable_clocks(0);
 }
 
 static void dispc_read_plane_fifo_sizes(void)
 {
-       const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
-                                     DISPC_VID_FIFO_SIZE_STATUS(0),
-                                     DISPC_VID_FIFO_SIZE_STATUS(1) };
        u32 size;
        int plane;
        u8 start, end;
@@ -1081,7 +1065,8 @@ static void dispc_read_plane_fifo_sizes(void)
        dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
 
        for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
-               size = FLD_GET(dispc_read_reg(fsz_reg[plane]), start, end);
+               size = FLD_GET(dispc_read_reg(DISPC_OVL_FIFO_SIZE_STATUS(plane)),
+                       start, end);
                dispc.fifo_size[plane] = size;
        }
 
@@ -1095,23 +1080,22 @@ u32 dispc_get_plane_fifo_size(enum omap_plane plane)
 
 void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
 {
-       const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
-                                      DISPC_VID_FIFO_THRESHOLD(0),
-                                      DISPC_VID_FIFO_THRESHOLD(1) };
        u8 hi_start, hi_end, lo_start, lo_end;
 
+       dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
+       dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
+
        enable_clocks(1);
 
        DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
                        plane,
-                       REG_GET(ftrs_reg[plane], 11, 0),
-                       REG_GET(ftrs_reg[plane], 27, 16),
+                       REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
+                               lo_start, lo_end),
+                       REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
+                               hi_start, hi_end),
                        low, high);
 
-       dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
-       dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
-
-       dispc_write_reg(ftrs_reg[plane],
+       dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
                        FLD_VAL(high, hi_start, hi_end) |
                        FLD_VAL(low, lo_start, lo_end));
 
@@ -1128,106 +1112,120 @@ void dispc_enable_fifomerge(bool enable)
        enable_clocks(0);
 }
 
-static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
+static void _dispc_set_fir(enum omap_plane plane,
+                               int hinc, int vinc,
+                               enum omap_color_component color_comp)
 {
        u32 val;
-       const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
-                                     DISPC_VID_FIR(1) };
-       u8 hinc_start, hinc_end, vinc_start, vinc_end;
-
-       BUG_ON(plane == OMAP_DSS_GFX);
 
-       dss_feat_get_reg_field(FEAT_REG_FIRHINC, &hinc_start, &hinc_end);
-       dss_feat_get_reg_field(FEAT_REG_FIRVINC, &vinc_start, &vinc_end);
+       if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
+               u8 hinc_start, hinc_end, vinc_start, vinc_end;
 
-       val = FLD_VAL(vinc, vinc_start, vinc_end) |
-                       FLD_VAL(hinc, hinc_start, hinc_end);
+               dss_feat_get_reg_field(FEAT_REG_FIRHINC,
+                                       &hinc_start, &hinc_end);
+               dss_feat_get_reg_field(FEAT_REG_FIRVINC,
+                                       &vinc_start, &vinc_end);
+               val = FLD_VAL(vinc, vinc_start, vinc_end) |
+                               FLD_VAL(hinc, hinc_start, hinc_end);
 
-       dispc_write_reg(fir_reg[plane-1], val);
+               dispc_write_reg(DISPC_OVL_FIR(plane), val);
+       } else {
+               val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
+               dispc_write_reg(DISPC_OVL_FIR2(plane), val);
+       }
 }
 
 static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
 {
        u32 val;
-       const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
-                                     DISPC_VID_ACCU0(1) };
        u8 hor_start, hor_end, vert_start, vert_end;
 
-       BUG_ON(plane == OMAP_DSS_GFX);
-
        dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
        dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
 
        val = FLD_VAL(vaccu, vert_start, vert_end) |
                        FLD_VAL(haccu, hor_start, hor_end);
 
-       dispc_write_reg(ac0_reg[plane-1], val);
+       dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
 }
 
 static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
 {
        u32 val;
-       const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
-                                     DISPC_VID_ACCU1(1) };
        u8 hor_start, hor_end, vert_start, vert_end;
 
-       BUG_ON(plane == OMAP_DSS_GFX);
-
        dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
        dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
 
        val = FLD_VAL(vaccu, vert_start, vert_end) |
                        FLD_VAL(haccu, hor_start, hor_end);
 
-       dispc_write_reg(ac1_reg[plane-1], val);
+       dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
+}
+
+static void _dispc_set_vid_accu2_0(enum omap_plane plane, int haccu, int vaccu)
+{
+       u32 val;
+
+       val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
+       dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
 }
 
+static void _dispc_set_vid_accu2_1(enum omap_plane plane, int haccu, int vaccu)
+{
+       u32 val;
 
-static void _dispc_set_scaling(enum omap_plane plane,
+       val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
+       dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
+}
+
+static void _dispc_set_scale_param(enum omap_plane plane,
                u16 orig_width, u16 orig_height,
                u16 out_width, u16 out_height,
-               bool ilace, bool five_taps,
-               bool fieldmode)
+               bool five_taps, u8 rotation,
+               enum omap_color_component color_comp)
 {
-       int fir_hinc;
-       int fir_vinc;
+       int fir_hinc, fir_vinc;
        int hscaleup, vscaleup;
-       int accu0 = 0;
-       int accu1 = 0;
-       u32 l;
-
-       BUG_ON(plane == OMAP_DSS_GFX);
 
        hscaleup = orig_width <= out_width;
        vscaleup = orig_height <= out_height;
 
-       _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
+       _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps, color_comp);
 
-       if (!orig_width || orig_width == out_width)
-               fir_hinc = 0;
-       else
-               fir_hinc = 1024 * orig_width / out_width;
+       fir_hinc = 1024 * orig_width / out_width;
+       fir_vinc = 1024 * orig_height / out_height;
 
-       if (!orig_height || orig_height == out_height)
-               fir_vinc = 0;
-       else
-               fir_vinc = 1024 * orig_height / out_height;
+       _dispc_set_fir(plane, fir_hinc, fir_vinc, color_comp);
+}
 
-       _dispc_set_fir(plane, fir_hinc, fir_vinc);
+static void _dispc_set_scaling_common(enum omap_plane plane,
+               u16 orig_width, u16 orig_height,
+               u16 out_width, u16 out_height,
+               bool ilace, bool five_taps,
+               bool fieldmode, enum omap_color_mode color_mode,
+               u8 rotation)
+{
+       int accu0 = 0;
+       int accu1 = 0;
+       u32 l;
 
-       l = dispc_read_reg(dispc_reg_att[plane]);
+       _dispc_set_scale_param(plane, orig_width, orig_height,
+                               out_width, out_height, five_taps,
+                               rotation, DISPC_COLOR_COMPONENT_RGB_Y);
+       l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
 
        /* RESIZEENABLE and VERTICALTAPS */
        l &= ~((0x3 << 5) | (0x1 << 21));
-       l |= fir_hinc ? (1 << 5) : 0;
-       l |= fir_vinc ? (1 << 6) : 0;
+       l |= (orig_width != out_width) ? (1 << 5) : 0;
+       l |= (orig_height != out_height) ? (1 << 6) : 0;
        l |= five_taps ? (1 << 21) : 0;
 
        /* VRESIZECONF and HRESIZECONF */
        if (dss_has_feature(FEAT_RESIZECONF)) {
                l &= ~(0x3 << 7);
-               l |= hscaleup ? 0 : (1 << 7);
-               l |= vscaleup ? 0 : (1 << 8);
+               l |= (orig_width <= out_width) ? 0 : (1 << 7);
+               l |= (orig_height <= out_height) ? 0 : (1 << 8);
        }
 
        /* LINEBUFFERSPLIT */
@@ -1236,7 +1234,7 @@ static void _dispc_set_scaling(enum omap_plane plane,
                l |= five_taps ? (1 << 22) : 0;
        }
 
-       dispc_write_reg(dispc_reg_att[plane], l);
+       dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
 
        /*
         * field 0 = even field = bottom field
@@ -1244,7 +1242,7 @@ static void _dispc_set_scaling(enum omap_plane plane,
         */
        if (ilace && !fieldmode) {
                accu1 = 0;
-               accu0 = (fir_vinc / 2) & 0x3ff;
+               accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
                if (accu0 >= 1024/2) {
                        accu1 = 1024/2;
                        accu0 -= accu1;
@@ -1255,6 +1253,93 @@ static void _dispc_set_scaling(enum omap_plane plane,
        _dispc_set_vid_accu1(plane, 0, accu1);
 }
 
+static void _dispc_set_scaling_uv(enum omap_plane plane,
+               u16 orig_width, u16 orig_height,
+               u16 out_width, u16 out_height,
+               bool ilace, bool five_taps,
+               bool fieldmode, enum omap_color_mode color_mode,
+               u8 rotation)
+{
+       int scale_x = out_width != orig_width;
+       int scale_y = out_height != orig_height;
+
+       if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
+               return;
+       if ((color_mode != OMAP_DSS_COLOR_YUV2 &&
+                       color_mode != OMAP_DSS_COLOR_UYVY &&
+                       color_mode != OMAP_DSS_COLOR_NV12)) {
+               /* reset chroma resampling for RGB formats  */
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
+               return;
+       }
+       switch (color_mode) {
+       case OMAP_DSS_COLOR_NV12:
+               /* UV is subsampled by 2 vertically*/
+               orig_height >>= 1;
+               /* UV is subsampled by 2 horz.*/
+               orig_width >>= 1;
+               break;
+       case OMAP_DSS_COLOR_YUV2:
+       case OMAP_DSS_COLOR_UYVY:
+               /*For YUV422 with 90/270 rotation,
+                *we don't upsample chroma
+                */
+               if (rotation == OMAP_DSS_ROT_0 ||
+                       rotation == OMAP_DSS_ROT_180)
+                       /* UV is subsampled by 2 hrz*/
+                       orig_width >>= 1;
+               /* must use FIR for YUV422 if rotated */
+               if (rotation != OMAP_DSS_ROT_0)
+                       scale_x = scale_y = true;
+               break;
+       default:
+               BUG();
+       }
+
+       if (out_width != orig_width)
+               scale_x = true;
+       if (out_height != orig_height)
+               scale_y = true;
+
+       _dispc_set_scale_param(plane, orig_width, orig_height,
+                       out_width, out_height, five_taps,
+                               rotation, DISPC_COLOR_COMPONENT_UV);
+
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
+               (scale_x || scale_y) ? 1 : 0, 8, 8);
+       /* set H scaling */
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
+       /* set V scaling */
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
+
+       _dispc_set_vid_accu2_0(plane, 0x80, 0);
+       _dispc_set_vid_accu2_1(plane, 0x80, 0);
+}
+
+static void _dispc_set_scaling(enum omap_plane plane,
+               u16 orig_width, u16 orig_height,
+               u16 out_width, u16 out_height,
+               bool ilace, bool five_taps,
+               bool fieldmode, enum omap_color_mode color_mode,
+               u8 rotation)
+{
+       BUG_ON(plane == OMAP_DSS_GFX);
+
+       _dispc_set_scaling_common(plane,
+                       orig_width, orig_height,
+                       out_width, out_height,
+                       ilace, five_taps,
+                       fieldmode, color_mode,
+                       rotation);
+
+       _dispc_set_scaling_uv(plane,
+               orig_width, orig_height,
+               out_width, out_height,
+               ilace, five_taps,
+               fieldmode, color_mode,
+               rotation);
+}
+
 static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
                bool mirroring, enum omap_color_mode color_mode)
 {
@@ -1302,9 +1387,10 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
                        row_repeat = false;
        }
 
-       REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
        if (dss_has_feature(FEAT_ROWREPEATENABLE))
-               REG_FLD_MOD(dispc_reg_att[plane], row_repeat ? 1 : 0, 18, 18);
+               REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
+                       row_repeat ? 1 : 0, 18, 18);
 }
 
 static int color_mode_to_bpp(enum omap_color_mode color_mode)
@@ -1317,12 +1403,17 @@ static int color_mode_to_bpp(enum omap_color_mode color_mode)
        case OMAP_DSS_COLOR_CLUT4:
                return 4;
        case OMAP_DSS_COLOR_CLUT8:
+       case OMAP_DSS_COLOR_NV12:
                return 8;
        case OMAP_DSS_COLOR_RGB12U:
        case OMAP_DSS_COLOR_RGB16:
        case OMAP_DSS_COLOR_ARGB16:
        case OMAP_DSS_COLOR_YUV2:
        case OMAP_DSS_COLOR_UYVY:
+       case OMAP_DSS_COLOR_RGBA16:
+       case OMAP_DSS_COLOR_RGBX16:
+       case OMAP_DSS_COLOR_ARGB16_1555:
+       case OMAP_DSS_COLOR_XRGB16_1555:
                return 16;
        case OMAP_DSS_COLOR_RGB24P:
                return 24;
@@ -1655,7 +1746,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
                enum omap_dss_rotation_type rotation_type,
                u8 rotation, int mirror,
                u8 global_alpha, u8 pre_mult_alpha,
-               enum omap_channel channel)
+               enum omap_channel channel, u32 puv_addr)
 {
        const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
        bool five_taps = 0;
@@ -1704,7 +1795,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
                        return -EINVAL;
 
                if (color_mode == OMAP_DSS_COLOR_YUV2 ||
-                       color_mode == OMAP_DSS_COLOR_UYVY)
+                       color_mode == OMAP_DSS_COLOR_UYVY ||
+                       color_mode == OMAP_DSS_COLOR_NV12)
                        cconv = 1;
 
                /* Must use 5-tap filter? */
@@ -1778,6 +1870,12 @@ static int _dispc_setup_plane(enum omap_plane plane,
        _dispc_set_plane_ba0(plane, paddr + offset0);
        _dispc_set_plane_ba1(plane, paddr + offset1);
 
+       if (OMAP_DSS_COLOR_NV12 == color_mode) {
+               _dispc_set_plane_ba0_uv(plane, puv_addr + offset0);
+               _dispc_set_plane_ba1_uv(plane, puv_addr + offset1);
+       }
+
+
        _dispc_set_row_inc(plane, row_inc);
        _dispc_set_pix_inc(plane, pix_inc);
 
@@ -1791,7 +1889,8 @@ static int _dispc_setup_plane(enum omap_plane plane,
        if (plane != OMAP_DSS_GFX) {
                _dispc_set_scaling(plane, width, height,
                                   out_width, out_height,
-                                  ilace, five_taps, fieldmode);
+                                  ilace, five_taps, fieldmode,
+                                  color_mode, rotation);
                _dispc_set_vid_size(plane, out_width, out_height);
                _dispc_set_vid_color_conv(plane, cconv);
        }
@@ -1806,7 +1905,7 @@ static int _dispc_setup_plane(enum omap_plane plane,
 
 static void _dispc_enable_plane(enum omap_plane plane, bool enable)
 {
-       REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
+       REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
 }
 
 static void dispc_disable_isr(void *data, u32 mask)
@@ -2353,14 +2452,20 @@ static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div,
 
 unsigned long dispc_fclk_rate(void)
 {
+       struct platform_device *dsidev;
        unsigned long r = 0;
 
        switch (dss_get_dispc_clk_source()) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                r = dss_clk_get_rate(DSS_CLK_FCK);
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
-               r = dsi_get_pll_hsdiv_dispc_rate();
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+               dsidev = dsi_get_dsidev_from_id(0);
+               r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+               dsidev = dsi_get_dsidev_from_id(1);
+               r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
                break;
        default:
                BUG();
@@ -2371,6 +2476,7 @@ unsigned long dispc_fclk_rate(void)
 
 unsigned long dispc_lclk_rate(enum omap_channel channel)
 {
+       struct platform_device *dsidev;
        int lcd;
        unsigned long r;
        u32 l;
@@ -2380,11 +2486,16 @@ unsigned long dispc_lclk_rate(enum omap_channel channel)
        lcd = FLD_GET(l, 23, 16);
 
        switch (dss_get_lcd_clk_source(channel)) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                r = dss_clk_get_rate(DSS_CLK_FCK);
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
-               r = dsi_get_pll_hsdiv_dispc_rate();
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+               dsidev = dsi_get_dsidev_from_id(0);
+               r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+               dsidev = dsi_get_dsidev_from_id(1);
+               r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
                break;
        default:
                BUG();
@@ -2412,8 +2523,8 @@ void dispc_dump_clocks(struct seq_file *s)
 {
        int lcd, pcd;
        u32 l;
-       enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
-       enum dss_clk_source lcd_clk_src;
+       enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
+       enum omap_dss_clk_source lcd_clk_src;
 
        enable_clocks(1);
 
@@ -2516,7 +2627,7 @@ void dispc_dump_irqs(struct seq_file *s)
 
 void dispc_dump_regs(struct seq_file *s)
 {
-#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
+#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
 
        dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
 
@@ -2528,152 +2639,227 @@ void dispc_dump_regs(struct seq_file *s)
        DUMPREG(DISPC_CONTROL);
        DUMPREG(DISPC_CONFIG);
        DUMPREG(DISPC_CAPABLE);
-       DUMPREG(DISPC_DEFAULT_COLOR(0));
-       DUMPREG(DISPC_DEFAULT_COLOR(1));
-       DUMPREG(DISPC_TRANS_COLOR(0));
-       DUMPREG(DISPC_TRANS_COLOR(1));
+       DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT));
+       DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT));
        DUMPREG(DISPC_LINE_STATUS);
        DUMPREG(DISPC_LINE_NUMBER);
-       DUMPREG(DISPC_TIMING_H(0));
-       DUMPREG(DISPC_TIMING_V(0));
-       DUMPREG(DISPC_POL_FREQ(0));
-       DUMPREG(DISPC_DIVISORo(0));
+       DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD));
        DUMPREG(DISPC_GLOBAL_ALPHA);
-       DUMPREG(DISPC_SIZE_DIG);
-       DUMPREG(DISPC_SIZE_LCD(0));
+       DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT));
+       DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
                DUMPREG(DISPC_CONTROL2);
                DUMPREG(DISPC_CONFIG2);
-               DUMPREG(DISPC_DEFAULT_COLOR(2));
-               DUMPREG(DISPC_TRANS_COLOR(2));
-               DUMPREG(DISPC_TIMING_H(2));
-               DUMPREG(DISPC_TIMING_V(2));
-               DUMPREG(DISPC_POL_FREQ(2));
-               DUMPREG(DISPC_DIVISORo(2));
-               DUMPREG(DISPC_SIZE_LCD(2));
-       }
-
-       DUMPREG(DISPC_GFX_BA0);
-       DUMPREG(DISPC_GFX_BA1);
-       DUMPREG(DISPC_GFX_POSITION);
-       DUMPREG(DISPC_GFX_SIZE);
-       DUMPREG(DISPC_GFX_ATTRIBUTES);
-       DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
-       DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
-       DUMPREG(DISPC_GFX_ROW_INC);
-       DUMPREG(DISPC_GFX_PIXEL_INC);
-       DUMPREG(DISPC_GFX_WINDOW_SKIP);
-       DUMPREG(DISPC_GFX_TABLE_BA);
-
-       DUMPREG(DISPC_DATA_CYCLE1(0));
-       DUMPREG(DISPC_DATA_CYCLE2(0));
-       DUMPREG(DISPC_DATA_CYCLE3(0));
-
-       DUMPREG(DISPC_CPR_COEF_R(0));
-       DUMPREG(DISPC_CPR_COEF_G(0));
-       DUMPREG(DISPC_CPR_COEF_B(0));
+               DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD2));
+       }
+
+       DUMPREG(DISPC_OVL_BA0(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_BA1(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_WINDOW_SKIP(OMAP_DSS_GFX));
+       DUMPREG(DISPC_OVL_TABLE_BA(OMAP_DSS_GFX));
+
+       DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD));
+
+       DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD));
+       DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD));
        if (dss_has_feature(FEAT_MGR_LCD2)) {
-               DUMPREG(DISPC_DATA_CYCLE1(2));
-               DUMPREG(DISPC_DATA_CYCLE2(2));
-               DUMPREG(DISPC_DATA_CYCLE3(2));
-
-               DUMPREG(DISPC_CPR_COEF_R(2));
-               DUMPREG(DISPC_CPR_COEF_G(2));
-               DUMPREG(DISPC_CPR_COEF_B(2));
-       }
-
-       DUMPREG(DISPC_GFX_PRELOAD);
-
-       DUMPREG(DISPC_VID_BA0(0));
-       DUMPREG(DISPC_VID_BA1(0));
-       DUMPREG(DISPC_VID_POSITION(0));
-       DUMPREG(DISPC_VID_SIZE(0));
-       DUMPREG(DISPC_VID_ATTRIBUTES(0));
-       DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
-       DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
-       DUMPREG(DISPC_VID_ROW_INC(0));
-       DUMPREG(DISPC_VID_PIXEL_INC(0));
-       DUMPREG(DISPC_VID_FIR(0));
-       DUMPREG(DISPC_VID_PICTURE_SIZE(0));
-       DUMPREG(DISPC_VID_ACCU0(0));
-       DUMPREG(DISPC_VID_ACCU1(0));
-
-       DUMPREG(DISPC_VID_BA0(1));
-       DUMPREG(DISPC_VID_BA1(1));
-       DUMPREG(DISPC_VID_POSITION(1));
-       DUMPREG(DISPC_VID_SIZE(1));
-       DUMPREG(DISPC_VID_ATTRIBUTES(1));
-       DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
-       DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
-       DUMPREG(DISPC_VID_ROW_INC(1));
-       DUMPREG(DISPC_VID_PIXEL_INC(1));
-       DUMPREG(DISPC_VID_FIR(1));
-       DUMPREG(DISPC_VID_PICTURE_SIZE(1));
-       DUMPREG(DISPC_VID_ACCU0(1));
-       DUMPREG(DISPC_VID_ACCU1(1));
-
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 0));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 1));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 2));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 3));
-       DUMPREG(DISPC_VID_CONV_COEF(0, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
-
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 0));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 1));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 2));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 3));
-       DUMPREG(DISPC_VID_CONV_COEF(1, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
-       DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
-
-       DUMPREG(DISPC_VID_PRELOAD(0));
-       DUMPREG(DISPC_VID_PRELOAD(1));
+               DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2));
+
+               DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2));
+               DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2));
+       }
+
+       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX));
+
+       DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO1));
+
+       DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO2));
+       DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO2));
+
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 7));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 7));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO1));
+               DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO1));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 7));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 7));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 7));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1));
+
+
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 7));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 7));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3));
+       DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6));
+       DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7));
+
+       if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
+               DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2));
+               DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO2));
+               DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO2));
+               DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO2));
+               DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO2));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 7));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 7));
+
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 0));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 1));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 2));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 3));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 4));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 5));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 6));
+               DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 7));
+       }
+       if (dss_has_feature(FEAT_ATTR2))
+               DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2));
+
+       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1));
+       DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2));
 
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
@@ -3388,11 +3574,12 @@ int dispc_setup_plane(enum omap_plane plane,
                       bool ilace,
                       enum omap_dss_rotation_type rotation_type,
                       u8 rotation, bool mirror, u8 global_alpha,
-                      u8 pre_mult_alpha, enum omap_channel channel)
+                      u8 pre_mult_alpha, enum omap_channel channel,
+                      u32 puv_addr)
 {
        int r = 0;
 
-       DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
+       DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d, %d, %dx%d -> "
               "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n",
               plane, paddr, screen_width, pos_x, pos_y,
               width, height,
@@ -3411,7 +3598,8 @@ int dispc_setup_plane(enum omap_plane plane,
                           rotation_type,
                           rotation, mirror,
                           global_alpha,
-                          pre_mult_alpha, channel);
+                          pre_mult_alpha,
+                          channel, puv_addr);
 
        enable_clocks(0);
 
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h
new file mode 100644 (file)
index 0000000..6c9ee0a
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * linux/drivers/video/omap2/dss/dispc.h
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Archit Taneja <archit@ti.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __OMAP2_DISPC_REG_H
+#define __OMAP2_DISPC_REG_H
+
+/* DISPC common registers */
+#define DISPC_REVISION                 0x0000
+#define DISPC_SYSCONFIG                        0x0010
+#define DISPC_SYSSTATUS                        0x0014
+#define DISPC_IRQSTATUS                        0x0018
+#define DISPC_IRQENABLE                        0x001C
+#define DISPC_CONTROL                  0x0040
+#define DISPC_CONFIG                   0x0044
+#define DISPC_CAPABLE                  0x0048
+#define DISPC_LINE_STATUS              0x005C
+#define DISPC_LINE_NUMBER              0x0060
+#define DISPC_GLOBAL_ALPHA             0x0074
+#define DISPC_CONTROL2                 0x0238
+#define DISPC_CONFIG2                  0x0620
+#define DISPC_DIVISOR                  0x0804
+
+/* DISPC overlay registers */
+#define DISPC_OVL_BA0(n)               (DISPC_OVL_BASE(n) + \
+                                       DISPC_BA0_OFFSET(n))
+#define DISPC_OVL_BA1(n)               (DISPC_OVL_BASE(n) + \
+                                       DISPC_BA1_OFFSET(n))
+#define DISPC_OVL_BA0_UV(n)            (DISPC_OVL_BASE(n) + \
+                                       DISPC_BA0_UV_OFFSET(n))
+#define DISPC_OVL_BA1_UV(n)            (DISPC_OVL_BASE(n) + \
+                                       DISPC_BA1_UV_OFFSET(n))
+#define DISPC_OVL_POSITION(n)          (DISPC_OVL_BASE(n) + \
+                                       DISPC_POS_OFFSET(n))
+#define DISPC_OVL_SIZE(n)              (DISPC_OVL_BASE(n) + \
+                                       DISPC_SIZE_OFFSET(n))
+#define DISPC_OVL_ATTRIBUTES(n)                (DISPC_OVL_BASE(n) + \
+                                       DISPC_ATTR_OFFSET(n))
+#define DISPC_OVL_ATTRIBUTES2(n)       (DISPC_OVL_BASE(n) + \
+                                       DISPC_ATTR2_OFFSET(n))
+#define DISPC_OVL_FIFO_THRESHOLD(n)    (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIFO_THRESH_OFFSET(n))
+#define DISPC_OVL_FIFO_SIZE_STATUS(n)  (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIFO_SIZE_STATUS_OFFSET(n))
+#define DISPC_OVL_ROW_INC(n)           (DISPC_OVL_BASE(n) + \
+                                       DISPC_ROW_INC_OFFSET(n))
+#define DISPC_OVL_PIXEL_INC(n)         (DISPC_OVL_BASE(n) + \
+                                       DISPC_PIX_INC_OFFSET(n))
+#define DISPC_OVL_WINDOW_SKIP(n)       (DISPC_OVL_BASE(n) + \
+                                       DISPC_WINDOW_SKIP_OFFSET(n))
+#define DISPC_OVL_TABLE_BA(n)          (DISPC_OVL_BASE(n) + \
+                                       DISPC_TABLE_BA_OFFSET(n))
+#define DISPC_OVL_FIR(n)               (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_OFFSET(n))
+#define DISPC_OVL_FIR2(n)              (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR2_OFFSET(n))
+#define DISPC_OVL_PICTURE_SIZE(n)      (DISPC_OVL_BASE(n) + \
+                                       DISPC_PIC_SIZE_OFFSET(n))
+#define DISPC_OVL_ACCU0(n)             (DISPC_OVL_BASE(n) + \
+                                       DISPC_ACCU0_OFFSET(n))
+#define DISPC_OVL_ACCU1(n)             (DISPC_OVL_BASE(n) + \
+                                       DISPC_ACCU1_OFFSET(n))
+#define DISPC_OVL_ACCU2_0(n)           (DISPC_OVL_BASE(n) + \
+                                       DISPC_ACCU2_0_OFFSET(n))
+#define DISPC_OVL_ACCU2_1(n)           (DISPC_OVL_BASE(n) + \
+                                       DISPC_ACCU2_1_OFFSET(n))
+#define DISPC_OVL_FIR_COEF_H(n, i)     (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_H_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_HV(n, i)    (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_HV_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_H2(n, i)    (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_H2_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_HV2(n, i)   (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_HV2_OFFSET(n, i))
+#define DISPC_OVL_CONV_COEF(n, i)      (DISPC_OVL_BASE(n) + \
+                                       DISPC_CONV_COEF_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_V(n, i)     (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_V_OFFSET(n, i))
+#define DISPC_OVL_FIR_COEF_V2(n, i)    (DISPC_OVL_BASE(n) + \
+                                       DISPC_FIR_COEF_V2_OFFSET(n, i))
+#define DISPC_OVL_PRELOAD(n)           (DISPC_OVL_BASE(n) + \
+                                       DISPC_PRELOAD_OFFSET(n))
+
+/* DISPC manager/channel specific registers */
+static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x004C;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               return 0x0050;
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03AC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0054;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               return 0x0058;
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03B0;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_TIMING_H(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0064;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x0400;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_TIMING_V(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0068;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x0404;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_POL_FREQ(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x006C;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x0408;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_DIVISORo(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0070;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x040C;
+       default:
+               BUG();
+       }
+}
+
+/* Named as DISPC_SIZE_LCD, DISPC_SIZE_DIGIT and DISPC_SIZE_LCD2 in TRM */
+static inline u16 DISPC_SIZE_MGR(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x007C;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               return 0x0078;
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03CC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x01D4;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03C0;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x01D8;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03C4;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x01DC;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03C8;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0220;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03BC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0224;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03B8;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel)
+{
+       switch (channel) {
+       case OMAP_DSS_CHANNEL_LCD:
+               return 0x0228;
+       case OMAP_DSS_CHANNEL_DIGIT:
+               BUG();
+       case OMAP_DSS_CHANNEL_LCD2:
+               return 0x03B4;
+       default:
+               BUG();
+       }
+}
+
+/* DISPC overlay register base addresses */
+static inline u16 DISPC_OVL_BASE(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0080;
+       case OMAP_DSS_VIDEO1:
+               return 0x00BC;
+       case OMAP_DSS_VIDEO2:
+               return 0x014C;
+       default:
+               BUG();
+       }
+}
+
+/* DISPC overlay register offsets */
+static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0000;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0004;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0544;
+       case OMAP_DSS_VIDEO2:
+               return 0x04BC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0548;
+       case OMAP_DSS_VIDEO2:
+               return 0x04C0;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_POS_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0008;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x000C;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0020;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0010;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0568;
+       case OMAP_DSS_VIDEO2:
+               return 0x04DC;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0024;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0014;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0028;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0018;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x002C;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x001C;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0030;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0020;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0034;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               BUG();
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x0038;
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               BUG();
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0024;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0580;
+       case OMAP_DSS_VIDEO2:
+               return 0x055C;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0028;
+       default:
+               BUG();
+       }
+}
+
+
+static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x002C;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0584;
+       case OMAP_DSS_VIDEO2:
+               return 0x0560;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0030;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0588;
+       case OMAP_DSS_VIDEO2:
+               return 0x0564;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0034 + i * 0x8;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x058C + i * 0x8;
+       case OMAP_DSS_VIDEO2:
+               return 0x0568 + i * 0x8;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0038 + i * 0x8;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0590 + i * 8;
+       case OMAP_DSS_VIDEO2:
+               return 0x056C + i * 0x8;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4,} */
+static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+       case OMAP_DSS_VIDEO2:
+               return 0x0074 + i * 0x4;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x0124 + i * 0x4;
+       case OMAP_DSS_VIDEO2:
+               return 0x00B4 + i * 0x4;
+       default:
+               BUG();
+       }
+}
+
+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
+static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               BUG();
+       case OMAP_DSS_VIDEO1:
+               return 0x05CC + i * 0x4;
+       case OMAP_DSS_VIDEO2:
+               return 0x05A8 + i * 0x4;
+       default:
+               BUG();
+       }
+}
+
+static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane)
+{
+       switch (plane) {
+       case OMAP_DSS_GFX:
+               return 0x01AC;
+       case OMAP_DSS_VIDEO1:
+               return 0x0174;
+       case OMAP_DSS_VIDEO2:
+               return 0x00E8;
+       default:
+               BUG();
+       }
+}
+#endif
index a85a6f38b40c126661e3cf9e61febef169d53fcc..c2dfc8c50057baad8be69900ba27f9a11434108b 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/jiffies.h>
 #include <linux/platform_device.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include "dss.h"
 
 static ssize_t display_enabled_show(struct device *dev,
@@ -44,9 +44,13 @@ static ssize_t display_enabled_store(struct device *dev,
                const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       bool enabled, r;
+       int r, enabled;
 
-       enabled = simple_strtoul(buf, NULL, 10);
+       r = kstrtoint(buf, 0, &enabled);
+       if (r)
+               return r;
+
+       enabled = !!enabled;
 
        if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
                if (enabled) {
@@ -82,7 +86,9 @@ static ssize_t display_upd_mode_store(struct device *dev,
        if (!dssdev->driver->set_update_mode)
                return -EINVAL;
 
-       val = simple_strtoul(buf, NULL, 10);
+       r = kstrtoint(buf, 0, &val);
+       if (r)
+               return r;
 
        switch (val) {
        case OMAP_DSS_UPDATE_DISABLED:
@@ -114,13 +120,16 @@ static ssize_t display_tear_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       unsigned long te;
-       int r;
+       int te, r;
 
        if (!dssdev->driver->enable_te || !dssdev->driver->get_te)
                return -ENOENT;
 
-       te = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &te);
+       if (r)
+               return r;
+
+       te = !!te;
 
        r = dssdev->driver->enable_te(dssdev, te);
        if (r)
@@ -196,13 +205,14 @@ static ssize_t display_rotate_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       unsigned long rot;
-       int r;
+       int rot, r;
 
        if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
                return -ENOENT;
 
-       rot = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &rot);
+       if (r)
+               return r;
 
        r = dssdev->driver->set_rotate(dssdev, rot);
        if (r)
@@ -226,13 +236,16 @@ static ssize_t display_mirror_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       unsigned long mirror;
-       int r;
+       int mirror, r;
 
        if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
                return -ENOENT;
 
-       mirror = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &mirror);
+       if (r)
+               return r;
+
+       mirror = !!mirror;
 
        r = dssdev->driver->set_mirror(dssdev, mirror);
        if (r)
@@ -259,14 +272,15 @@ static ssize_t display_wss_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t size)
 {
        struct omap_dss_device *dssdev = to_dss_device(dev);
-       unsigned long wss;
+       u32 wss;
        int r;
 
        if (!dssdev->driver->get_wss || !dssdev->driver->set_wss)
                return -ENOENT;
 
-       if (strict_strtoul(buf, 0, &wss))
-               return -EINVAL;
+       r = kstrtou32(buf, 0, &wss);
+       if (r)
+               return r;
 
        if (wss > 0xfffff)
                return -EINVAL;
index 2d3ca4ca4a05b14583b89f5cf9e622edef4a72cd..ff6bd30132df04da253f639ea9c8fe5fe221c87a 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
 
 static struct {
        struct regulator *vdds_dsi_reg;
+       struct platform_device *dsidev;
 } dpi;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
+{
+       int dsi_module;
+
+       dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1;
+
+       return dsi_get_dsidev_from_id(dsi_module);
+}
+
+static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)
+{
+       if (dssdev->clocks.dispc.dispc_fclk_src ==
+                       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
+                       dssdev->clocks.dispc.dispc_fclk_src ==
+                       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC ||
+                       dssdev->clocks.dispc.channel.lcd_clk_src ==
+                       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
+                       dssdev->clocks.dispc.channel.lcd_clk_src ==
+                       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC)
+               return true;
+       else
+               return false;
+}
+
 static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
                unsigned long pck_req, unsigned long *fck, int *lck_div,
                int *pck_div)
@@ -48,16 +72,16 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
        struct dispc_clock_info dispc_cinfo;
        int r;
 
-       r = dsi_pll_calc_clock_div_pck(is_tft, pck_req, &dsi_cinfo,
-                       &dispc_cinfo);
+       r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft, pck_req,
+                       &dsi_cinfo, &dispc_cinfo);
        if (r)
                return r;
 
-       r = dsi_pll_set_clock_div(&dsi_cinfo);
+       r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
        if (r)
                return r;
 
-       dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
+       dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
 
        r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo);
        if (r)
@@ -69,7 +93,7 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft,
 
        return 0;
 }
-#else
+
 static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,
                unsigned long pck_req, unsigned long *fck, int *lck_div,
                int *pck_div)
@@ -96,13 +120,12 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft,
 
        return 0;
 }
-#endif
 
 static int dpi_set_mode(struct omap_dss_device *dssdev)
 {
        struct omap_video_timings *t = &dssdev->panel.timings;
-       int lck_div, pck_div;
-       unsigned long fck;
+       int lck_div = 0, pck_div = 0;
+       unsigned long fck = 0;
        unsigned long pck;
        bool is_tft;
        int r = 0;
@@ -114,13 +137,12 @@ static int dpi_set_mode(struct omap_dss_device *dssdev)
 
        is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
-                       &lck_div, &pck_div);
-#else
-       r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, &fck,
-                       &lck_div, &pck_div);
-#endif
+       if (dpi_use_dsi_pll(dssdev))
+               r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000,
+                               &fck, &lck_div, &pck_div);
+       else
+               r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000,
+                               &fck, &lck_div, &pck_div);
        if (r)
                goto err0;
 
@@ -179,12 +201,13 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
        if (r)
                goto err2;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       dss_clk_enable(DSS_CLK_SYSCK);
-       r = dsi_pll_init(dssdev, 0, 1);
-       if (r)
-               goto err3;
-#endif
+       if (dpi_use_dsi_pll(dssdev)) {
+               dss_clk_enable(DSS_CLK_SYSCK);
+               r = dsi_pll_init(dpi.dsidev, 0, 1);
+               if (r)
+                       goto err3;
+       }
+
        r = dpi_set_mode(dssdev);
        if (r)
                goto err4;
@@ -196,11 +219,11 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
        return 0;
 
 err4:
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       dsi_pll_uninit();
+       if (dpi_use_dsi_pll(dssdev))
+               dsi_pll_uninit(dpi.dsidev, true);
 err3:
-       dss_clk_disable(DSS_CLK_SYSCK);
-#endif
+       if (dpi_use_dsi_pll(dssdev))
+               dss_clk_disable(DSS_CLK_SYSCK);
 err2:
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
        if (cpu_is_omap34xx())
@@ -216,11 +239,11 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
 {
        dssdev->manager->disable(dssdev->manager);
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
-       dsi_pll_uninit();
-       dss_clk_disable(DSS_CLK_SYSCK);
-#endif
+       if (dpi_use_dsi_pll(dssdev)) {
+               dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
+               dsi_pll_uninit(dpi.dsidev, true);
+               dss_clk_disable(DSS_CLK_SYSCK);
+       }
 
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
@@ -251,6 +274,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
        int lck_div, pck_div;
        unsigned long fck;
        unsigned long pck;
+       struct dispc_clock_info dispc_cinfo;
 
        if (!dispc_lcd_timings_ok(timings))
                return -EINVAL;
@@ -260,11 +284,9 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
 
        is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       {
+       if (dpi_use_dsi_pll(dssdev)) {
                struct dsi_clock_info dsi_cinfo;
-               struct dispc_clock_info dispc_cinfo;
-               r = dsi_pll_calc_clock_div_pck(is_tft,
+               r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft,
                                timings->pixel_clock * 1000,
                                &dsi_cinfo, &dispc_cinfo);
 
@@ -272,13 +294,8 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
                        return r;
 
                fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
-               lck_div = dispc_cinfo.lck_div;
-               pck_div = dispc_cinfo.pck_div;
-       }
-#else
-       {
+       } else {
                struct dss_clock_info dss_cinfo;
-               struct dispc_clock_info dispc_cinfo;
                r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000,
                                &dss_cinfo, &dispc_cinfo);
 
@@ -286,10 +303,10 @@ int dpi_check_timings(struct omap_dss_device *dssdev,
                        return r;
 
                fck = dss_cinfo.fck;
-               lck_div = dispc_cinfo.lck_div;
-               pck_div = dispc_cinfo.pck_div;
        }
-#endif
+
+       lck_div = dispc_cinfo.lck_div;
+       pck_div = dispc_cinfo.pck_div;
 
        pck = fck / lck_div / pck_div / 1000;
 
@@ -316,6 +333,12 @@ int dpi_init_display(struct omap_dss_device *dssdev)
                dpi.vdds_dsi_reg = vdds_dsi;
        }
 
+       if (dpi_use_dsi_pll(dssdev)) {
+               enum omap_dss_clk_source dispc_fclk_src =
+                       dssdev->clocks.dispc.dispc_fclk_src;
+               dpi.dsidev = dpi_get_dsidev(dispc_fclk_src);
+       }
+
        return 0;
 }
 
index 0a7f1a47f8e3b5fb0b30c369f971dd77146490b4..345757cfcbee187cf90f7685b3bc1830ef2b783f 100644 (file)
 #include <linux/regulator/consumer.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/clock.h>
 
 #include "dss.h"
@@ -56,6 +59,7 @@ struct dsi_reg { u16 idx; };
 #define DSI_IRQSTATUS                  DSI_REG(0x0018)
 #define DSI_IRQENABLE                  DSI_REG(0x001C)
 #define DSI_CTRL                       DSI_REG(0x0040)
+#define DSI_GNQ                                DSI_REG(0x0044)
 #define DSI_COMPLEXIO_CFG1             DSI_REG(0x0048)
 #define DSI_COMPLEXIO_IRQ_STATUS       DSI_REG(0x004C)
 #define DSI_COMPLEXIO_IRQ_ENABLE       DSI_REG(0x0050)
@@ -90,6 +94,7 @@ struct dsi_reg { u16 idx; };
 #define DSI_DSIPHY_CFG1                        DSI_REG(0x200 + 0x0004)
 #define DSI_DSIPHY_CFG2                        DSI_REG(0x200 + 0x0008)
 #define DSI_DSIPHY_CFG5                        DSI_REG(0x200 + 0x0014)
+#define DSI_DSIPHY_CFG10               DSI_REG(0x200 + 0x0028)
 
 /* DSI_PLL_CTRL_SCP */
 
@@ -99,11 +104,11 @@ struct dsi_reg { u16 idx; };
 #define DSI_PLL_CONFIGURATION1         DSI_REG(0x300 + 0x000C)
 #define DSI_PLL_CONFIGURATION2         DSI_REG(0x300 + 0x0010)
 
-#define REG_GET(idx, start, end) \
-       FLD_GET(dsi_read_reg(idx), start, end)
+#define REG_GET(dsidev, idx, start, end) \
+       FLD_GET(dsi_read_reg(dsidev, idx), start, end)
 
-#define REG_FLD_MOD(idx, val, start, end) \
-       dsi_write_reg(idx, FLD_MOD(dsi_read_reg(idx), val, start, end))
+#define REG_FLD_MOD(dsidev, idx, val, start, end) \
+       dsi_write_reg(dsidev, idx, FLD_MOD(dsi_read_reg(dsidev, idx), val, start, end))
 
 /* Global interrupts */
 #define DSI_IRQ_VC0            (1 << 0)
@@ -147,31 +152,50 @@ struct dsi_reg { u16 idx; };
 #define DSI_CIO_IRQ_ERRSYNCESC1                (1 << 0)
 #define DSI_CIO_IRQ_ERRSYNCESC2                (1 << 1)
 #define DSI_CIO_IRQ_ERRSYNCESC3                (1 << 2)
+#define DSI_CIO_IRQ_ERRSYNCESC4                (1 << 3)
+#define DSI_CIO_IRQ_ERRSYNCESC5                (1 << 4)
 #define DSI_CIO_IRQ_ERRESC1            (1 << 5)
 #define DSI_CIO_IRQ_ERRESC2            (1 << 6)
 #define DSI_CIO_IRQ_ERRESC3            (1 << 7)
+#define DSI_CIO_IRQ_ERRESC4            (1 << 8)
+#define DSI_CIO_IRQ_ERRESC5            (1 << 9)
 #define DSI_CIO_IRQ_ERRCONTROL1                (1 << 10)
 #define DSI_CIO_IRQ_ERRCONTROL2                (1 << 11)
 #define DSI_CIO_IRQ_ERRCONTROL3                (1 << 12)
+#define DSI_CIO_IRQ_ERRCONTROL4                (1 << 13)
+#define DSI_CIO_IRQ_ERRCONTROL5                (1 << 14)
 #define DSI_CIO_IRQ_STATEULPS1         (1 << 15)
 #define DSI_CIO_IRQ_STATEULPS2         (1 << 16)
 #define DSI_CIO_IRQ_STATEULPS3         (1 << 17)
+#define DSI_CIO_IRQ_STATEULPS4         (1 << 18)
+#define DSI_CIO_IRQ_STATEULPS5         (1 << 19)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
 #define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_4 (1 << 26)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_4 (1 << 27)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_5 (1 << 28)
+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_5 (1 << 29)
 #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
 #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
 #define DSI_CIO_IRQ_ERROR_MASK \
        (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
-        DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
-        DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRCONTROL1 | \
-        DSI_CIO_IRQ_ERRCONTROL2 | DSI_CIO_IRQ_ERRCONTROL3 | \
+        DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRSYNCESC4 | \
+        DSI_CIO_IRQ_ERRSYNCESC5 | \
+        DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
+        DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRESC4 | \
+        DSI_CIO_IRQ_ERRESC5 | \
+        DSI_CIO_IRQ_ERRCONTROL1 | DSI_CIO_IRQ_ERRCONTROL2 | \
+        DSI_CIO_IRQ_ERRCONTROL3 | DSI_CIO_IRQ_ERRCONTROL4 | \
+        DSI_CIO_IRQ_ERRCONTROL5 | \
         DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
         DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
-        DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3)
+        DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3 | \
+        DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \
+        DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5)
 
 #define DSI_DT_DCS_SHORT_WRITE_0       0x05
 #define DSI_DT_DCS_SHORT_WRITE_1       0x15
@@ -208,6 +232,19 @@ enum dsi_vc_mode {
        DSI_VC_MODE_VP,
 };
 
+enum dsi_lane {
+       DSI_CLK_P       = 1 << 0,
+       DSI_CLK_N       = 1 << 1,
+       DSI_DATA1_P     = 1 << 2,
+       DSI_DATA1_N     = 1 << 3,
+       DSI_DATA2_P     = 1 << 4,
+       DSI_DATA2_N     = 1 << 5,
+       DSI_DATA3_P     = 1 << 6,
+       DSI_DATA3_N     = 1 << 7,
+       DSI_DATA4_P     = 1 << 8,
+       DSI_DATA4_N     = 1 << 9,
+};
+
 struct dsi_update_region {
        u16 x, y, w, h;
        struct omap_dss_device *device;
@@ -227,14 +264,16 @@ struct dsi_isr_tables {
        struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
 };
 
-static struct
-{
+struct dsi_data {
        struct platform_device *pdev;
        void __iomem    *base;
        int irq;
 
+       void (*dsi_mux_pads)(bool enable);
+
        struct dsi_clock_info current_cinfo;
 
+       bool vdds_dsi_enabled;
        struct regulator *vdds_dsi_reg;
 
        struct {
@@ -258,8 +297,7 @@ static struct
        struct dsi_update_region update_region;
 
        bool te_enabled;
-
-       struct workqueue_struct *workqueue;
+       bool ulps_enabled;
 
        void (*framedone_callback)(int, void *);
        void *framedone_data;
@@ -292,21 +330,63 @@ static struct
        unsigned long  regm_dispc_max, regm_dsi_max;
        unsigned long  fint_min, fint_max;
        unsigned long lpdiv_max;
-} dsi;
+
+       int num_data_lanes;
+
+       unsigned scp_clk_refcount;
+};
+
+struct dsi_packet_sent_handler_data {
+       struct platform_device *dsidev;
+       struct completion *completion;
+};
+
+static struct platform_device *dsi_pdev_map[MAX_NUM_DSI];
 
 #ifdef DEBUG
 static unsigned int dsi_perf;
 module_param_named(dsi_perf, dsi_perf, bool, 0644);
 #endif
 
-static inline void dsi_write_reg(const struct dsi_reg idx, u32 val)
+static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev)
 {
-       __raw_writel(val, dsi.base + idx.idx);
+       return dev_get_drvdata(&dsidev->dev);
 }
 
-static inline u32 dsi_read_reg(const struct dsi_reg idx)
+static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev)
 {
-       return __raw_readl(dsi.base + idx.idx);
+       return dsi_pdev_map[dssdev->phy.dsi.module];
+}
+
+struct platform_device *dsi_get_dsidev_from_id(int module)
+{
+       return dsi_pdev_map[module];
+}
+
+static int dsi_get_dsidev_id(struct platform_device *dsidev)
+{
+       /* TEMP: Pass 0 as the dsi module index till the time the dsi platform
+        * device names aren't changed to the form "omapdss_dsi.0",
+        * "omapdss_dsi.1" and so on */
+       BUG_ON(dsidev->id != -1);
+
+       return 0;
+}
+
+static inline void dsi_write_reg(struct platform_device *dsidev,
+               const struct dsi_reg idx, u32 val)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       __raw_writel(val, dsi->base + idx.idx);
+}
+
+static inline u32 dsi_read_reg(struct platform_device *dsidev,
+               const struct dsi_reg idx)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return __raw_readl(dsi->base + idx.idx);
 }
 
 
@@ -318,21 +398,29 @@ void dsi_restore_context(void)
 {
 }
 
-void dsi_bus_lock(void)
+void dsi_bus_lock(struct omap_dss_device *dssdev)
 {
-       down(&dsi.bus_lock);
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       down(&dsi->bus_lock);
 }
 EXPORT_SYMBOL(dsi_bus_lock);
 
-void dsi_bus_unlock(void)
+void dsi_bus_unlock(struct omap_dss_device *dssdev)
 {
-       up(&dsi.bus_lock);
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       up(&dsi->bus_lock);
 }
 EXPORT_SYMBOL(dsi_bus_unlock);
 
-static bool dsi_bus_is_locked(void)
+static bool dsi_bus_is_locked(struct platform_device *dsidev)
 {
-       return dsi.bus_lock.count == 0;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return dsi->bus_lock.count == 0;
 }
 
 static void dsi_completion_handler(void *data, u32 mask)
@@ -340,12 +428,12 @@ static void dsi_completion_handler(void *data, u32 mask)
        complete((struct completion *)data);
 }
 
-static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
-               int value)
+static inline int wait_for_bit_change(struct platform_device *dsidev,
+               const struct dsi_reg idx, int bitnum, int value)
 {
        int t = 100000;
 
-       while (REG_GET(idx, bitnum, bitnum) != value) {
+       while (REG_GET(dsidev, idx, bitnum, bitnum) != value) {
                if (--t == 0)
                        return !value;
        }
@@ -354,18 +442,21 @@ static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
 }
 
 #ifdef DEBUG
-static void dsi_perf_mark_setup(void)
+static void dsi_perf_mark_setup(struct platform_device *dsidev)
 {
-       dsi.perf_setup_time = ktime_get();
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       dsi->perf_setup_time = ktime_get();
 }
 
-static void dsi_perf_mark_start(void)
+static void dsi_perf_mark_start(struct platform_device *dsidev)
 {
-       dsi.perf_start_time = ktime_get();
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       dsi->perf_start_time = ktime_get();
 }
 
-static void dsi_perf_show(const char *name)
+static void dsi_perf_show(struct platform_device *dsidev, const char *name)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        ktime_t t, setup_time, trans_time;
        u32 total_bytes;
        u32 setup_us, trans_us, total_us;
@@ -375,21 +466,21 @@ static void dsi_perf_show(const char *name)
 
        t = ktime_get();
 
-       setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time);
+       setup_time = ktime_sub(dsi->perf_start_time, dsi->perf_setup_time);
        setup_us = (u32)ktime_to_us(setup_time);
        if (setup_us == 0)
                setup_us = 1;
 
-       trans_time = ktime_sub(t, dsi.perf_start_time);
+       trans_time = ktime_sub(t, dsi->perf_start_time);
        trans_us = (u32)ktime_to_us(trans_time);
        if (trans_us == 0)
                trans_us = 1;
 
        total_us = setup_us + trans_us;
 
-       total_bytes = dsi.update_region.w *
-               dsi.update_region.h *
-               dsi.update_region.device->ctrl.pixel_size / 8;
+       total_bytes = dsi->update_region.w *
+               dsi->update_region.h *
+               dsi->update_region.device->ctrl.pixel_size / 8;
 
        printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
                        "%u bytes, %u kbytes/sec\n",
@@ -402,9 +493,9 @@ static void dsi_perf_show(const char *name)
                        total_bytes * 1000 / total_us);
 }
 #else
-#define dsi_perf_mark_setup()
-#define dsi_perf_mark_start()
-#define dsi_perf_show(x)
+#define dsi_perf_mark_setup(x)
+#define dsi_perf_mark_start(x)
+#define dsi_perf_show(x, y)
 #endif
 
 static void print_irq_status(u32 status)
@@ -510,38 +601,42 @@ static void print_irq_status_cio(u32 status)
 }
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-static void dsi_collect_irq_stats(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+static void dsi_collect_irq_stats(struct platform_device *dsidev, u32 irqstatus,
+               u32 *vcstatus, u32 ciostatus)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int i;
 
-       spin_lock(&dsi.irq_stats_lock);
+       spin_lock(&dsi->irq_stats_lock);
 
-       dsi.irq_stats.irq_count++;
-       dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
+       dsi->irq_stats.irq_count++;
+       dss_collect_irq_stats(irqstatus, dsi->irq_stats.dsi_irqs);
 
        for (i = 0; i < 4; ++i)
-               dss_collect_irq_stats(vcstatus[i], dsi.irq_stats.vc_irqs[i]);
+               dss_collect_irq_stats(vcstatus[i], dsi->irq_stats.vc_irqs[i]);
 
-       dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
+       dss_collect_irq_stats(ciostatus, dsi->irq_stats.cio_irqs);
 
-       spin_unlock(&dsi.irq_stats_lock);
+       spin_unlock(&dsi->irq_stats_lock);
 }
 #else
-#define dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus)
+#define dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus)
 #endif
 
 static int debug_irq;
 
-static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus)
+static void dsi_handle_irq_errors(struct platform_device *dsidev, u32 irqstatus,
+               u32 *vcstatus, u32 ciostatus)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int i;
 
        if (irqstatus & DSI_IRQ_ERROR_MASK) {
                DSSERR("DSI error, irqstatus %x\n", irqstatus);
                print_irq_status(irqstatus);
-               spin_lock(&dsi.errors_lock);
-               dsi.errors |= irqstatus & DSI_IRQ_ERROR_MASK;
-               spin_unlock(&dsi.errors_lock);
+               spin_lock(&dsi->errors_lock);
+               dsi->errors |= irqstatus & DSI_IRQ_ERROR_MASK;
+               spin_unlock(&dsi->errors_lock);
        } else if (debug_irq) {
                print_irq_status(irqstatus);
        }
@@ -602,22 +697,27 @@ static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables,
 
 static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
 {
+       struct platform_device *dsidev;
+       struct dsi_data *dsi;
        u32 irqstatus, vcstatus[4], ciostatus;
        int i;
 
-       spin_lock(&dsi.irq_lock);
+       dsidev = (struct platform_device *) arg;
+       dsi = dsi_get_dsidrv_data(dsidev);
+
+       spin_lock(&dsi->irq_lock);
 
-       irqstatus = dsi_read_reg(DSI_IRQSTATUS);
+       irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS);
 
        /* IRQ is not for us */
        if (!irqstatus) {
-               spin_unlock(&dsi.irq_lock);
+               spin_unlock(&dsi->irq_lock);
                return IRQ_NONE;
        }
 
-       dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
+       dsi_write_reg(dsidev, DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
        /* flush posted write */
-       dsi_read_reg(DSI_IRQSTATUS);
+       dsi_read_reg(dsidev, DSI_IRQSTATUS);
 
        for (i = 0; i < 4; ++i) {
                if ((irqstatus & (1 << i)) == 0) {
@@ -625,45 +725,47 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg)
                        continue;
                }
 
-               vcstatus[i] = dsi_read_reg(DSI_VC_IRQSTATUS(i));
+               vcstatus[i] = dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
 
-               dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus[i]);
+               dsi_write_reg(dsidev, DSI_VC_IRQSTATUS(i), vcstatus[i]);
                /* flush posted write */
-               dsi_read_reg(DSI_VC_IRQSTATUS(i));
+               dsi_read_reg(dsidev, DSI_VC_IRQSTATUS(i));
        }
 
        if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
-               ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+               ciostatus = dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
 
-               dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
+               dsi_write_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
                /* flush posted write */
-               dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
+               dsi_read_reg(dsidev, DSI_COMPLEXIO_IRQ_STATUS);
        } else {
                ciostatus = 0;
        }
 
 #ifdef DSI_CATCH_MISSING_TE
        if (irqstatus & DSI_IRQ_TE_TRIGGER)
-               del_timer(&dsi.te_timer);
+               del_timer(&dsi->te_timer);
 #endif
 
        /* make a copy and unlock, so that isrs can unregister
         * themselves */
-       memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables));
+       memcpy(&dsi->isr_tables_copy, &dsi->isr_tables,
+               sizeof(dsi->isr_tables));
 
-       spin_unlock(&dsi.irq_lock);
+       spin_unlock(&dsi->irq_lock);
 
-       dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus);
+       dsi_handle_isrs(&dsi->isr_tables_copy, irqstatus, vcstatus, ciostatus);
 
-       dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus);
+       dsi_handle_irq_errors(dsidev, irqstatus, vcstatus, ciostatus);
 
-       dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus);
+       dsi_collect_irq_stats(dsidev, irqstatus, vcstatus, ciostatus);
 
        return IRQ_HANDLED;
 }
 
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array,
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_configure_irqs(struct platform_device *dsidev,
+               struct dsi_isr_data *isr_array,
                unsigned isr_array_size, u32 default_mask,
                const struct dsi_reg enable_reg,
                const struct dsi_reg status_reg)
@@ -684,61 +786,67 @@ static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array,
                mask |= isr_data->mask;
        }
 
-       old_mask = dsi_read_reg(enable_reg);
+       old_mask = dsi_read_reg(dsidev, enable_reg);
        /* clear the irqstatus for newly enabled irqs */
-       dsi_write_reg(status_reg, (mask ^ old_mask) & mask);
-       dsi_write_reg(enable_reg, mask);
+       dsi_write_reg(dsidev, status_reg, (mask ^ old_mask) & mask);
+       dsi_write_reg(dsidev, enable_reg, mask);
 
        /* flush posted writes */
-       dsi_read_reg(enable_reg);
-       dsi_read_reg(status_reg);
+       dsi_read_reg(dsidev, enable_reg);
+       dsi_read_reg(dsidev, status_reg);
 }
 
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_set_irqs(void)
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs(struct platform_device *dsidev)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 mask = DSI_IRQ_ERROR_MASK;
 #ifdef DSI_CATCH_MISSING_TE
        mask |= DSI_IRQ_TE_TRIGGER;
 #endif
-       _omap_dsi_configure_irqs(dsi.isr_tables.isr_table,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table), mask,
+       _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table), mask,
                        DSI_IRQENABLE, DSI_IRQSTATUS);
 }
 
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_set_irqs_vc(int vc)
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_vc(struct platform_device *dsidev, int vc)
 {
-       _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc],
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]),
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_vc[vc],
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_vc[vc]),
                        DSI_VC_IRQ_ERROR_MASK,
                        DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc));
 }
 
-/* dsi.irq_lock has to be locked by the caller */
-static void _omap_dsi_set_irqs_cio(void)
+/* dsi->irq_lock has to be locked by the caller */
+static void _omap_dsi_set_irqs_cio(struct platform_device *dsidev)
 {
-       _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_cio),
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       _omap_dsi_configure_irqs(dsidev, dsi->isr_tables.isr_table_cio,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_cio),
                        DSI_CIO_IRQ_ERROR_MASK,
                        DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS);
 }
 
-static void _dsi_initialize_irq(void)
+static void _dsi_initialize_irq(struct platform_device *dsidev)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int vc;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables));
+       memset(&dsi->isr_tables, 0, sizeof(dsi->isr_tables));
 
-       _omap_dsi_set_irqs();
+       _omap_dsi_set_irqs(dsidev);
        for (vc = 0; vc < 4; ++vc)
-               _omap_dsi_set_irqs_vc(vc);
-       _omap_dsi_set_irqs_cio();
+               _omap_dsi_set_irqs_vc(dsidev, vc);
+       _omap_dsi_set_irqs_cio(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 }
 
 static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
@@ -797,126 +905,137 @@ static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask,
        return -EINVAL;
 }
 
-static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
+static int dsi_register_isr(struct platform_device *dsidev, omap_dsi_isr_t isr,
+               void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table));
+       r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table));
 
        if (r == 0)
-               _omap_dsi_set_irqs();
+               _omap_dsi_set_irqs(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask)
+static int dsi_unregister_isr(struct platform_device *dsidev,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table));
+       r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table));
 
        if (r == 0)
-               _omap_dsi_set_irqs();
+               _omap_dsi_set_irqs(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
-               u32 mask)
+static int dsi_register_isr_vc(struct platform_device *dsidev, int channel,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
        r = _dsi_register_isr(isr, arg, mask,
-                       dsi.isr_tables.isr_table_vc[channel],
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+                       dsi->isr_tables.isr_table_vc[channel],
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
 
        if (r == 0)
-               _omap_dsi_set_irqs_vc(channel);
+               _omap_dsi_set_irqs_vc(dsidev, channel);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg,
-               u32 mask)
+static int dsi_unregister_isr_vc(struct platform_device *dsidev, int channel,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
        r = _dsi_unregister_isr(isr, arg, mask,
-                       dsi.isr_tables.isr_table_vc[channel],
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel]));
+                       dsi->isr_tables.isr_table_vc[channel],
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_vc[channel]));
 
        if (r == 0)
-               _omap_dsi_set_irqs_vc(channel);
+               _omap_dsi_set_irqs_vc(dsidev, channel);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+static int dsi_register_isr_cio(struct platform_device *dsidev,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+       r = _dsi_register_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
 
        if (r == 0)
-               _omap_dsi_set_irqs_cio();
+               _omap_dsi_set_irqs_cio(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask)
+static int dsi_unregister_isr_cio(struct platform_device *dsidev,
+               omap_dsi_isr_t isr, void *arg, u32 mask)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        int r;
 
-       spin_lock_irqsave(&dsi.irq_lock, flags);
+       spin_lock_irqsave(&dsi->irq_lock, flags);
 
-       r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio,
-                       ARRAY_SIZE(dsi.isr_tables.isr_table_cio));
+       r = _dsi_unregister_isr(isr, arg, mask, dsi->isr_tables.isr_table_cio,
+                       ARRAY_SIZE(dsi->isr_tables.isr_table_cio));
 
        if (r == 0)
-               _omap_dsi_set_irqs_cio();
+               _omap_dsi_set_irqs_cio(dsidev);
 
-       spin_unlock_irqrestore(&dsi.irq_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_lock, flags);
 
        return r;
 }
 
-static u32 dsi_get_errors(void)
+static u32 dsi_get_errors(struct platform_device *dsidev)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        u32 e;
-       spin_lock_irqsave(&dsi.errors_lock, flags);
-       e = dsi.errors;
-       dsi.errors = 0;
-       spin_unlock_irqrestore(&dsi.errors_lock, flags);
+       spin_lock_irqsave(&dsi->errors_lock, flags);
+       e = dsi->errors;
+       dsi->errors = 0;
+       spin_unlock_irqrestore(&dsi->errors_lock, flags);
        return e;
 }
 
@@ -930,23 +1049,27 @@ static inline void enable_clocks(bool enable)
 }
 
 /* source clock for DSI PLL. this could also be PCLKFREE */
-static inline void dsi_enable_pll_clock(bool enable)
+static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
+               bool enable)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        if (enable)
                dss_clk_enable(DSS_CLK_SYSCK);
        else
                dss_clk_disable(DSS_CLK_SYSCK);
 
-       if (enable && dsi.pll_locked) {
-               if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
+       if (enable && dsi->pll_locked) {
+               if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
                        DSSERR("cannot lock PLL when enabling clocks\n");
        }
 }
 
 #ifdef DEBUG
-static void _dsi_print_reset_status(void)
+static void _dsi_print_reset_status(struct platform_device *dsidev)
 {
        u32 l;
+       int b0, b1, b2;
 
        if (!dss_debug)
                return;
@@ -954,35 +1077,47 @@ static void _dsi_print_reset_status(void)
        /* A dummy read using the SCP interface to any DSIPHY register is
         * required after DSIPHY reset to complete the reset of the DSI complex
         * I/O. */
-       l = dsi_read_reg(DSI_DSIPHY_CFG5);
+       l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
 
        printk(KERN_DEBUG "DSI resets: ");
 
-       l = dsi_read_reg(DSI_PLL_STATUS);
+       l = dsi_read_reg(dsidev, DSI_PLL_STATUS);
        printk("PLL (%d) ", FLD_GET(l, 0, 0));
 
-       l = dsi_read_reg(DSI_COMPLEXIO_CFG1);
+       l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
        printk("CIO (%d) ", FLD_GET(l, 29, 29));
 
-       l = dsi_read_reg(DSI_DSIPHY_CFG5);
-       printk("PHY (%x, %d, %d, %d)\n",
-                       FLD_GET(l, 28, 26),
+       if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
+               b0 = 28;
+               b1 = 27;
+               b2 = 26;
+       } else {
+               b0 = 24;
+               b1 = 25;
+               b2 = 26;
+       }
+
+       l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
+       printk("PHY (%x%x%x, %d, %d, %d)\n",
+                       FLD_GET(l, b0, b0),
+                       FLD_GET(l, b1, b1),
+                       FLD_GET(l, b2, b2),
                        FLD_GET(l, 29, 29),
                        FLD_GET(l, 30, 30),
                        FLD_GET(l, 31, 31));
 }
 #else
-#define _dsi_print_reset_status()
+#define _dsi_print_reset_status(x)
 #endif
 
-static inline int dsi_if_enable(bool enable)
+static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
 {
        DSSDBG("dsi_if_enable(%d)\n", enable);
 
        enable = enable ? 1 : 0;
-       REG_FLD_MOD(DSI_CTRL, enable, 0, 0); /* IF_EN */
+       REG_FLD_MOD(dsidev, DSI_CTRL, enable, 0, 0); /* IF_EN */
 
-       if (wait_for_bit_change(DSI_CTRL, 0, enable) != enable) {
+       if (wait_for_bit_change(dsidev, DSI_CTRL, 0, enable) != enable) {
                        DSSERR("Failed to set dsi_if_enable to %d\n", enable);
                        return -EIO;
        }
@@ -990,31 +1125,38 @@ static inline int dsi_if_enable(bool enable)
        return 0;
 }
 
-unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
+unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
 {
-       return dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk;
 }
 
-static unsigned long dsi_get_pll_hsdiv_dsi_rate(void)
+static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
 {
-       return dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk;
 }
 
-static unsigned long dsi_get_txbyteclkhs(void)
+static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
 {
-       return dsi.current_cinfo.clkin4ddr / 16;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       return dsi->current_cinfo.clkin4ddr / 16;
 }
 
-static unsigned long dsi_fclk_rate(void)
+static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
 {
        unsigned long r;
+       int dsi_module = dsi_get_dsidev_id(dsidev);
 
-       if (dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK) {
+       if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) {
                /* DSI FCLK source is DSS_CLK_FCK */
                r = dss_clk_get_rate(DSS_CLK_FCK);
        } else {
                /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */
-               r = dsi_get_pll_hsdiv_dsi_rate();
+               r = dsi_get_pll_hsdiv_dsi_rate(dsidev);
        }
 
        return r;
@@ -1022,31 +1164,50 @@ static unsigned long dsi_fclk_rate(void)
 
 static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long dsi_fclk;
        unsigned lp_clk_div;
        unsigned long lp_clk;
 
-       lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
+       lp_clk_div = dssdev->clocks.dsi.lp_clk_div;
 
-       if (lp_clk_div == 0 || lp_clk_div > dsi.lpdiv_max)
+       if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
                return -EINVAL;
 
-       dsi_fclk = dsi_fclk_rate();
+       dsi_fclk = dsi_fclk_rate(dsidev);
 
        lp_clk = dsi_fclk / 2 / lp_clk_div;
 
        DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
-       dsi.current_cinfo.lp_clk = lp_clk;
-       dsi.current_cinfo.lp_clk_div = lp_clk_div;
+       dsi->current_cinfo.lp_clk = lp_clk;
+       dsi->current_cinfo.lp_clk_div = lp_clk_div;
 
-       REG_FLD_MOD(DSI_CLK_CTRL, lp_clk_div, 12, 0);   /* LP_CLK_DIVISOR */
+       /* LP_CLK_DIVISOR */
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
 
-       REG_FLD_MOD(DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0,
-                       21, 21);                /* LP_RX_SYNCHRO_ENABLE */
+       /* LP_RX_SYNCHRO_ENABLE */
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0, 21, 21);
 
        return 0;
 }
 
+static void dsi_enable_scp_clk(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->scp_clk_refcount++ == 0)
+               REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 14, 14); /* CIO_CLK_ICG */
+}
+
+static void dsi_disable_scp_clk(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       WARN_ON(dsi->scp_clk_refcount == 0);
+       if (--dsi->scp_clk_refcount == 0)
+               REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 14, 14); /* CIO_CLK_ICG */
+}
 
 enum dsi_pll_power_state {
        DSI_PLL_POWER_OFF       = 0x0,
@@ -1055,14 +1216,21 @@ enum dsi_pll_power_state {
        DSI_PLL_POWER_ON_DIV    = 0x3,
 };
 
-static int dsi_pll_power(enum dsi_pll_power_state state)
+static int dsi_pll_power(struct platform_device *dsidev,
+               enum dsi_pll_power_state state)
 {
        int t = 0;
 
-       REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30);       /* PLL_PWR_CMD */
+       /* DSI-PLL power command 0x3 is not working */
+       if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
+                       state == DSI_PLL_POWER_ON_DIV)
+               state = DSI_PLL_POWER_ON_ALL;
+
+       /* PLL_PWR_CMD */
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, state, 31, 30);
 
        /* PLL_PWR_STATUS */
-       while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) {
+       while (FLD_GET(dsi_read_reg(dsidev, DSI_CLK_CTRL), 29, 28) != state) {
                if (++t > 1000) {
                        DSSERR("Failed to set DSI PLL power mode to %d\n",
                                        state);
@@ -1078,16 +1246,19 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
 static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
                struct dsi_clock_info *cinfo)
 {
-       if (cinfo->regn == 0 || cinfo->regn > dsi.regn_max)
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max)
                return -EINVAL;
 
-       if (cinfo->regm == 0 || cinfo->regm > dsi.regm_max)
+       if (cinfo->regm == 0 || cinfo->regm > dsi->regm_max)
                return -EINVAL;
 
-       if (cinfo->regm_dispc > dsi.regm_dispc_max)
+       if (cinfo->regm_dispc > dsi->regm_dispc_max)
                return -EINVAL;
 
-       if (cinfo->regm_dsi > dsi.regm_dsi_max)
+       if (cinfo->regm_dsi > dsi->regm_dsi_max)
                return -EINVAL;
 
        if (cinfo->use_sys_clk) {
@@ -1106,7 +1277,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
 
        cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
 
-       if (cinfo->fint > dsi.fint_max || cinfo->fint < dsi.fint_min)
+       if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min)
                return -EINVAL;
 
        cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
@@ -1129,10 +1300,11 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev,
        return 0;
 }
 
-int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
-               struct dsi_clock_info *dsi_cinfo,
+int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
+               unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,
                struct dispc_clock_info *dispc_cinfo)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        struct dsi_clock_info cur, best;
        struct dispc_clock_info best_dispc;
        int min_fck_per_pck;
@@ -1143,10 +1315,10 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
 
        max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 
-       if (req_pck == dsi.cache_req_pck &&
-                       dsi.cache_cinfo.clkin == dss_sys_clk) {
+       if (req_pck == dsi->cache_req_pck &&
+                       dsi->cache_cinfo.clkin == dss_sys_clk) {
                DSSDBG("DSI clock info found from cache\n");
-               *dsi_cinfo = dsi.cache_cinfo;
+               *dsi_cinfo = dsi->cache_cinfo;
                dispc_find_clk_divs(is_tft, req_pck,
                        dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo);
                return 0;
@@ -1176,17 +1348,17 @@ retry:
        /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
        /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
        /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
-       for (cur.regn = 1; cur.regn < dsi.regn_max; ++cur.regn) {
+       for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
                if (cur.highfreq == 0)
                        cur.fint = cur.clkin / cur.regn;
                else
                        cur.fint = cur.clkin / (2 * cur.regn);
 
-               if (cur.fint > dsi.fint_max || cur.fint < dsi.fint_min)
+               if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
                        continue;
 
                /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
-               for (cur.regm = 1; cur.regm < dsi.regm_max; ++cur.regm) {
+               for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) {
                        unsigned long a, b;
 
                        a = 2 * cur.regm * (cur.clkin/1000);
@@ -1198,8 +1370,8 @@ retry:
 
                        /* dsi_pll_hsdiv_dispc_clk(MHz) =
                         * DSIPHY(MHz) / regm_dispc  < 173MHz/186Mhz */
-                       for (cur.regm_dispc = 1; cur.regm_dispc < dsi.regm_dispc_max;
-                                       ++cur.regm_dispc) {
+                       for (cur.regm_dispc = 1; cur.regm_dispc <
+                                       dsi->regm_dispc_max; ++cur.regm_dispc) {
                                struct dispc_clock_info cur_dispc;
                                cur.dsi_pll_hsdiv_dispc_clk =
                                        cur.clkin4ddr / cur.regm_dispc;
@@ -1259,34 +1431,39 @@ found:
        if (dispc_cinfo)
                *dispc_cinfo = best_dispc;
 
-       dsi.cache_req_pck = req_pck;
-       dsi.cache_clk_freq = 0;
-       dsi.cache_cinfo = best;
+       dsi->cache_req_pck = req_pck;
+       dsi->cache_clk_freq = 0;
+       dsi->cache_cinfo = best;
 
        return 0;
 }
 
-int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
+int dsi_pll_set_clock_div(struct platform_device *dsidev,
+               struct dsi_clock_info *cinfo)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r = 0;
        u32 l;
-       int f;
+       int f = 0;
        u8 regn_start, regn_end, regm_start, regm_end;
        u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
 
        DSSDBGF();
 
-       dsi.current_cinfo.fint = cinfo->fint;
-       dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
-       dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk =
+       dsi->current_cinfo.use_sys_clk = cinfo->use_sys_clk;
+       dsi->current_cinfo.highfreq = cinfo->highfreq;
+
+       dsi->current_cinfo.fint = cinfo->fint;
+       dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
+       dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk =
                        cinfo->dsi_pll_hsdiv_dispc_clk;
-       dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk =
+       dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk =
                        cinfo->dsi_pll_hsdiv_dsi_clk;
 
-       dsi.current_cinfo.regn = cinfo->regn;
-       dsi.current_cinfo.regm = cinfo->regm;
-       dsi.current_cinfo.regm_dispc = cinfo->regm_dispc;
-       dsi.current_cinfo.regm_dsi = cinfo->regm_dsi;
+       dsi->current_cinfo.regn = cinfo->regn;
+       dsi->current_cinfo.regm = cinfo->regm;
+       dsi->current_cinfo.regm_dispc = cinfo->regm_dispc;
+       dsi->current_cinfo.regm_dsi = cinfo->regm_dsi;
 
        DSSDBG("DSI Fint %ld\n", cinfo->fint);
 
@@ -1309,12 +1486,12 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
 
        DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
-               dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
-               dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+               dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+               dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
                cinfo->dsi_pll_hsdiv_dispc_clk);
        DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
-               dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
-               dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+               dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+               dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
                cinfo->dsi_pll_hsdiv_dsi_clk);
 
        dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
@@ -1324,9 +1501,10 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
                        &regm_dsi_end);
 
-       REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
+       /* DSI_PLL_AUTOMODE = manual */
+       REG_FLD_MOD(dsidev, DSI_PLL_CONTROL, 0, 0, 0);
 
-       l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
+       l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION1);
        l = FLD_MOD(l, 1, 0, 0);                /* DSI_PLL_STOPMODE */
        /* DSI_PLL_REGN */
        l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
@@ -1338,22 +1516,22 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        /* DSIPROTO_CLOCK_DIV */
        l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
                        regm_dsi_start, regm_dsi_end);
-       dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
-
-       BUG_ON(cinfo->fint < dsi.fint_min || cinfo->fint > dsi.fint_max);
-       if (cinfo->fint < 1000000)
-               f = 0x3;
-       else if (cinfo->fint < 1250000)
-               f = 0x4;
-       else if (cinfo->fint < 1500000)
-               f = 0x5;
-       else if (cinfo->fint < 1750000)
-               f = 0x6;
-       else
-               f = 0x7;
+       dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION1, l);
+
+       BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
+
+       if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
+               f = cinfo->fint < 1000000 ? 0x3 :
+                       cinfo->fint < 1250000 ? 0x4 :
+                       cinfo->fint < 1500000 ? 0x5 :
+                       cinfo->fint < 1750000 ? 0x6 :
+                       0x7;
+       }
+
+       l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
 
-       l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
-       l = FLD_MOD(l, f, 4, 1);                /* DSI_PLL_FREQSEL */
+       if (dss_has_feature(FEAT_DSI_PLL_FREQSEL))
+               l = FLD_MOD(l, f, 4, 1);        /* DSI_PLL_FREQSEL */
        l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1,
                        11, 11);                /* DSI_PLL_CLKSEL */
        l = FLD_MOD(l, cinfo->highfreq,
@@ -1361,25 +1539,25 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        l = FLD_MOD(l, 1, 13, 13);              /* DSI_PLL_REFEN */
        l = FLD_MOD(l, 0, 14, 14);              /* DSIPHY_CLKINEN */
        l = FLD_MOD(l, 1, 20, 20);              /* DSI_HSDIVBYPASS */
-       dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
+       dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
 
-       REG_FLD_MOD(DSI_PLL_GO, 1, 0, 0);       /* DSI_PLL_GO */
+       REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0);       /* DSI_PLL_GO */
 
-       if (wait_for_bit_change(DSI_PLL_GO, 0, 0) != 0) {
+       if (wait_for_bit_change(dsidev, DSI_PLL_GO, 0, 0) != 0) {
                DSSERR("dsi pll go bit not going down.\n");
                r = -EIO;
                goto err;
        }
 
-       if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) {
+       if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) {
                DSSERR("cannot lock PLL\n");
                r = -EIO;
                goto err;
        }
 
-       dsi.pll_locked = 1;
+       dsi->pll_locked = 1;
 
-       l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
+       l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
        l = FLD_MOD(l, 0, 0, 0);        /* DSI_PLL_IDLE */
        l = FLD_MOD(l, 0, 5, 5);        /* DSI_PLL_PLLLPMODE */
        l = FLD_MOD(l, 0, 6, 6);        /* DSI_PLL_LOWCURRSTBY */
@@ -1394,52 +1572,53 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
        l = FLD_MOD(l, 1, 18, 18);      /* DSI_PROTO_CLOCK_EN */
        l = FLD_MOD(l, 0, 19, 19);      /* DSI_PROTO_CLOCK_PWDN */
        l = FLD_MOD(l, 0, 20, 20);      /* DSI_HSDIVBYPASS */
-       dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
+       dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
 
        DSSDBG("PLL config done\n");
 err:
        return r;
 }
 
-int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
+int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
                bool enable_hsdiv)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r = 0;
        enum dsi_pll_power_state pwstate;
 
        DSSDBG("PLL init\n");
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
-       /*
-        * HACK: this is just a quick hack to get the USE_DSI_PLL
-        * option working. USE_DSI_PLL is itself a big hack, and
-        * should be removed.
-        */
-       if (dsi.vdds_dsi_reg == NULL) {
+       if (dsi->vdds_dsi_reg == NULL) {
                struct regulator *vdds_dsi;
 
-               vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+               vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
 
                if (IS_ERR(vdds_dsi)) {
                        DSSERR("can't get VDDS_DSI regulator\n");
                        return PTR_ERR(vdds_dsi);
                }
 
-               dsi.vdds_dsi_reg = vdds_dsi;
+               dsi->vdds_dsi_reg = vdds_dsi;
        }
-#endif
 
        enable_clocks(1);
-       dsi_enable_pll_clock(1);
+       dsi_enable_pll_clock(dsidev, 1);
+       /*
+        * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
+        */
+       dsi_enable_scp_clk(dsidev);
 
-       r = regulator_enable(dsi.vdds_dsi_reg);
-       if (r)
-               goto err0;
+       if (!dsi->vdds_dsi_enabled) {
+               r = regulator_enable(dsi->vdds_dsi_reg);
+               if (r)
+                       goto err0;
+               dsi->vdds_dsi_enabled = true;
+       }
 
        /* XXX PLL does not come out of reset without this... */
        dispc_pck_free_enable(1);
 
-       if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
+       if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 0, 1) != 1) {
                DSSERR("PLL not coming out of reset.\n");
                r = -ENODEV;
                dispc_pck_free_enable(0);
@@ -1459,7 +1638,7 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
        else
                pwstate = DSI_PLL_POWER_OFF;
 
-       r = dsi_pll_power(pwstate);
+       r = dsi_pll_power(dsidev, pwstate);
 
        if (r)
                goto err1;
@@ -1468,42 +1647,53 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
 
        return 0;
 err1:
-       regulator_disable(dsi.vdds_dsi_reg);
+       if (dsi->vdds_dsi_enabled) {
+               regulator_disable(dsi->vdds_dsi_reg);
+               dsi->vdds_dsi_enabled = false;
+       }
 err0:
+       dsi_disable_scp_clk(dsidev);
        enable_clocks(0);
-       dsi_enable_pll_clock(0);
+       dsi_enable_pll_clock(dsidev, 0);
        return r;
 }
 
-void dsi_pll_uninit(void)
+void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi->pll_locked = 0;
+       dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
+       if (disconnect_lanes) {
+               WARN_ON(!dsi->vdds_dsi_enabled);
+               regulator_disable(dsi->vdds_dsi_reg);
+               dsi->vdds_dsi_enabled = false;
+       }
+
+       dsi_disable_scp_clk(dsidev);
        enable_clocks(0);
-       dsi_enable_pll_clock(0);
+       dsi_enable_pll_clock(dsidev, 0);
 
-       dsi.pll_locked = 0;
-       dsi_pll_power(DSI_PLL_POWER_OFF);
-       regulator_disable(dsi.vdds_dsi_reg);
        DSSDBG("PLL uninit done\n");
 }
 
-void dsi_dump_clocks(struct seq_file *s)
+static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
+               struct seq_file *s)
 {
-       int clksel;
-       struct dsi_clock_info *cinfo = &dsi.current_cinfo;
-       enum dss_clk_source dispc_clk_src, dsi_clk_src;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       struct dsi_clock_info *cinfo = &dsi->current_cinfo;
+       enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
+       int dsi_module = dsi_get_dsidev_id(dsidev);
 
        dispc_clk_src = dss_get_dispc_clk_source();
-       dsi_clk_src = dss_get_dsi_clk_source();
+       dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
 
        enable_clocks(1);
 
-       clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
-
-       seq_printf(s,   "- DSI PLL -\n");
+       seq_printf(s,   "- DSI%d PLL -\n", dsi_module + 1);
 
        seq_printf(s,   "dsi pll source = %s\n",
-                       clksel == 0 ?
-                       "dss_sys_clk" : "pclkfree");
+                       cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree");
 
        seq_printf(s,   "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
 
@@ -1515,7 +1705,7 @@ void dsi_dump_clocks(struct seq_file *s)
                        dss_feat_get_clk_source_name(dispc_clk_src),
                        cinfo->dsi_pll_hsdiv_dispc_clk,
                        cinfo->regm_dispc,
-                       dispc_clk_src == DSS_CLK_SRC_FCK ?
+                       dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
                        "off" : "on");
 
        seq_printf(s,   "%s (%s)\t%-16luregm_dsi %u\t(%s)\n",
@@ -1523,45 +1713,55 @@ void dsi_dump_clocks(struct seq_file *s)
                        dss_feat_get_clk_source_name(dsi_clk_src),
                        cinfo->dsi_pll_hsdiv_dsi_clk,
                        cinfo->regm_dsi,
-                       dsi_clk_src == DSS_CLK_SRC_FCK ?
+                       dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
                        "off" : "on");
 
-       seq_printf(s,   "- DSI -\n");
+       seq_printf(s,   "- DSI%d -\n", dsi_module + 1);
 
        seq_printf(s,   "dsi fclk source = %s (%s)\n",
                        dss_get_generic_clk_source_name(dsi_clk_src),
                        dss_feat_get_clk_source_name(dsi_clk_src));
 
-       seq_printf(s,   "DSI_FCLK\t%lu\n", dsi_fclk_rate());
+       seq_printf(s,   "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
 
        seq_printf(s,   "DDR_CLK\t\t%lu\n",
                        cinfo->clkin4ddr / 4);
 
-       seq_printf(s,   "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs());
+       seq_printf(s,   "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
 
        seq_printf(s,   "LP_CLK\t\t%lu\n", cinfo->lp_clk);
 
-       seq_printf(s,   "VP_CLK\t\t%lu\n"
-                       "VP_PCLK\t\t%lu\n",
-                       dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD),
-                       dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD));
-
        enable_clocks(0);
 }
 
+void dsi_dump_clocks(struct seq_file *s)
+{
+       struct platform_device *dsidev;
+       int i;
+
+       for  (i = 0; i < MAX_NUM_DSI; i++) {
+               dsidev = dsi_get_dsidev_from_id(i);
+               if (dsidev)
+                       dsi_dump_dsidev_clocks(dsidev, s);
+       }
+}
+
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-void dsi_dump_irqs(struct seq_file *s)
+static void dsi_dump_dsidev_irqs(struct platform_device *dsidev,
+               struct seq_file *s)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned long flags;
        struct dsi_irq_stats stats;
+       int dsi_module = dsi_get_dsidev_id(dsidev);
 
-       spin_lock_irqsave(&dsi.irq_stats_lock, flags);
+       spin_lock_irqsave(&dsi->irq_stats_lock, flags);
 
-       stats = dsi.irq_stats;
-       memset(&dsi.irq_stats, 0, sizeof(dsi.irq_stats));
-       dsi.irq_stats.last_reset = jiffies;
+       stats = dsi->irq_stats;
+       memset(&dsi->irq_stats, 0, sizeof(dsi->irq_stats));
+       dsi->irq_stats.last_reset = jiffies;
 
-       spin_unlock_irqrestore(&dsi.irq_stats_lock, flags);
+       spin_unlock_irqrestore(&dsi->irq_stats_lock, flags);
 
        seq_printf(s, "period %u ms\n",
                        jiffies_to_msecs(jiffies - stats.last_reset));
@@ -1570,7 +1770,7 @@ void dsi_dump_irqs(struct seq_file *s)
 #define PIS(x) \
        seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
 
-       seq_printf(s, "-- DSI interrupts --\n");
+       seq_printf(s, "-- DSI%d interrupts --\n", dsi_module + 1);
        PIS(VC0);
        PIS(VC1);
        PIS(VC2);
@@ -1636,13 +1836,45 @@ void dsi_dump_irqs(struct seq_file *s)
        PIS(ULPSACTIVENOT_ALL1);
 #undef PIS
 }
+
+static void dsi1_dump_irqs(struct seq_file *s)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
+
+       dsi_dump_dsidev_irqs(dsidev, s);
+}
+
+static void dsi2_dump_irqs(struct seq_file *s)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
+
+       dsi_dump_dsidev_irqs(dsidev, s);
+}
+
+void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
+               const struct file_operations *debug_fops)
+{
+       struct platform_device *dsidev;
+
+       dsidev = dsi_get_dsidev_from_id(0);
+       if (dsidev)
+               debugfs_create_file("dsi1_irqs", S_IRUGO, debugfs_dir,
+                       &dsi1_dump_irqs, debug_fops);
+
+       dsidev = dsi_get_dsidev_from_id(1);
+       if (dsidev)
+               debugfs_create_file("dsi2_irqs", S_IRUGO, debugfs_dir,
+                       &dsi2_dump_irqs, debug_fops);
+}
 #endif
 
-void dsi_dump_regs(struct seq_file *s)
+static void dsi_dump_dsidev_regs(struct platform_device *dsidev,
+               struct seq_file *s)
 {
-#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
+#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(dsidev, r))
 
        dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
+       dsi_enable_scp_clk(dsidev);
 
        DUMPREG(DSI_REVISION);
        DUMPREG(DSI_SYSCONFIG);
@@ -1714,25 +1946,57 @@ void dsi_dump_regs(struct seq_file *s)
        DUMPREG(DSI_PLL_CONFIGURATION1);
        DUMPREG(DSI_PLL_CONFIGURATION2);
 
+       dsi_disable_scp_clk(dsidev);
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 #undef DUMPREG
 }
 
-enum dsi_complexio_power_state {
+static void dsi1_dump_regs(struct seq_file *s)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_id(0);
+
+       dsi_dump_dsidev_regs(dsidev, s);
+}
+
+static void dsi2_dump_regs(struct seq_file *s)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_id(1);
+
+       dsi_dump_dsidev_regs(dsidev, s);
+}
+
+void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
+               const struct file_operations *debug_fops)
+{
+       struct platform_device *dsidev;
+
+       dsidev = dsi_get_dsidev_from_id(0);
+       if (dsidev)
+               debugfs_create_file("dsi1_regs", S_IRUGO, debugfs_dir,
+                       &dsi1_dump_regs, debug_fops);
+
+       dsidev = dsi_get_dsidev_from_id(1);
+       if (dsidev)
+               debugfs_create_file("dsi2_regs", S_IRUGO, debugfs_dir,
+                       &dsi2_dump_regs, debug_fops);
+}
+enum dsi_cio_power_state {
        DSI_COMPLEXIO_POWER_OFF         = 0x0,
        DSI_COMPLEXIO_POWER_ON          = 0x1,
        DSI_COMPLEXIO_POWER_ULPS        = 0x2,
 };
 
-static int dsi_complexio_power(enum dsi_complexio_power_state state)
+static int dsi_cio_power(struct platform_device *dsidev,
+               enum dsi_cio_power_state state)
 {
        int t = 0;
 
        /* PWR_CMD */
-       REG_FLD_MOD(DSI_COMPLEXIO_CFG1, state, 28, 27);
+       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG1, state, 28, 27);
 
        /* PWR_STATUS */
-       while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) {
+       while (FLD_GET(dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1),
+                       26, 25) != state) {
                if (++t > 1000) {
                        DSSERR("failed to set complexio power state to "
                                        "%d\n", state);
@@ -1744,9 +2008,70 @@ static int dsi_complexio_power(enum dsi_complexio_power_state state)
        return 0;
 }
 
-static void dsi_complexio_config(struct omap_dss_device *dssdev)
+/* Number of data lanes present on DSI interface */
+static inline int dsi_get_num_data_lanes(struct platform_device *dsidev)
 {
+       /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
+        * of data lanes as 2 by default */
+       if (dss_has_feature(FEAT_DSI_GNQ))
+               return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */
+       else
+               return 2;
+}
+
+/* Number of data lanes used by the dss device */
+static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev)
+{
+       int num_data_lanes = 0;
+
+       if (dssdev->phy.dsi.data1_lane != 0)
+               num_data_lanes++;
+       if (dssdev->phy.dsi.data2_lane != 0)
+               num_data_lanes++;
+       if (dssdev->phy.dsi.data3_lane != 0)
+               num_data_lanes++;
+       if (dssdev->phy.dsi.data4_lane != 0)
+               num_data_lanes++;
+
+       return num_data_lanes;
+}
+
+static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
+{
+       int val;
+
+       /* line buffer on OMAP3 is 1024 x 24bits */
+       /* XXX: for some reason using full buffer size causes
+        * considerable TX slowdown with update sizes that fill the
+        * whole buffer */
+       if (!dss_has_feature(FEAT_DSI_GNQ))
+               return 1023 * 3;
+
+       val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */
+
+       switch (val) {
+       case 1:
+               return 512 * 3;         /* 512x24 bits */
+       case 2:
+               return 682 * 3;         /* 682x24 bits */
+       case 3:
+               return 853 * 3;         /* 853x24 bits */
+       case 4:
+               return 1024 * 3;        /* 1024x24 bits */
+       case 5:
+               return 1194 * 3;        /* 1194x24 bits */
+       case 6:
+               return 1365 * 3;        /* 1365x24 bits */
+       default:
+               BUG();
+       }
+}
+
+static void dsi_set_lane_config(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        u32 r;
+       int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev);
 
        int clk_lane   = dssdev->phy.dsi.clk_lane;
        int data1_lane = dssdev->phy.dsi.data1_lane;
@@ -1755,14 +2080,28 @@ static void dsi_complexio_config(struct omap_dss_device *dssdev)
        int data1_pol  = dssdev->phy.dsi.data1_pol;
        int data2_pol  = dssdev->phy.dsi.data2_pol;
 
-       r = dsi_read_reg(DSI_COMPLEXIO_CFG1);
+       r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1);
        r = FLD_MOD(r, clk_lane, 2, 0);
        r = FLD_MOD(r, clk_pol, 3, 3);
        r = FLD_MOD(r, data1_lane, 6, 4);
        r = FLD_MOD(r, data1_pol, 7, 7);
        r = FLD_MOD(r, data2_lane, 10, 8);
        r = FLD_MOD(r, data2_pol, 11, 11);
-       dsi_write_reg(DSI_COMPLEXIO_CFG1, r);
+       if (num_data_lanes_dssdev > 2) {
+               int data3_lane  = dssdev->phy.dsi.data3_lane;
+               int data3_pol  = dssdev->phy.dsi.data3_pol;
+
+               r = FLD_MOD(r, data3_lane, 14, 12);
+               r = FLD_MOD(r, data3_pol, 15, 15);
+       }
+       if (num_data_lanes_dssdev > 3) {
+               int data4_lane  = dssdev->phy.dsi.data4_lane;
+               int data4_pol  = dssdev->phy.dsi.data4_pol;
+
+               r = FLD_MOD(r, data4_lane, 18, 16);
+               r = FLD_MOD(r, data4_pol, 19, 19);
+       }
+       dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
 
        /* The configuration of the DSI complex I/O (number of data lanes,
           position, differential order) should not be changed while
@@ -1776,27 +2115,31 @@ static void dsi_complexio_config(struct omap_dss_device *dssdev)
           DSI complex I/O configuration is unknown. */
 
        /*
-       REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
-       REG_FLD_MOD(DSI_CTRL, 0, 0, 0);
-       REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20);
-       REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20);
+       REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0);
        */
 }
 
-static inline unsigned ns2ddr(unsigned ns)
+static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        /* convert time in ns to ddr ticks, rounding up */
-       unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
+       unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
        return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
 }
 
-static inline unsigned ddr2ns(unsigned ddr)
+static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
 {
-       unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
        return ddr * 1000 * 1000 / (ddr_clk / 1000);
 }
 
-static void dsi_complexio_timings(void)
+static void dsi_cio_timings(struct platform_device *dsidev)
 {
        u32 r;
        u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
@@ -1808,139 +2151,323 @@ static void dsi_complexio_timings(void)
        /* 1 * DDR_CLK = 2 * UI */
 
        /* min 40ns + 4*UI      max 85ns + 6*UI */
-       ths_prepare = ns2ddr(70) + 2;
+       ths_prepare = ns2ddr(dsidev, 70) + 2;
 
        /* min 145ns + 10*UI */
-       ths_prepare_ths_zero = ns2ddr(175) + 2;
+       ths_prepare_ths_zero = ns2ddr(dsidev, 175) + 2;
 
        /* min max(8*UI, 60ns+4*UI) */
-       ths_trail = ns2ddr(60) + 5;
+       ths_trail = ns2ddr(dsidev, 60) + 5;
 
        /* min 100ns */
-       ths_exit = ns2ddr(145);
+       ths_exit = ns2ddr(dsidev, 145);
 
        /* tlpx min 50n */
-       tlpx_half = ns2ddr(25);
+       tlpx_half = ns2ddr(dsidev, 25);
 
        /* min 60ns */
-       tclk_trail = ns2ddr(60) + 2;
+       tclk_trail = ns2ddr(dsidev, 60) + 2;
 
        /* min 38ns, max 95ns */
-       tclk_prepare = ns2ddr(65);
+       tclk_prepare = ns2ddr(dsidev, 65);
 
        /* min tclk-prepare + tclk-zero = 300ns */
-       tclk_zero = ns2ddr(260);
+       tclk_zero = ns2ddr(dsidev, 260);
 
        DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
-               ths_prepare, ddr2ns(ths_prepare),
-               ths_prepare_ths_zero, ddr2ns(ths_prepare_ths_zero));
+               ths_prepare, ddr2ns(dsidev, ths_prepare),
+               ths_prepare_ths_zero, ddr2ns(dsidev, ths_prepare_ths_zero));
        DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
-                       ths_trail, ddr2ns(ths_trail),
-                       ths_exit, ddr2ns(ths_exit));
+                       ths_trail, ddr2ns(dsidev, ths_trail),
+                       ths_exit, ddr2ns(dsidev, ths_exit));
 
        DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
                        "tclk_zero %u (%uns)\n",
-                       tlpx_half, ddr2ns(tlpx_half),
-                       tclk_trail, ddr2ns(tclk_trail),
-                       tclk_zero, ddr2ns(tclk_zero));
+                       tlpx_half, ddr2ns(dsidev, tlpx_half),
+                       tclk_trail, ddr2ns(dsidev, tclk_trail),
+                       tclk_zero, ddr2ns(dsidev, tclk_zero));
        DSSDBG("tclk_prepare %u (%uns)\n",
-                       tclk_prepare, ddr2ns(tclk_prepare));
+                       tclk_prepare, ddr2ns(dsidev, tclk_prepare));
 
        /* program timings */
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG0);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
        r = FLD_MOD(r, ths_prepare, 31, 24);
        r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
        r = FLD_MOD(r, ths_trail, 15, 8);
        r = FLD_MOD(r, ths_exit, 7, 0);
-       dsi_write_reg(DSI_DSIPHY_CFG0, r);
+       dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r);
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG1);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
        r = FLD_MOD(r, tlpx_half, 22, 16);
        r = FLD_MOD(r, tclk_trail, 15, 8);
        r = FLD_MOD(r, tclk_zero, 7, 0);
-       dsi_write_reg(DSI_DSIPHY_CFG1, r);
+       dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r);
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG2);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
        r = FLD_MOD(r, tclk_prepare, 7, 0);
-       dsi_write_reg(DSI_DSIPHY_CFG2, r);
+       dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r);
 }
 
+static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
+               enum dsi_lane lanes)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int clk_lane   = dssdev->phy.dsi.clk_lane;
+       int data1_lane = dssdev->phy.dsi.data1_lane;
+       int data2_lane = dssdev->phy.dsi.data2_lane;
+       int data3_lane = dssdev->phy.dsi.data3_lane;
+       int data4_lane = dssdev->phy.dsi.data4_lane;
+       int clk_pol    = dssdev->phy.dsi.clk_pol;
+       int data1_pol  = dssdev->phy.dsi.data1_pol;
+       int data2_pol  = dssdev->phy.dsi.data2_pol;
+       int data3_pol  = dssdev->phy.dsi.data3_pol;
+       int data4_pol  = dssdev->phy.dsi.data4_pol;
+
+       u32 l = 0;
+       u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26;
+
+       if (lanes & DSI_CLK_P)
+               l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1));
+       if (lanes & DSI_CLK_N)
+               l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0));
+
+       if (lanes & DSI_DATA1_P)
+               l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1));
+       if (lanes & DSI_DATA1_N)
+               l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0));
+
+       if (lanes & DSI_DATA2_P)
+               l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1));
+       if (lanes & DSI_DATA2_N)
+               l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0));
+
+       if (lanes & DSI_DATA3_P)
+               l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1));
+       if (lanes & DSI_DATA3_N)
+               l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0));
+
+       if (lanes & DSI_DATA4_P)
+               l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1));
+       if (lanes & DSI_DATA4_N)
+               l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0));
+       /*
+        * Bits in REGLPTXSCPDAT4TO0DXDY:
+        * 17: DY0 18: DX0
+        * 19: DY1 20: DX1
+        * 21: DY2 22: DX2
+        * 23: DY3 24: DX3
+        * 25: DY4 26: DX4
+        */
+
+       /* Set the lane override configuration */
+
+       /* REGLPTXSCPDAT4TO0DXDY */
+       REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17);
 
-static int dsi_complexio_init(struct omap_dss_device *dssdev)
+       /* Enable lane override */
+
+       /* ENLPTXSCPDAT */
+       REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 1, 27, 27);
+}
+
+static void dsi_cio_disable_lane_override(struct platform_device *dsidev)
 {
-       int r = 0;
+       /* Disable lane override */
+       REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 27, 27); /* ENLPTXSCPDAT */
+       /* Reset the lane override configuration */
+       /* REGLPTXSCPDAT4TO0DXDY */
+       REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17);
+}
+
+static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       int t;
+       int bits[3];
+       bool in_use[3];
+
+       if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) {
+               bits[0] = 28;
+               bits[1] = 27;
+               bits[2] = 26;
+       } else {
+               bits[0] = 24;
+               bits[1] = 25;
+               bits[2] = 26;
+       }
+
+       in_use[0] = false;
+       in_use[1] = false;
+       in_use[2] = false;
+
+       if (dssdev->phy.dsi.clk_lane != 0)
+               in_use[dssdev->phy.dsi.clk_lane - 1] = true;
+       if (dssdev->phy.dsi.data1_lane != 0)
+               in_use[dssdev->phy.dsi.data1_lane - 1] = true;
+       if (dssdev->phy.dsi.data2_lane != 0)
+               in_use[dssdev->phy.dsi.data2_lane - 1] = true;
+
+       t = 100000;
+       while (true) {
+               u32 l;
+               int i;
+               int ok;
+
+               l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
+
+               ok = 0;
+               for (i = 0; i < 3; ++i) {
+                       if (!in_use[i] || (l & (1 << bits[i])))
+                               ok++;
+               }
+
+               if (ok == 3)
+                       break;
+
+               if (--t == 0) {
+                       for (i = 0; i < 3; ++i) {
+                               if (!in_use[i] || (l & (1 << bits[i])))
+                                       continue;
+
+                               DSSERR("CIO TXCLKESC%d domain not coming " \
+                                               "out of reset\n", i);
+                       }
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+static int dsi_cio_init(struct omap_dss_device *dssdev)
+{
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int r;
+       int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev);
+       u32 l;
 
-       DSSDBG("dsi_complexio_init\n");
+       DSSDBGF();
 
-       /* CIO_CLK_ICG, enable L3 clk to CIO */
-       REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
+       if (dsi->dsi_mux_pads)
+               dsi->dsi_mux_pads(true);
+
+       dsi_enable_scp_clk(dsidev);
 
        /* A dummy read using the SCP interface to any DSIPHY register is
         * required after DSIPHY reset to complete the reset of the DSI complex
         * I/O. */
-       dsi_read_reg(DSI_DSIPHY_CFG5);
+       dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
 
-       if (wait_for_bit_change(DSI_DSIPHY_CFG5, 30, 1) != 1) {
-               DSSERR("ComplexIO PHY not coming out of reset.\n");
-               r = -ENODEV;
-               goto err;
+       if (wait_for_bit_change(dsidev, DSI_DSIPHY_CFG5, 30, 1) != 1) {
+               DSSERR("CIO SCP Clock domain not coming out of reset.\n");
+               r = -EIO;
+               goto err_scp_clk_dom;
        }
 
-       dsi_complexio_config(dssdev);
+       dsi_set_lane_config(dssdev);
+
+       /* set TX STOP MODE timer to maximum for this operation */
+       l = dsi_read_reg(dsidev, DSI_TIMING1);
+       l = FLD_MOD(l, 1, 15, 15);      /* FORCE_TX_STOP_MODE_IO */
+       l = FLD_MOD(l, 1, 14, 14);      /* STOP_STATE_X16_IO */
+       l = FLD_MOD(l, 1, 13, 13);      /* STOP_STATE_X4_IO */
+       l = FLD_MOD(l, 0x1fff, 12, 0);  /* STOP_STATE_COUNTER_IO */
+       dsi_write_reg(dsidev, DSI_TIMING1, l);
 
-       r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
+       if (dsi->ulps_enabled) {
+               u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P;
 
+               DSSDBG("manual ulps exit\n");
+
+               /* ULPS is exited by Mark-1 state for 1ms, followed by
+                * stop state. DSS HW cannot do this via the normal
+                * ULPS exit sequence, as after reset the DSS HW thinks
+                * that we are not in ULPS mode, and refuses to send the
+                * sequence. So we need to send the ULPS exit sequence
+                * manually.
+                */
+
+               if (num_data_lanes_dssdev > 2)
+                       lane_mask |= DSI_DATA3_P;
+
+               if (num_data_lanes_dssdev > 3)
+                       lane_mask |= DSI_DATA4_P;
+
+               dsi_cio_enable_lane_override(dssdev, lane_mask);
+       }
+
+       r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
        if (r)
-               goto err;
+               goto err_cio_pwr;
 
-       if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
-               DSSERR("ComplexIO not coming out of reset.\n");
+       if (wait_for_bit_change(dsidev, DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
+               DSSERR("CIO PWR clock domain not coming out of reset.\n");
                r = -ENODEV;
-               goto err;
+               goto err_cio_pwr_dom;
        }
 
-       if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
-               DSSERR("ComplexIO LDO power down.\n");
-               r = -ENODEV;
-               goto err;
+       dsi_if_enable(dsidev, true);
+       dsi_if_enable(dsidev, false);
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
+
+       r = dsi_cio_wait_tx_clk_esc_reset(dssdev);
+       if (r)
+               goto err_tx_clk_esc_rst;
+
+       if (dsi->ulps_enabled) {
+               /* Keep Mark-1 state for 1ms (as per DSI spec) */
+               ktime_t wait = ns_to_ktime(1000 * 1000);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
+
+               /* Disable the override. The lanes should be set to Mark-11
+                * state by the HW */
+               dsi_cio_disable_lane_override(dsidev);
        }
 
-       dsi_complexio_timings();
+       /* FORCE_TX_STOP_MODE_IO */
+       REG_FLD_MOD(dsidev, DSI_TIMING1, 0, 15, 15);
 
-       /*
-          The configuration of the DSI complex I/O (number of data lanes,
-          position, differential order) should not be changed while
-          DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. For the
-          hardware to recognize a new configuration of the complex I/O (done
-          in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to follow
-          this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, next
-          reset the DSS.DSI_CTRL[0] IF_EN to 0, then set DSS.DSI_CLK_CTRL[20]
-          LP_CLK_ENABLE to 1, and finally, set again the DSS.DSI_CTRL[0] IF_EN
-          bit to 1. If the sequence is not followed, the DSi complex I/O
-          configuration is undetermined.
-          */
-       dsi_if_enable(1);
-       dsi_if_enable(0);
-       REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
-       dsi_if_enable(1);
-       dsi_if_enable(0);
+       dsi_cio_timings(dsidev);
+
+       dsi->ulps_enabled = false;
 
        DSSDBG("CIO init done\n");
-err:
+
+       return 0;
+
+err_tx_clk_esc_rst:
+       REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 20, 20); /* LP_CLK_ENABLE */
+err_cio_pwr_dom:
+       dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
+err_cio_pwr:
+       if (dsi->ulps_enabled)
+               dsi_cio_disable_lane_override(dsidev);
+err_scp_clk_dom:
+       dsi_disable_scp_clk(dsidev);
+       if (dsi->dsi_mux_pads)
+               dsi->dsi_mux_pads(false);
        return r;
 }
 
-static void dsi_complexio_uninit(void)
+static void dsi_cio_uninit(struct platform_device *dsidev)
 {
-       dsi_complexio_power(DSI_COMPLEXIO_POWER_OFF);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
+       dsi_disable_scp_clk(dsidev);
+       if (dsi->dsi_mux_pads)
+               dsi->dsi_mux_pads(false);
 }
 
-static int _dsi_wait_reset(void)
+static int _dsi_wait_reset(struct platform_device *dsidev)
 {
        int t = 0;
 
-       while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) {
+       while (REG_GET(dsidev, DSI_SYSSTATUS, 0, 0) == 0) {
                if (++t > 5) {
                        DSSERR("soft reset failed\n");
                        return -ENODEV;
@@ -1951,28 +2478,30 @@ static int _dsi_wait_reset(void)
        return 0;
 }
 
-static int _dsi_reset(void)
+static int _dsi_reset(struct platform_device *dsidev)
 {
        /* Soft reset */
-       REG_FLD_MOD(DSI_SYSCONFIG, 1, 1, 1);
-       return _dsi_wait_reset();
+       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 1, 1);
+       return _dsi_wait_reset(dsidev);
 }
 
-static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
+static void dsi_config_tx_fifo(struct platform_device *dsidev,
+               enum fifo_size size1, enum fifo_size size2,
                enum fifo_size size3, enum fifo_size size4)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 r = 0;
        int add = 0;
        int i;
 
-       dsi.vc[0].fifo_size = size1;
-       dsi.vc[1].fifo_size = size2;
-       dsi.vc[2].fifo_size = size3;
-       dsi.vc[3].fifo_size = size4;
+       dsi->vc[0].fifo_size = size1;
+       dsi->vc[1].fifo_size = size2;
+       dsi->vc[2].fifo_size = size3;
+       dsi->vc[3].fifo_size = size4;
 
        for (i = 0; i < 4; i++) {
                u8 v;
-               int size = dsi.vc[i].fifo_size;
+               int size = dsi->vc[i].fifo_size;
 
                if (add + size > 4) {
                        DSSERR("Illegal FIFO configuration\n");
@@ -1985,24 +2514,26 @@ static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
                add += size;
        }
 
-       dsi_write_reg(DSI_TX_FIFO_VC_SIZE, r);
+       dsi_write_reg(dsidev, DSI_TX_FIFO_VC_SIZE, r);
 }
 
-static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
+static void dsi_config_rx_fifo(struct platform_device *dsidev,
+               enum fifo_size size1, enum fifo_size size2,
                enum fifo_size size3, enum fifo_size size4)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 r = 0;
        int add = 0;
        int i;
 
-       dsi.vc[0].fifo_size = size1;
-       dsi.vc[1].fifo_size = size2;
-       dsi.vc[2].fifo_size = size3;
-       dsi.vc[3].fifo_size = size4;
+       dsi->vc[0].fifo_size = size1;
+       dsi->vc[1].fifo_size = size2;
+       dsi->vc[2].fifo_size = size3;
+       dsi->vc[3].fifo_size = size4;
 
        for (i = 0; i < 4; i++) {
                u8 v;
-               int size = dsi.vc[i].fifo_size;
+               int size = dsi->vc[i].fifo_size;
 
                if (add + size > 4) {
                        DSSERR("Illegal FIFO configuration\n");
@@ -2015,18 +2546,18 @@ static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
                add += size;
        }
 
-       dsi_write_reg(DSI_RX_FIFO_VC_SIZE, r);
+       dsi_write_reg(dsidev, DSI_RX_FIFO_VC_SIZE, r);
 }
 
-static int dsi_force_tx_stop_mode_io(void)
+static int dsi_force_tx_stop_mode_io(struct platform_device *dsidev)
 {
        u32 r;
 
-       r = dsi_read_reg(DSI_TIMING1);
+       r = dsi_read_reg(dsidev, DSI_TIMING1);
        r = FLD_MOD(r, 1, 15, 15);      /* FORCE_TX_STOP_MODE_IO */
-       dsi_write_reg(DSI_TIMING1, r);
+       dsi_write_reg(dsidev, DSI_TIMING1, r);
 
-       if (wait_for_bit_change(DSI_TIMING1, 15, 0) != 0) {
+       if (wait_for_bit_change(dsidev, DSI_TIMING1, 15, 0) != 0) {
                DSSERR("TX_STOP bit not going down\n");
                return -EIO;
        }
@@ -2034,16 +2565,135 @@ static int dsi_force_tx_stop_mode_io(void)
        return 0;
 }
 
-static int dsi_vc_enable(int channel, bool enable)
+static bool dsi_vc_is_enabled(struct platform_device *dsidev, int channel)
+{
+       return REG_GET(dsidev, DSI_VC_CTRL(channel), 0, 0);
+}
+
+static void dsi_packet_sent_handler_vp(void *data, u32 mask)
+{
+       struct dsi_packet_sent_handler_data *vp_data =
+               (struct dsi_packet_sent_handler_data *) data;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(vp_data->dsidev);
+       const int channel = dsi->update_channel;
+       u8 bit = dsi->te_enabled ? 30 : 31;
+
+       if (REG_GET(vp_data->dsidev, DSI_VC_TE(channel), bit, bit) == 0)
+               complete(vp_data->completion);
+}
+
+static int dsi_sync_vc_vp(struct platform_device *dsidev, int channel)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       DECLARE_COMPLETION_ONSTACK(completion);
+       struct dsi_packet_sent_handler_data vp_data = { dsidev, &completion };
+       int r = 0;
+       u8 bit;
+
+       bit = dsi->te_enabled ? 30 : 31;
+
+       r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
+               &vp_data, DSI_VC_IRQ_PACKET_SENT);
+       if (r)
+               goto err0;
+
+       /* Wait for completion only if TE_EN/TE_START is still set */
+       if (REG_GET(dsidev, DSI_VC_TE(channel), bit, bit)) {
+               if (wait_for_completion_timeout(&completion,
+                               msecs_to_jiffies(10)) == 0) {
+                       DSSERR("Failed to complete previous frame transfer\n");
+                       r = -EIO;
+                       goto err1;
+               }
+       }
+
+       dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
+               &vp_data, DSI_VC_IRQ_PACKET_SENT);
+
+       return 0;
+err1:
+       dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_vp,
+               &vp_data, DSI_VC_IRQ_PACKET_SENT);
+err0:
+       return r;
+}
+
+static void dsi_packet_sent_handler_l4(void *data, u32 mask)
+{
+       struct dsi_packet_sent_handler_data *l4_data =
+               (struct dsi_packet_sent_handler_data *) data;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(l4_data->dsidev);
+       const int channel = dsi->update_channel;
+
+       if (REG_GET(l4_data->dsidev, DSI_VC_CTRL(channel), 5, 5) == 0)
+               complete(l4_data->completion);
+}
+
+static int dsi_sync_vc_l4(struct platform_device *dsidev, int channel)
+{
+       DECLARE_COMPLETION_ONSTACK(completion);
+       struct dsi_packet_sent_handler_data l4_data = { dsidev, &completion };
+       int r = 0;
+
+       r = dsi_register_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
+               &l4_data, DSI_VC_IRQ_PACKET_SENT);
+       if (r)
+               goto err0;
+
+       /* Wait for completion only if TX_FIFO_NOT_EMPTY is still set */
+       if (REG_GET(dsidev, DSI_VC_CTRL(channel), 5, 5)) {
+               if (wait_for_completion_timeout(&completion,
+                               msecs_to_jiffies(10)) == 0) {
+                       DSSERR("Failed to complete previous l4 transfer\n");
+                       r = -EIO;
+                       goto err1;
+               }
+       }
+
+       dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
+               &l4_data, DSI_VC_IRQ_PACKET_SENT);
+
+       return 0;
+err1:
+       dsi_unregister_isr_vc(dsidev, channel, dsi_packet_sent_handler_l4,
+               &l4_data, DSI_VC_IRQ_PACKET_SENT);
+err0:
+       return r;
+}
+
+static int dsi_sync_vc(struct platform_device *dsidev, int channel)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       WARN_ON(!dsi_bus_is_locked(dsidev));
+
+       WARN_ON(in_interrupt());
+
+       if (!dsi_vc_is_enabled(dsidev, channel))
+               return 0;
+
+       switch (dsi->vc[channel].mode) {
+       case DSI_VC_MODE_VP:
+               return dsi_sync_vc_vp(dsidev, channel);
+       case DSI_VC_MODE_L4:
+               return dsi_sync_vc_l4(dsidev, channel);
+       default:
+               BUG();
+       }
+}
+
+static int dsi_vc_enable(struct platform_device *dsidev, int channel,
+               bool enable)
 {
        DSSDBG("dsi_vc_enable channel %d, enable %d\n",
                        channel, enable);
 
        enable = enable ? 1 : 0;
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 0, 0);
 
-       if (wait_for_bit_change(DSI_VC_CTRL(channel), 0, enable) != enable) {
+       if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel),
+               0, enable) != enable) {
                        DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
                        return -EIO;
        }
@@ -2051,13 +2701,13 @@ static int dsi_vc_enable(int channel, bool enable)
        return 0;
 }
 
-static void dsi_vc_initial_config(int channel)
+static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
 {
        u32 r;
 
        DSSDBGF("%d", channel);
 
-       r = dsi_read_reg(DSI_VC_CTRL(channel));
+       r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel));
 
        if (FLD_GET(r, 15, 15)) /* VC_BUSY */
                DSSERR("VC(%d) busy when trying to configure it!\n",
@@ -2070,85 +2720,107 @@ static void dsi_vc_initial_config(int channel)
        r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
        r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
        r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
+       if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH))
+               r = FLD_MOD(r, 3, 11, 10);      /* OCP_WIDTH = 32 bit */
 
        r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
        r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
 
-       dsi_write_reg(DSI_VC_CTRL(channel), r);
+       dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
 }
 
-static int dsi_vc_config_l4(int channel)
+static int dsi_vc_config_l4(struct platform_device *dsidev, int channel)
 {
-       if (dsi.vc[channel].mode == DSI_VC_MODE_L4)
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->vc[channel].mode == DSI_VC_MODE_L4)
                return 0;
 
        DSSDBGF("%d", channel);
 
-       dsi_vc_enable(channel, 0);
+       dsi_sync_vc(dsidev, channel);
+
+       dsi_vc_enable(dsidev, channel, 0);
 
        /* VC_BUSY */
-       if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) {
+       if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
                DSSERR("vc(%d) busy when trying to config for L4\n", channel);
                return -EIO;
        }
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
+
+       /* DCS_CMD_ENABLE */
+       if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
+               REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 30, 30);
 
-       dsi_vc_enable(channel, 1);
+       dsi_vc_enable(dsidev, channel, 1);
 
-       dsi.vc[channel].mode = DSI_VC_MODE_L4;
+       dsi->vc[channel].mode = DSI_VC_MODE_L4;
 
        return 0;
 }
 
-static int dsi_vc_config_vp(int channel)
+static int dsi_vc_config_vp(struct platform_device *dsidev, int channel)
 {
-       if (dsi.vc[channel].mode == DSI_VC_MODE_VP)
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->vc[channel].mode == DSI_VC_MODE_VP)
                return 0;
 
        DSSDBGF("%d", channel);
 
-       dsi_vc_enable(channel, 0);
+       dsi_sync_vc(dsidev, channel);
+
+       dsi_vc_enable(dsidev, channel, 0);
 
        /* VC_BUSY */
-       if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) {
+       if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) {
                DSSERR("vc(%d) busy when trying to config for VP\n", channel);
                return -EIO;
        }
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
+       /* SOURCE, 1 = video port */
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 1, 1);
+
+       /* DCS_CMD_ENABLE */
+       if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC))
+               REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 30, 30);
 
-       dsi_vc_enable(channel, 1);
+       dsi_vc_enable(dsidev, channel, 1);
 
-       dsi.vc[channel].mode = DSI_VC_MODE_VP;
+       dsi->vc[channel].mode = DSI_VC_MODE_VP;
 
        return 0;
 }
 
 
-void omapdss_dsi_vc_enable_hs(int channel, bool enable)
+void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
+               bool enable)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
        DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       dsi_vc_enable(channel, 0);
-       dsi_if_enable(0);
+       dsi_vc_enable(dsidev, channel, 0);
+       dsi_if_enable(dsidev, 0);
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 9, 9);
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 9, 9);
 
-       dsi_vc_enable(channel, 1);
-       dsi_if_enable(1);
+       dsi_vc_enable(dsidev, channel, 1);
+       dsi_if_enable(dsidev, 1);
 
-       dsi_force_tx_stop_mode_io();
+       dsi_force_tx_stop_mode_io(dsidev);
 }
 EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs);
 
-static void dsi_vc_flush_long_data(int channel)
+static void dsi_vc_flush_long_data(struct platform_device *dsidev, int channel)
 {
-       while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
+       while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
                u32 val;
-               val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
+               val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
                DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
                                (val >> 0) & 0xff,
                                (val >> 8) & 0xff,
@@ -2194,13 +2866,14 @@ static void dsi_show_rx_ack_with_err(u16 err)
                DSSERR("\t\tDSI Protocol Violation\n");
 }
 
-static u16 dsi_vc_flush_receive_data(int channel)
+static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev,
+               int channel)
 {
        /* RX_FIFO_NOT_EMPTY */
-       while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
+       while (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
                u32 val;
                u8 dt;
-               val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
+               val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
                DSSERR("\trawval %#08x\n", val);
                dt = FLD_GET(val, 5, 0);
                if (dt == DSI_DT_RX_ACK_WITH_ERR) {
@@ -2215,7 +2888,7 @@ static u16 dsi_vc_flush_receive_data(int channel)
                } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
                        DSSERR("\tDCS long response, len %d\n",
                                        FLD_GET(val, 23, 8));
-                       dsi_vc_flush_long_data(channel);
+                       dsi_vc_flush_long_data(dsidev, channel);
                } else {
                        DSSERR("\tunknown datatype 0x%02x\n", dt);
                }
@@ -2223,40 +2896,44 @@ static u16 dsi_vc_flush_receive_data(int channel)
        return 0;
 }
 
-static int dsi_vc_send_bta(int channel)
+static int dsi_vc_send_bta(struct platform_device *dsidev, int channel)
 {
-       if (dsi.debug_write || dsi.debug_read)
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->debug_write || dsi->debug_read)
                DSSDBG("dsi_vc_send_bta %d\n", channel);
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {    /* RX_FIFO_NOT_EMPTY */
+       /* RX_FIFO_NOT_EMPTY */
+       if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
                DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
-               dsi_vc_flush_receive_data(channel);
+               dsi_vc_flush_receive_data(dsidev, channel);
        }
 
-       REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
+       REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
 
        return 0;
 }
 
-int dsi_vc_send_bta_sync(int channel)
+int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        DECLARE_COMPLETION_ONSTACK(completion);
        int r = 0;
        u32 err;
 
-       r = dsi_register_isr_vc(channel, dsi_completion_handler,
+       r = dsi_register_isr_vc(dsidev, channel, dsi_completion_handler,
                        &completion, DSI_VC_IRQ_BTA);
        if (r)
                goto err0;
 
-       r = dsi_register_isr(dsi_completion_handler, &completion,
+       r = dsi_register_isr(dsidev, dsi_completion_handler, &completion,
                        DSI_IRQ_ERROR_MASK);
        if (r)
                goto err1;
 
-       r = dsi_vc_send_bta(channel);
+       r = dsi_vc_send_bta(dsidev, channel);
        if (r)
                goto err2;
 
@@ -2267,41 +2944,42 @@ int dsi_vc_send_bta_sync(int channel)
                goto err2;
        }
 
-       err = dsi_get_errors();
+       err = dsi_get_errors(dsidev);
        if (err) {
                DSSERR("Error while sending BTA: %x\n", err);
                r = -EIO;
                goto err2;
        }
 err2:
-       dsi_unregister_isr(dsi_completion_handler, &completion,
+       dsi_unregister_isr(dsidev, dsi_completion_handler, &completion,
                        DSI_IRQ_ERROR_MASK);
 err1:
-       dsi_unregister_isr_vc(channel, dsi_completion_handler,
+       dsi_unregister_isr_vc(dsidev, channel, dsi_completion_handler,
                        &completion, DSI_VC_IRQ_BTA);
 err0:
        return r;
 }
 EXPORT_SYMBOL(dsi_vc_send_bta_sync);
 
-static inline void dsi_vc_write_long_header(int channel, u8 data_type,
-               u16 len, u8 ecc)
+static inline void dsi_vc_write_long_header(struct platform_device *dsidev,
+               int channel, u8 data_type, u16 len, u8 ecc)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 val;
        u8 data_id;
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       data_id = data_type | dsi.vc[channel].vc_id << 6;
+       data_id = data_type | dsi->vc[channel].vc_id << 6;
 
        val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
                FLD_VAL(ecc, 31, 24);
 
-       dsi_write_reg(DSI_VC_LONG_PACKET_HEADER(channel), val);
+       dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_HEADER(channel), val);
 }
 
-static inline void dsi_vc_write_long_payload(int channel,
-               u8 b1, u8 b2, u8 b3, u8 b4)
+static inline void dsi_vc_write_long_payload(struct platform_device *dsidev,
+               int channel, u8 b1, u8 b2, u8 b3, u8 b4)
 {
        u32 val;
 
@@ -2310,34 +2988,35 @@ static inline void dsi_vc_write_long_payload(int channel,
 /*     DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
                        b1, b2, b3, b4, val); */
 
-       dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
+       dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
 }
 
-static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
-               u8 ecc)
+static int dsi_vc_send_long(struct platform_device *dsidev, int channel,
+               u8 data_type, u8 *data, u16 len, u8 ecc)
 {
        /*u32 val; */
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int i;
        u8 *p;
        int r = 0;
        u8 b1, b2, b3, b4;
 
-       if (dsi.debug_write)
+       if (dsi->debug_write)
                DSSDBG("dsi_vc_send_long, %d bytes\n", len);
 
        /* len + header */
-       if (dsi.vc[channel].fifo_size * 32 * 4 < len + 4) {
+       if (dsi->vc[channel].fifo_size * 32 * 4 < len + 4) {
                DSSERR("unable to send long packet: packet too long.\n");
                return -EINVAL;
        }
 
-       dsi_vc_config_l4(channel);
+       dsi_vc_config_l4(dsidev, channel);
 
-       dsi_vc_write_long_header(channel, data_type, len, ecc);
+       dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc);
 
        p = data;
        for (i = 0; i < len >> 2; i++) {
-               if (dsi.debug_write)
+               if (dsi->debug_write)
                        DSSDBG("\tsending full packet %d\n", i);
 
                b1 = *p++;
@@ -2345,14 +3024,14 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
                b3 = *p++;
                b4 = *p++;
 
-               dsi_vc_write_long_payload(channel, b1, b2, b3, b4);
+               dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, b4);
        }
 
        i = len % 4;
        if (i) {
                b1 = 0; b2 = 0; b3 = 0;
 
-               if (dsi.debug_write)
+               if (dsi->debug_write)
                        DSSDBG("\tsending remainder bytes %d\n", i);
 
                switch (i) {
@@ -2370,62 +3049,69 @@ static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
                        break;
                }
 
-               dsi_vc_write_long_payload(channel, b1, b2, b3, 0);
+               dsi_vc_write_long_payload(dsidev, channel, b1, b2, b3, 0);
        }
 
        return r;
 }
 
-static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
+static int dsi_vc_send_short(struct platform_device *dsidev, int channel,
+               u8 data_type, u16 data, u8 ecc)
 {
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 r;
        u8 data_id;
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       if (dsi.debug_write)
+       if (dsi->debug_write)
                DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
                                channel,
                                data_type, data & 0xff, (data >> 8) & 0xff);
 
-       dsi_vc_config_l4(channel);
+       dsi_vc_config_l4(dsidev, channel);
 
-       if (FLD_GET(dsi_read_reg(DSI_VC_CTRL(channel)), 16, 16)) {
+       if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) {
                DSSERR("ERROR FIFO FULL, aborting transfer\n");
                return -EINVAL;
        }
 
-       data_id = data_type | dsi.vc[channel].vc_id << 6;
+       data_id = data_type | dsi->vc[channel].vc_id << 6;
 
        r = (data_id << 0) | (data << 8) | (ecc << 24);
 
-       dsi_write_reg(DSI_VC_SHORT_PACKET_HEADER(channel), r);
+       dsi_write_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel), r);
 
        return 0;
 }
 
-int dsi_vc_send_null(int channel)
+int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        u8 nullpkg[] = {0, 0, 0, 0};
-       return dsi_vc_send_long(channel, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
+
+       return dsi_vc_send_long(dsidev, channel, DSI_DT_NULL_PACKET, nullpkg,
+               4, 0);
 }
 EXPORT_SYMBOL(dsi_vc_send_null);
 
-int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
+int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
+               u8 *data, int len)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
        BUG_ON(len == 0);
 
        if (len == 1) {
-               r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_0,
+               r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_0,
                                data[0], 0);
        } else if (len == 2) {
-               r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_1,
+               r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_1,
                                data[0] | (data[1] << 8), 0);
        } else {
                /* 0x39 = DCS Long Write */
-               r = dsi_vc_send_long(channel, DSI_DT_DCS_LONG_WRITE,
+               r = dsi_vc_send_long(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
                                data, len, 0);
        }
 
@@ -2433,21 +3119,24 @@ int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
 
-int dsi_vc_dcs_write(int channel, u8 *data, int len)
+int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+               int len)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        int r;
 
-       r = dsi_vc_dcs_write_nosync(channel, data, len);
+       r = dsi_vc_dcs_write_nosync(dssdev, channel, data, len);
        if (r)
                goto err;
 
-       r = dsi_vc_send_bta_sync(channel);
+       r = dsi_vc_send_bta_sync(dssdev, channel);
        if (r)
                goto err;
 
-       if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {    /* RX_FIFO_NOT_EMPTY */
+       /* RX_FIFO_NOT_EMPTY */
+       if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20)) {
                DSSERR("rx fifo not empty after write, dumping data:\n");
-               dsi_vc_flush_receive_data(channel);
+               dsi_vc_flush_receive_data(dsidev, channel);
                r = -EIO;
                goto err;
        }
@@ -2460,47 +3149,51 @@ err:
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write);
 
-int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd)
+int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd)
 {
-       return dsi_vc_dcs_write(channel, &dcs_cmd, 1);
+       return dsi_vc_dcs_write(dssdev, channel, &dcs_cmd, 1);
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write_0);
 
-int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param)
+int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 param)
 {
        u8 buf[2];
        buf[0] = dcs_cmd;
        buf[1] = param;
-       return dsi_vc_dcs_write(channel, buf, 2);
+       return dsi_vc_dcs_write(dssdev, channel, buf, 2);
 }
 EXPORT_SYMBOL(dsi_vc_dcs_write_1);
 
-int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
+int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *buf, int buflen)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        u32 val;
        u8 dt;
        int r;
 
-       if (dsi.debug_read)
+       if (dsi->debug_read)
                DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd);
 
-       r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
+       r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_READ, dcs_cmd, 0);
        if (r)
                goto err;
 
-       r = dsi_vc_send_bta_sync(channel);
+       r = dsi_vc_send_bta_sync(dssdev, channel);
        if (r)
                goto err;
 
        /* RX_FIFO_NOT_EMPTY */
-       if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) {
+       if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) {
                DSSERR("RX fifo empty when trying to read.\n");
                r = -EIO;
                goto err;
        }
 
-       val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
-       if (dsi.debug_read)
+       val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel));
+       if (dsi->debug_read)
                DSSDBG("\theader: %08x\n", val);
        dt = FLD_GET(val, 5, 0);
        if (dt == DSI_DT_RX_ACK_WITH_ERR) {
@@ -2511,7 +3204,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
 
        } else if (dt == DSI_DT_RX_SHORT_READ_1) {
                u8 data = FLD_GET(val, 15, 8);
-               if (dsi.debug_read)
+               if (dsi->debug_read)
                        DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
 
                if (buflen < 1) {
@@ -2524,7 +3217,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
                return 1;
        } else if (dt == DSI_DT_RX_SHORT_READ_2) {
                u16 data = FLD_GET(val, 23, 8);
-               if (dsi.debug_read)
+               if (dsi->debug_read)
                        DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
 
                if (buflen < 2) {
@@ -2539,7 +3232,7 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
        } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
                int w;
                int len = FLD_GET(val, 23, 8);
-               if (dsi.debug_read)
+               if (dsi->debug_read)
                        DSSDBG("\tDCS long response, len %d\n", len);
 
                if (len > buflen) {
@@ -2550,8 +3243,9 @@ int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
                /* two byte checksum ends the packet, not included in len */
                for (w = 0; w < len + 2;) {
                        int b;
-                       val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
-                       if (dsi.debug_read)
+                       val = dsi_read_reg(dsidev,
+                               DSI_VC_SHORT_PACKET_HEADER(channel));
+                       if (dsi->debug_read)
                                DSSDBG("\t\t%02x %02x %02x %02x\n",
                                                (val >> 0) & 0xff,
                                                (val >> 8) & 0xff,
@@ -2582,11 +3276,12 @@ err:
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read);
 
-int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
+int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *data)
 {
        int r;
 
-       r = dsi_vc_dcs_read(channel, dcs_cmd, data, 1);
+       r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, data, 1);
 
        if (r < 0)
                return r;
@@ -2598,12 +3293,13 @@ int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read_1);
 
-int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2)
+int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *data1, u8 *data2)
 {
        u8 buf[2];
        int r;
 
-       r = dsi_vc_dcs_read(channel, dcs_cmd, buf, 2);
+       r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, buf, 2);
 
        if (r < 0)
                return r;
@@ -2618,14 +3314,94 @@ int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2)
 }
 EXPORT_SYMBOL(dsi_vc_dcs_read_2);
 
-int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
+int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
+               u16 len)
 {
-       return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+
+       return dsi_vc_send_short(dsidev, channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
                        len, 0);
 }
 EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
 
-static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
+static int dsi_enter_ulps(struct platform_device *dsidev)
+{
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       DECLARE_COMPLETION_ONSTACK(completion);
+       int r;
+
+       DSSDBGF();
+
+       WARN_ON(!dsi_bus_is_locked(dsidev));
+
+       WARN_ON(dsi->ulps_enabled);
+
+       if (dsi->ulps_enabled)
+               return 0;
+
+       if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) {
+               DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n");
+               return -EIO;
+       }
+
+       dsi_sync_vc(dsidev, 0);
+       dsi_sync_vc(dsidev, 1);
+       dsi_sync_vc(dsidev, 2);
+       dsi_sync_vc(dsidev, 3);
+
+       dsi_force_tx_stop_mode_io(dsidev);
+
+       dsi_vc_enable(dsidev, 0, false);
+       dsi_vc_enable(dsidev, 1, false);
+       dsi_vc_enable(dsidev, 2, false);
+       dsi_vc_enable(dsidev, 3, false);
+
+       if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 16, 16)) {      /* HS_BUSY */
+               DSSERR("HS busy when enabling ULPS\n");
+               return -EIO;
+       }
+
+       if (REG_GET(dsidev, DSI_COMPLEXIO_CFG2, 17, 17)) {      /* LP_BUSY */
+               DSSERR("LP busy when enabling ULPS\n");
+               return -EIO;
+       }
+
+       r = dsi_register_isr_cio(dsidev, dsi_completion_handler, &completion,
+                       DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
+       if (r)
+               return r;
+
+       /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */
+       /* LANEx_ULPS_SIG2 */
+       REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2),
+               7, 5);
+
+       if (wait_for_completion_timeout(&completion,
+                               msecs_to_jiffies(1000)) == 0) {
+               DSSERR("ULPS enable timeout\n");
+               r = -EIO;
+               goto err;
+       }
+
+       dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
+                       DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
+
+       dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS);
+
+       dsi_if_enable(dsidev, false);
+
+       dsi->ulps_enabled = true;
+
+       return 0;
+
+err:
+       dsi_unregister_isr_cio(dsidev, dsi_completion_handler, &completion,
+                       DSI_CIO_IRQ_ULPSACTIVENOT_ALL0);
+       return r;
+}
+
+static void dsi_set_lp_rx_timeout(struct platform_device *dsidev,
+               unsigned ticks, bool x4, bool x16)
 {
        unsigned long fck;
        unsigned long total_ticks;
@@ -2634,14 +3410,14 @@ static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
        BUG_ON(ticks > 0x1fff);
 
        /* ticks in DSI_FCK */
-       fck = dsi_fclk_rate();
+       fck = dsi_fclk_rate(dsidev);
 
-       r = dsi_read_reg(DSI_TIMING2);
+       r = dsi_read_reg(dsidev, DSI_TIMING2);
        r = FLD_MOD(r, 1, 15, 15);      /* LP_RX_TO */
        r = FLD_MOD(r, x16 ? 1 : 0, 14, 14);    /* LP_RX_TO_X16 */
        r = FLD_MOD(r, x4 ? 1 : 0, 13, 13);     /* LP_RX_TO_X4 */
        r = FLD_MOD(r, ticks, 12, 0);   /* LP_RX_COUNTER */
-       dsi_write_reg(DSI_TIMING2, r);
+       dsi_write_reg(dsidev, DSI_TIMING2, r);
 
        total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
 
@@ -2651,7 +3427,8 @@ static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
                        (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16)
+static void dsi_set_ta_timeout(struct platform_device *dsidev, unsigned ticks,
+               bool x8, bool x16)
 {
        unsigned long fck;
        unsigned long total_ticks;
@@ -2660,14 +3437,14 @@ static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16)
        BUG_ON(ticks > 0x1fff);
 
        /* ticks in DSI_FCK */
-       fck = dsi_fclk_rate();
+       fck = dsi_fclk_rate(dsidev);
 
-       r = dsi_read_reg(DSI_TIMING1);
+       r = dsi_read_reg(dsidev, DSI_TIMING1);
        r = FLD_MOD(r, 1, 31, 31);      /* TA_TO */
        r = FLD_MOD(r, x16 ? 1 : 0, 30, 30);    /* TA_TO_X16 */
        r = FLD_MOD(r, x8 ? 1 : 0, 29, 29);     /* TA_TO_X8 */
        r = FLD_MOD(r, ticks, 28, 16);  /* TA_TO_COUNTER */
-       dsi_write_reg(DSI_TIMING1, r);
+       dsi_write_reg(dsidev, DSI_TIMING1, r);
 
        total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);
 
@@ -2677,7 +3454,8 @@ static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16)
                        (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16)
+static void dsi_set_stop_state_counter(struct platform_device *dsidev,
+               unsigned ticks, bool x4, bool x16)
 {
        unsigned long fck;
        unsigned long total_ticks;
@@ -2686,14 +3464,14 @@ static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16)
        BUG_ON(ticks > 0x1fff);
 
        /* ticks in DSI_FCK */
-       fck = dsi_fclk_rate();
+       fck = dsi_fclk_rate(dsidev);
 
-       r = dsi_read_reg(DSI_TIMING1);
+       r = dsi_read_reg(dsidev, DSI_TIMING1);
        r = FLD_MOD(r, 1, 15, 15);      /* FORCE_TX_STOP_MODE_IO */
        r = FLD_MOD(r, x16 ? 1 : 0, 14, 14);    /* STOP_STATE_X16_IO */
        r = FLD_MOD(r, x4 ? 1 : 0, 13, 13);     /* STOP_STATE_X4_IO */
        r = FLD_MOD(r, ticks, 12, 0);   /* STOP_STATE_COUNTER_IO */
-       dsi_write_reg(DSI_TIMING1, r);
+       dsi_write_reg(dsidev, DSI_TIMING1, r);
 
        total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
 
@@ -2703,7 +3481,8 @@ static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16)
                        (total_ticks * 1000) / (fck / 1000 / 1000));
 }
 
-static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16)
+static void dsi_set_hs_tx_timeout(struct platform_device *dsidev,
+               unsigned ticks, bool x4, bool x16)
 {
        unsigned long fck;
        unsigned long total_ticks;
@@ -2712,14 +3491,14 @@ static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16)
        BUG_ON(ticks > 0x1fff);
 
        /* ticks in TxByteClkHS */
-       fck = dsi_get_txbyteclkhs();
+       fck = dsi_get_txbyteclkhs(dsidev);
 
-       r = dsi_read_reg(DSI_TIMING2);
+       r = dsi_read_reg(dsidev, DSI_TIMING2);
        r = FLD_MOD(r, 1, 31, 31);      /* HS_TX_TO */
        r = FLD_MOD(r, x16 ? 1 : 0, 30, 30);    /* HS_TX_TO_X16 */
        r = FLD_MOD(r, x4 ? 1 : 0, 29, 29);     /* HS_TX_TO_X8 (4 really) */
        r = FLD_MOD(r, ticks, 28, 16);  /* HS_TX_TO_COUNTER */
-       dsi_write_reg(DSI_TIMING2, r);
+       dsi_write_reg(dsidev, DSI_TIMING2, r);
 
        total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
 
@@ -2730,24 +3509,25 @@ static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16)
 }
 static int dsi_proto_config(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        u32 r;
        int buswidth = 0;
 
-       dsi_config_tx_fifo(DSI_FIFO_SIZE_32,
+       dsi_config_tx_fifo(dsidev, DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32);
 
-       dsi_config_rx_fifo(DSI_FIFO_SIZE_32,
+       dsi_config_rx_fifo(dsidev, DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32,
                        DSI_FIFO_SIZE_32);
 
        /* XXX what values for the timeouts? */
-       dsi_set_stop_state_counter(0x1000, false, false);
-       dsi_set_ta_timeout(0x1fff, true, true);
-       dsi_set_lp_rx_timeout(0x1fff, true, true);
-       dsi_set_hs_tx_timeout(0x1fff, true, true);
+       dsi_set_stop_state_counter(dsidev, 0x1000, false, false);
+       dsi_set_ta_timeout(dsidev, 0x1fff, true, true);
+       dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true);
+       dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true);
 
        switch (dssdev->ctrl.pixel_size) {
        case 16:
@@ -2763,7 +3543,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
                BUG();
        }
 
-       r = dsi_read_reg(DSI_CTRL);
+       r = dsi_read_reg(dsidev, DSI_CTRL);
        r = FLD_MOD(r, 1, 1, 1);        /* CS_RX_EN */
        r = FLD_MOD(r, 1, 2, 2);        /* ECC_RX_EN */
        r = FLD_MOD(r, 1, 3, 3);        /* TX_FIFO_ARBITRATION */
@@ -2773,21 +3553,25 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
        r = FLD_MOD(r, 2, 13, 12);      /* LINE_BUFFER, 2 lines */
        r = FLD_MOD(r, 1, 14, 14);      /* TRIGGER_RESET_MODE */
        r = FLD_MOD(r, 1, 19, 19);      /* EOT_ENABLE */
-       r = FLD_MOD(r, 1, 24, 24);      /* DCS_CMD_ENABLE */
-       r = FLD_MOD(r, 0, 25, 25);      /* DCS_CMD_CODE, 1=start, 0=continue */
+       if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) {
+               r = FLD_MOD(r, 1, 24, 24);      /* DCS_CMD_ENABLE */
+               /* DCS_CMD_CODE, 1=start, 0=continue */
+               r = FLD_MOD(r, 0, 25, 25);
+       }
 
-       dsi_write_reg(DSI_CTRL, r);
+       dsi_write_reg(dsidev, DSI_CTRL, r);
 
-       dsi_vc_initial_config(0);
-       dsi_vc_initial_config(1);
-       dsi_vc_initial_config(2);
-       dsi_vc_initial_config(3);
+       dsi_vc_initial_config(dsidev, 0);
+       dsi_vc_initial_config(dsidev, 1);
+       dsi_vc_initial_config(dsidev, 2);
+       dsi_vc_initial_config(dsidev, 3);
 
        return 0;
 }
 
 static void dsi_proto_timings(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
        unsigned tclk_pre, tclk_post;
        unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
@@ -2797,32 +3581,27 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        unsigned ths_eot;
        u32 r;
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG0);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0);
        ths_prepare = FLD_GET(r, 31, 24);
        ths_prepare_ths_zero = FLD_GET(r, 23, 16);
        ths_zero = ths_prepare_ths_zero - ths_prepare;
        ths_trail = FLD_GET(r, 15, 8);
        ths_exit = FLD_GET(r, 7, 0);
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG1);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1);
        tlpx = FLD_GET(r, 22, 16) * 2;
        tclk_trail = FLD_GET(r, 15, 8);
        tclk_zero = FLD_GET(r, 7, 0);
 
-       r = dsi_read_reg(DSI_DSIPHY_CFG2);
+       r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2);
        tclk_prepare = FLD_GET(r, 7, 0);
 
        /* min 8*UI */
        tclk_pre = 20;
        /* min 60ns + 52*UI */
-       tclk_post = ns2ddr(60) + 26;
+       tclk_post = ns2ddr(dsidev, 60) + 26;
 
-       /* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */
-       if (dssdev->phy.dsi.data1_lane != 0 &&
-                       dssdev->phy.dsi.data2_lane != 0)
-               ths_eot = 2;
-       else
-               ths_eot = 4;
+       ths_eot = DIV_ROUND_UP(4, dsi_get_num_data_lanes_dssdev(dssdev));
 
        ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
                        4);
@@ -2831,10 +3610,10 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
        BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
        BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
 
-       r = dsi_read_reg(DSI_CLK_TIMING);
+       r = dsi_read_reg(dsidev, DSI_CLK_TIMING);
        r = FLD_MOD(r, ddr_clk_pre, 15, 8);
        r = FLD_MOD(r, ddr_clk_post, 7, 0);
-       dsi_write_reg(DSI_CLK_TIMING, r);
+       dsi_write_reg(dsidev, DSI_CLK_TIMING, r);
 
        DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
                        ddr_clk_pre,
@@ -2848,7 +3627,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
 
        r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
                FLD_VAL(exit_hs_mode_lat, 15, 0);
-       dsi_write_reg(DSI_VM_TIMING7, r);
+       dsi_write_reg(dsidev, DSI_VM_TIMING7, r);
 
        DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
                        enter_hs_mode_lat, exit_hs_mode_lat);
@@ -2858,25 +3637,27 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
 #define DSI_DECL_VARS \
        int __dsi_cb = 0; u32 __dsi_cv = 0;
 
-#define DSI_FLUSH(ch) \
+#define DSI_FLUSH(dsidev, ch) \
        if (__dsi_cb > 0) { \
                /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
-               dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
+               dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
                __dsi_cb = __dsi_cv = 0; \
        }
 
-#define DSI_PUSH(ch, data) \
+#define DSI_PUSH(dsidev, ch, data) \
        do { \
                __dsi_cv |= (data) << (__dsi_cb * 8); \
                /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
                if (++__dsi_cb > 3) \
-                       DSI_FLUSH(ch); \
+                       DSI_FLUSH(dsidev, ch); \
        } while (0)
 
 static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
                        int x, int y, int w, int h)
 {
        /* Note: supports only 24bit colors in 32bit container */
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int first = 1;
        int fifo_stalls = 0;
        int max_dsi_packet_size;
@@ -2915,7 +3696,7 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
         * in fifo */
 
        /* When using CPU, max long packet size is TX buffer size */
-       max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4;
+       max_dsi_packet_size = dsi->vc[0].fifo_size * 32 * 4;
 
        /* we seem to get better perf if we divide the tx fifo to half,
           and while the other half is being sent, we fill the other half
@@ -2944,35 +3725,36 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
 #if 1
                /* using fifo not empty */
                /* TX_FIFO_NOT_EMPTY */
-               while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) {
+               while (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(0)), 5, 5)) {
                        fifo_stalls++;
                        if (fifo_stalls > 0xfffff) {
                                DSSERR("fifo stalls overflow, pixels left %d\n",
                                                pixels_left);
-                               dsi_if_enable(0);
+                               dsi_if_enable(dsidev, 0);
                                return -EIO;
                        }
                        udelay(1);
                }
 #elif 1
                /* using fifo emptiness */
-               while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
+               while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
                                max_dsi_packet_size) {
                        fifo_stalls++;
                        if (fifo_stalls > 0xfffff) {
                                DSSERR("fifo stalls overflow, pixels left %d\n",
                                               pixels_left);
-                               dsi_if_enable(0);
+                               dsi_if_enable(dsidev, 0);
                                return -EIO;
                        }
                }
 #else
-               while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 == 0) {
+               while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS,
+                               7, 0) + 1) * 4 == 0) {
                        fifo_stalls++;
                        if (fifo_stalls > 0xfffff) {
                                DSSERR("fifo stalls overflow, pixels left %d\n",
                                               pixels_left);
-                               dsi_if_enable(0);
+                               dsi_if_enable(dsidev, 0);
                                return -EIO;
                        }
                }
@@ -2981,17 +3763,17 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
 
                pixels_left -= pixels;
 
-               dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE,
+               dsi_vc_write_long_header(dsidev, 0, DSI_DT_DCS_LONG_WRITE,
                                1 + pixels * bytespp, 0);
 
-               DSI_PUSH(0, dcs_cmd);
+               DSI_PUSH(dsidev, 0, dcs_cmd);
 
                while (pixels-- > 0) {
                        u32 pix = __raw_readl(data++);
 
-                       DSI_PUSH(0, (pix >> 16) & 0xff);
-                       DSI_PUSH(0, (pix >> 8) & 0xff);
-                       DSI_PUSH(0, (pix >> 0) & 0xff);
+                       DSI_PUSH(dsidev, 0, (pix >> 16) & 0xff);
+                       DSI_PUSH(dsidev, 0, (pix >> 8) & 0xff);
+                       DSI_PUSH(dsidev, 0, (pix >> 0) & 0xff);
 
                        current_x++;
                        if (current_x == x+w) {
@@ -3000,7 +3782,7 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
                        }
                }
 
-               DSI_FLUSH(0);
+               DSI_FLUSH(dsidev, 0);
        }
 
        return 0;
@@ -3009,6 +3791,8 @@ static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
 static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
                u16 x, u16 y, u16 w, u16 h)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        unsigned bytespp;
        unsigned bytespl;
        unsigned bytespf;
@@ -3017,16 +3801,13 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
        unsigned packet_len;
        u32 l;
        int r;
-       const unsigned channel = dsi.update_channel;
-       /* line buffer is 1024 x 24bits */
-       /* XXX: for some reason using full buffer size causes considerable TX
-        * slowdown with update sizes that fill the whole buffer */
-       const unsigned line_buf_size = 1023 * 3;
+       const unsigned channel = dsi->update_channel;
+       const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
 
        DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
                        x, y, w, h);
 
-       dsi_vc_config_vp(channel);
+       dsi_vc_config_vp(dsidev, channel);
 
        bytespp = dssdev->ctrl.pixel_size / 8;
        bytespl = w * bytespp;
@@ -3047,15 +3828,16 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
                total_len += (bytespf % packet_payload) + 1;
 
        l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
-       dsi_write_reg(DSI_VC_TE(channel), l);
+       dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
 
-       dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
+       dsi_vc_write_long_header(dsidev, channel, DSI_DT_DCS_LONG_WRITE,
+               packet_len, 0);
 
-       if (dsi.te_enabled)
+       if (dsi->te_enabled)
                l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
        else
                l = FLD_MOD(l, 1, 31, 31); /* TE_START */
-       dsi_write_reg(DSI_VC_TE(channel), l);
+       dsi_write_reg(dsidev, DSI_VC_TE(channel), l);
 
        /* We put SIDLEMODE to no-idle for the duration of the transfer,
         * because DSS interrupts are not capable of waking up the CPU and the
@@ -3065,23 +3847,23 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
         */
        dispc_disable_sidle();
 
-       dsi_perf_mark_start();
+       dsi_perf_mark_start(dsidev);
 
-       r = queue_delayed_work(dsi.workqueue, &dsi.framedone_timeout_work,
-                       msecs_to_jiffies(250));
+       r = schedule_delayed_work(&dsi->framedone_timeout_work,
+               msecs_to_jiffies(250));
        BUG_ON(r == 0);
 
        dss_start_update(dssdev);
 
-       if (dsi.te_enabled) {
+       if (dsi->te_enabled) {
                /* disable LP_RX_TO, so that we can receive TE.  Time to wait
                 * for TE is longer than the timer allows */
-               REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
+               REG_FLD_MOD(dsidev, DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
 
-               dsi_vc_send_bta(channel);
+               dsi_vc_send_bta(dsidev, channel);
 
 #ifdef DSI_CATCH_MISSING_TE
-               mod_timer(&dsi.te_timer, jiffies + msecs_to_jiffies(250));
+               mod_timer(&dsi->te_timer, jiffies + msecs_to_jiffies(250));
 #endif
        }
 }
@@ -3093,41 +3875,28 @@ static void dsi_te_timeout(unsigned long arg)
 }
 #endif
 
-static void dsi_framedone_bta_callback(void *data, u32 mask);
-
-static void dsi_handle_framedone(int error)
+static void dsi_handle_framedone(struct platform_device *dsidev, int error)
 {
-       const int channel = dsi.update_channel;
-
-       dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
-                       NULL, DSI_VC_IRQ_BTA);
-
-       cancel_delayed_work(&dsi.framedone_timeout_work);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        /* SIDLEMODE back to smart-idle */
        dispc_enable_sidle();
 
-       if (dsi.te_enabled) {
+       if (dsi->te_enabled) {
                /* enable LP_RX_TO again after the TE */
-               REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
+               REG_FLD_MOD(dsidev, DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
        }
 
-       /* RX_FIFO_NOT_EMPTY */
-       if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
-               DSSERR("Received error during frame transfer:\n");
-               dsi_vc_flush_receive_data(channel);
-               if (!error)
-                       error = -EIO;
-       }
-
-       dsi.framedone_callback(error, dsi.framedone_data);
+       dsi->framedone_callback(error, dsi->framedone_data);
 
        if (!error)
-               dsi_perf_show("DISPC");
+               dsi_perf_show(dsidev, "DISPC");
 }
 
 static void dsi_framedone_timeout_work_callback(struct work_struct *work)
 {
+       struct dsi_data *dsi = container_of(work, struct dsi_data,
+                       framedone_timeout_work.work);
        /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
         * 250ms which would conflict with this timeout work. What should be
         * done is first cancel the transfer on the HW, and then cancel the
@@ -3137,70 +3906,34 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work)
 
        DSSERR("Framedone not received for 250ms!\n");
 
-       dsi_handle_framedone(-ETIMEDOUT);
-}
-
-static void dsi_framedone_bta_callback(void *data, u32 mask)
-{
-       dsi_handle_framedone(0);
-
-#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
-       dispc_fake_vsync_irq();
-#endif
+       dsi_handle_framedone(dsi->pdev, -ETIMEDOUT);
 }
 
 static void dsi_framedone_irq_callback(void *data, u32 mask)
 {
-       const int channel = dsi.update_channel;
-       int r;
+       struct omap_dss_device *dssdev = (struct omap_dss_device *) data;
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
        /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
         * turns itself off. However, DSI still has the pixels in its buffers,
         * and is sending the data.
         */
 
-       if (dsi.te_enabled) {
-               /* enable LP_RX_TO again after the TE */
-               REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
-       }
-
-       /* Send BTA after the frame. We need this for the TE to work, as TE
-        * trigger is only sent for BTAs without preceding packet. Thus we need
-        * to BTA after the pixel packets so that next BTA will cause TE
-        * trigger.
-        *
-        * This is not needed when TE is not in use, but we do it anyway to
-        * make sure that the transfer has been completed. It would be more
-        * optimal, but more complex, to wait only just before starting next
-        * transfer.
-        *
-        * Also, as there's no interrupt telling when the transfer has been
-        * done and the channel could be reconfigured, the only way is to
-        * busyloop until TE_SIZE is zero. With BTA we can do this
-        * asynchronously.
-        * */
-
-       r = dsi_register_isr_vc(channel, dsi_framedone_bta_callback,
-                       NULL, DSI_VC_IRQ_BTA);
-       if (r) {
-               DSSERR("Failed to register BTA ISR\n");
-               dsi_handle_framedone(-EIO);
-               return;
-       }
+       __cancel_delayed_work(&dsi->framedone_timeout_work);
 
-       r = dsi_vc_send_bta(channel);
-       if (r) {
-               DSSERR("BTA after framedone failed\n");
-               dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback,
-                               NULL, DSI_VC_IRQ_BTA);
-               dsi_handle_framedone(-EIO);
-       }
+       dsi_handle_framedone(dsidev, 0);
+
+#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
+       dispc_fake_vsync_irq();
+#endif
 }
 
 int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
                                    u16 *x, u16 *y, u16 *w, u16 *h,
                                    bool enlarge_update_area)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        u16 dw, dh;
 
        dssdev->driver->get_resolution(dssdev, &dw, &dh);
@@ -3220,7 +3953,7 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
        if (*w == 0 || *h == 0)
                return -EINVAL;
 
-       dsi_perf_mark_setup();
+       dsi_perf_mark_setup(dsidev);
 
        if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
                dss_setup_partial_planes(dssdev, x, y, w, h,
@@ -3237,7 +3970,10 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
                u16 x, u16 y, u16 w, u16 h,
                void (*callback)(int, void *), void *data)
 {
-       dsi.update_channel = channel;
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi->update_channel = channel;
 
        /* OMAP DSS cannot send updates of odd widths.
         * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON
@@ -3246,14 +3982,14 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
        BUG_ON(x % 2 == 1);
 
        if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
-               dsi.framedone_callback = callback;
-               dsi.framedone_data = data;
+               dsi->framedone_callback = callback;
+               dsi->framedone_data = data;
 
-               dsi.update_region.x = x;
-               dsi.update_region.y = y;
-               dsi.update_region.w = w;
-               dsi.update_region.h = h;
-               dsi.update_region.device = dssdev;
+               dsi->update_region.x = x;
+               dsi->update_region.y = y;
+               dsi->update_region.w = w;
+               dsi->update_region.h = h;
+               dsi->update_region.device = dssdev;
 
                dsi_update_screen_dispc(dssdev, x, y, w, h);
        } else {
@@ -3263,7 +3999,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
                if (r)
                        return r;
 
-               dsi_perf_show("L4");
+               dsi_perf_show(dsidev, "L4");
                callback(0, data);
        }
 
@@ -3276,9 +4012,13 @@ EXPORT_SYMBOL(omap_dsi_update);
 static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 {
        int r;
+       u32 irq;
+
+       irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
+               DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
 
-       r = omap_dispc_register_isr(dsi_framedone_irq_callback, NULL,
-                       DISPC_IRQ_FRAMEDONE);
+       r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev,
+                       irq);
        if (r) {
                DSSERR("can't get FRAMEDONE irq\n");
                return r;
@@ -3311,28 +4051,34 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
 
 static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
 {
-       omap_dispc_unregister_isr(dsi_framedone_irq_callback, NULL,
-                       DISPC_IRQ_FRAMEDONE);
+       u32 irq;
+
+       irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ?
+               DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2;
+
+       omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev,
+                       irq);
 }
 
 static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dsi_clock_info cinfo;
        int r;
 
        /* we always use DSS_CLK_SYSCK as input clock */
        cinfo.use_sys_clk = true;
-       cinfo.regn  = dssdev->phy.dsi.div.regn;
-       cinfo.regm  = dssdev->phy.dsi.div.regm;
-       cinfo.regm_dispc = dssdev->phy.dsi.div.regm_dispc;
-       cinfo.regm_dsi = dssdev->phy.dsi.div.regm_dsi;
+       cinfo.regn  = dssdev->clocks.dsi.regn;
+       cinfo.regm  = dssdev->clocks.dsi.regm;
+       cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc;
+       cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi;
        r = dsi_calc_clock_rates(dssdev, &cinfo);
        if (r) {
                DSSERR("Failed to calc dsi clocks\n");
                return r;
        }
 
-       r = dsi_pll_set_clock_div(&cinfo);
+       r = dsi_pll_set_clock_div(dsidev, &cinfo);
        if (r) {
                DSSERR("Failed to set dsi clocks\n");
                return r;
@@ -3343,14 +4089,15 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
 
 static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
        struct dispc_clock_info dispc_cinfo;
        int r;
        unsigned long long fck;
 
-       fck = dsi_get_pll_hsdiv_dispc_rate();
+       fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
 
-       dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div;
-       dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div;
+       dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div;
+       dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div;
 
        r = dispc_calc_clock_rates(fck, &dispc_cinfo);
        if (r) {
@@ -3369,11 +4116,11 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
 
 static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       int dsi_module = dsi_get_dsidev_id(dsidev);
        int r;
 
-       _dsi_print_reset_status();
-
-       r = dsi_pll_init(dssdev, true, true);
+       r = dsi_pll_init(dsidev, true, true);
        if (r)
                goto err0;
 
@@ -3381,8 +4128,10 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
        if (r)
                goto err1;
 
-       dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC);
-       dss_select_dsi_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI);
+       dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
+       dss_select_dsi_clk_source(dsi_module, dssdev->clocks.dsi.dsi_fclk_src);
+       dss_select_lcd_clk_source(dssdev->manager->id,
+                       dssdev->clocks.dispc.channel.lcd_clk_src);
 
        DSSDBG("PLL OK\n");
 
@@ -3390,82 +4139,92 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
        if (r)
                goto err2;
 
-       r = dsi_complexio_init(dssdev);
+       r = dsi_cio_init(dssdev);
        if (r)
                goto err2;
 
-       _dsi_print_reset_status();
+       _dsi_print_reset_status(dsidev);
 
        dsi_proto_timings(dssdev);
        dsi_set_lp_clk_divisor(dssdev);
 
        if (1)
-               _dsi_print_reset_status();
+               _dsi_print_reset_status(dsidev);
 
        r = dsi_proto_config(dssdev);
        if (r)
                goto err3;
 
        /* enable interface */
-       dsi_vc_enable(0, 1);
-       dsi_vc_enable(1, 1);
-       dsi_vc_enable(2, 1);
-       dsi_vc_enable(3, 1);
-       dsi_if_enable(1);
-       dsi_force_tx_stop_mode_io();
+       dsi_vc_enable(dsidev, 0, 1);
+       dsi_vc_enable(dsidev, 1, 1);
+       dsi_vc_enable(dsidev, 2, 1);
+       dsi_vc_enable(dsidev, 3, 1);
+       dsi_if_enable(dsidev, 1);
+       dsi_force_tx_stop_mode_io(dsidev);
 
        return 0;
 err3:
-       dsi_complexio_uninit();
+       dsi_cio_uninit(dsidev);
 err2:
-       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
-       dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
+       dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
+       dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
 err1:
-       dsi_pll_uninit();
+       dsi_pll_uninit(dsidev, true);
 err0:
        return r;
 }
 
-static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
+static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
+               bool disconnect_lanes, bool enter_ulps)
 {
-       /* disable interface */
-       dsi_if_enable(0);
-       dsi_vc_enable(0, 0);
-       dsi_vc_enable(1, 0);
-       dsi_vc_enable(2, 0);
-       dsi_vc_enable(3, 0);
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int dsi_module = dsi_get_dsidev_id(dsidev);
 
-       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
-       dss_select_dsi_clk_source(DSS_CLK_SRC_FCK);
-       dsi_complexio_uninit();
-       dsi_pll_uninit();
+       if (enter_ulps && !dsi->ulps_enabled)
+               dsi_enter_ulps(dsidev);
+
+       /* disable interface */
+       dsi_if_enable(dsidev, 0);
+       dsi_vc_enable(dsidev, 0, 0);
+       dsi_vc_enable(dsidev, 1, 0);
+       dsi_vc_enable(dsidev, 2, 0);
+       dsi_vc_enable(dsidev, 3, 0);
+
+       dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
+       dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK);
+       dsi_cio_uninit(dsidev);
+       dsi_pll_uninit(dsidev, disconnect_lanes);
 }
 
-static int dsi_core_init(void)
+static int dsi_core_init(struct platform_device *dsidev)
 {
        /* Autoidle */
-       REG_FLD_MOD(DSI_SYSCONFIG, 1, 0, 0);
+       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 0, 0);
 
        /* ENWAKEUP */
-       REG_FLD_MOD(DSI_SYSCONFIG, 1, 2, 2);
+       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 1, 2, 2);
 
        /* SIDLEMODE smart-idle */
-       REG_FLD_MOD(DSI_SYSCONFIG, 2, 4, 3);
+       REG_FLD_MOD(dsidev, DSI_SYSCONFIG, 2, 4, 3);
 
-       _dsi_initialize_irq();
+       _dsi_initialize_irq(dsidev);
 
        return 0;
 }
 
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int r = 0;
 
        DSSDBG("dsi_display_enable\n");
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       mutex_lock(&dsi.lock);
+       mutex_lock(&dsi->lock);
 
        r = omap_dss_start_device(dssdev);
        if (r) {
@@ -3474,13 +4233,13 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
        }
 
        enable_clocks(1);
-       dsi_enable_pll_clock(1);
+       dsi_enable_pll_clock(dsidev, 1);
 
-       r = _dsi_reset();
+       r = _dsi_reset(dsidev);
        if (r)
                goto err1;
 
-       dsi_core_init();
+       dsi_core_init(dsidev);
 
        r = dsi_display_init_dispc(dssdev);
        if (r)
@@ -3490,7 +4249,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
        if (r)
                goto err2;
 
-       mutex_unlock(&dsi.lock);
+       mutex_unlock(&dsi->lock);
 
        return 0;
 
@@ -3498,39 +4257,46 @@ err2:
        dsi_display_uninit_dispc(dssdev);
 err1:
        enable_clocks(0);
-       dsi_enable_pll_clock(0);
+       dsi_enable_pll_clock(dsidev, 0);
        omap_dss_stop_device(dssdev);
 err0:
-       mutex_unlock(&dsi.lock);
+       mutex_unlock(&dsi->lock);
        DSSDBG("dsi_display_enable FAILED\n");
        return r;
 }
 EXPORT_SYMBOL(omapdss_dsi_display_enable);
 
-void omapdss_dsi_display_disable(struct omap_dss_device *dssdev)
+void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
+               bool disconnect_lanes, bool enter_ulps)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        DSSDBG("dsi_display_disable\n");
 
-       WARN_ON(!dsi_bus_is_locked());
+       WARN_ON(!dsi_bus_is_locked(dsidev));
 
-       mutex_lock(&dsi.lock);
+       mutex_lock(&dsi->lock);
 
        dsi_display_uninit_dispc(dssdev);
 
-       dsi_display_uninit_dsi(dssdev);
+       dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
 
        enable_clocks(0);
-       dsi_enable_pll_clock(0);
+       dsi_enable_pll_clock(dsidev, 0);
 
        omap_dss_stop_device(dssdev);
 
-       mutex_unlock(&dsi.lock);
+       mutex_unlock(&dsi->lock);
 }
 EXPORT_SYMBOL(omapdss_dsi_display_disable);
 
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
 {
-       dsi.te_enabled = enable;
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi->te_enabled = enable;
        return 0;
 }
 EXPORT_SYMBOL(omapdss_dsi_enable_te);
@@ -3550,23 +4316,33 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
 
 int dsi_init_display(struct omap_dss_device *dssdev)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+       int dsi_module = dsi_get_dsidev_id(dsidev);
+
        DSSDBG("DSI init\n");
 
        /* XXX these should be figured out dynamically */
        dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
                OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
 
-       if (dsi.vdds_dsi_reg == NULL) {
+       if (dsi->vdds_dsi_reg == NULL) {
                struct regulator *vdds_dsi;
 
-               vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi");
+               vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi");
 
                if (IS_ERR(vdds_dsi)) {
                        DSSERR("can't get VDDS_DSI regulator\n");
                        return PTR_ERR(vdds_dsi);
                }
 
-               dsi.vdds_dsi_reg = vdds_dsi;
+               dsi->vdds_dsi_reg = vdds_dsi;
+       }
+
+       if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) {
+               DSSERR("DSI%d can't support more than %d data lanes\n",
+                       dsi_module + 1, dsi->num_data_lanes);
+               return -EINVAL;
        }
 
        return 0;
@@ -3574,11 +4350,13 @@ int dsi_init_display(struct omap_dss_device *dssdev)
 
 int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
-               if (!dsi.vc[i].dssdev) {
-                       dsi.vc[i].dssdev = dssdev;
+       for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
+               if (!dsi->vc[i].dssdev) {
+                       dsi->vc[i].dssdev = dssdev;
                        *channel = i;
                        return 0;
                }
@@ -3591,6 +4369,9 @@ EXPORT_SYMBOL(omap_dsi_request_vc);
 
 int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        if (vc_id < 0 || vc_id > 3) {
                DSSERR("VC ID out of range\n");
                return -EINVAL;
@@ -3601,13 +4382,13 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id)
                return -EINVAL;
        }
 
-       if (dsi.vc[channel].dssdev != dssdev) {
+       if (dsi->vc[channel].dssdev != dssdev) {
                DSSERR("Virtual Channel not allocated to display %s\n",
                        dssdev->name);
                return -EINVAL;
        }
 
-       dsi.vc[channel].vc_id = vc_id;
+       dsi->vc[channel].vc_id = vc_id;
 
        return 0;
 }
@@ -3615,143 +4396,172 @@ EXPORT_SYMBOL(omap_dsi_set_vc_id);
 
 void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel)
 {
+       struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
        if ((channel >= 0 && channel <= 3) &&
-               dsi.vc[channel].dssdev == dssdev) {
-               dsi.vc[channel].dssdev = NULL;
-               dsi.vc[channel].vc_id = 0;
+               dsi->vc[channel].dssdev == dssdev) {
+               dsi->vc[channel].dssdev = NULL;
+               dsi->vc[channel].vc_id = 0;
        }
 }
 EXPORT_SYMBOL(omap_dsi_release_vc);
 
-void dsi_wait_pll_hsdiv_dispc_active(void)
+void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
 {
-       if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1)
+       if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 7, 1) != 1)
                DSSERR("%s (%s) not active\n",
-                       dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
-                       dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
+                       dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
+                       dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
 }
 
-void dsi_wait_pll_hsdiv_dsi_active(void)
+void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
 {
-       if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1)
+       if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 8, 1) != 1)
                DSSERR("%s (%s) not active\n",
-                       dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
-                       dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
+                       dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
+                       dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
 }
 
-static void dsi_calc_clock_param_ranges(void)
+static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
 {
-       dsi.regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
-       dsi.regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
-       dsi.regm_dispc_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
-       dsi.regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
-       dsi.fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
-       dsi.fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
-       dsi.lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi->regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
+       dsi->regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
+       dsi->regm_dispc_max =
+               dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
+       dsi->regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
+       dsi->fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
+       dsi->fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
+       dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
 }
 
-static int dsi_init(struct platform_device *pdev)
+static int dsi_init(struct platform_device *dsidev)
 {
+       struct omap_display_platform_data *dss_plat_data;
+       struct omap_dss_board_info *board_info;
        u32 rev;
-       int r, i;
+       int r, i, dsi_module = dsi_get_dsidev_id(dsidev);
        struct resource *dsi_mem;
+       struct dsi_data *dsi;
+
+       dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
+       if (!dsi) {
+               r = -ENOMEM;
+               goto err0;
+       }
+
+       dsi->pdev = dsidev;
+       dsi_pdev_map[dsi_module] = dsidev;
+       dev_set_drvdata(&dsidev->dev, dsi);
+
+       dss_plat_data = dsidev->dev.platform_data;
+       board_info = dss_plat_data->board_data;
+       dsi->dsi_mux_pads = board_info->dsi_mux_pads;
 
-       spin_lock_init(&dsi.irq_lock);
-       spin_lock_init(&dsi.errors_lock);
-       dsi.errors = 0;
+       spin_lock_init(&dsi->irq_lock);
+       spin_lock_init(&dsi->errors_lock);
+       dsi->errors = 0;
 
 #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
-       spin_lock_init(&dsi.irq_stats_lock);
-       dsi.irq_stats.last_reset = jiffies;
+       spin_lock_init(&dsi->irq_stats_lock);
+       dsi->irq_stats.last_reset = jiffies;
 #endif
 
-       mutex_init(&dsi.lock);
-       sema_init(&dsi.bus_lock, 1);
+       mutex_init(&dsi->lock);
+       sema_init(&dsi->bus_lock, 1);
 
-       dsi.workqueue = create_singlethread_workqueue("dsi");
-       if (dsi.workqueue == NULL)
-               return -ENOMEM;
-
-       INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work,
+       INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work,
                        dsi_framedone_timeout_work_callback);
 
 #ifdef DSI_CATCH_MISSING_TE
-       init_timer(&dsi.te_timer);
-       dsi.te_timer.function = dsi_te_timeout;
-       dsi.te_timer.data = 0;
+       init_timer(&dsi->te_timer);
+       dsi->te_timer.function = dsi_te_timeout;
+       dsi->te_timer.data = 0;
 #endif
-       dsi_mem = platform_get_resource(dsi.pdev, IORESOURCE_MEM, 0);
+       dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0);
        if (!dsi_mem) {
                DSSERR("can't get IORESOURCE_MEM DSI\n");
                r = -EINVAL;
                goto err1;
        }
-       dsi.base = ioremap(dsi_mem->start, resource_size(dsi_mem));
-       if (!dsi.base) {
+       dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem));
+       if (!dsi->base) {
                DSSERR("can't ioremap DSI\n");
                r = -ENOMEM;
                goto err1;
        }
-       dsi.irq = platform_get_irq(dsi.pdev, 0);
-       if (dsi.irq < 0) {
+       dsi->irq = platform_get_irq(dsi->pdev, 0);
+       if (dsi->irq < 0) {
                DSSERR("platform_get_irq failed\n");
                r = -ENODEV;
                goto err2;
        }
 
-       r = request_irq(dsi.irq, omap_dsi_irq_handler, IRQF_SHARED,
-               "OMAP DSI1", dsi.pdev);
+       r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED,
+               dev_name(&dsidev->dev), dsi->pdev);
        if (r < 0) {
                DSSERR("request_irq failed\n");
                goto err2;
        }
 
        /* DSI VCs initialization */
-       for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) {
-               dsi.vc[i].mode = DSI_VC_MODE_L4;
-               dsi.vc[i].dssdev = NULL;
-               dsi.vc[i].vc_id = 0;
+       for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
+               dsi->vc[i].mode = DSI_VC_MODE_L4;
+               dsi->vc[i].dssdev = NULL;
+               dsi->vc[i].vc_id = 0;
        }
 
-       dsi_calc_clock_param_ranges();
+       dsi_calc_clock_param_ranges(dsidev);
 
        enable_clocks(1);
 
-       rev = dsi_read_reg(DSI_REVISION);
-       dev_dbg(&pdev->dev, "OMAP DSI rev %d.%d\n",
+       rev = dsi_read_reg(dsidev, DSI_REVISION);
+       dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
               FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 
+       dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev);
+
        enable_clocks(0);
 
        return 0;
 err2:
-       iounmap(dsi.base);
+       iounmap(dsi->base);
 err1:
-       destroy_workqueue(dsi.workqueue);
+       kfree(dsi);
+err0:
        return r;
 }
 
-static void dsi_exit(void)
+static void dsi_exit(struct platform_device *dsidev)
 {
-       if (dsi.vdds_dsi_reg != NULL) {
-               regulator_put(dsi.vdds_dsi_reg);
-               dsi.vdds_dsi_reg = NULL;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       if (dsi->vdds_dsi_reg != NULL) {
+               if (dsi->vdds_dsi_enabled) {
+                       regulator_disable(dsi->vdds_dsi_reg);
+                       dsi->vdds_dsi_enabled = false;
+               }
+
+               regulator_put(dsi->vdds_dsi_reg);
+               dsi->vdds_dsi_reg = NULL;
        }
 
-       free_irq(dsi.irq, dsi.pdev);
-       iounmap(dsi.base);
+       free_irq(dsi->irq, dsi->pdev);
+       iounmap(dsi->base);
 
-       destroy_workqueue(dsi.workqueue);
+       kfree(dsi);
 
        DSSDBG("omap_dsi_exit\n");
 }
 
 /* DSI1 HW IP initialisation */
-static int omap_dsi1hw_probe(struct platform_device *pdev)
+static int omap_dsi1hw_probe(struct platform_device *dsidev)
 {
        int r;
-       dsi.pdev = pdev;
-       r = dsi_init(pdev);
+
+       r = dsi_init(dsidev);
        if (r) {
                DSSERR("Failed to initialize DSI\n");
                goto err_dsi;
@@ -3760,9 +4570,12 @@ err_dsi:
        return r;
 }
 
-static int omap_dsi1hw_remove(struct platform_device *pdev)
+static int omap_dsi1hw_remove(struct platform_device *dsidev)
 {
-       dsi_exit();
+       struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+
+       dsi_exit(dsidev);
+       WARN_ON(dsi->scp_clk_refcount > 0);
        return 0;
 }
 
index 3f1fee63c67830d2e9778238d2040b865df6cbef..d9489d5c4f08d96c942676ee00dddc93d62f3208 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/seq_file.h>
 #include <linux/clk.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/clock.h>
 #include "dss.h"
 #include "dss_features.h"
@@ -45,7 +45,6 @@ struct dss_reg {
 #define DSS_REVISION                   DSS_REG(0x0000)
 #define DSS_SYSCONFIG                  DSS_REG(0x0010)
 #define DSS_SYSSTATUS                  DSS_REG(0x0014)
-#define DSS_IRQSTATUS                  DSS_REG(0x0018)
 #define DSS_CONTROL                    DSS_REG(0x0040)
 #define DSS_SDI_CONTROL                        DSS_REG(0x0044)
 #define DSS_PLL_CONTROL                        DSS_REG(0x0048)
@@ -75,17 +74,17 @@ static struct {
        struct dss_clock_info cache_dss_cinfo;
        struct dispc_clock_info cache_dispc_cinfo;
 
-       enum dss_clk_source dsi_clk_source;
-       enum dss_clk_source dispc_clk_source;
-       enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
+       enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
+       enum omap_dss_clk_source dispc_clk_source;
+       enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
 
        u32             ctx[DSS_SZ_REGS / sizeof(u32)];
 } dss;
 
 static const char * const dss_generic_clk_source_names[] = {
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "DSI_PLL_HSDIV_DISPC",
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "DSI_PLL_HSDIV_DSI",
-       [DSS_CLK_SRC_FCK]                       = "DSS_FCK",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]  = "DSI_PLL_HSDIV_DISPC",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]    = "DSI_PLL_HSDIV_DSI",
+       [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCK",
 };
 
 static void dss_clk_enable_all_no_ctx(void);
@@ -230,7 +229,7 @@ void dss_sdi_disable(void)
        REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
 }
 
-const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src)
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
 {
        return dss_generic_clk_source_names[clk_src];
 }
@@ -246,8 +245,8 @@ void dss_dump_clocks(struct seq_file *s)
 
        seq_printf(s, "- DSS -\n");
 
-       fclk_name = dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK);
-       fclk_real_name = dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK);
+       fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
+       fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
        fclk_rate = dss_clk_get_rate(DSS_CLK_FCK);
 
        if (dss.dpll4_m4_ck) {
@@ -286,7 +285,6 @@ void dss_dump_regs(struct seq_file *s)
        DUMPREG(DSS_REVISION);
        DUMPREG(DSS_SYSCONFIG);
        DUMPREG(DSS_SYSSTATUS);
-       DUMPREG(DSS_IRQSTATUS);
        DUMPREG(DSS_CONTROL);
 
        if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
@@ -300,18 +298,25 @@ void dss_dump_regs(struct seq_file *s)
 #undef DUMPREG
 }
 
-void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
+void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
 {
+       struct platform_device *dsidev;
        int b;
        u8 start, end;
 
        switch (clk_src) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                b = 0;
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
                b = 1;
-               dsi_wait_pll_hsdiv_dispc_active();
+               dsidev = dsi_get_dsidev_from_id(0);
+               dsi_wait_pll_hsdiv_dispc_active(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+               b = 2;
+               dsidev = dsi_get_dsidev_from_id(1);
+               dsi_wait_pll_hsdiv_dispc_active(dsidev);
                break;
        default:
                BUG();
@@ -324,17 +329,27 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
        dss.dispc_clk_source = clk_src;
 }
 
-void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
+void dss_select_dsi_clk_source(int dsi_module,
+               enum omap_dss_clk_source clk_src)
 {
+       struct platform_device *dsidev;
        int b;
 
        switch (clk_src) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                b = 0;
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
+               BUG_ON(dsi_module != 0);
+               b = 1;
+               dsidev = dsi_get_dsidev_from_id(0);
+               dsi_wait_pll_hsdiv_dsi_active(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
+               BUG_ON(dsi_module != 1);
                b = 1;
-               dsi_wait_pll_hsdiv_dsi_active();
+               dsidev = dsi_get_dsidev_from_id(1);
+               dsi_wait_pll_hsdiv_dsi_active(dsidev);
                break;
        default:
                BUG();
@@ -342,25 +357,33 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
 
        REG_FLD_MOD(DSS_CONTROL, b, 1, 1);      /* DSI_CLK_SWITCH */
 
-       dss.dsi_clk_source = clk_src;
+       dss.dsi_clk_source[dsi_module] = clk_src;
 }
 
 void dss_select_lcd_clk_source(enum omap_channel channel,
-               enum dss_clk_source clk_src)
+               enum omap_dss_clk_source clk_src)
 {
+       struct platform_device *dsidev;
        int b, ix, pos;
 
        if (!dss_has_feature(FEAT_LCD_CLK_SRC))
                return;
 
        switch (clk_src) {
-       case DSS_CLK_SRC_FCK:
+       case OMAP_DSS_CLK_SRC_FCK:
                b = 0;
                break;
-       case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
+       case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
                BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
                b = 1;
-               dsi_wait_pll_hsdiv_dispc_active();
+               dsidev = dsi_get_dsidev_from_id(0);
+               dsi_wait_pll_hsdiv_dispc_active(dsidev);
+               break;
+       case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
+               BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2);
+               b = 1;
+               dsidev = dsi_get_dsidev_from_id(1);
+               dsi_wait_pll_hsdiv_dispc_active(dsidev);
                break;
        default:
                BUG();
@@ -373,20 +396,26 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
        dss.lcd_clk_source[ix] = clk_src;
 }
 
-enum dss_clk_source dss_get_dispc_clk_source(void)
+enum omap_dss_clk_source dss_get_dispc_clk_source(void)
 {
        return dss.dispc_clk_source;
 }
 
-enum dss_clk_source dss_get_dsi_clk_source(void)
+enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
 {
-       return dss.dsi_clk_source;
+       return dss.dsi_clk_source[dsi_module];
 }
 
-enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
+enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
 {
-       int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
-       return dss.lcd_clk_source[ix];
+       if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
+               int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+               return dss.lcd_clk_source[ix];
+       } else {
+               /* LCD_CLK source is the same as DISPC_FCLK source for
+                * OMAP2 and OMAP3 */
+               return dss.dispc_clk_source;
+       }
 }
 
 /* calculate clock rates using dividers in cinfo */
@@ -659,13 +688,18 @@ static int dss_init(void)
         * the kernel resets it */
        omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
 
+#ifdef CONFIG_OMAP2_DSS_SLEEP_BEFORE_RESET
        /* We need to wait here a bit, otherwise we sometimes start to
         * get synclost errors, and after that only power cycle will
         * restore DSS functionality. I have no idea why this happens.
         * And we have to wait _before_ resetting the DSS, but after
         * enabling clocks.
+        *
+        * This bug was at least present on OMAP3430. It's unknown
+        * if it happens on OMAP2 or OMAP3630.
         */
        msleep(50);
+#endif
 
        _omap_dss_reset();
 
@@ -700,10 +734,11 @@ static int dss_init(void)
 
        dss.dpll4_m4_ck = dpll4_m4_ck;
 
-       dss.dsi_clk_source = DSS_CLK_SRC_FCK;
-       dss.dispc_clk_source = DSS_CLK_SRC_FCK;
-       dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK;
-       dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK;
+       dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+       dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
+       dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
+       dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
 
        dss_save_context();
 
@@ -1015,6 +1050,14 @@ static void core_dump_clocks(struct seq_file *s)
                dss.dss_video_fck
        };
 
+       const char *names[5] = {
+               "ick",
+               "fck",
+               "sys_clk",
+               "tv_fck",
+               "video_fck"
+       };
+
        seq_printf(s, "- CORE -\n");
 
        seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled);
@@ -1022,8 +1065,11 @@ static void core_dump_clocks(struct seq_file *s)
        for (i = 0; i < 5; i++) {
                if (!clocks[i])
                        continue;
-               seq_printf(s, "%-15s\t%lu\t%d\n",
+               seq_printf(s, "%s (%s)%*s\t%lu\t%d\n",
+                               names[i],
                                clocks[i]->name,
+                               24 - strlen(names[i]) - strlen(clocks[i]->name),
+                               "",
                                clk_get_rate(clocks[i]),
                                clocks[i]->usecount);
        }
index c2f582bb19c05f49f22c34e6bea1a1bd015a9cb1..8ab6d43329bb31af71feec89b876208e8ff4f054 100644 (file)
@@ -117,15 +117,6 @@ enum dss_clock {
        DSS_CLK_VIDFCK  = 1 << 4,       /* DSS_96M_FCLK*/
 };
 
-enum dss_clk_source {
-       DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC,        /* OMAP3: DSI1_PLL_FCLK
-                                                * OMAP4: PLL1_CLK1 */
-       DSS_CLK_SRC_DSI_PLL_HSDIV_DSI,          /* OMAP3: DSI2_PLL_FCLK
-                                                * OMAP4: PLL1_CLK2 */
-       DSS_CLK_SRC_FCK,                        /* OMAP2/3: DSS1_ALWON_FCLK
-                                                * OMAP4: DSS_FCLK */
-};
-
 enum dss_hdmi_venc_clk_source_select {
        DSS_VENC_TV_CLK = 0,
        DSS_HDMI_M_PCLK = 1,
@@ -236,7 +227,7 @@ void dss_clk_enable(enum dss_clock clks);
 void dss_clk_disable(enum dss_clock clks);
 unsigned long dss_clk_get_rate(enum dss_clock clk);
 int dss_need_ctx_restore(void);
-const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src);
+const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
 void dss_dump_clocks(struct seq_file *s);
 
 void dss_dump_regs(struct seq_file *s);
@@ -248,13 +239,14 @@ void dss_sdi_init(u8 datapairs);
 int dss_sdi_enable(void);
 void dss_sdi_disable(void);
 
-void dss_select_dispc_clk_source(enum dss_clk_source clk_src);
-void dss_select_dsi_clk_source(enum dss_clk_source clk_src);
+void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src);
+void dss_select_dsi_clk_source(int dsi_module,
+               enum omap_dss_clk_source clk_src);
 void dss_select_lcd_clk_source(enum omap_channel channel,
-               enum dss_clk_source clk_src);
-enum dss_clk_source dss_get_dispc_clk_source(void);
-enum dss_clk_source dss_get_dsi_clk_source(void);
-enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
+               enum omap_dss_clk_source clk_src);
+enum omap_dss_clk_source dss_get_dispc_clk_source(void);
+enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module);
+enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel);
 
 void dss_set_venc_output(enum omap_dss_venc_type type);
 void dss_set_dac_pwrdn_bgz(bool enable);
@@ -284,31 +276,39 @@ static inline void sdi_exit(void)
 
 /* DSI */
 #ifdef CONFIG_OMAP2_DSS_DSI
+
+struct dentry;
+struct file_operations;
+
 int dsi_init_platform_driver(void);
 void dsi_uninit_platform_driver(void);
 
 void dsi_dump_clocks(struct seq_file *s);
-void dsi_dump_irqs(struct seq_file *s);
-void dsi_dump_regs(struct seq_file *s);
+void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir,
+               const struct file_operations *debug_fops);
+void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir,
+               const struct file_operations *debug_fops);
 
 void dsi_save_context(void);
 void dsi_restore_context(void);
 
 int dsi_init_display(struct omap_dss_device *display);
 void dsi_irq_handler(void);
-unsigned long dsi_get_pll_hsdiv_dispc_rate(void);
-int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
-int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
-               struct dsi_clock_info *cinfo,
+unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
+int dsi_pll_set_clock_div(struct platform_device *dsidev,
+               struct dsi_clock_info *cinfo);
+int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft,
+               unsigned long req_pck, struct dsi_clock_info *cinfo,
                struct dispc_clock_info *dispc_cinfo);
-int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
+int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
                bool enable_hsdiv);
-void dsi_pll_uninit(void);
+void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
 void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
                u32 fifo_size, enum omap_burst_size *burst_size,
                u32 *fifo_low, u32 *fifo_high);
-void dsi_wait_pll_hsdiv_dispc_active(void);
-void dsi_wait_pll_hsdiv_dsi_active(void);
+void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
+void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
+struct platform_device *dsi_get_dsidev_from_id(int module);
 #else
 static inline int dsi_init_platform_driver(void)
 {
@@ -317,17 +317,47 @@ static inline int dsi_init_platform_driver(void)
 static inline void dsi_uninit_platform_driver(void)
 {
 }
-static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(void)
+static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
 {
        WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
        return 0;
 }
-static inline void dsi_wait_pll_hsdiv_dispc_active(void)
+static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
+               struct dsi_clock_info *cinfo)
+{
+       WARN("%s: DSI not compiled in\n", __func__);
+       return -ENODEV;
+}
+static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
+               bool is_tft, unsigned long req_pck,
+               struct dsi_clock_info *dsi_cinfo,
+               struct dispc_clock_info *dispc_cinfo)
+{
+       WARN("%s: DSI not compiled in\n", __func__);
+       return -ENODEV;
+}
+static inline int dsi_pll_init(struct platform_device *dsidev,
+               bool enable_hsclk, bool enable_hsdiv)
 {
+       WARN("%s: DSI not compiled in\n", __func__);
+       return -ENODEV;
 }
-static inline void dsi_wait_pll_hsdiv_dsi_active(void)
+static inline void dsi_pll_uninit(struct platform_device *dsidev,
+               bool disconnect_lanes)
 {
 }
+static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
+{
+}
+static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
+{
+}
+static inline struct platform_device *dsi_get_dsidev_from_id(int module)
+{
+       WARN("%s: DSI not compiled in, returning platform device as NULL\n",
+                       __func__);
+       return NULL;
+}
 #endif
 
 /* DPI */
@@ -391,7 +421,8 @@ int dispc_setup_plane(enum omap_plane plane,
                      enum omap_dss_rotation_type rotation_type,
                      u8 rotation, bool mirror,
                      u8 global_alpha, u8 pre_mult_alpha,
-                     enum omap_channel channel);
+                     enum omap_channel channel,
+                     u32 puv_addr);
 
 bool dispc_go_busy(enum omap_channel channel);
 void dispc_go(enum omap_channel channel);
@@ -485,13 +516,6 @@ void hdmi_panel_exit(void);
 int rfbi_init_platform_driver(void);
 void rfbi_uninit_platform_driver(void);
 void rfbi_dump_regs(struct seq_file *s);
-
-int rfbi_configure(int rfbi_module, int bpp, int lines);
-void rfbi_enable_rfbi(bool enable);
-void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
-               u16 height, void (callback)(void *data), void *data);
-void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
-unsigned long rfbi_get_max_tx_rate(void);
 int rfbi_init_display(struct omap_dss_device *display);
 #else
 static inline int rfbi_init_platform_driver(void)
index aa1622241d0d728612c57bda460951d251cf590d..1c18888e5df39a06548d5dbf210ddcaa4e6f2600 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -52,7 +52,7 @@ struct omap_dss_features {
 };
 
 /* This struct is assigned to one of the below during initialization */
-static struct omap_dss_features *omap_current_dss_features;
+static const struct omap_dss_features *omap_current_dss_features;
 
 static const struct dss_reg_field omap2_dss_reg_fields[] = {
        [FEAT_REG_FIRHINC]                      = { 11, 0 },
@@ -177,22 +177,55 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = {
        OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
 };
 
+static const enum omap_color_mode omap4_dss_supported_color_modes[] = {
+       /* OMAP_DSS_GFX */
+       OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
+       OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
+       OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
+       OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 |
+       OMAP_DSS_COLOR_ARGB16_1555,
+
+       /* OMAP_DSS_VIDEO1 */
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+       OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+       OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+       OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+       OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+       OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+       OMAP_DSS_COLOR_RGBX32,
+
+       /* OMAP_DSS_VIDEO2 */
+       OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U |
+       OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 |
+       OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 |
+       OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U |
+       OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY |
+       OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 |
+       OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 |
+       OMAP_DSS_COLOR_RGBX32,
+};
+
 static const char * const omap2_dss_clk_source_names[] = {
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "N/A",
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "N/A",
-       [DSS_CLK_SRC_FCK]                       = "DSS_FCLK1",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]  = "N/A",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]    = "N/A",
+       [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCLK1",
 };
 
 static const char * const omap3_dss_clk_source_names[] = {
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "DSI1_PLL_FCLK",
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "DSI2_PLL_FCLK",
-       [DSS_CLK_SRC_FCK]                       = "DSS1_ALWON_FCLK",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]  = "DSI1_PLL_FCLK",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]    = "DSI2_PLL_FCLK",
+       [OMAP_DSS_CLK_SRC_FCK]                  = "DSS1_ALWON_FCLK",
 };
 
 static const char * const omap4_dss_clk_source_names[] = {
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]       = "PLL1_CLK1",
-       [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]         = "PLL1_CLK2",
-       [DSS_CLK_SRC_FCK]                       = "DSS_FCLK",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]  = "PLL1_CLK1",
+       [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]    = "PLL1_CLK2",
+       [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCLK",
+       [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "PLL2_CLK1",
+       [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI]   = "PLL2_CLK2",
 };
 
 static const struct dss_param_range omap2_dss_param_range[] = {
@@ -226,7 +259,7 @@ static const struct dss_param_range omap4_dss_param_range[] = {
 };
 
 /* OMAP2 DSS Features */
-static struct omap_dss_features omap2_dss_features = {
+static const struct omap_dss_features omap2_dss_features = {
        .reg_fields = omap2_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields),
 
@@ -244,7 +277,7 @@ static struct omap_dss_features omap2_dss_features = {
 };
 
 /* OMAP3 DSS Features */
-static struct omap_dss_features omap3430_dss_features = {
+static const struct omap_dss_features omap3430_dss_features = {
        .reg_fields = omap3_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
@@ -252,7 +285,8 @@ static struct omap_dss_features omap3430_dss_features = {
                FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL |
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
                FEAT_FUNCGATED | FEAT_ROWREPEATENABLE |
-               FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF,
+               FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF |
+               FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC,
 
        .num_mgrs = 2,
        .num_ovls = 3,
@@ -262,7 +296,7 @@ static struct omap_dss_features omap3430_dss_features = {
        .dss_params = omap3_dss_param_range,
 };
 
-static struct omap_dss_features omap3630_dss_features = {
+static const struct omap_dss_features omap3630_dss_features = {
        .reg_fields = omap3_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
 
@@ -271,7 +305,8 @@ static struct omap_dss_features omap3630_dss_features = {
                FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
                FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
                FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
-               FEAT_RESIZECONF,
+               FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG |
+               FEAT_DSI_PLL_FREQSEL,
 
        .num_mgrs = 2,
        .num_ovls = 3,
@@ -282,19 +317,43 @@ static struct omap_dss_features omap3630_dss_features = {
 };
 
 /* OMAP4 DSS Features */
-static struct omap_dss_features omap4_dss_features = {
+/* For OMAP4430 ES 1.0 revision */
+static const struct omap_dss_features omap4430_es1_0_dss_features  = {
        .reg_fields = omap4_dss_reg_fields,
        .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
 
        .has_feature    =
                FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
                FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
-               FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC,
+               FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
+               FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
+               FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
 
        .num_mgrs = 3,
        .num_ovls = 3,
        .supported_displays = omap4_dss_supported_displays,
-       .supported_color_modes = omap3_dss_supported_color_modes,
+       .supported_color_modes = omap4_dss_supported_color_modes,
+       .clksrc_names = omap4_dss_clk_source_names,
+       .dss_params = omap4_dss_param_range,
+};
+
+/* For all the other OMAP4 versions */
+static const struct omap_dss_features omap4_dss_features = {
+       .reg_fields = omap4_dss_reg_fields,
+       .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields),
+
+       .has_feature    =
+               FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
+               FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
+               FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
+               FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
+               FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE |
+               FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2,
+
+       .num_mgrs = 3,
+       .num_ovls = 3,
+       .supported_displays = omap4_dss_supported_displays,
+       .supported_color_modes = omap4_dss_supported_color_modes,
        .clksrc_names = omap4_dss_clk_source_names,
        .dss_params = omap4_dss_param_range,
 };
@@ -337,7 +396,7 @@ bool dss_feat_color_mode_supported(enum omap_plane plane,
                        color_mode;
 }
 
-const char *dss_feat_get_clk_source_name(enum dss_clk_source id)
+const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id)
 {
        return omap_current_dss_features->clksrc_names[id];
 }
@@ -365,6 +424,10 @@ void dss_features_init(void)
                omap_current_dss_features = &omap3630_dss_features;
        else if (cpu_is_omap34xx())
                omap_current_dss_features = &omap3430_dss_features;
-       else
+       else if (omap_rev() == OMAP4430_REV_ES1_0)
+               omap_current_dss_features = &omap4430_es1_0_dss_features;
+       else if (cpu_is_omap44xx())
                omap_current_dss_features = &omap4_dss_features;
+       else
+               DSSWARN("Unsupported OMAP version");
 }
index 12e9c4ef0dec4426fb0197c62559152f623ef703..07b346f7d916569d5c84d0d901b3f4d911dcf299 100644 (file)
 #define MAX_DSS_MANAGERS       3
 #define MAX_DSS_OVERLAYS       3
 #define MAX_DSS_LCD_MANAGERS   2
+#define MAX_NUM_DSI            2
 
 /* DSS has feature id */
 enum dss_feat_id {
-       FEAT_GLOBAL_ALPHA       = 1 << 0,
-       FEAT_GLOBAL_ALPHA_VID1  = 1 << 1,
-       FEAT_PRE_MULT_ALPHA     = 1 << 2,
-       FEAT_LCDENABLEPOL       = 1 << 3,
-       FEAT_LCDENABLESIGNAL    = 1 << 4,
-       FEAT_PCKFREEENABLE      = 1 << 5,
-       FEAT_FUNCGATED          = 1 << 6,
-       FEAT_MGR_LCD2           = 1 << 7,
-       FEAT_LINEBUFFERSPLIT    = 1 << 8,
-       FEAT_ROWREPEATENABLE    = 1 << 9,
-       FEAT_RESIZECONF         = 1 << 10,
+       FEAT_GLOBAL_ALPHA               = 1 << 0,
+       FEAT_GLOBAL_ALPHA_VID1          = 1 << 1,
+       FEAT_PRE_MULT_ALPHA             = 1 << 2,
+       FEAT_LCDENABLEPOL               = 1 << 3,
+       FEAT_LCDENABLESIGNAL            = 1 << 4,
+       FEAT_PCKFREEENABLE              = 1 << 5,
+       FEAT_FUNCGATED                  = 1 << 6,
+       FEAT_MGR_LCD2                   = 1 << 7,
+       FEAT_LINEBUFFERSPLIT            = 1 << 8,
+       FEAT_ROWREPEATENABLE            = 1 << 9,
+       FEAT_RESIZECONF                 = 1 << 10,
        /* Independent core clk divider */
-       FEAT_CORE_CLK_DIV       = 1 << 11,
-       FEAT_LCD_CLK_SRC        = 1 << 12,
+       FEAT_CORE_CLK_DIV               = 1 << 11,
+       FEAT_LCD_CLK_SRC                = 1 << 12,
+       /* DSI-PLL power command 0x3 is not working */
+       FEAT_DSI_PLL_PWR_BUG            = 1 << 13,
+       FEAT_DSI_PLL_FREQSEL            = 1 << 14,
+       FEAT_DSI_DCS_CMD_CONFIG_VC      = 1 << 15,
+       FEAT_DSI_VC_OCP_WIDTH           = 1 << 16,
+       FEAT_DSI_REVERSE_TXCLKESC       = 1 << 17,
+       FEAT_DSI_GNQ                    = 1 << 18,
+       FEAT_HDMI_CTS_SWMODE            = 1 << 19,
+       FEAT_HANDLE_UV_SEPARATE         = 1 << 20,
+       FEAT_ATTR2                      = 1 << 21,
 };
 
 /* DSS register field id */
@@ -77,7 +88,7 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel
 enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane);
 bool dss_feat_color_mode_supported(enum omap_plane plane,
                enum omap_color_mode color_mode);
-const char *dss_feat_get_clk_source_name(enum dss_clk_source id);
+const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id);
 
 bool dss_has_feature(enum dss_feat_id id);
 void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
index a981def8099ad99ef761a28392bd229de234750d..b0555f4f0a78b534c52cd427d871603d3424969f 100644 (file)
 #include <linux/mutex.h>
 #include <linux/delay.h>
 #include <linux/string.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#endif
 
 #include "dss.h"
 #include "hdmi.h"
+#include "dss_features.h"
 
 static struct {
        struct mutex lock;
@@ -1052,25 +1058,26 @@ static void update_hdmi_timings(struct hdmi_config *cfg,
        cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol;
 }
 
-static void hdmi_compute_pll(unsigned long clkin, int phy,
-       int n, struct hdmi_pll_info *pi)
+static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy,
+               struct hdmi_pll_info *pi)
 {
-       unsigned long refclk;
+       unsigned long clkin, refclk;
        u32 mf;
 
+       clkin = dss_clk_get_rate(DSS_CLK_SYSCK) / 10000;
        /*
         * Input clock is predivided by N + 1
         * out put of which is reference clk
         */
-       refclk = clkin / (n + 1);
-       pi->regn = n;
+       pi->regn = dssdev->clocks.hdmi.regn;
+       refclk = clkin / (pi->regn + 1);
 
        /*
         * multiplier is pixel_clk/ref_clk
         * Multiplying by 100 to avoid fractional part removal
         */
-       pi->regm = (phy * 100/(refclk))/100;
-       pi->regm2 = 1;
+       pi->regm = (phy * 100 / (refclk)) / 100;
+       pi->regm2 = dssdev->clocks.hdmi.regm2;
 
        /*
         * fractional multiplier is remainder of the difference between
@@ -1078,14 +1085,14 @@ static void hdmi_compute_pll(unsigned long clkin, int phy,
         * multiplied by 2^18(262144) divided by the reference clock
         */
        mf = (phy - pi->regm * refclk) * 262144;
-       pi->regmf = mf/(refclk);
+       pi->regmf = mf / (refclk);
 
        /*
         * Dcofreq should be set to 1 if required pixel clock
         * is greater than 1000MHz
         */
        pi->dcofreq = phy > 1000 * 100;
-       pi->regsd = ((pi->regm * clkin / 10) / ((n + 1) * 250) + 5) / 10;
+       pi->regsd = ((pi->regm * clkin / 10) / ((pi->regn + 1) * 250) + 5) / 10;
 
        DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
        DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
@@ -1106,7 +1113,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        int r, code = 0;
        struct hdmi_pll_info pll_data;
        struct omap_video_timings *p;
-       int clkin, n, phy;
+       unsigned long phy;
 
        hdmi_enable_clocks(1);
 
@@ -1126,11 +1133,9 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
        dssdev->panel.timings = cea_vesa_timings[code].timings;
        update_hdmi_timings(&hdmi.cfg, p, code);
 
-       clkin = 3840; /* 38.4 MHz */
-       n = 15; /* this is a constant for our math */
        phy = p->pixel_clock;
 
-       hdmi_compute_pll(clkin, phy, n, &pll_data);
+       hdmi_compute_pll(dssdev, phy, &pll_data);
 
        hdmi_wp_video_start(0);
 
@@ -1160,7 +1165,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev)
         * dynamically by user. This can be moved to single location , say
         * Boardfile.
         */
-       dss_select_dispc_clk_source(DSS_CLK_SRC_FCK);
+       dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
 
        /* bypass TV gamma table */
        dispc_enable_gamma_table(0);
@@ -1275,10 +1280,420 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
        mutex_unlock(&hdmi.lock);
 }
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+static void hdmi_wp_audio_config_format(
+               struct hdmi_audio_format *aud_fmt)
+{
+       u32 r;
+
+       DSSDBG("Enter hdmi_wp_audio_config_format\n");
+
+       r = hdmi_read_reg(HDMI_WP_AUDIO_CFG);
+       r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
+       r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+       r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
+       r = FLD_MOD(r, aud_fmt->type, 4, 4);
+       r = FLD_MOD(r, aud_fmt->justification, 3, 3);
+       r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
+       r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
+       r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
+       hdmi_write_reg(HDMI_WP_AUDIO_CFG, r);
+}
+
+static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma)
+{
+       u32 r;
+
+       DSSDBG("Enter hdmi_wp_audio_config_dma\n");
+
+       r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2);
+       r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
+       r = FLD_MOD(r, aud_dma->block_size, 7, 0);
+       hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r);
+
+       r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL);
+       r = FLD_MOD(r, aud_dma->mode, 9, 9);
+       r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
+       hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r);
+}
+
+static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg)
+{
+       u32 r;
+
+       /* audio clock recovery parameters */
+       r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL);
+       r = FLD_MOD(r, cfg->use_mclk, 2, 2);
+       r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
+       r = FLD_MOD(r, cfg->cts_mode, 0, 0);
+       hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r);
+
+       REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
+       REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
+       REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
+
+       if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) {
+               REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
+               REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
+               REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
+       } else {
+               /*
+                * HDMI IP uses this configuration to divide the MCLK to
+                * update CTS value.
+                */
+               REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
+
+               /* Configure clock for audio packets */
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
+                       cfg->aud_par_busclk, 7, 0);
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
+                       (cfg->aud_par_busclk >> 8), 7, 0);
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
+                       (cfg->aud_par_busclk >> 16), 7, 0);
+       }
+
+       /* Override of SPDIF sample frequency with value in I2S_CHST4 */
+       REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1);
+
+       /* I2S parameters */
+       REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0);
+
+       r = hdmi_read_reg(HDMI_CORE_AV_I2S_IN_CTRL);
+       r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7);
+       r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
+       r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5);
+       r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
+       r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3);
+       r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
+       r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
+       r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
+       hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r);
+
+       r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5);
+       r = FLD_MOD(r, cfg->freq_sample, 7, 4);
+       r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1);
+       r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0);
+       hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r);
+
+       REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0);
+
+       /* Audio channels and mode parameters */
+       REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
+       r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE);
+       r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4);
+       r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3);
+       r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
+       r = FLD_MOD(r, cfg->en_spdif, 1, 1);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r);
+}
+
+static void hdmi_core_audio_infoframe_config(
+               struct hdmi_core_infoframe_audio *info_aud)
+{
+       u8 val;
+       u8 sum = 0, checksum = 0;
+
+       /*
+        * Set audio info frame type, version and length as
+        * described in HDMI 1.4a Section 8.2.2 specification.
+        * Checksum calculation is defined in Section 5.3.5.
+        */
+       hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84);
+       hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01);
+       hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a);
+       sum += 0x84 + 0x001 + 0x00a;
+
+       val = (info_aud->db1_coding_type << 4)
+                       | (info_aud->db1_channel_count - 1);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val);
+       sum += val;
+
+       val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size;
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val);
+       sum += val;
+
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00);
+
+       val = info_aud->db4_channel_alloc;
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val);
+       sum += val;
+
+       val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val);
+       sum += val;
+
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
+       hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
+
+       checksum = 0x100 - sum;
+       hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum);
+
+       /*
+        * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
+        * is available.
+        */
+}
+
+static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts)
+{
+       u32 r;
+       u32 deep_color = 0;
+       u32 pclk = hdmi.cfg.timings.timings.pixel_clock;
+
+       if (n == NULL || cts == NULL)
+               return -EINVAL;
+       /*
+        * Obtain current deep color configuration. This needed
+        * to calculate the TMDS clock based on the pixel clock.
+        */
+       r = REG_GET(HDMI_WP_VIDEO_CFG, 1, 0);
+       switch (r) {
+       case 1: /* No deep color selected */
+               deep_color = 100;
+               break;
+       case 2: /* 10-bit deep color selected */
+               deep_color = 125;
+               break;
+       case 3: /* 12-bit deep color selected */
+               deep_color = 150;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (sample_freq) {
+       case 32000:
+               if ((deep_color == 125) && ((pclk == 54054)
+                               || (pclk == 74250)))
+                       *n = 8192;
+               else
+                       *n = 4096;
+               break;
+       case 44100:
+               *n = 6272;
+               break;
+       case 48000:
+               if ((deep_color == 125) && ((pclk == 54054)
+                               || (pclk == 74250)))
+                       *n = 8192;
+               else
+                       *n = 6144;
+               break;
+       default:
+               *n = 0;
+               return -EINVAL;
+       }
+
+       /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
+       *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
+
+       return 0;
+}
+
+static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
+                                   struct snd_pcm_hw_params *params,
+                                   struct snd_soc_dai *dai)
+{
+       struct hdmi_audio_format audio_format;
+       struct hdmi_audio_dma audio_dma;
+       struct hdmi_core_audio_config core_cfg;
+       struct hdmi_core_infoframe_audio aud_if_cfg;
+       int err, n, cts;
+       enum hdmi_core_audio_sample_freq sample_freq;
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               core_cfg.i2s_cfg.word_max_length =
+                       HDMI_AUDIO_I2S_MAX_WORD_20BITS;
+               core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS;
+               core_cfg.i2s_cfg.in_length_bits =
+                       HDMI_AUDIO_I2S_INPUT_LENGTH_16;
+               core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+               audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
+               audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
+               audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+               audio_dma.transfer_size = 0x10;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               core_cfg.i2s_cfg.word_max_length =
+                       HDMI_AUDIO_I2S_MAX_WORD_24BITS;
+               core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS;
+               core_cfg.i2s_cfg.in_length_bits =
+                       HDMI_AUDIO_I2S_INPUT_LENGTH_24;
+               audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE;
+               audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS;
+               audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+               core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT;
+               audio_dma.transfer_size = 0x20;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params_rate(params)) {
+       case 32000:
+               sample_freq = HDMI_AUDIO_FS_32000;
+               break;
+       case 44100:
+               sample_freq = HDMI_AUDIO_FS_44100;
+               break;
+       case 48000:
+               sample_freq = HDMI_AUDIO_FS_48000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       err = hdmi_config_audio_acr(params_rate(params), &n, &cts);
+       if (err < 0)
+               return err;
+
+       /* Audio wrapper config */
+       audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL;
+       audio_format.active_chnnls_msk = 0x03;
+       audio_format.type = HDMI_AUDIO_TYPE_LPCM;
+       audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+       /* Disable start/stop signals of IEC 60958 blocks */
+       audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF;
+
+       audio_dma.block_size = 0xC0;
+       audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
+       audio_dma.fifo_threshold = 0x20; /* in number of samples */
+
+       hdmi_wp_audio_config_dma(&audio_dma);
+       hdmi_wp_audio_config_format(&audio_format);
+
+       /*
+        * I2S config
+        */
+       core_cfg.i2s_cfg.en_high_bitrate_aud = false;
+       /* Only used with high bitrate audio */
+       core_cfg.i2s_cfg.cbit_order = false;
+       /* Serial data and word select should change on sck rising edge */
+       core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING;
+       core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM;
+       /* Set I2S word select polarity */
+       core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT;
+       core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST;
+       /* Set serial data to word select shift. See Phillips spec. */
+       core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT;
+       /* Enable one of the four available serial data channels */
+       core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN;
+
+       /* Core audio config */
+       core_cfg.freq_sample = sample_freq;
+       core_cfg.n = n;
+       core_cfg.cts = cts;
+       if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) {
+               core_cfg.aud_par_busclk = 0;
+               core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
+               core_cfg.use_mclk = false;
+       } else {
+               core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8);
+               core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
+               core_cfg.use_mclk = true;
+               core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS;
+       }
+       core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
+       core_cfg.en_spdif = false;
+       /* Use sample frequency from channel status word */
+       core_cfg.fs_override = true;
+       /* Enable ACR packets */
+       core_cfg.en_acr_pkt = true;
+       /* Disable direct streaming digital audio */
+       core_cfg.en_dsd_audio = false;
+       /* Use parallel audio interface */
+       core_cfg.en_parallel_aud_input = true;
+
+       hdmi_core_audio_config(&core_cfg);
+
+       /*
+        * Configure packet
+        * info frame audio see doc CEA861-D page 74
+        */
+       aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM;
+       aud_if_cfg.db1_channel_count = 2;
+       aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM;
+       aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM;
+       aud_if_cfg.db4_channel_alloc = 0x00;
+       aud_if_cfg.db5_downmix_inh = false;
+       aud_if_cfg.db5_lsv = 0;
+
+       hdmi_core_audio_infoframe_config(&aud_if_cfg);
+       return 0;
+}
+
+static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd,
+                                 struct snd_soc_dai *dai)
+{
+       int err = 0;
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0);
+               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31);
+               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0);
+               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30);
+               REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31);
+               break;
+       default:
+               err = -EINVAL;
+       }
+       return err;
+}
+
+static int hdmi_audio_startup(struct snd_pcm_substream *substream,
+                                 struct snd_soc_dai *dai)
+{
+       if (!hdmi.mode) {
+               pr_err("Current video settings do not support audio.\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static struct snd_soc_codec_driver hdmi_audio_codec_drv = {
+};
+
+static struct snd_soc_dai_ops hdmi_audio_codec_ops = {
+       .hw_params = hdmi_audio_hw_params,
+       .trigger = hdmi_audio_trigger,
+       .startup = hdmi_audio_startup,
+};
+
+static struct snd_soc_dai_driver hdmi_codec_dai_drv = {
+               .name = "hdmi-audio-codec",
+               .playback = {
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = SNDRV_PCM_RATE_32000 |
+                               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                               SNDRV_PCM_FMTBIT_S24_LE,
+               },
+               .ops = &hdmi_audio_codec_ops,
+};
+#endif
+
 /* HDMI HW IP initialisation */
 static int omapdss_hdmihw_probe(struct platform_device *pdev)
 {
        struct resource *hdmi_mem;
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+       int ret;
+#endif
 
        hdmi.pdata = pdev->dev.platform_data;
        hdmi.pdev = pdev;
@@ -1300,6 +1715,17 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
 
        hdmi_panel_init();
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+
+       /* Register ASoC codec DAI */
+       ret = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv,
+                                       &hdmi_codec_dai_drv, 1);
+       if (ret) {
+               DSSERR("can't register ASoC HDMI audio codec\n");
+               return ret;
+       }
+#endif
        return 0;
 }
 
@@ -1307,6 +1733,11 @@ static int omapdss_hdmihw_remove(struct platform_device *pdev)
 {
        hdmi_panel_exit();
 
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+       defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+       snd_soc_unregister_codec(&pdev->dev);
+#endif
+
        iounmap(hdmi.base_wp);
 
        return 0;
index 9887ab96da3c563a908fa510441201c8c0d0b255..c885f9cb0659154b80b67f9a35e57004066b88f0 100644 (file)
@@ -22,7 +22,7 @@
 #define _OMAP4_DSS_HDMI_H_
 
 #include <linux/string.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #define HDMI_WP                0x0
 #define HDMI_CORE_SYS          0x400
@@ -48,6 +48,10 @@ struct hdmi_reg { u16 idx; };
 #define HDMI_WP_VIDEO_TIMING_H                 HDMI_WP_REG(0x68)
 #define HDMI_WP_VIDEO_TIMING_V                 HDMI_WP_REG(0x6C)
 #define HDMI_WP_WP_CLK                         HDMI_WP_REG(0x70)
+#define HDMI_WP_AUDIO_CFG                      HDMI_WP_REG(0x80)
+#define HDMI_WP_AUDIO_CFG2                     HDMI_WP_REG(0x84)
+#define HDMI_WP_AUDIO_CTRL                     HDMI_WP_REG(0x88)
+#define HDMI_WP_AUDIO_DATA                     HDMI_WP_REG(0x8C)
 
 /* HDMI IP Core System */
 #define HDMI_CORE_SYS_REG(idx)                 HDMI_REG(HDMI_CORE_SYS + idx)
@@ -105,6 +109,8 @@ struct hdmi_reg { u16 idx; };
 #define HDMI_CORE_AV_AVI_DBYTE_NELEMS          HDMI_CORE_AV_REG(15)
 #define HDMI_CORE_AV_SPD_DBYTE                 HDMI_CORE_AV_REG(0x190)
 #define HDMI_CORE_AV_SPD_DBYTE_NELEMS          HDMI_CORE_AV_REG(27)
+#define HDMI_CORE_AV_AUD_DBYTE(n)              HDMI_CORE_AV_REG(n * 4 + 0x210)
+#define HDMI_CORE_AV_AUD_DBYTE_NELEMS          HDMI_CORE_AV_REG(10)
 #define HDMI_CORE_AV_MPEG_DBYTE                HDMI_CORE_AV_REG(0x290)
 #define HDMI_CORE_AV_MPEG_DBYTE_NELEMS         HDMI_CORE_AV_REG(27)
 #define HDMI_CORE_AV_GEN_DBYTE                 HDMI_CORE_AV_REG(0x300)
@@ -153,6 +159,10 @@ struct hdmi_reg { u16 idx; };
 #define HDMI_CORE_AV_SPD_VERS                  HDMI_CORE_AV_REG(0x184)
 #define HDMI_CORE_AV_SPD_LEN                   HDMI_CORE_AV_REG(0x188)
 #define HDMI_CORE_AV_SPD_CHSUM                 HDMI_CORE_AV_REG(0x18C)
+#define HDMI_CORE_AV_AUDIO_TYPE                HDMI_CORE_AV_REG(0x200)
+#define HDMI_CORE_AV_AUDIO_VERS                HDMI_CORE_AV_REG(0x204)
+#define HDMI_CORE_AV_AUDIO_LEN                 HDMI_CORE_AV_REG(0x208)
+#define HDMI_CORE_AV_AUDIO_CHSUM               HDMI_CORE_AV_REG(0x20C)
 #define HDMI_CORE_AV_MPEG_TYPE                 HDMI_CORE_AV_REG(0x280)
 #define HDMI_CORE_AV_MPEG_VERS                 HDMI_CORE_AV_REG(0x284)
 #define HDMI_CORE_AV_MPEG_LEN                  HDMI_CORE_AV_REG(0x288)
@@ -272,7 +282,7 @@ enum hdmi_core_packet_ctrl {
        HDMI_PACKETREPEATOFF = 0
 };
 
-/* INFOFRAME_AVI_ definitions */
+/* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */
 enum hdmi_core_infoframe {
        HDMI_INFOFRAME_AVI_DB1Y_RGB = 0,
        HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1,
@@ -317,7 +327,36 @@ enum hdmi_core_infoframe {
        HDMI_INFOFRAME_AVI_DB5PR_7 = 6,
        HDMI_INFOFRAME_AVI_DB5PR_8 = 7,
        HDMI_INFOFRAME_AVI_DB5PR_9 = 8,
-       HDMI_INFOFRAME_AVI_DB5PR_10 = 9
+       HDMI_INFOFRAME_AVI_DB5PR_10 = 9,
+       HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM = 0,
+       HDMI_INFOFRAME_AUDIO_DB1CT_IEC60958 = 1,
+       HDMI_INFOFRAME_AUDIO_DB1CT_AC3 = 2,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG1 = 3,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MP3 = 4,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MPEG2_MULTICH = 5,
+       HDMI_INFOFRAME_AUDIO_DB1CT_AAC = 6,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DTS = 7,
+       HDMI_INFOFRAME_AUDIO_DB1CT_ATRAC = 8,
+       HDMI_INFOFRAME_AUDIO_DB1CT_ONEBIT = 9,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DOLBY_DIGITAL_PLUS = 10,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DTS_HD = 11,
+       HDMI_INFOFRAME_AUDIO_DB1CT_MAT = 12,
+       HDMI_INFOFRAME_AUDIO_DB1CT_DST = 13,
+       HDMI_INFOFRAME_AUDIO_DB1CT_WMA_PRO = 14,
+       HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM = 0,
+       HDMI_INFOFRAME_AUDIO_DB2SF_32000 = 1,
+       HDMI_INFOFRAME_AUDIO_DB2SF_44100 = 2,
+       HDMI_INFOFRAME_AUDIO_DB2SF_48000 = 3,
+       HDMI_INFOFRAME_AUDIO_DB2SF_88200 = 4,
+       HDMI_INFOFRAME_AUDIO_DB2SF_96000 = 5,
+       HDMI_INFOFRAME_AUDIO_DB2SF_176400 = 6,
+       HDMI_INFOFRAME_AUDIO_DB2SF_192000 = 7,
+       HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM = 0,
+       HDMI_INFOFRAME_AUDIO_DB2SS_16BIT = 1,
+       HDMI_INFOFRAME_AUDIO_DB2SS_20BIT = 2,
+       HDMI_INFOFRAME_AUDIO_DB2SS_24BIT = 3,
+       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PERMITTED = 0,
+       HDMI_INFOFRAME_AUDIO_DB5_DM_INH_PROHIBITED = 1
 };
 
 enum hdmi_packing_mode {
@@ -327,6 +366,121 @@ enum hdmi_packing_mode {
        HDMI_PACK_ALREADYPACKED = 7
 };
 
+enum hdmi_core_audio_sample_freq {
+       HDMI_AUDIO_FS_32000 = 0x3,
+       HDMI_AUDIO_FS_44100 = 0x0,
+       HDMI_AUDIO_FS_48000 = 0x2,
+       HDMI_AUDIO_FS_88200 = 0x8,
+       HDMI_AUDIO_FS_96000 = 0xA,
+       HDMI_AUDIO_FS_176400 = 0xC,
+       HDMI_AUDIO_FS_192000 = 0xE,
+       HDMI_AUDIO_FS_NOT_INDICATED = 0x1
+};
+
+enum hdmi_core_audio_layout {
+       HDMI_AUDIO_LAYOUT_2CH = 0,
+       HDMI_AUDIO_LAYOUT_8CH = 1
+};
+
+enum hdmi_core_cts_mode {
+       HDMI_AUDIO_CTS_MODE_HW = 0,
+       HDMI_AUDIO_CTS_MODE_SW = 1
+};
+
+enum hdmi_stereo_channels {
+       HDMI_AUDIO_STEREO_NOCHANNELS = 0,
+       HDMI_AUDIO_STEREO_ONECHANNEL = 1,
+       HDMI_AUDIO_STEREO_TWOCHANNELS = 2,
+       HDMI_AUDIO_STEREO_THREECHANNELS = 3,
+       HDMI_AUDIO_STEREO_FOURCHANNELS = 4
+};
+
+enum hdmi_audio_type {
+       HDMI_AUDIO_TYPE_LPCM = 0,
+       HDMI_AUDIO_TYPE_IEC = 1
+};
+
+enum hdmi_audio_justify {
+       HDMI_AUDIO_JUSTIFY_LEFT = 0,
+       HDMI_AUDIO_JUSTIFY_RIGHT = 1
+};
+
+enum hdmi_audio_sample_order {
+       HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0,
+       HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1
+};
+
+enum hdmi_audio_samples_perword {
+       HDMI_AUDIO_ONEWORD_ONESAMPLE = 0,
+       HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1
+};
+
+enum hdmi_audio_sample_size {
+       HDMI_AUDIO_SAMPLE_16BITS = 0,
+       HDMI_AUDIO_SAMPLE_24BITS = 1
+};
+
+enum hdmi_audio_transf_mode {
+       HDMI_AUDIO_TRANSF_DMA = 0,
+       HDMI_AUDIO_TRANSF_IRQ = 1
+};
+
+enum hdmi_audio_blk_strt_end_sig {
+       HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0,
+       HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1
+};
+
+enum hdmi_audio_i2s_config {
+       HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT = 0,
+       HDMI_AUDIO_I2S_WS_POLARIT_YLOW_IS_RIGHT = 1,
+       HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0,
+       HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1,
+       HDMI_AUDIO_I2S_MAX_WORD_20BITS = 0,
+       HDMI_AUDIO_I2S_MAX_WORD_24BITS = 1,
+       HDMI_AUDIO_I2S_CHST_WORD_NOT_SPECIFIED = 0,
+       HDMI_AUDIO_I2S_CHST_WORD_16_BITS = 1,
+       HDMI_AUDIO_I2S_CHST_WORD_17_BITS = 6,
+       HDMI_AUDIO_I2S_CHST_WORD_18_BITS = 2,
+       HDMI_AUDIO_I2S_CHST_WORD_19_BITS = 4,
+       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_20MAX = 5,
+       HDMI_AUDIO_I2S_CHST_WORD_20_BITS_24MAX = 1,
+       HDMI_AUDIO_I2S_CHST_WORD_21_BITS = 6,
+       HDMI_AUDIO_I2S_CHST_WORD_22_BITS = 2,
+       HDMI_AUDIO_I2S_CHST_WORD_23_BITS = 4,
+       HDMI_AUDIO_I2S_CHST_WORD_24_BITS = 5,
+       HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0,
+       HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1,
+       HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0,
+       HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_NA = 0,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_16 = 2,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_17 = 12,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_18 = 4,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_19 = 8,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_20 = 10,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_21 = 13,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_22 = 5,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_23 = 9,
+       HDMI_AUDIO_I2S_INPUT_LENGTH_24 = 11,
+       HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0,
+       HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1,
+       HDMI_AUDIO_I2S_SD0_EN = 1,
+       HDMI_AUDIO_I2S_SD1_EN = 1 << 1,
+       HDMI_AUDIO_I2S_SD2_EN = 1 << 2,
+       HDMI_AUDIO_I2S_SD3_EN = 1 << 3,
+};
+
+enum hdmi_audio_mclk_mode {
+       HDMI_AUDIO_MCLK_128FS = 0,
+       HDMI_AUDIO_MCLK_256FS = 1,
+       HDMI_AUDIO_MCLK_384FS = 2,
+       HDMI_AUDIO_MCLK_512FS = 3,
+       HDMI_AUDIO_MCLK_768FS = 4,
+       HDMI_AUDIO_MCLK_1024FS = 5,
+       HDMI_AUDIO_MCLK_1152FS = 6,
+       HDMI_AUDIO_MCLK_192FS = 7
+};
+
 struct hdmi_core_video_config {
        enum hdmi_core_inputbus_width   ip_bus_width;
        enum hdmi_core_dither_trunc     op_dither_truc;
@@ -376,6 +530,19 @@ struct hdmi_core_infoframe_avi {
        u16     db12_13_pixel_sofright;
                /* Pixel number start of right bar */
 };
+/*
+ * Refer to section 8.2 in HDMI 1.3 specification for
+ * details about infoframe databytes
+ */
+struct hdmi_core_infoframe_audio {
+       u8 db1_coding_type;
+       u8 db1_channel_count;
+       u8 db2_sample_freq;
+       u8 db2_sample_size;
+       u8 db4_channel_alloc;
+       bool db5_downmix_inh;
+       u8 db5_lsv;     /* Level shift values for downmix */
+};
 
 struct hdmi_core_packet_enable_repeat {
        u32     audio_pkt;
@@ -412,4 +579,53 @@ struct hdmi_config {
        struct hdmi_cm cm;
 };
 
+struct hdmi_audio_format {
+       enum hdmi_stereo_channels               stereo_channels;
+       u8                                      active_chnnls_msk;
+       enum hdmi_audio_type                    type;
+       enum hdmi_audio_justify                 justification;
+       enum hdmi_audio_sample_order            sample_order;
+       enum hdmi_audio_samples_perword         samples_per_word;
+       enum hdmi_audio_sample_size             sample_size;
+       enum hdmi_audio_blk_strt_end_sig        en_sig_blk_strt_end;
+};
+
+struct hdmi_audio_dma {
+       u8                              transfer_size;
+       u8                              block_size;
+       enum hdmi_audio_transf_mode     mode;
+       u16                             fifo_threshold;
+};
+
+struct hdmi_core_audio_i2s_config {
+       u8 word_max_length;
+       u8 word_length;
+       u8 in_length_bits;
+       u8 justification;
+       u8 en_high_bitrate_aud;
+       u8 sck_edge_mode;
+       u8 cbit_order;
+       u8 vbit;
+       u8 ws_polarity;
+       u8 direction;
+       u8 shift;
+       u8 active_sds;
+};
+
+struct hdmi_core_audio_config {
+       struct hdmi_core_audio_i2s_config       i2s_cfg;
+       enum hdmi_core_audio_sample_freq        freq_sample;
+       bool                                    fs_override;
+       u32                                     n;
+       u32                                     cts;
+       u32                                     aud_par_busclk;
+       enum hdmi_core_audio_layout             layout;
+       enum hdmi_core_cts_mode                 cts_mode;
+       bool                                    use_mclk;
+       enum hdmi_audio_mclk_mode               mclk_mode;
+       bool                                    en_acr_pkt;
+       bool                                    en_dsd_audio;
+       bool                                    en_parallel_aud_input;
+       bool                                    en_spdif;
+};
 #endif
index ffb5de94131faa402c0ec5a33272918ac44fdda5..7d4f2bd7c50619591cbba2c6fb76bbafaa8ae6a5 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/io.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #include "dss.h"
 
index bcd37ec86952fae81d0327366833503717de520e..9aeea50e33ffd49f5fc6376746c76c950caffc92 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/spinlock.h>
 #include <linux/jiffies.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -393,6 +393,7 @@ struct overlay_cache_data {
 
        u32 paddr;
        void __iomem *vaddr;
+       u32 p_uv_addr; /* relevant for NV12 format only */
        u16 screen_width;
        u16 width;
        u16 height;
@@ -775,10 +776,17 @@ static int configure_overlay(enum omap_plane plane)
                }
 
                switch (c->color_mode) {
+               case OMAP_DSS_COLOR_NV12:
+                       bpp = 8;
+                       break;
                case OMAP_DSS_COLOR_RGB16:
                case OMAP_DSS_COLOR_ARGB16:
                case OMAP_DSS_COLOR_YUV2:
                case OMAP_DSS_COLOR_UYVY:
+               case OMAP_DSS_COLOR_RGBA16:
+               case OMAP_DSS_COLOR_RGBX16:
+               case OMAP_DSS_COLOR_ARGB16_1555:
+               case OMAP_DSS_COLOR_XRGB16_1555:
                        bpp = 16;
                        break;
 
@@ -854,7 +862,8 @@ static int configure_overlay(enum omap_plane plane)
                        c->mirror,
                        c->global_alpha,
                        c->pre_mult_alpha,
-                       c->channel);
+                       c->channel,
+                       c->p_uv_addr);
 
        if (r) {
                /* this shouldn't happen */
@@ -1269,6 +1278,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
 
                oc->paddr = ovl->info.paddr;
                oc->vaddr = ovl->info.vaddr;
+               oc->p_uv_addr = ovl->info.p_uv_addr;
                oc->screen_width = ovl->info.screen_width;
                oc->width = ovl->info.width;
                oc->height = ovl->info.height;
index f1aca6d0401117c9858a4300b5dfe0748a7863e4..0f08025b1f0e95b9e65fb597d0fd63a16609f970 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -201,12 +201,16 @@ static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
 static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
                size_t size)
 {
-       int r;
+       int r, enable;
        struct omap_overlay_info info;
 
        ovl->get_overlay_info(ovl, &info);
 
-       info.enabled = simple_strtoul(buf, NULL, 10);
+       r = kstrtoint(buf, 0, &enable);
+       if (r)
+               return r;
+
+       info.enabled = !!enable;
 
        r = ovl->set_overlay_info(ovl, &info);
        if (r)
@@ -231,8 +235,13 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
                const char *buf, size_t size)
 {
        int r;
+       u8 alpha;
        struct omap_overlay_info info;
 
+       r = kstrtou8(buf, 0, &alpha);
+       if (r)
+               return r;
+
        ovl->get_overlay_info(ovl, &info);
 
        /* Video1 plane does not support global alpha
@@ -242,7 +251,7 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
                        ovl->id == OMAP_DSS_VIDEO1)
                info.global_alpha = 255;
        else
-               info.global_alpha = simple_strtoul(buf, NULL, 10);
+               info.global_alpha = alpha;
 
        r = ovl->set_overlay_info(ovl, &info);
        if (r)
@@ -268,8 +277,13 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
                const char *buf, size_t size)
 {
        int r;
+       u8 alpha;
        struct omap_overlay_info info;
 
+       r = kstrtou8(buf, 0, &alpha);
+       if (r)
+               return r;
+
        ovl->get_overlay_info(ovl, &info);
 
        /* only GFX and Video2 plane support pre alpha multiplied
@@ -279,7 +293,7 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl,
                ovl->id == OMAP_DSS_VIDEO1)
                info.pre_mult_alpha = 0;
        else
-               info.pre_mult_alpha = simple_strtoul(buf, NULL, 10);
+               info.pre_mult_alpha = alpha;
 
        r = ovl->set_overlay_info(ovl, &info);
        if (r)
@@ -491,13 +505,18 @@ static int omap_dss_set_manager(struct omap_overlay *ovl,
        ovl->manager = mgr;
 
        dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK);
-       /* XXX: on manual update display, in auto update mode, a bug happens
-        * here. When an overlay is first enabled on LCD, then it's disabled,
-        * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
-        * errors. Waiting before changing the channel_out fixes it. I'm
-        * guessing that the overlay is still somehow being used for the LCD,
-        * but I don't understand how or why. */
-       msleep(40);
+       /* XXX: When there is an overlay on a DSI manual update display, and
+        * the overlay is first disabled, then moved to tv, and enabled, we
+        * seem to get SYNC_LOST_DIGIT error.
+        *
+        * Waiting doesn't seem to help, but updating the manual update display
+        * after disabling the overlay seems to fix this. This hints that the
+        * overlay is perhaps somehow tied to the LCD output until the output
+        * is updated.
+        *
+        * Userspace workaround for this is to update the LCD after disabling
+        * the overlay, but before moving the overlay to TV.
+        */
        dispc_set_channel_out(ovl->id, mgr->id);
        dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 
index 5ea17f49c6110c3d3703c89b34e5f52e366f67ce..c06fbe0bc6789bee3c32a796b1b9efdb4efc763d 100644 (file)
@@ -32,8 +32,9 @@
 #include <linux/ktime.h>
 #include <linux/hrtimer.h>
 #include <linux/seq_file.h>
+#include <linux/semaphore.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include "dss.h"
 
 struct rfbi_reg { u16 idx; };
@@ -65,9 +66,6 @@ struct rfbi_reg { u16 idx; };
 #define REG_FLD_MOD(idx, val, start, end) \
        rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
 
-/* To work around an RFBI transfer rate limitation */
-#define OMAP_RFBI_RATE_LIMIT    1
-
 enum omap_rfbi_cycleformat {
        OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
        OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
@@ -89,11 +87,6 @@ enum omap_rfbi_parallelmode {
        OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
 };
 
-enum update_cmd {
-       RFBI_CMD_UPDATE = 0,
-       RFBI_CMD_SYNC   = 1,
-};
-
 static int rfbi_convert_timings(struct rfbi_timings *t);
 static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
 
@@ -114,20 +107,9 @@ static struct {
 
        struct omap_dss_device *dssdev[2];
 
-       struct kfifo      cmd_fifo;
-       spinlock_t        cmd_lock;
-       struct completion cmd_done;
-       atomic_t          cmd_fifo_full;
-       atomic_t          cmd_pending;
+       struct semaphore bus_lock;
 } rfbi;
 
-struct update_region {
-       u16     x;
-       u16     y;
-       u16     w;
-       u16     h;
-};
-
 static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
 {
        __raw_writel(val, rfbi.base + idx.idx);
@@ -146,9 +128,20 @@ static void rfbi_enable_clocks(bool enable)
                dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK);
 }
 
+void rfbi_bus_lock(void)
+{
+       down(&rfbi.bus_lock);
+}
+EXPORT_SYMBOL(rfbi_bus_lock);
+
+void rfbi_bus_unlock(void)
+{
+       up(&rfbi.bus_lock);
+}
+EXPORT_SYMBOL(rfbi_bus_unlock);
+
 void omap_rfbi_write_command(const void *buf, u32 len)
 {
-       rfbi_enable_clocks(1);
        switch (rfbi.parallelmode) {
        case OMAP_DSS_RFBI_PARALLELMODE_8:
        {
@@ -172,13 +165,11 @@ void omap_rfbi_write_command(const void *buf, u32 len)
        default:
                BUG();
        }
-       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_write_command);
 
 void omap_rfbi_read_data(void *buf, u32 len)
 {
-       rfbi_enable_clocks(1);
        switch (rfbi.parallelmode) {
        case OMAP_DSS_RFBI_PARALLELMODE_8:
        {
@@ -206,13 +197,11 @@ void omap_rfbi_read_data(void *buf, u32 len)
        default:
                BUG();
        }
-       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_read_data);
 
 void omap_rfbi_write_data(const void *buf, u32 len)
 {
-       rfbi_enable_clocks(1);
        switch (rfbi.parallelmode) {
        case OMAP_DSS_RFBI_PARALLELMODE_8:
        {
@@ -237,7 +226,6 @@ void omap_rfbi_write_data(const void *buf, u32 len)
                BUG();
 
        }
-       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_write_data);
 
@@ -249,8 +237,6 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
        int horiz_offset = scr_width - w;
        int i;
 
-       rfbi_enable_clocks(1);
-
        if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
           rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
                const u16 __iomem *pd = buf;
@@ -295,12 +281,10 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
        } else {
                BUG();
        }
-
-       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omap_rfbi_write_pixels);
 
-void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
+static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
                u16 height, void (*callback)(void *data), void *data)
 {
        u32 l;
@@ -317,8 +301,6 @@ void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width,
        rfbi.framedone_callback = callback;
        rfbi.framedone_callback_data = data;
 
-       rfbi_enable_clocks(1);
-
        rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
 
        l = rfbi_read_reg(RFBI_CONTROL);
@@ -337,15 +319,11 @@ static void framedone_callback(void *data, u32 mask)
 
        REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
 
-       rfbi_enable_clocks(0);
-
        callback = rfbi.framedone_callback;
        rfbi.framedone_callback = NULL;
 
        if (callback != NULL)
                callback(rfbi.framedone_callback_data);
-
-       atomic_set(&rfbi.cmd_pending, 0);
 }
 
 #if 1 /* VERBOSE */
@@ -435,7 +413,7 @@ static int calc_extif_timings(struct rfbi_timings *t)
 }
 
 
-void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
+static void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
 {
        int r;
 
@@ -447,7 +425,6 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
 
        BUG_ON(!t->converted);
 
-       rfbi_enable_clocks(1);
        rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
        rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
 
@@ -456,7 +433,6 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
                    (t->tim[2] ? 1 : 0), 4, 4);
 
        rfbi_print_timings();
-       rfbi_enable_clocks(0);
 }
 
 static int ps_to_rfbi_ticks(int time, int div)
@@ -472,59 +448,6 @@ static int ps_to_rfbi_ticks(int time, int div)
        return ret;
 }
 
-#ifdef OMAP_RFBI_RATE_LIMIT
-unsigned long rfbi_get_max_tx_rate(void)
-{
-       unsigned long   l4_rate, dss1_rate;
-       int             min_l4_ticks = 0;
-       int             i;
-
-       /* According to TI this can't be calculated so make the
-        * adjustments for a couple of known frequencies and warn for
-        * others.
-        */
-       static const struct {
-               unsigned long l4_clk;           /* HZ */
-               unsigned long dss1_clk;         /* HZ */
-               unsigned long min_l4_ticks;
-       } ftab[] = {
-               { 55,   132,    7, },           /* 7.86 MPix/s */
-               { 110,  110,    12, },          /* 9.16 MPix/s */
-               { 110,  132,    10, },          /* 11   Mpix/s */
-               { 120,  120,    10, },          /* 12   Mpix/s */
-               { 133,  133,    10, },          /* 13.3 Mpix/s */
-       };
-
-       l4_rate = rfbi.l4_khz / 1000;
-       dss1_rate = dss_clk_get_rate(DSS_CLK_FCK) / 1000000;
-
-       for (i = 0; i < ARRAY_SIZE(ftab); i++) {
-               /* Use a window instead of an exact match, to account
-                * for different DPLL multiplier / divider pairs.
-                */
-               if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
-                   abs(ftab[i].dss1_clk - dss1_rate) < 3) {
-                       min_l4_ticks = ftab[i].min_l4_ticks;
-                       break;
-               }
-       }
-       if (i == ARRAY_SIZE(ftab)) {
-               /* Can't be sure, return anyway the maximum not
-                * rate-limited. This might cause a problem only for the
-                * tearing synchronisation.
-                */
-               DSSERR("can't determine maximum RFBI transfer rate\n");
-               return rfbi.l4_khz * 1000;
-       }
-       return rfbi.l4_khz * 1000 / min_l4_ticks;
-}
-#else
-int rfbi_get_max_tx_rate(void)
-{
-       return rfbi.l4_khz * 1000;
-}
-#endif
-
 static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
 {
        *clk_period = 1000000000 / rfbi.l4_khz;
@@ -644,7 +567,6 @@ int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
        DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
                mode, hs, vs, hs_pol_inv, vs_pol_inv);
 
-       rfbi_enable_clocks(1);
        rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
        rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
 
@@ -657,7 +579,6 @@ int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
                l &= ~(1 << 20);
        else
                l |= 1 << 20;
-       rfbi_enable_clocks(0);
 
        return 0;
 }
@@ -672,7 +593,6 @@ int omap_rfbi_enable_te(bool enable, unsigned line)
        if (line > (1 << 11) - 1)
                return -EINVAL;
 
-       rfbi_enable_clocks(1);
        l = rfbi_read_reg(RFBI_CONFIG(0));
        l &= ~(0x3 << 2);
        if (enable) {
@@ -682,50 +602,12 @@ int omap_rfbi_enable_te(bool enable, unsigned line)
                rfbi.te_enabled = 0;
        rfbi_write_reg(RFBI_CONFIG(0), l);
        rfbi_write_reg(RFBI_LINE_NUMBER, line);
-       rfbi_enable_clocks(0);
 
        return 0;
 }
 EXPORT_SYMBOL(omap_rfbi_enable_te);
 
-#if 0
-static void rfbi_enable_config(int enable1, int enable2)
-{
-       u32 l;
-       int cs = 0;
-
-       if (enable1)
-               cs |= 1<<0;
-       if (enable2)
-               cs |= 1<<1;
-
-       rfbi_enable_clocks(1);
-
-       l = rfbi_read_reg(RFBI_CONTROL);
-
-       l = FLD_MOD(l, cs, 3, 2);
-       l = FLD_MOD(l, 0, 1, 1);
-
-       rfbi_write_reg(RFBI_CONTROL, l);
-
-
-       l = rfbi_read_reg(RFBI_CONFIG(0));
-       l = FLD_MOD(l, 0, 3, 2); /* TRIGGERMODE: ITE */
-       /*l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
-       /*l |= FLD_VAL(0, 8, 7); */ /* L4FORMAT, 1pix/L4 */
-
-       l = FLD_MOD(l, 0, 16, 16); /* A0POLARITY */
-       l = FLD_MOD(l, 1, 20, 20); /* TE_VSYNC_POLARITY */
-       l = FLD_MOD(l, 1, 21, 21); /* HSYNCPOLARITY */
-
-       l = FLD_MOD(l, OMAP_DSS_RFBI_PARALLELMODE_8, 1, 0);
-       rfbi_write_reg(RFBI_CONFIG(0), l);
-
-       rfbi_enable_clocks(0);
-}
-#endif
-
-int rfbi_configure(int rfbi_module, int bpp, int lines)
+static int rfbi_configure(int rfbi_module, int bpp, int lines)
 {
        u32 l;
        int cycle1 = 0, cycle2 = 0, cycle3 = 0;
@@ -821,8 +703,6 @@ int rfbi_configure(int rfbi_module, int bpp, int lines)
                break;
        }
 
-       rfbi_enable_clocks(1);
-
        REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
 
        l = 0;
@@ -856,11 +736,15 @@ int rfbi_configure(int rfbi_module, int bpp, int lines)
        DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
               bpp, lines, cycle1, cycle2, cycle3);
 
-       rfbi_enable_clocks(0);
-
        return 0;
 }
-EXPORT_SYMBOL(rfbi_configure);
+
+int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size,
+               int data_lines)
+{
+       return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines);
+}
+EXPORT_SYMBOL(omap_rfbi_configure);
 
 int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
                u16 *x, u16 *y, u16 *w, u16 *h)
@@ -960,6 +844,8 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev)
 {
        int r;
 
+       rfbi_enable_clocks(1);
+
        r = omap_dss_start_device(dssdev);
        if (r) {
                DSSERR("failed to start device\n");
@@ -1002,6 +888,8 @@ void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev)
        omap_dispc_unregister_isr(framedone_callback, NULL,
                        DISPC_IRQ_FRAMEDONE);
        omap_dss_stop_device(dssdev);
+
+       rfbi_enable_clocks(0);
 }
 EXPORT_SYMBOL(omapdss_rfbi_display_disable);
 
@@ -1021,11 +909,7 @@ static int omap_rfbihw_probe(struct platform_device *pdev)
 
        rfbi.pdev = pdev;
 
-       spin_lock_init(&rfbi.cmd_lock);
-
-       init_completion(&rfbi.cmd_done);
-       atomic_set(&rfbi.cmd_fifo_full, 0);
-       atomic_set(&rfbi.cmd_pending, 0);
+       sema_init(&rfbi.bus_lock, 1);
 
        rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0);
        if (!rfbi_mem) {
index 54a53e648180e1e31fe830777d2302056f33b2fc..0bd4b0350f809cde6daede29823fc6dd7f0acf0c 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/err.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 #include "dss.h"
 
index 8e35a5bae429c8a858e0c6acf5ac3bca92c2ca79..980f919ed987609b1b646af56ba47dee10b81767 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/cpu.h>
 
 #include "dss.h"
@@ -373,8 +373,11 @@ static void venc_reset(void)
                }
        }
 
+#ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
        /* the magical sleep that makes things work */
+       /* XXX more info? What bug this circumvents? */
        msleep(20);
+#endif
 }
 
 static void venc_enable_clocks(int enable)
@@ -473,6 +476,12 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
 
        mutex_lock(&venc.venc_lock);
 
+       r = omap_dss_start_device(dssdev);
+       if (r) {
+               DSSERR("failed to start device\n");
+               goto err0;
+       }
+
        if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
                r = -EINVAL;
                goto err1;
@@ -484,10 +493,11 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
 
        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
-       /* wait couple of vsyncs until enabling the LCD */
-       msleep(50);
-
+       mutex_unlock(&venc.venc_lock);
+       return 0;
 err1:
+       omap_dss_stop_device(dssdev);
+err0:
        mutex_unlock(&venc.venc_lock);
 
        return r;
@@ -510,10 +520,9 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
 
        venc_power_off(dssdev);
 
-       /* wait at least 5 vsyncs after disabling the LCD */
-       msleep(100);
-
        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+       omap_dss_stop_device(dssdev);
 end:
        mutex_unlock(&venc.venc_lock);
 }
index 6f435450987e7596d1e81963ea53bcc82bcd3f42..cff450392b797053ac7aff3acd5d5bc7a51d0030 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/omapfb.h>
 #include <linux/vmalloc.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vrfb.h>
 #include <plat/vram.h>
 
@@ -895,8 +895,16 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
 
                p.display_info.xres = xres;
                p.display_info.yres = yres;
-               p.display_info.width = 0;
-               p.display_info.height = 0;
+
+               if (display->driver->get_dimensions) {
+                       u32 w, h;
+                       display->driver->get_dimensions(display, &w, &h);
+                       p.display_info.width = w;
+                       p.display_info.height = h;
+               } else {
+                       p.display_info.width = 0;
+                       p.display_info.height = 0;
+               }
 
                if (copy_to_user((void __user *)arg, &p.display_info,
                                        sizeof(p.display_info)))
index 505ec667204906130eb4457e6d96d75b885f670b..505bc12a3031a877ad5617a0259dce21f519f970 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/platform_device.h>
 #include <linux/omapfb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vram.h>
 #include <plat/vrfb.h>
 
@@ -702,8 +702,16 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
                        var->xres, var->yres,
                        var->xres_virtual, var->yres_virtual);
 
-       var->height             = -1;
-       var->width              = -1;
+       if (display && display->driver->get_dimensions) {
+               u32 w, h;
+               display->driver->get_dimensions(display, &w, &h);
+               var->width = DIV_ROUND_CLOSEST(w, 1000);
+               var->height = DIV_ROUND_CLOSEST(h, 1000);
+       } else {
+               var->height = -1;
+               var->width = -1;
+       }
+
        var->grayscale          = 0;
 
        if (display && display->driver->get_timings) {
@@ -749,35 +757,6 @@ static int omapfb_open(struct fb_info *fbi, int user)
 
 static int omapfb_release(struct fb_info *fbi, int user)
 {
-#if 0
-       struct omapfb_info *ofbi = FB2OFB(fbi);
-       struct omapfb2_device *fbdev = ofbi->fbdev;
-       struct omap_dss_device *display = fb2display(fbi);
-
-       DBG("Closing fb with plane index %d\n", ofbi->id);
-
-       omapfb_lock(fbdev);
-
-       if (display && display->get_update_mode && display->update) {
-               /* XXX this update should be removed, I think. But it's
-                * good for debugging */
-               if (display->get_update_mode(display) ==
-                               OMAP_DSS_UPDATE_MANUAL) {
-                       u16 w, h;
-
-                       if (display->sync)
-                               display->sync(display);
-
-                       display->get_resolution(display, &w, &h);
-                       display->update(display, 0, 0, w, h);
-               }
-       }
-
-       if (display && display->sync)
-               display->sync(display);
-
-       omapfb_unlock(fbdev);
-#endif
        return 0;
 }
 
@@ -1263,7 +1242,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
        struct omapfb_info *ofbi = FB2OFB(fbi);
        struct omapfb2_device *fbdev = ofbi->fbdev;
        struct omap_dss_device *display = fb2display(fbi);
-       int do_update = 0;
        int r = 0;
 
        if (!display)
@@ -1279,11 +1257,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
                if (display->driver->resume)
                        r = display->driver->resume(display);
 
-               if (r == 0 && display->driver->get_update_mode &&
-                               display->driver->get_update_mode(display) ==
-                               OMAP_DSS_UPDATE_MANUAL)
-                       do_update = 1;
-
                break;
 
        case FB_BLANK_NORMAL:
@@ -1307,13 +1280,6 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
 exit:
        omapfb_unlock(fbdev);
 
-       if (r == 0 && do_update && display->driver->update) {
-               u16 w, h;
-               display->driver->get_resolution(display, &w, &h);
-
-               r = display->driver->update(display, 0, 0, w, h);
-       }
-
        return r;
 }
 
@@ -2030,9 +1996,9 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
 static int omapfb_mode_to_timings(const char *mode_str,
                struct omap_video_timings *timings, u8 *bpp)
 {
-       struct fb_info fbi;
-       struct fb_var_screeninfo var;
-       struct fb_ops fbops;
+       struct fb_info *fbi;
+       struct fb_var_screeninfo *var;
+       struct fb_ops *fbops;
        int r;
 
 #ifdef CONFIG_OMAP2_DSS_VENC
@@ -2050,39 +2016,66 @@ static int omapfb_mode_to_timings(const char *mode_str,
        /* this is quite a hack, but I wanted to use the modedb and for
         * that we need fb_info and var, so we create dummy ones */
 
-       memset(&fbi, 0, sizeof(fbi));
-       memset(&var, 0, sizeof(var));
-       memset(&fbops, 0, sizeof(fbops));
-       fbi.fbops = &fbops;
-
-       r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
-
-       if (r != 0) {
-               timings->pixel_clock = PICOS2KHZ(var.pixclock);
-               timings->hbp = var.left_margin;
-               timings->hfp = var.right_margin;
-               timings->vbp = var.upper_margin;
-               timings->vfp = var.lower_margin;
-               timings->hsw = var.hsync_len;
-               timings->vsw = var.vsync_len;
-               timings->x_res = var.xres;
-               timings->y_res = var.yres;
-
-               switch (var.bits_per_pixel) {
-               case 16:
-                       *bpp = 16;
-                       break;
-               case 24:
-               case 32:
-               default:
-                       *bpp = 24;
-                       break;
-               }
+       *bpp = 0;
+       fbi = NULL;
+       var = NULL;
+       fbops = NULL;
 
-               return 0;
-       } else {
-               return -EINVAL;
+       fbi = kzalloc(sizeof(*fbi), GFP_KERNEL);
+       if (fbi == NULL) {
+               r = -ENOMEM;
+               goto err;
+       }
+
+       var = kzalloc(sizeof(*var), GFP_KERNEL);
+       if (var == NULL) {
+               r = -ENOMEM;
+               goto err;
+       }
+
+       fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
+       if (fbops == NULL) {
+               r = -ENOMEM;
+               goto err;
+       }
+
+       fbi->fbops = fbops;
+
+       r = fb_find_mode(var, fbi, mode_str, NULL, 0, NULL, 24);
+       if (r == 0) {
+               r = -EINVAL;
+               goto err;
+       }
+
+       timings->pixel_clock = PICOS2KHZ(var->pixclock);
+       timings->hbp = var->left_margin;
+       timings->hfp = var->right_margin;
+       timings->vbp = var->upper_margin;
+       timings->vfp = var->lower_margin;
+       timings->hsw = var->hsync_len;
+       timings->vsw = var->vsync_len;
+       timings->x_res = var->xres;
+       timings->y_res = var->yres;
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               *bpp = 16;
+               break;
+       case 24:
+       case 32:
+       default:
+               *bpp = 24;
+               break;
        }
+
+       r = 0;
+
+err:
+       kfree(fbi);
+       kfree(var);
+       kfree(fbops);
+
+       return r;
 }
 
 static int omapfb_set_def_mode(struct omapfb2_device *fbdev,
@@ -2185,6 +2178,61 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
        return r;
 }
 
+static int omapfb_init_display(struct omapfb2_device *fbdev,
+               struct omap_dss_device *dssdev)
+{
+       struct omap_dss_driver *dssdrv = dssdev->driver;
+       int r;
+
+       r = dssdrv->enable(dssdev);
+       if (r) {
+               dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
+                               dssdev->name);
+               return r;
+       }
+
+       if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+               u16 w, h;
+               if (dssdrv->enable_te) {
+                       r = dssdrv->enable_te(dssdev, 1);
+                       if (r) {
+                               dev_err(fbdev->dev, "Failed to set TE\n");
+                               return r;
+                       }
+               }
+
+               if (dssdrv->set_update_mode) {
+                       r = dssdrv->set_update_mode(dssdev,
+                                       OMAP_DSS_UPDATE_MANUAL);
+                       if (r) {
+                               dev_err(fbdev->dev,
+                                               "Failed to set update mode\n");
+                               return r;
+                       }
+               }
+
+               dssdrv->get_resolution(dssdev, &w, &h);
+               r = dssdrv->update(dssdev, 0, 0, w, h);
+               if (r) {
+                       dev_err(fbdev->dev,
+                                       "Failed to update display\n");
+                       return r;
+               }
+       } else {
+               if (dssdrv->set_update_mode) {
+                       r = dssdrv->set_update_mode(dssdev,
+                                       OMAP_DSS_UPDATE_AUTO);
+                       if (r) {
+                               dev_err(fbdev->dev,
+                                               "Failed to set update mode\n");
+                               return r;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 static int omapfb_probe(struct platform_device *pdev)
 {
        struct omapfb2_device *fbdev = NULL;
@@ -2284,30 +2332,13 @@ static int omapfb_probe(struct platform_device *pdev)
        }
 
        if (def_display) {
-               struct omap_dss_driver *dssdrv = def_display->driver;
-
-               r = def_display->driver->enable(def_display);
+               r = omapfb_init_display(fbdev, def_display);
                if (r) {
-                       dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
-                                       def_display->name);
+                       dev_err(fbdev->dev,
+                                       "failed to initialize default "
+                                       "display\n");
                        goto cleanup;
                }
-
-               if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-                       u16 w, h;
-                       if (dssdrv->enable_te)
-                               dssdrv->enable_te(def_display, 1);
-                       if (dssdrv->set_update_mode)
-                               dssdrv->set_update_mode(def_display,
-                                               OMAP_DSS_UPDATE_MANUAL);
-
-                       dssdrv->get_resolution(def_display, &w, &h);
-                       def_display->driver->update(def_display, 0, 0, w, h);
-               } else {
-                       if (dssdrv->set_update_mode)
-                               dssdrv->set_update_mode(def_display,
-                                               OMAP_DSS_UPDATE_AUTO);
-               }
        }
 
        DBG("create sysfs for fbs\n");
index 6f9c72cd6bb0e52675375e4cd4c2bd168e175701..2f5e817b2a9a65904e4f41631036fb350c478784 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/mm.h>
 #include <linux/omapfb.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 #include <plat/vrfb.h>
 
 #include "omapfb.h"
@@ -50,10 +50,12 @@ static ssize_t store_rotate_type(struct device *dev,
        struct fb_info *fbi = dev_get_drvdata(dev);
        struct omapfb_info *ofbi = FB2OFB(fbi);
        struct omapfb2_mem_region *rg;
-       enum omap_dss_rotation_type rot_type;
+       int rot_type;
        int r;
 
-       rot_type = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &rot_type);
+       if (r)
+               return r;
 
        if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
                return -EINVAL;
@@ -102,14 +104,15 @@ static ssize_t store_mirror(struct device *dev,
 {
        struct fb_info *fbi = dev_get_drvdata(dev);
        struct omapfb_info *ofbi = FB2OFB(fbi);
-       unsigned long mirror;
+       int mirror;
        int r;
        struct fb_var_screeninfo new_var;
 
-       mirror = simple_strtoul(buf, NULL, 0);
+       r = kstrtoint(buf, 0, &mirror);
+       if (r)
+               return r;
 
-       if (mirror != 0 && mirror != 1)
-               return -EINVAL;
+       mirror = !!mirror;
 
        if (!lock_fb_info(fbi))
                return -ENODEV;
@@ -445,7 +448,11 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
        int r;
        int i;
 
-       size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
+       r = kstrtoul(buf, 0, &size);
+       if (r)
+               return r;
+
+       size = PAGE_ALIGN(size);
 
        if (!lock_fb_info(fbi))
                return -ENODEV;
index 1305fc9880badaaf62699a7ee916cff62034658c..aa1b1d9742760e86507102da28635a2f84a65ca7 100644 (file)
 
 #include <linux/rwsem.h>
 
-#include <plat/display.h>
+#include <video/omapdss.h>
 
 #ifdef DEBUG
 extern unsigned int omapfb_debug;
 #define DBG(format, ...) \
-       if (omapfb_debug) \
-               printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
+       do { \
+               if (omapfb_debug) \
+                       printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__); \
+       } while (0)
 #else
 #define DBG(format, ...)
 #endif
index 3b6cdcac8f1a6a930dd49399dd4af97a9a835a8b..0352afa49a392716762f7304cbdd00ae1770b396 100644 (file)
@@ -182,6 +182,7 @@ struct s3c_fb_vsync {
 
 /**
  * struct s3c_fb - overall hardware state of the hardware
+ * @slock: The spinlock protection for this data sturcture.
  * @dev: The device that we bound to, for printing, etc.
  * @regs_res: The resource we claimed for the IO registers.
  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
@@ -195,6 +196,7 @@ struct s3c_fb_vsync {
  * @vsync_info: VSYNC-related information (count, queues...)
  */
 struct s3c_fb {
+       spinlock_t              slock;
        struct device           *dev;
        struct resource         *regs_res;
        struct clk              *bus_clk;
@@ -300,6 +302,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
                var->blue.length        = 5;
                break;
 
+       case 32:
        case 28:
        case 25:
                var->transp.length      = var->bits_per_pixel - 24;
@@ -308,7 +311,6 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
        case 24:
                /* our 24bpp is unpacked, so 32bpp */
                var->bits_per_pixel     = 32;
-       case 32:
                var->red.offset         = 16;
                var->red.length         = 8;
                var->green.offset       = 8;
@@ -947,6 +949,8 @@ static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
        void __iomem  *regs = sfb->regs;
        u32 irq_sts_reg;
 
+       spin_lock(&sfb->slock);
+
        irq_sts_reg = readl(regs + VIDINTCON1);
 
        if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
@@ -963,6 +967,7 @@ static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
         */
        s3c_fb_disable_irq(sfb);
 
+       spin_unlock(&sfb->slock);
        return IRQ_HANDLED;
 }
 
@@ -1339,6 +1344,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
        sfb->pdata = pd;
        sfb->variant = fbdrv->variant;
 
+       spin_lock_init(&sfb->slock);
+
        sfb->bus_clk = clk_get(dev, "lcd");
        if (IS_ERR(sfb->bus_clk)) {
                dev_err(dev, "failed to get bus clock\n");
@@ -1442,8 +1449,7 @@ err_ioremap:
        iounmap(sfb->regs);
 
 err_req_region:
-       release_resource(sfb->regs_res);
-       kfree(sfb->regs_res);
+       release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
 err_clk:
        clk_disable(sfb->bus_clk);
@@ -1479,8 +1485,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
        clk_disable(sfb->bus_clk);
        clk_put(sfb->bus_clk);
 
-       release_resource(sfb->regs_res);
-       kfree(sfb->regs_res);
+       release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res));
 
        kfree(sfb);
 
@@ -1521,7 +1526,8 @@ static int s3c_fb_resume(struct device *dev)
 
        clk_enable(sfb->bus_clk);
 
-       /* setup registers */
+       /* setup gpio and output polarity controls */
+       pd->setup_gpio();
        writel(pd->vidcon1, sfb->regs + VIDCON1);
 
        /* zero all windows before we do anything */
@@ -1549,7 +1555,7 @@ static int s3c_fb_resume(struct device *dev)
        return 0;
 }
 
-int s3c_fb_runtime_suspend(struct device *dev)
+static int s3c_fb_runtime_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
@@ -1569,7 +1575,7 @@ int s3c_fb_runtime_suspend(struct device *dev)
        return 0;
 }
 
-int s3c_fb_runtime_resume(struct device *dev)
+static int s3c_fb_runtime_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct s3c_fb *sfb = platform_get_drvdata(pdev);
@@ -1579,7 +1585,8 @@ int s3c_fb_runtime_resume(struct device *dev)
 
        clk_enable(sfb->bus_clk);
 
-       /* setup registers */
+       /* setup gpio and output polarity controls */
+       pd->setup_gpio();
        writel(pd->vidcon1, sfb->regs + VIDCON1);
 
        /* zero all windows before we do anything */
@@ -1623,28 +1630,31 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
                .has_osd_c      = 1,
                .osd_size_off   = 0x8,
                .palette_sz     = 256,
-               .valid_bpp      = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(24)),
        },
        [1] = {
                .has_osd_c      = 1,
                .has_osd_d      = 1,
-               .osd_size_off   = 0x12,
+               .osd_size_off   = 0xc,
                .has_osd_alpha  = 1,
                .palette_sz     = 256,
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
                                   VALID_BPP(18) | VALID_BPP(19) |
-                                  VALID_BPP(24) | VALID_BPP(25)),
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(28)),
        },
        [2] = {
                .has_osd_c      = 1,
                .has_osd_d      = 1,
-               .osd_size_off   = 0x12,
+               .osd_size_off   = 0xc,
                .has_osd_alpha  = 1,
                .palette_sz     = 16,
                .palette_16bpp  = 1,
                .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
                                   VALID_BPP(18) | VALID_BPP(19) |
-                                  VALID_BPP(24) | VALID_BPP(25)),
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(28)),
        },
        [3] = {
                .has_osd_c      = 1,
@@ -1653,7 +1663,8 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
                .palette_16bpp  = 1,
                .valid_bpp      = (VALID_BPP124  | VALID_BPP(16) |
                                   VALID_BPP(18) | VALID_BPP(19) |
-                                  VALID_BPP(24) | VALID_BPP(25)),
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(28)),
        },
        [4] = {
                .has_osd_c      = 1,
@@ -1662,7 +1673,65 @@ static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
                .palette_16bpp  = 1,
                .valid_bpp      = (VALID_BPP(1) | VALID_BPP(2) |
                                   VALID_BPP(16) | VALID_BPP(18) |
-                                  VALID_BPP(24) | VALID_BPP(25)),
+                                  VALID_BPP(19) | VALID_BPP(24) |
+                                  VALID_BPP(25) | VALID_BPP(28)),
+       },
+};
+
+static struct s3c_fb_win_variant s3c_fb_data_s5p_wins[] = {
+       [0] = {
+               .has_osd_c      = 1,
+               .osd_size_off   = 0x8,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
+       },
+       [1] = {
+               .has_osd_c      = 1,
+               .has_osd_d      = 1,
+               .osd_size_off   = 0xc,
+               .has_osd_alpha  = 1,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
+       },
+       [2] = {
+               .has_osd_c      = 1,
+               .has_osd_d      = 1,
+               .osd_size_off   = 0xc,
+               .has_osd_alpha  = 1,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
+       },
+       [3] = {
+               .has_osd_c      = 1,
+               .has_osd_alpha  = 1,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
+       },
+       [4] = {
+               .has_osd_c      = 1,
+               .has_osd_alpha  = 1,
+               .palette_sz     = 256,
+               .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
+                                  VALID_BPP(15) | VALID_BPP(16) |
+                                  VALID_BPP(18) | VALID_BPP(19) |
+                                  VALID_BPP(24) | VALID_BPP(25) |
+                                  VALID_BPP(32)),
        },
 };
 
@@ -1719,11 +1788,11 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
 
                .has_prtcon     = 1,
        },
-       .win[0] = &s3c_fb_data_64xx_wins[0],
-       .win[1] = &s3c_fb_data_64xx_wins[1],
-       .win[2] = &s3c_fb_data_64xx_wins[2],
-       .win[3] = &s3c_fb_data_64xx_wins[3],
-       .win[4] = &s3c_fb_data_64xx_wins[4],
+       .win[0] = &s3c_fb_data_s5p_wins[0],
+       .win[1] = &s3c_fb_data_s5p_wins[1],
+       .win[2] = &s3c_fb_data_s5p_wins[2],
+       .win[3] = &s3c_fb_data_s5p_wins[3],
+       .win[4] = &s3c_fb_data_s5p_wins[4],
 };
 
 static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
@@ -1749,11 +1818,11 @@ static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
 
                .has_shadowcon  = 1,
        },
-       .win[0] = &s3c_fb_data_64xx_wins[0],
-       .win[1] = &s3c_fb_data_64xx_wins[1],
-       .win[2] = &s3c_fb_data_64xx_wins[2],
-       .win[3] = &s3c_fb_data_64xx_wins[3],
-       .win[4] = &s3c_fb_data_64xx_wins[4],
+       .win[0] = &s3c_fb_data_s5p_wins[0],
+       .win[1] = &s3c_fb_data_s5p_wins[1],
+       .win[2] = &s3c_fb_data_s5p_wins[2],
+       .win[3] = &s3c_fb_data_s5p_wins[3],
+       .win[4] = &s3c_fb_data_s5p_wins[4],
 };
 
 /* S3C2443/S3C2416 style hardware */
index 61c819e35f7f42b978838ff9c60dde28aade586a..0aa13761de6ec3168c38569dd2a9ee479689cdfb 100644 (file)
@@ -867,7 +867,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
                goto dealloc_fb;
        }
 
-       size = (res->end - res->start) + 1;
+       size = resource_size(res);
        info->mem = request_mem_region(res->start, size, pdev->name);
        if (info->mem == NULL) {
                dev_err(&pdev->dev, "failed to get memory region\n");
@@ -997,8 +997,7 @@ release_irq:
 release_regs:
        iounmap(info->io);
 release_mem:
-       release_resource(info->mem);
-       kfree(info->mem);
+       release_mem_region(res->start, size);
 dealloc_fb:
        platform_set_drvdata(pdev, NULL);
        framebuffer_release(fbinfo);
@@ -1044,8 +1043,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev)
 
        iounmap(info->io);
 
-       release_resource(info->mem);
-       kfree(info->mem);
+       release_mem_region(info->mem->start, resource_size(info->mem));
 
        platform_set_drvdata(pdev, NULL);
        framebuffer_release(fbinfo);
index c4482f2e5799130f946cb8daf80c63a295a83ee1..4ca5d0c8fe84a6501ca6ef4f31898c0babac2725 100644 (file)
@@ -25,6 +25,9 @@
 #include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
 #include <video/vga.h>
 
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
@@ -36,6 +39,12 @@ struct s3fb_info {
        struct mutex open_lock;
        unsigned int ref_count;
        u32 pseudo_palette[16];
+#ifdef CONFIG_FB_S3_DDC
+       u8 __iomem *mmio;
+       bool ddc_registered;
+       struct i2c_adapter ddc_adapter;
+       struct i2c_algo_bit_data ddc_algo;
+#endif
 };
 
 
@@ -105,6 +114,9 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
 #define CHIP_UNDECIDED_FLAG    0x80
 #define CHIP_MASK              0xFF
 
+#define MMIO_OFFSET            0x1000000
+#define MMIO_SIZE              0x10000
+
 /* CRT timing register sets */
 
 static const struct vga_regset s3_h_total_regs[]        = {{0x00, 0, 7}, {0x5D, 0, 0}, VGA_REGSET_END};
@@ -140,7 +152,7 @@ static const struct svga_timing_regs s3_timing_regs     = {
 /* Module parameters */
 
 
-static char *mode_option __devinitdata = "640x480-8@60";
+static char *mode_option __devinitdata;
 
 #ifdef CONFIG_MTRR
 static int mtrr __devinitdata = 1;
@@ -167,6 +179,119 @@ module_param(fasttext, int, 0644);
 MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, default=1)");
 
 
+/* ------------------------------------------------------------------------- */
+
+#ifdef CONFIG_FB_S3_DDC
+
+#define DDC_REG                0xaa            /* Trio 3D/1X/2X */
+#define DDC_MMIO_REG   0xff20          /* all other chips */
+#define DDC_SCL_OUT    (1 << 0)
+#define DDC_SDA_OUT    (1 << 1)
+#define DDC_SCL_IN     (1 << 2)
+#define DDC_SDA_IN     (1 << 3)
+#define DDC_DRIVE_EN   (1 << 4)
+
+static bool s3fb_ddc_needs_mmio(int chip)
+{
+       return !(chip == CHIP_360_TRIO3D_1X  ||
+                chip == CHIP_362_TRIO3D_2X  ||
+                chip == CHIP_368_TRIO3D_2X);
+}
+
+static u8 s3fb_ddc_read(struct s3fb_info *par)
+{
+       if (s3fb_ddc_needs_mmio(par->chip))
+               return readb(par->mmio + DDC_MMIO_REG);
+       else
+               return vga_rcrt(par->state.vgabase, DDC_REG);
+}
+
+static void s3fb_ddc_write(struct s3fb_info *par, u8 val)
+{
+       if (s3fb_ddc_needs_mmio(par->chip))
+               writeb(val, par->mmio + DDC_MMIO_REG);
+       else
+               vga_wcrt(par->state.vgabase, DDC_REG, val);
+}
+
+static void s3fb_ddc_setscl(void *data, int val)
+{
+       struct s3fb_info *par = data;
+       unsigned char reg;
+
+       reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
+       if (val)
+               reg |= DDC_SCL_OUT;
+       else
+               reg &= ~DDC_SCL_OUT;
+       s3fb_ddc_write(par, reg);
+}
+
+static void s3fb_ddc_setsda(void *data, int val)
+{
+       struct s3fb_info *par = data;
+       unsigned char reg;
+
+       reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
+       if (val)
+               reg |= DDC_SDA_OUT;
+       else
+               reg &= ~DDC_SDA_OUT;
+       s3fb_ddc_write(par, reg);
+}
+
+static int s3fb_ddc_getscl(void *data)
+{
+       struct s3fb_info *par = data;
+
+       return !!(s3fb_ddc_read(par) & DDC_SCL_IN);
+}
+
+static int s3fb_ddc_getsda(void *data)
+{
+       struct s3fb_info *par = data;
+
+       return !!(s3fb_ddc_read(par) & DDC_SDA_IN);
+}
+
+static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)
+{
+       struct s3fb_info *par = info->par;
+
+       strlcpy(par->ddc_adapter.name, info->fix.id,
+               sizeof(par->ddc_adapter.name));
+       par->ddc_adapter.owner          = THIS_MODULE;
+       par->ddc_adapter.class          = I2C_CLASS_DDC;
+       par->ddc_adapter.algo_data      = &par->ddc_algo;
+       par->ddc_adapter.dev.parent     = info->device;
+       par->ddc_algo.setsda            = s3fb_ddc_setsda;
+       par->ddc_algo.setscl            = s3fb_ddc_setscl;
+       par->ddc_algo.getsda            = s3fb_ddc_getsda;
+       par->ddc_algo.getscl            = s3fb_ddc_getscl;
+       par->ddc_algo.udelay            = 10;
+       par->ddc_algo.timeout           = 20;
+       par->ddc_algo.data              = par;
+
+       i2c_set_adapdata(&par->ddc_adapter, par);
+
+       /*
+        * some Virge cards have external MUX to switch chip I2C bus between
+        * DDC and extension pins - switch it do DDC
+        */
+/*     vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */
+       if (par->chip == CHIP_357_VIRGE_GX2 ||
+           par->chip == CHIP_359_VIRGE_GX2P)
+               svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03);
+       else
+               svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03);
+       /* some Virge need this or the DDC is ignored */
+       svga_wcrt_mask(par->state.vgabase, 0x5c, 0x03, 0x03);
+
+       return i2c_bit_add_bus(&par->ddc_adapter);
+}
+#endif /* CONFIG_FB_S3_DDC */
+
+
 /* ------------------------------------------------------------------------- */
 
 /* Set font in S3 fast text mode */
@@ -994,6 +1119,7 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
        struct s3fb_info *par;
        int rc;
        u8 regval, cr38, cr39;
+       bool found = false;
 
        /* Ignore secondary VGA device because there is no VGA arbitration */
        if (! svga_primary_device(dev)) {
@@ -1110,12 +1236,69 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
        info->fix.ypanstep = 0;
        info->fix.accel = FB_ACCEL_NONE;
        info->pseudo_palette = (void*) (par->pseudo_palette);
+       info->var.bits_per_pixel = 8;
+
+#ifdef CONFIG_FB_S3_DDC
+       /* Enable MMIO if needed */
+       if (s3fb_ddc_needs_mmio(par->chip)) {
+               par->mmio = ioremap(info->fix.smem_start + MMIO_OFFSET, MMIO_SIZE);
+               if (par->mmio)
+                       svga_wcrt_mask(par->state.vgabase, 0x53, 0x08, 0x08);   /* enable MMIO */
+               else
+                       dev_err(info->device, "unable to map MMIO at 0x%lx, disabling DDC",
+                               info->fix.smem_start + MMIO_OFFSET);
+       }
+       if (!s3fb_ddc_needs_mmio(par->chip) || par->mmio)
+               if (s3fb_setup_ddc_bus(info) == 0) {
+                       u8 *edid = fb_ddc_read(&par->ddc_adapter);
+                       par->ddc_registered = true;
+                       if (edid) {
+                               fb_edid_to_monspecs(edid, &info->monspecs);
+                               kfree(edid);
+                               if (!info->monspecs.modedb)
+                                       dev_err(info->device, "error getting mode database\n");
+                               else {
+                                       const struct fb_videomode *m;
+
+                                       fb_videomode_to_modelist(info->monspecs.modedb,
+                                                                info->monspecs.modedb_len,
+                                                                &info->modelist);
+                                       m = fb_find_best_display(&info->monspecs, &info->modelist);
+                                       if (m) {
+                                               fb_videomode_to_var(&info->var, m);
+                                               /* fill all other info->var's fields */
+                                               if (s3fb_check_var(&info->var, info) == 0)
+                                                       found = true;
+                                       }
+                               }
+                       }
+               }
+#endif
+       if (!mode_option && !found)
+               mode_option = "640x480-8@60";
 
        /* Prepare startup mode */
-       rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
-       if (! ((rc == 1) || (rc == 2))) {
-               rc = -EINVAL;
-               dev_err(info->device, "mode %s not found\n", mode_option);
+       if (mode_option) {
+               rc = fb_find_mode(&info->var, info, mode_option,
+                                  info->monspecs.modedb, info->monspecs.modedb_len,
+                                  NULL, info->var.bits_per_pixel);
+               if (!rc || rc == 4) {
+                       rc = -EINVAL;
+                       dev_err(info->device, "mode %s not found\n", mode_option);
+                       fb_destroy_modedb(info->monspecs.modedb);
+                       info->monspecs.modedb = NULL;
+                       goto err_find_mode;
+               }
+       }
+
+       fb_destroy_modedb(info->monspecs.modedb);
+       info->monspecs.modedb = NULL;
+
+       /* maximize virtual vertical size for fast scrolling */
+       info->var.yres_virtual = info->fix.smem_len * 8 /
+                       (info->var.bits_per_pixel * info->var.xres_virtual);
+       if (info->var.yres_virtual < info->var.yres) {
+               dev_err(info->device, "virtual vertical size smaller than real\n");
                goto err_find_mode;
        }
 
@@ -1164,6 +1347,12 @@ err_reg_fb:
        fb_dealloc_cmap(&info->cmap);
 err_alloc_cmap:
 err_find_mode:
+#ifdef CONFIG_FB_S3_DDC
+       if (par->ddc_registered)
+               i2c_del_adapter(&par->ddc_adapter);
+       if (par->mmio)
+               iounmap(par->mmio);
+#endif
        pci_iounmap(dev, info->screen_base);
 err_iomap:
        pci_release_regions(dev);
@@ -1180,12 +1369,11 @@ err_enable_device:
 static void __devexit s3_pci_remove(struct pci_dev *dev)
 {
        struct fb_info *info = pci_get_drvdata(dev);
+       struct s3fb_info __maybe_unused *par = info->par;
 
        if (info) {
 
 #ifdef CONFIG_MTRR
-               struct s3fb_info *par = info->par;
-
                if (par->mtrr_reg >= 0) {
                        mtrr_del(par->mtrr_reg, 0, 0);
                        par->mtrr_reg = -1;
@@ -1195,6 +1383,13 @@ static void __devexit s3_pci_remove(struct pci_dev *dev)
                unregister_framebuffer(info);
                fb_dealloc_cmap(&info->cmap);
 
+#ifdef CONFIG_FB_S3_DDC
+               if (par->ddc_registered)
+                       i2c_del_adapter(&par->ddc_adapter);
+               if (par->mmio)
+                       iounmap(par->mmio);
+#endif
+
                pci_iounmap(dev, info->screen_base);
                pci_release_regions(dev);
 /*             pci_disable_device(dev); */
index bb71fea07284e547cbf2632141748b8155691a74..80fa87e2ae2ff52eb188e2312c4fed2507df9425 100644 (file)
@@ -171,6 +171,8 @@ void savagefb_create_i2c_busses(struct fb_info *info)
 
        switch (par->chip) {
        case S3_PROSAVAGE:
+       case S3_PROSAVAGEDDR:
+       case S3_TWISTER:
                par->chan.reg         = CR_SERIAL2;
                par->chan.ioaddr      = par->mmio.vbase;
                par->chan.algo.setsda = prosavage_gpio_setsda;
index 4e9490c19d7d3a7a07a3a87360de200ff2fb808e..32549d177b198ae2f7f2b9a738d6b8a0cb9de049 100644 (file)
@@ -36,7 +36,6 @@
 #define PCI_CHIP_SAVAGE_IX    0x8c13
 #define PCI_CHIP_PROSAVAGE_PM 0x8a25
 #define PCI_CHIP_PROSAVAGE_KM 0x8a26
- /* Twister is a code name; hope I get the real name soon. */
 #define PCI_CHIP_S3TWISTER_P  0x8d01
 #define PCI_CHIP_S3TWISTER_K  0x8d02
 #define PCI_CHIP_PROSAVAGE_DDR          0x8d03
 #define PCI_CHIP_SUPSAV_IXCDDR         0x8c2f
 
 
+#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
 
 #define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
 
-#define S3_SAVAGE4_SERIES(chip)   ((chip==S3_SAVAGE4) || (chip==S3_PROSAVAGE))
+#define S3_SAVAGE4_SERIES(chip)   ((chip>=S3_SAVAGE4) || (chip<=S3_PROSAVAGEDDR))
 
 #define S3_SAVAGE_MOBILE_SERIES(chip)  ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
 
-#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip==S3_PROSAVAGEDDR))
 
 /* Chip tags.  These are used to group the adapters into
  * related families.
@@ -71,6 +71,8 @@ typedef enum {
   S3_SAVAGE_MX,
   S3_SAVAGE4,
   S3_PROSAVAGE,
+  S3_TWISTER,
+  S3_PROSAVAGEDDR,
   S3_SUPERSAVAGE,
   S3_SAVAGE2000,
   S3_LAST
index a2dc1a7ec7586bd3e5ae6d1689ccf71490317ed1..3b7f2f5bae71dc78b98bf8e4d7befd1b75c05bba 100644 (file)
@@ -328,7 +328,9 @@ SavageSetup2DEngine(struct savagefb_par  *par)
                savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x0C, par);
                break;
        case S3_SAVAGE4:
+       case S3_TWISTER:
        case S3_PROSAVAGE:
+       case S3_PROSAVAGEDDR:
        case S3_SUPERSAVAGE:
                /* Disable BCI */
                savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par);
@@ -1886,6 +1888,8 @@ static int savage_init_hw(struct savagefb_par *par)
                break;
 
        case S3_PROSAVAGE:
+       case S3_PROSAVAGEDDR:
+       case S3_TWISTER:
                videoRam = RamSavageNB[(config1 & 0xE0) >> 5] * 1024;
                break;
 
@@ -1963,7 +1967,8 @@ static int savage_init_hw(struct savagefb_par *par)
                }
        }
 
-       if (S3_SAVAGE_MOBILE_SERIES(par->chip) && !par->crtonly)
+       if ((S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+            S3_MOBILE_TWISTER_SERIES(par->chip)) && !par->crtonly)
                par->display_type = DISP_LCD;
        else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi))
                par->display_type = DISP_DFP;
@@ -2111,19 +2116,19 @@ static int __devinit savage_init_fb_info(struct fb_info *info,
                snprintf(info->fix.id, 16, "ProSavageKM");
                break;
        case FB_ACCEL_S3TWISTER_P:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_TWISTER;
                snprintf(info->fix.id, 16, "TwisterP");
                break;
        case FB_ACCEL_S3TWISTER_K:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_TWISTER;
                snprintf(info->fix.id, 16, "TwisterK");
                break;
        case FB_ACCEL_PROSAVAGE_DDR:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_PROSAVAGEDDR;
                snprintf(info->fix.id, 16, "ProSavageDDR");
                break;
        case FB_ACCEL_PROSAVAGE_DDRK:
-               par->chip = S3_PROSAVAGE;
+               par->chip = S3_PROSAVAGEDDR;
                snprintf(info->fix.id, 16, "ProSavage8");
                break;
        }
index 8fe19582c4602f65badeb17fbccb930574e243dc..45e47d8471634d2bd9f57c2ef5e3da88cdc8494b 100644 (file)
@@ -551,8 +551,7 @@ out_unmap:
                free_irq(par->irq, &par->vsync);
        iounmap(par->base);
 out_res:
-       release_resource(par->ioarea);
-       kfree(par->ioarea);
+       release_mem_region(res->start, resource_size(res));
 out_fb:
        framebuffer_release(info);
        return ret;
@@ -570,8 +569,7 @@ static int __devexit sh7760fb_remove(struct platform_device *dev)
        if (par->irq >= 0)
                free_irq(par->irq, par);
        iounmap(par->base);
-       release_resource(par->ioarea);
-       kfree(par->ioarea);
+       release_mem_region(par->ioarea->start, resource_size(par->ioarea));
        framebuffer_release(info);
        platform_set_drvdata(dev, NULL);
 
index 2b9e56a6bde4780933d444b1f7e29aada38274eb..6ae40b630dc9eb7c9c39641d4a0d2c27f7f1b1b3 100644 (file)
@@ -1131,15 +1131,19 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
                pm_runtime_get_sync(hdmi->dev);
 
                ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
-               if (ret < 0)
+               if (ret < 0) {
+                       pm_runtime_put(hdmi->dev);
                        goto out;
+               }
 
                hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE;
 
                /* Reconfigure the clock */
                ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate);
-               if (ret < 0)
+               if (ret < 0) {
+                       pm_runtime_put(hdmi->dev);
                        goto out;
+               }
 
                msleep(10);
                sh_hdmi_configure(hdmi);
@@ -1336,6 +1340,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 ecodec:
        free_irq(irq, hdmi);
 ereqirq:
+       pm_runtime_suspend(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        iounmap(hdmi->base);
 emap:
@@ -1372,6 +1377,7 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
        free_irq(irq, hdmi);
        /* Wait for already scheduled work */
        cancel_delayed_work_sync(&hdmi->edid_work);
+       pm_runtime_suspend(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        clk_disable(hdmi->hdmi_clk);
        clk_put(hdmi->hdmi_clk);
index 9bcc61b4ef149a258e6159a9728ffebac2bd5daf..404c03b4b7c7c4e570646a3fb4461e8a70a8855f 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/atomic.h>
 
 #include "sh_mobile_lcdcfb.h"
+#include "sh_mobile_meram.h"
 
 #define SIDE_B_OFFSET 0x1000
 #define MIRROR_OFFSET 0x2000
@@ -143,6 +144,7 @@ struct sh_mobile_lcdc_priv {
        unsigned long saved_shared_regs[NR_SHARED_REGS];
        int started;
        int forced_bpp; /* 2 channel LCDC must share bpp setting */
+       struct sh_mobile_meram_info *meram_dev;
 };
 
 static bool banked(int reg_nr)
@@ -469,7 +471,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
        int bpp = 0;
        unsigned long ldddsr;
        int k, m;
-       int ret = 0;
 
        /* enable clocks before accessing the hardware */
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
@@ -538,11 +539,12 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                lcdc_write_chan(ch, LDPMR, 0);
 
                board_cfg = &ch->cfg.board_cfg;
-               if (board_cfg->setup_sys)
-                       ret = board_cfg->setup_sys(board_cfg->board_data, ch,
-                                                  &sh_mobile_lcdc_sys_bus_ops);
-               if (ret)
-                       return ret;
+               if (board_cfg->setup_sys) {
+                       int ret = board_cfg->setup_sys(board_cfg->board_data,
+                                               ch, &sh_mobile_lcdc_sys_bus_ops);
+                       if (ret)
+                               return ret;
+               }
        }
 
        /* word and long word swap */
@@ -564,6 +566,9 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
        }
 
        for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+               unsigned long base_addr_y;
+               unsigned long base_addr_c = 0;
+               int pitch;
                ch = &priv->ch[k];
 
                if (!priv->ch[k].enabled)
@@ -598,16 +603,68 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
                }
                lcdc_write_chan(ch, LDDFR, tmp);
 
+               base_addr_y = ch->info->fix.smem_start;
+               base_addr_c = base_addr_y +
+                               ch->info->var.xres *
+                               ch->info->var.yres_virtual;
+               pitch = ch->info->fix.line_length;
+
+               /* test if we can enable meram */
+               if (ch->cfg.meram_cfg && priv->meram_dev &&
+                               priv->meram_dev->ops) {
+                       struct sh_mobile_meram_cfg *cfg;
+                       struct sh_mobile_meram_info *mdev;
+                       unsigned long icb_addr_y, icb_addr_c;
+                       int icb_pitch;
+                       int pf;
+
+                       cfg = ch->cfg.meram_cfg;
+                       mdev = priv->meram_dev;
+                       /* we need to de-init configured ICBs before we
+                        * we can re-initialize them.
+                        */
+                       if (ch->meram_enabled)
+                               mdev->ops->meram_unregister(mdev, cfg);
+
+                       ch->meram_enabled = 0;
+
+                       if (ch->info->var.nonstd) {
+                               if (ch->info->var.bits_per_pixel == 24)
+                                       pf = SH_MOBILE_MERAM_PF_NV24;
+                               else
+                                       pf = SH_MOBILE_MERAM_PF_NV;
+                       } else {
+                               pf = SH_MOBILE_MERAM_PF_RGB;
+                       }
+
+                       ret = mdev->ops->meram_register(mdev, cfg, pitch,
+                                               ch->info->var.yres,
+                                               pf,
+                                               base_addr_y,
+                                               base_addr_c,
+                                               &icb_addr_y,
+                                               &icb_addr_c,
+                                               &icb_pitch);
+                       if (!ret)  {
+                               /* set LDSA1R value */
+                               base_addr_y = icb_addr_y;
+                               pitch = icb_pitch;
+
+                               /* set LDSA2R value if required */
+                               if (base_addr_c)
+                                       base_addr_c = icb_addr_c;
+
+                               ch->meram_enabled = 1;
+                       }
+               }
+
                /* point out our frame buffer */
-               lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start);
+               lcdc_write_chan(ch, LDSA1R, base_addr_y);
                if (ch->info->var.nonstd)
-                       lcdc_write_chan(ch, LDSA2R,
-                               ch->info->fix.smem_start +
-                               ch->info->var.xres *
-                               ch->info->var.yres_virtual);
+                       lcdc_write_chan(ch, LDSA2R, base_addr_c);
 
                /* set line size */
-               lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length);
+               lcdc_write_chan(ch, LDMLSR, pitch);
 
                /* setup deferred io if SYS bus */
                tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
@@ -692,6 +749,17 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
                        board_cfg->display_off(board_cfg->board_data);
                        module_put(board_cfg->owner);
                }
+
+               /* disable the meram */
+               if (ch->meram_enabled) {
+                       struct sh_mobile_meram_cfg *cfg;
+                       struct sh_mobile_meram_info *mdev;
+                       cfg = ch->cfg.meram_cfg;
+                       mdev = priv->meram_dev;
+                       mdev->ops->meram_unregister(mdev, cfg);
+                       ch->meram_enabled = 0;
+               }
+
        }
 
        /* stop the lcdc */
@@ -875,9 +943,29 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var,
        } else
                base_addr_c = 0;
 
-       lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
-       if (base_addr_c)
-               lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
+       if (!ch->meram_enabled) {
+               lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y);
+               if (base_addr_c)
+                       lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c);
+       } else {
+               struct sh_mobile_meram_cfg *cfg;
+               struct sh_mobile_meram_info *mdev;
+               unsigned long icb_addr_y, icb_addr_c;
+               int ret;
+
+               cfg = ch->cfg.meram_cfg;
+               mdev = priv->meram_dev;
+               ret = mdev->ops->meram_update(mdev, cfg,
+                                       base_addr_y, base_addr_c,
+                                       &icb_addr_y, &icb_addr_c);
+               if (ret)
+                       return ret;
+
+               lcdc_write_chan_mirror(ch, LDSA1R, icb_addr_y);
+               if (icb_addr_c)
+                       lcdc_write_chan_mirror(ch, LDSA2R, icb_addr_c);
+
+       }
 
        if (lcdc_chan_is_sublcd(ch))
                lcdc_write(ch->lcdc, _LDRCNTR, ldrcntr ^ LDRCNTR_SRS);
@@ -1288,7 +1376,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
        struct fb_info *info = event->info;
        struct sh_mobile_lcdc_chan *ch = info->par;
        struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
-       int ret;
 
        if (&ch->lcdc->notifier != nb)
                return NOTIFY_DONE;
@@ -1302,7 +1389,6 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
                        board_cfg->display_off(board_cfg->board_data);
                        module_put(board_cfg->owner);
                }
-               pm_runtime_put(info->device);
                sh_mobile_lcdc_stop(ch->lcdc);
                break;
        case FB_EVENT_RESUME:
@@ -1316,9 +1402,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
                        module_put(board_cfg->owner);
                }
 
-               ret = sh_mobile_lcdc_start(ch->lcdc);
-               if (!ret)
-                       pm_runtime_get_sync(info->device);
+               sh_mobile_lcdc_start(ch->lcdc);
        }
 
        return NOTIFY_OK;
@@ -1420,6 +1504,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
                goto err1;
        }
 
+       priv->meram_dev = pdata->meram_dev;
+
        for (i = 0; i < j; i++) {
                struct fb_var_screeninfo *var;
                const struct fb_videomode *lcd_cfg, *max_cfg = NULL;
index f16cb5645a13fd12b8c95881dd51a5daab6352ad..aeed6687e6a737b9d51852380c48bea7e5ab0e6d 100644 (file)
@@ -39,6 +39,7 @@ struct sh_mobile_lcdc_chan {
        int use_count;
        int blank_status;
        struct mutex open_lock;         /* protects the use counter */
+       int meram_enabled;
 };
 
 #endif
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c
new file mode 100644 (file)
index 0000000..9170c82
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * SuperH Mobile MERAM Driver for SuperH Mobile LCDC Driver
+ *
+ * Copyright (c) 2011  Damian Hobson-Garcia <dhobsong@igel.co.jp>
+ *                      Takanari Hayama <taki@igel.co.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include "sh_mobile_meram.h"
+
+/* meram registers */
+#define MExxCTL 0x0
+#define MExxBSIZE 0x4
+#define MExxMNCF 0x8
+#define MExxSARA 0x10
+#define MExxSARB 0x14
+#define MExxSBSIZE 0x18
+
+#define MERAM_MExxCTL_VAL(ctl, next_icb, addr) \
+       ((ctl) | (((next_icb) & 0x1f) << 11) | (((addr) & 0x7ff) << 16))
+#define        MERAM_MExxBSIZE_VAL(a, b, c) \
+       (((a) << 28) | ((b) << 16) | (c))
+
+#define MEVCR1 0x4
+#define MEACTS 0x10
+#define MEQSEL1 0x40
+#define MEQSEL2 0x44
+
+/* settings */
+#define MERAM_SEC_LINE 15
+#define MERAM_LINE_WIDTH 2048
+
+/*
+ * MERAM/ICB access functions
+ */
+
+#define MERAM_ICB_OFFSET(base, idx, off)       \
+       ((base) + (0x400 + ((idx) * 0x20) + (off)))
+
+static inline void meram_write_icb(void __iomem *base, int idx, int off,
+       unsigned long val)
+{
+       iowrite32(val, MERAM_ICB_OFFSET(base, idx, off));
+}
+
+static inline unsigned long meram_read_icb(void __iomem *base, int idx, int off)
+{
+       return ioread32(MERAM_ICB_OFFSET(base, idx, off));
+}
+
+static inline void meram_write_reg(void __iomem *base, int off,
+               unsigned long val)
+{
+       iowrite32(val, base + off);
+}
+
+static inline unsigned long meram_read_reg(void __iomem *base, int off)
+{
+       return ioread32(base + off);
+}
+
+/*
+ * register ICB
+ */
+
+#define MERAM_CACHE_START(p)    ((p) >> 16)
+#define MERAM_CACHE_END(p)      ((p) & 0xffff)
+#define MERAM_CACHE_SET(o, s)   ((((o) & 0xffff) << 16) | \
+                                 (((o) + (s) - 1) & 0xffff))
+
+/*
+ * check if there's no overlaps in MERAM allocation.
+ */
+
+static inline int meram_check_overlap(struct sh_mobile_meram_priv *priv,
+                                     struct sh_mobile_meram_icb *new)
+{
+       int i;
+       int used_start, used_end, meram_start, meram_end;
+
+       /* valid ICB? */
+       if (new->marker_icb & ~0x1f || new->cache_icb & ~0x1f)
+               return 1;
+
+       if (test_bit(new->marker_icb, &priv->used_icb) ||
+                       test_bit(new->cache_icb,  &priv->used_icb))
+               return  1;
+
+       for (i = 0; i < priv->used_meram_cache_regions; i++) {
+               used_start = MERAM_CACHE_START(priv->used_meram_cache[i]);
+               used_end   = MERAM_CACHE_END(priv->used_meram_cache[i]);
+               meram_start = new->meram_offset;
+               meram_end   = new->meram_offset + new->meram_size;
+
+               if ((meram_start >= used_start && meram_start < used_end) ||
+                       (meram_end > used_start && meram_end < used_end))
+                       return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * mark the specified ICB as used
+ */
+
+static inline void meram_mark(struct sh_mobile_meram_priv *priv,
+                             struct sh_mobile_meram_icb *new)
+{
+       int n;
+
+       if (new->marker_icb < 0 || new->cache_icb < 0)
+               return;
+
+       __set_bit(new->marker_icb, &priv->used_icb);
+       __set_bit(new->cache_icb, &priv->used_icb);
+
+       n = priv->used_meram_cache_regions;
+
+       priv->used_meram_cache[n] = MERAM_CACHE_SET(new->meram_offset,
+                                                   new->meram_size);
+
+       priv->used_meram_cache_regions++;
+}
+
+/*
+ * unmark the specified ICB as used
+ */
+
+static inline void meram_unmark(struct sh_mobile_meram_priv *priv,
+                               struct sh_mobile_meram_icb *icb)
+{
+       int i;
+       unsigned long pattern;
+
+       if (icb->marker_icb < 0 || icb->cache_icb < 0)
+               return;
+
+       __clear_bit(icb->marker_icb, &priv->used_icb);
+       __clear_bit(icb->cache_icb, &priv->used_icb);
+
+       pattern = MERAM_CACHE_SET(icb->meram_offset, icb->meram_size);
+       for (i = 0; i < priv->used_meram_cache_regions; i++) {
+               if (priv->used_meram_cache[i] == pattern) {
+                       while (i < priv->used_meram_cache_regions - 1) {
+                               priv->used_meram_cache[i] =
+                                       priv->used_meram_cache[i + 1] ;
+                               i++;
+                       }
+                       priv->used_meram_cache[i] = 0;
+                       priv->used_meram_cache_regions--;
+                       break;
+               }
+       }
+}
+
+/*
+ * is this a YCbCr(NV12, NV16 or NV24) colorspace
+ */
+static inline int is_nvcolor(int cspace)
+{
+       if (cspace == SH_MOBILE_MERAM_PF_NV ||
+                       cspace == SH_MOBILE_MERAM_PF_NV24)
+               return 1;
+       return 0;
+}
+
+/*
+ * set the next address to fetch
+ */
+static inline void meram_set_next_addr(struct sh_mobile_meram_priv *priv,
+                                      struct sh_mobile_meram_cfg *cfg,
+                                      unsigned long base_addr_y,
+                                      unsigned long base_addr_c)
+{
+       unsigned long target;
+
+       target = (cfg->current_reg) ? MExxSARA : MExxSARB;
+       cfg->current_reg ^= 1;
+
+       /* set the next address to fetch */
+       meram_write_icb(priv->base, cfg->icb[0].cache_icb,  target,
+                       base_addr_y);
+       meram_write_icb(priv->base, cfg->icb[0].marker_icb, target,
+                       base_addr_y + cfg->icb[0].cache_unit);
+
+       if (is_nvcolor(cfg->pixelformat)) {
+               meram_write_icb(priv->base, cfg->icb[1].cache_icb,  target,
+                               base_addr_c);
+               meram_write_icb(priv->base, cfg->icb[1].marker_icb, target,
+                               base_addr_c + cfg->icb[1].cache_unit);
+       }
+}
+
+/*
+ * get the next ICB address
+ */
+static inline void meram_get_next_icb_addr(struct sh_mobile_meram_info *pdata,
+                                          struct sh_mobile_meram_cfg *cfg,
+                                          unsigned long *icb_addr_y,
+                                          unsigned long *icb_addr_c)
+{
+       unsigned long icb_offset;
+
+       if (pdata->addr_mode == SH_MOBILE_MERAM_MODE0)
+               icb_offset = 0x80000000 | (cfg->current_reg << 29);
+       else
+               icb_offset = 0xc0000000 | (cfg->current_reg << 23);
+
+       *icb_addr_y = icb_offset | (cfg->icb[0].marker_icb << 24);
+       if ((*icb_addr_c) && is_nvcolor(cfg->pixelformat))
+               *icb_addr_c = icb_offset | (cfg->icb[1].marker_icb << 24);
+}
+
+#define MERAM_CALC_BYTECOUNT(x, y) \
+       (((x) * (y) + (MERAM_LINE_WIDTH - 1)) & ~(MERAM_LINE_WIDTH - 1))
+
+/*
+ * initialize MERAM
+ */
+
+static int meram_init(struct sh_mobile_meram_priv *priv,
+                     struct sh_mobile_meram_icb *icb,
+                     int xres, int yres, int *out_pitch)
+{
+       unsigned long total_byte_count = MERAM_CALC_BYTECOUNT(xres, yres);
+       unsigned long bnm;
+       int lcdc_pitch, xpitch, line_cnt;
+       int save_lines;
+
+       /* adjust pitch to 1024, 2048, 4096 or 8192 */
+       lcdc_pitch = (xres - 1) | 1023;
+       lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 1);
+       lcdc_pitch = lcdc_pitch | (lcdc_pitch >> 2);
+       lcdc_pitch += 1;
+
+       /* derive settings */
+       if (lcdc_pitch == 8192 && yres >= 1024) {
+               lcdc_pitch = xpitch = MERAM_LINE_WIDTH;
+               line_cnt = total_byte_count >> 11;
+               *out_pitch = xres;
+               save_lines = (icb->meram_size / 16 / MERAM_SEC_LINE);
+               save_lines *= MERAM_SEC_LINE;
+       } else {
+               xpitch = xres;
+               line_cnt = yres;
+               *out_pitch = lcdc_pitch;
+               save_lines = icb->meram_size / (lcdc_pitch >> 10) / 2;
+               save_lines &= 0xff;
+       }
+       bnm = (save_lines - 1) << 16;
+
+       /* TODO: we better to check if we have enough MERAM buffer size */
+
+       /* set up ICB */
+       meram_write_icb(priv->base, icb->cache_icb,  MExxBSIZE,
+                       MERAM_MExxBSIZE_VAL(0x0, line_cnt - 1, xpitch - 1));
+       meram_write_icb(priv->base, icb->marker_icb, MExxBSIZE,
+                       MERAM_MExxBSIZE_VAL(0xf, line_cnt - 1, xpitch - 1));
+
+       meram_write_icb(priv->base, icb->cache_icb,  MExxMNCF, bnm);
+       meram_write_icb(priv->base, icb->marker_icb, MExxMNCF, bnm);
+
+       meram_write_icb(priv->base, icb->cache_icb,  MExxSBSIZE, xpitch);
+       meram_write_icb(priv->base, icb->marker_icb, MExxSBSIZE, xpitch);
+
+       /* save a cache unit size */
+       icb->cache_unit = xres * save_lines;
+
+       /*
+        * Set MERAM for framebuffer
+        *
+        * 0x70f:  WD = 0x3, WS=0x1, CM=0x1, MD=FB mode
+        * we also chain the cache_icb and the marker_icb.
+        * we also split the allocated MERAM buffer between two ICBs.
+        */
+       meram_write_icb(priv->base, icb->cache_icb, MExxCTL,
+                       MERAM_MExxCTL_VAL(0x70f, icb->marker_icb,
+                                         icb->meram_offset));
+       meram_write_icb(priv->base, icb->marker_icb, MExxCTL,
+                       MERAM_MExxCTL_VAL(0x70f, icb->cache_icb,
+                                         icb->meram_offset +
+                                         icb->meram_size / 2));
+
+       return 0;
+}
+
+static void meram_deinit(struct sh_mobile_meram_priv *priv,
+                       struct sh_mobile_meram_icb *icb)
+{
+       /* disable ICB */
+       meram_write_icb(priv->base, icb->cache_icb,  MExxCTL, 0);
+       meram_write_icb(priv->base, icb->marker_icb, MExxCTL, 0);
+       icb->cache_unit = 0;
+}
+
+/*
+ * register the ICB
+ */
+
+static int sh_mobile_meram_register(struct sh_mobile_meram_info *pdata,
+                                   struct sh_mobile_meram_cfg *cfg,
+                                   int xres, int yres, int pixelformat,
+                                   unsigned long base_addr_y,
+                                   unsigned long base_addr_c,
+                                   unsigned long *icb_addr_y,
+                                   unsigned long *icb_addr_c,
+                                   int *pitch)
+{
+       struct platform_device *pdev;
+       struct sh_mobile_meram_priv *priv;
+       int n, out_pitch;
+       int error = 0;
+
+       if (!pdata || !pdata->priv || !pdata->pdev || !cfg)
+               return -EINVAL;
+
+       if (pixelformat != SH_MOBILE_MERAM_PF_NV &&
+           pixelformat != SH_MOBILE_MERAM_PF_NV24 &&
+           pixelformat != SH_MOBILE_MERAM_PF_RGB)
+               return -EINVAL;
+
+       priv = pdata->priv;
+       pdev = pdata->pdev;
+
+       dev_dbg(&pdev->dev, "registering %dx%d (%s) (y=%08lx, c=%08lx)",
+               xres, yres, (!pixelformat) ? "yuv" : "rgb",
+               base_addr_y, base_addr_c);
+
+       mutex_lock(&priv->lock);
+
+       /* we can't handle wider than 8192px */
+       if (xres > 8192) {
+               dev_err(&pdev->dev, "width exceeding the limit (> 8192).");
+               error = -EINVAL;
+               goto err;
+       }
+
+       if (priv->used_meram_cache_regions + 2 > SH_MOBILE_MERAM_ICB_NUM) {
+               dev_err(&pdev->dev, "no more ICB available.");
+               error = -EINVAL;
+               goto err;
+       }
+
+       /* do we have at least one ICB config? */
+       if (cfg->icb[0].marker_icb < 0 || cfg->icb[0].cache_icb < 0) {
+               dev_err(&pdev->dev, "at least one ICB is required.");
+               error = -EINVAL;
+               goto err;
+       }
+
+       /* make sure that there's no overlaps */
+       if (meram_check_overlap(priv, &cfg->icb[0])) {
+               dev_err(&pdev->dev, "conflicting config detected.");
+               error = -EINVAL;
+               goto err;
+       }
+       n = 1;
+
+       /* do the same if we have the second ICB set */
+       if (cfg->icb[1].marker_icb >= 0 && cfg->icb[1].cache_icb >= 0) {
+               if (meram_check_overlap(priv, &cfg->icb[1])) {
+                       dev_err(&pdev->dev, "conflicting config detected.");
+                       error = -EINVAL;
+                       goto err;
+               }
+               n = 2;
+       }
+
+       if (is_nvcolor(pixelformat) && n != 2) {
+               dev_err(&pdev->dev, "requires two ICB sets for planar Y/C.");
+               error =  -EINVAL;
+               goto err;
+       }
+
+       /* we now register the ICB */
+       cfg->pixelformat = pixelformat;
+       meram_mark(priv, &cfg->icb[0]);
+       if (is_nvcolor(pixelformat))
+               meram_mark(priv, &cfg->icb[1]);
+
+       /* initialize MERAM */
+       meram_init(priv, &cfg->icb[0], xres, yres, &out_pitch);
+       *pitch = out_pitch;
+       if (pixelformat == SH_MOBILE_MERAM_PF_NV)
+               meram_init(priv, &cfg->icb[1], xres, (yres + 1) / 2,
+                       &out_pitch);
+       else if (pixelformat == SH_MOBILE_MERAM_PF_NV24)
+               meram_init(priv, &cfg->icb[1], 2 * xres, (yres + 1) / 2,
+                       &out_pitch);
+
+       cfg->current_reg = 1;
+       meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
+       meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
+
+       dev_dbg(&pdev->dev, "registered - can access via y=%08lx, c=%08lx",
+               *icb_addr_y, *icb_addr_c);
+
+err:
+       mutex_unlock(&priv->lock);
+       return error;
+}
+
+static int sh_mobile_meram_unregister(struct sh_mobile_meram_info *pdata,
+                                     struct sh_mobile_meram_cfg *cfg)
+{
+       struct sh_mobile_meram_priv *priv;
+
+       if (!pdata || !pdata->priv || !cfg)
+               return -EINVAL;
+
+       priv = pdata->priv;
+
+       mutex_lock(&priv->lock);
+
+       /* deinit & unmark */
+       if (is_nvcolor(cfg->pixelformat)) {
+               meram_deinit(priv, &cfg->icb[1]);
+               meram_unmark(priv, &cfg->icb[1]);
+       }
+       meram_deinit(priv, &cfg->icb[0]);
+       meram_unmark(priv, &cfg->icb[0]);
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static int sh_mobile_meram_update(struct sh_mobile_meram_info *pdata,
+                                 struct sh_mobile_meram_cfg *cfg,
+                                 unsigned long base_addr_y,
+                                 unsigned long base_addr_c,
+                                 unsigned long *icb_addr_y,
+                                 unsigned long *icb_addr_c)
+{
+       struct sh_mobile_meram_priv *priv;
+
+       if (!pdata || !pdata->priv || !cfg)
+               return -EINVAL;
+
+       priv = pdata->priv;
+
+       mutex_lock(&priv->lock);
+
+       meram_set_next_addr(priv, cfg, base_addr_y, base_addr_c);
+       meram_get_next_icb_addr(pdata, cfg, icb_addr_y, icb_addr_c);
+
+       mutex_unlock(&priv->lock);
+
+       return 0;
+}
+
+static struct sh_mobile_meram_ops sh_mobile_meram_ops = {
+       .module                 = THIS_MODULE,
+       .meram_register         = sh_mobile_meram_register,
+       .meram_unregister       = sh_mobile_meram_unregister,
+       .meram_update           = sh_mobile_meram_update,
+};
+
+/*
+ * initialize MERAM
+ */
+
+static int sh_mobile_meram_remove(struct platform_device *pdev);
+
+static int __devinit sh_mobile_meram_probe(struct platform_device *pdev)
+{
+       struct sh_mobile_meram_priv *priv;
+       struct sh_mobile_meram_info *pdata = pdev->dev.platform_data;
+       struct resource *res;
+       int error;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "cannot get platform resources\n");
+               return -ENOENT;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "cannot allocate device data\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, priv);
+
+       /* initialize private data */
+       mutex_init(&priv->lock);
+       priv->base = ioremap_nocache(res->start, resource_size(res));
+       if (!priv->base) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               error = -EFAULT;
+               goto err;
+       }
+       pdata->ops = &sh_mobile_meram_ops;
+       pdata->priv = priv;
+       pdata->pdev = pdev;
+
+       /* initialize ICB addressing mode */
+       if (pdata->addr_mode == SH_MOBILE_MERAM_MODE1)
+               meram_write_reg(priv->base, MEVCR1, 1 << 29);
+
+       dev_info(&pdev->dev, "sh_mobile_meram initialized.");
+
+       return 0;
+
+err:
+       sh_mobile_meram_remove(pdev);
+
+       return error;
+}
+
+
+static int sh_mobile_meram_remove(struct platform_device *pdev)
+{
+       struct sh_mobile_meram_priv *priv = platform_get_drvdata(pdev);
+
+       if (priv->base)
+               iounmap(priv->base);
+
+       mutex_destroy(&priv->lock);
+
+       kfree(priv);
+
+       return 0;
+}
+
+static struct platform_driver sh_mobile_meram_driver = {
+       .driver = {
+               .name           = "sh_mobile_meram",
+               .owner          = THIS_MODULE,
+       },
+       .probe          = sh_mobile_meram_probe,
+       .remove         = sh_mobile_meram_remove,
+};
+
+static int __init sh_mobile_meram_init(void)
+{
+       return platform_driver_register(&sh_mobile_meram_driver);
+}
+
+static void __exit sh_mobile_meram_exit(void)
+{
+       platform_driver_unregister(&sh_mobile_meram_driver);
+}
+
+module_init(sh_mobile_meram_init);
+module_exit(sh_mobile_meram_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile MERAM driver");
+MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/sh_mobile_meram.h b/drivers/video/sh_mobile_meram.h
new file mode 100644 (file)
index 0000000..82c54fb
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __sh_mobile_meram_h__
+#define __sh_mobile_meram_h__
+
+#include <linux/mutex.h>
+#include <video/sh_mobile_meram.h>
+
+/*
+ * MERAM private
+ */
+
+#define MERAM_ICB_Y 0x1
+#define MERAM_ICB_C 0x2
+
+/* MERAM cache size */
+#define SH_MOBILE_MERAM_ICB_NUM                32
+
+#define SH_MOBILE_MERAM_CACHE_OFFSET(p)        ((p) >> 16)
+#define SH_MOBILE_MERAM_CACHE_SIZE(p)  ((p) & 0xffff)
+
+struct sh_mobile_meram_priv {
+       void __iomem    *base;
+       struct mutex    lock;
+       unsigned long   used_icb;
+       int             used_meram_cache_regions;
+       unsigned long   used_meram_cache[SH_MOBILE_MERAM_ICB_NUM];
+};
+
+int sh_mobile_meram_alloc_icb(const struct sh_mobile_meram_cfg *cfg,
+                  int xres,
+                  int yres,
+                  unsigned int base_addr,
+                  int yuv_mode,
+                  int *marker_icb,
+                  int *out_pitch);
+
+void sh_mobile_meram_free_icb(int marker_icb);
+
+#define SH_MOBILE_MERAM_START(ind, ab) \
+       (0xC0000000 | ((ab & 0x1) << 23) | ((ind & 0x1F) << 24))
+
+#endif /* !__sh_mobile_meram_h__ */
index 56ef6b3a9851ca6f26a41b7be16a4c9678dacc9c..87f0be1e78b555e52297ed7d399f3bfe9364a1a5 100644 (file)
@@ -1625,22 +1625,22 @@ static int sm501fb_start(struct sm501fb_info *info,
        return 0; /* everything is setup */
 
  err_mem_res:
-       release_resource(info->fbmem_res);
-       kfree(info->fbmem_res);
+       release_mem_region(info->fbmem_res->start,
+                          resource_size(info->fbmem_res));
 
  err_regs2d_map:
        iounmap(info->regs2d);
 
  err_regs2d_res:
-       release_resource(info->regs2d_res);
-       kfree(info->regs2d_res);
+       release_mem_region(info->regs2d_res->start,
+                          resource_size(info->regs2d_res));
 
  err_regs_map:
        iounmap(info->regs);
 
  err_regs_res:
-       release_resource(info->regs_res);
-       kfree(info->regs_res);
+       release_mem_region(info->regs_res->start,
+                          resource_size(info->regs_res));
 
  err_release:
        return ret;
@@ -1652,16 +1652,16 @@ static void sm501fb_stop(struct sm501fb_info *info)
        sm501_unit_power(info->dev->parent, SM501_GATE_DISPLAY, 0);
 
        iounmap(info->fbmem);
-       release_resource(info->fbmem_res);
-       kfree(info->fbmem_res);
+       release_mem_region(info->fbmem_res->start,
+                          resource_size(info->fbmem_res));
 
        iounmap(info->regs2d);
-       release_resource(info->regs2d_res);
-       kfree(info->regs2d_res);
+       release_mem_region(info->regs2d_res->start,
+                          resource_size(info->regs2d_res));
 
        iounmap(info->regs);
-       release_resource(info->regs_res);
-       kfree(info->regs_res);
+       release_mem_region(info->regs_res->start,
+                          resource_size(info->regs_res));
 }
 
 static int sm501fb_init_fb(struct fb_info *fb,
index 695066b5b2e6d628204695727c3afde94a0f6de7..52b0f3e8ccac694743aa4ba6b2d3db0c86448a0e 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/prefetch.h>
 #include <linux/delay.h>
+#include <linux/prefetch.h>
 #include <video/udlfb.h>
 #include "edid.h"
 
@@ -1587,10 +1588,19 @@ static int dlfb_usb_probe(struct usb_interface *interface,
                goto error;
        }
 
-       for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
-               device_create_file(info->dev, &fb_device_attrs[i]);
+       for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
+               retval = device_create_file(info->dev, &fb_device_attrs[i]);
+               if (retval) {
+                       pr_err("device_create_file failed %d\n", retval);
+                       goto err_del_attrs;
+               }
+       }
 
-       device_create_bin_file(info->dev, &edid_attr);
+       retval = device_create_bin_file(info->dev, &edid_attr);
+       if (retval) {
+               pr_err("device_create_bin_file failed %d\n", retval);
+               goto err_del_attrs;
+       }
 
        pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
                        " Using %dK framebuffer memory\n", info->node,
@@ -1599,6 +1609,10 @@ static int dlfb_usb_probe(struct usb_interface *interface,
                        info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
        return 0;
 
+err_del_attrs:
+       for (i -= 1; i >= 0; i--)
+               device_remove_file(info->dev, &fb_device_attrs[i]);
+
 error:
        if (dev) {
 
index 814ac4e213a8a2c37873f99a68a7d639d575e6cf..0a93dc1cb4ac92868d1ecd6cbe8da687b23a4001 100644 (file)
@@ -1,6 +1,6 @@
 config 9P_FS
-       tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
-       depends on INET && NET_9P && EXPERIMENTAL
+       tristate "Plan 9 Resource Sharing Support (9P2000)"
+       depends on INET && NET_9P
        help
          If you say Y here, you will get experimental support for
          Plan 9 resource sharing via the 9P2000 protocol.
@@ -10,7 +10,6 @@ config 9P_FS
          If unsure, say N.
 
 if 9P_FS
-
 config 9P_FSCACHE
        bool "Enable 9P client caching support (EXPERIMENTAL)"
        depends on EXPERIMENTAL
index 82a7c38ddad0dec0c9ecded6fcc4d3eb93a50350..691c78f58bef23eaeac32489399479d981397aed 100644 (file)
@@ -259,7 +259,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
                if (IS_ERR(inode_fid)) {
                        err = PTR_ERR(inode_fid);
                        mutex_unlock(&v9inode->v_mutex);
-                       goto error;
+                       goto err_clunk_old_fid;
                }
                v9inode->writeback_fid = (void *) inode_fid;
        }
@@ -267,8 +267,8 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
        /* Since we are opening a file, assign the open fid to the file */
        filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
        if (IS_ERR(filp)) {
-               p9_client_clunk(ofid);
-               return PTR_ERR(filp);
+               err = PTR_ERR(filp);
+               goto err_clunk_old_fid;
        }
        filp->private_data = ofid;
 #ifdef CONFIG_9P_FSCACHE
@@ -278,10 +278,11 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
        return 0;
 
 error:
-       if (ofid)
-               p9_client_clunk(ofid);
        if (fid)
                p9_client_clunk(fid);
+err_clunk_old_fid:
+       if (ofid)
+               p9_client_clunk(ofid);
        return err;
 }
 
index f3aa9b08b228b7287886f418d2291962cf8eef2c..f6edba2e069f3a4a13f3c06a4786cfa9ed2532c3 100644 (file)
@@ -124,6 +124,7 @@ config TMPFS
 config TMPFS_POSIX_ACL
        bool "Tmpfs POSIX Access Control Lists"
        depends on TMPFS
+       select TMPFS_XATTR
        select GENERIC_ACL
        help
          POSIX Access Control Lists (ACLs) support permissions for users and
@@ -134,6 +135,22 @@ config TMPFS_POSIX_ACL
 
          If you don't know what Access Control Lists are, say N.
 
+config TMPFS_XATTR
+       bool "Tmpfs extended attributes"
+       depends on TMPFS
+       default n
+       help
+         Extended attributes are name:value pairs associated with inodes by
+         the kernel or by users (see the attr(5) manual page, or visit
+         <http://acl.bestbits.at/> for details).
+
+         Currently this enables support for the trusted.* and
+         security.* namespaces.
+
+         You need this for POSIX ACL support on tmpfs.
+
+         If unsure, say N.
+
 config HUGETLBFS
        bool "HugeTLB file system support"
        depends on X86 || IA64 || SPARC64 || (S390 && 64BIT) || \
index bf9c7a72037179c7ad524c439f1735a98ef5fda3..1f2b1997833340fc4e80b0c5a3c115a7f949fd15 100644 (file)
@@ -1238,6 +1238,8 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
        res = __blkdev_get(bdev, mode, 0);
 
        if (whole) {
+               struct gendisk *disk = whole->bd_disk;
+
                /* finish claiming */
                mutex_lock(&bdev->bd_mutex);
                spin_lock(&bdev_lock);
@@ -1264,15 +1266,16 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
                spin_unlock(&bdev_lock);
 
                /*
-                * Block event polling for write claims.  Any write
-                * holder makes the write_holder state stick until all
-                * are released.  This is good enough and tracking
-                * individual writeable reference is too fragile given
-                * the way @mode is used in blkdev_get/put().
+                * Block event polling for write claims if requested.  Any
+                * write holder makes the write_holder state stick until
+                * all are released.  This is good enough and tracking
+                * individual writeable reference is too fragile given the
+                * way @mode is used in blkdev_get/put().
                 */
-               if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder) {
+               if ((disk->flags & GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE) &&
+                   !res && (mode & FMODE_WRITE) && !bdev->bd_write_holder) {
                        bdev->bd_write_holder = true;
-                       disk_block_events(bdev->bd_disk);
+                       disk_block_events(disk);
                }
 
                mutex_unlock(&bdev->bd_mutex);
index 38b8ab554924cd2d4a9ddf11ce3a79efe3d411cd..33da49dc3cc6fa49498df7dd902481f86d8fac9e 100644 (file)
@@ -848,7 +848,8 @@ get_more_pages:
                op->payload_len = cpu_to_le32(len);
                req->r_request->hdr.data_len = cpu_to_le32(len);
 
-               ceph_osdc_start_request(&fsc->client->osdc, req, true);
+               rc = ceph_osdc_start_request(&fsc->client->osdc, req, true);
+               BUG_ON(rc);
                req = NULL;
 
                /* continue? */
@@ -880,8 +881,6 @@ release_pvec_pages:
 out:
        if (req)
                ceph_osdc_put_request(req);
-       if (rc > 0)
-               rc = 0;  /* vfs expects us to return 0 */
        ceph_put_snap_context(snapc);
        dout("writepages done, rc = %d\n", rc);
        return rc;
index 2a5404c1c42f4efd1be78f5d24eed337c24429e3..1f72b00447c40e6383330496421a177b79150405 100644 (file)
@@ -569,7 +569,8 @@ retry:
                list_add_tail(&cap->session_caps, &session->s_caps);
                session->s_nr_caps++;
                spin_unlock(&session->s_cap_lock);
-       }
+       } else if (new_cap)
+               ceph_put_cap(mdsc, new_cap);
 
        if (!ci->i_snap_realm) {
                /*
@@ -2634,6 +2635,7 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex,
                              struct ceph_mds_session *session,
                              int *open_target_sessions)
 {
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        int mds = session->s_mds;
        unsigned mseq = le32_to_cpu(ex->migrate_seq);
@@ -2670,6 +2672,19 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex,
                         * export targets, so that we get the matching IMPORT
                         */
                        *open_target_sessions = 1;
+
+                       /*
+                        * we can't flush dirty caps that we've seen the
+                        * EXPORT but no IMPORT for
+                        */
+                       spin_lock(&mdsc->cap_dirty_lock);
+                       if (!list_empty(&ci->i_dirty_item)) {
+                               dout(" moving %p to cap_dirty_migrating\n",
+                                    inode);
+                               list_move(&ci->i_dirty_item,
+                                         &mdsc->cap_dirty_migrating);
+                       }
+                       spin_unlock(&mdsc->cap_dirty_lock);
                }
                __ceph_remove_cap(cap);
        }
@@ -2707,6 +2722,13 @@ static void handle_cap_import(struct ceph_mds_client *mdsc,
                ci->i_cap_exporting_issued = 0;
                ci->i_cap_exporting_mseq = 0;
                ci->i_cap_exporting_mds = -1;
+
+               spin_lock(&mdsc->cap_dirty_lock);
+               if (!list_empty(&ci->i_dirty_item)) {
+                       dout(" moving %p back to cap_dirty\n", inode);
+                       list_move(&ci->i_dirty_item, &mdsc->cap_dirty);
+               }
+               spin_unlock(&mdsc->cap_dirty_lock);
        } else {
                dout("handle_cap_import inode %p ci %p mds%d mseq %d\n",
                     inode, ci, mds, mseq);
@@ -2910,38 +2932,16 @@ void ceph_check_delayed_caps(struct ceph_mds_client *mdsc)
  */
 void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
 {
-       struct ceph_inode_info *ci, *nci = NULL;
-       struct inode *inode, *ninode = NULL;
-       struct list_head *p, *n;
+       struct ceph_inode_info *ci;
+       struct inode *inode;
 
        dout("flush_dirty_caps\n");
        spin_lock(&mdsc->cap_dirty_lock);
-       list_for_each_safe(p, n, &mdsc->cap_dirty) {
-               if (nci) {
-                       ci = nci;
-                       inode = ninode;
-                       ci->i_ceph_flags &= ~CEPH_I_NOFLUSH;
-                       dout("flush_dirty_caps inode %p (was next inode)\n",
-                            inode);
-               } else {
-                       ci = list_entry(p, struct ceph_inode_info,
-                                       i_dirty_item);
-                       inode = igrab(&ci->vfs_inode);
-                       BUG_ON(!inode);
-                       dout("flush_dirty_caps inode %p\n", inode);
-               }
-               if (n != &mdsc->cap_dirty) {
-                       nci = list_entry(n, struct ceph_inode_info,
-                                        i_dirty_item);
-                       ninode = igrab(&nci->vfs_inode);
-                       BUG_ON(!ninode);
-                       nci->i_ceph_flags |= CEPH_I_NOFLUSH;
-                       dout("flush_dirty_caps next inode %p, noflush\n",
-                            ninode);
-               } else {
-                       nci = NULL;
-                       ninode = NULL;
-               }
+       while (!list_empty(&mdsc->cap_dirty)) {
+               ci = list_first_entry(&mdsc->cap_dirty, struct ceph_inode_info,
+                                     i_dirty_item);
+               inode = igrab(&ci->vfs_inode);
+               dout("flush_dirty_caps %p\n", inode);
                spin_unlock(&mdsc->cap_dirty_lock);
                if (inode) {
                        ceph_check_caps(ci, CHECK_CAPS_NODELAY|CHECK_CAPS_FLUSH,
@@ -2951,6 +2951,7 @@ void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc)
                spin_lock(&mdsc->cap_dirty_lock);
        }
        spin_unlock(&mdsc->cap_dirty_lock);
+       dout("flush_dirty_caps done\n");
 }
 
 /*
index 1a867a3601aea88ee25c9fadf399d4a2a3472498..33729e822bb96dc0e1197cca57106fb64a9f0abe 100644 (file)
@@ -360,7 +360,7 @@ more:
        rinfo = &fi->last_readdir->r_reply_info;
        dout("readdir frag %x num %d off %d chunkoff %d\n", frag,
             rinfo->dir_nr, off, fi->offset);
-       while (off - fi->offset >= 0 && off - fi->offset < rinfo->dir_nr) {
+       while (off >= fi->offset && off - fi->offset < rinfo->dir_nr) {
                u64 pos = ceph_make_fpos(frag, off);
                struct ceph_mds_reply_inode *in =
                        rinfo->dir_in[off - fi->offset].in;
@@ -1066,16 +1066,17 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        int left;
+       const int bufsize = 1024;
 
        if (!ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT))
                return -EISDIR;
 
        if (!cf->dir_info) {
-               cf->dir_info = kmalloc(1024, GFP_NOFS);
+               cf->dir_info = kmalloc(bufsize, GFP_NOFS);
                if (!cf->dir_info)
                        return -ENOMEM;
                cf->dir_info_len =
-                       sprintf(cf->dir_info,
+                       snprintf(cf->dir_info, bufsize,
                                "entries:   %20lld\n"
                                " files:    %20lld\n"
                                " subdirs:  %20lld\n"
index e41056174bf81ad96397500ad89b19754a9bc0ff..a610d3d674886a082e5a0e0803f3612534b62f74 100644 (file)
@@ -86,6 +86,7 @@ static int ceph_encode_fh(struct dentry *dentry, u32 *rawfh, int *max_len,
 static struct dentry *__fh_to_dentry(struct super_block *sb,
                                     struct ceph_nfs_fh *fh)
 {
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
        struct inode *inode;
        struct dentry *dentry;
        struct ceph_vino vino;
@@ -95,8 +96,24 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,
        vino.ino = fh->ino;
        vino.snap = CEPH_NOSNAP;
        inode = ceph_find_inode(sb, vino);
-       if (!inode)
-               return ERR_PTR(-ESTALE);
+       if (!inode) {
+               struct ceph_mds_request *req;
+
+               req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPINO,
+                                              USE_ANY_MDS);
+               if (IS_ERR(req))
+                       return ERR_CAST(req);
+
+               req->r_ino1 = vino;
+               req->r_num_caps = 1;
+               err = ceph_mdsc_do_request(mdsc, NULL, req);
+               inode = req->r_target_inode;
+               if (inode)
+                       igrab(inode);
+               ceph_mdsc_put_request(req);
+               if (!inode)
+                       return ERR_PTR(-ESTALE);
+       }
 
        dentry = d_obtain_alias(inode);
        if (IS_ERR(dentry)) {
@@ -148,8 +165,10 @@ static struct dentry *__cfh_to_dentry(struct super_block *sb,
                snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash);
                req->r_num_caps = 1;
                err = ceph_mdsc_do_request(mdsc, NULL, req);
+               inode = req->r_target_inode;
+               if (inode)
+                       igrab(inode);
                ceph_mdsc_put_request(req);
-               inode = ceph_find_inode(sb, vino);
                if (!inode)
                        return ERR_PTR(err ? err : -ESTALE);
        }
index d0fae4ce9ba55b704ccedadbfd3f298e3a00cfb4..79743d146be69ec8ce3f279a032e1a5459eb462c 100644 (file)
@@ -578,6 +578,7 @@ static void __register_request(struct ceph_mds_client *mdsc,
        if (dir) {
                struct ceph_inode_info *ci = ceph_inode(dir);
 
+               ihold(dir);
                spin_lock(&ci->i_unsafe_lock);
                req->r_unsafe_dir = dir;
                list_add_tail(&req->r_unsafe_dir_item, &ci->i_unsafe_dirops);
@@ -598,6 +599,9 @@ static void __unregister_request(struct ceph_mds_client *mdsc,
                spin_lock(&ci->i_unsafe_lock);
                list_del_init(&req->r_unsafe_dir_item);
                spin_unlock(&ci->i_unsafe_lock);
+
+               iput(req->r_unsafe_dir);
+               req->r_unsafe_dir = NULL;
        }
 
        ceph_mdsc_put_request(req);
@@ -2691,7 +2695,6 @@ static void handle_lease(struct ceph_mds_client *mdsc,
 {
        struct super_block *sb = mdsc->fsc->sb;
        struct inode *inode;
-       struct ceph_inode_info *ci;
        struct dentry *parent, *dentry;
        struct ceph_dentry_info *di;
        int mds = session->s_mds;
@@ -2728,7 +2731,6 @@ static void handle_lease(struct ceph_mds_client *mdsc,
                dout("handle_lease no inode %llx\n", vino.ino);
                goto release;
        }
-       ci = ceph_inode(inode);
 
        /* dentry */
        parent = d_find_alias(inode);
@@ -3002,6 +3004,7 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
        spin_lock_init(&mdsc->snap_flush_lock);
        mdsc->cap_flush_seq = 0;
        INIT_LIST_HEAD(&mdsc->cap_dirty);
+       INIT_LIST_HEAD(&mdsc->cap_dirty_migrating);
        mdsc->num_cap_flushing = 0;
        spin_lock_init(&mdsc->cap_dirty_lock);
        init_waitqueue_head(&mdsc->cap_flushing_wq);
index 4e3a9cc0bba6f1f89a77e6355a8f72a52614d43f..7d8a0d662d56cfa73876d302f8de892a046a9972 100644 (file)
@@ -278,6 +278,7 @@ struct ceph_mds_client {
 
        u64               cap_flush_seq;
        struct list_head  cap_dirty;        /* inodes with dirty caps */
+       struct list_head  cap_dirty_migrating; /* ...that are migration... */
        int               num_cap_flushing; /* # caps we are flushing */
        spinlock_t        cap_dirty_lock;   /* protects above items */
        wait_queue_head_t cap_flushing_wq;
index 18b2a1f10ed89cab1562f696adebf391bf2a8763..37f72ee5bf7c9577f164ce4a472d7d4d8f0c4aaa 100644 (file)
@@ -1220,7 +1220,7 @@ void shrink_dcache_parent(struct dentry * parent)
 EXPORT_SYMBOL(shrink_dcache_parent);
 
 /*
- * Scan `nr' dentries and return the number which remain.
+ * Scan `sc->nr_slab_to_reclaim' dentries and return the number which remain.
  *
  * We need to avoid reentering the filesystem if the caller is performing a
  * GFP_NOFS allocation attempt.  One example deadlock is:
@@ -1231,8 +1231,12 @@ EXPORT_SYMBOL(shrink_dcache_parent);
  *
  * In this case we return -1 to tell the caller that we baled.
  */
-static int shrink_dcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int shrink_dcache_memory(struct shrinker *shrink,
+                               struct shrink_control *sc)
 {
+       int nr = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
+
        if (nr) {
                if (!(gfp_mask & __GFP_FS))
                        return -1;
index 98b77c89494caf7c364272194316d431e10cfcef..c00e055b62820945bef291fa68b145a4d7145667 100644 (file)
@@ -40,9 +40,12 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
 static void drop_slab(void)
 {
        int nr_objects;
+       struct shrink_control shrink = {
+               .gfp_mask = GFP_KERNEL,
+       };
 
        do {
-               nr_objects = shrink_slab(1000, GFP_KERNEL, 1000);
+               nr_objects = shrink_slab(&shrink, 1000, 1000);
        } while (nr_objects > 10);
 }
 
index c1cf372f17a7fdb5bb0d7dc89f1ae8ccf5964638..936f5776655c906c25a40400ace80bc33b643c87 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -200,7 +200,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
 
 #ifdef CONFIG_STACK_GROWSUP
        if (write) {
-               ret = expand_stack_downwards(bprm->vma, pos);
+               ret = expand_downwards(bprm->vma, pos);
                if (ret < 0)
                        return NULL;
        }
@@ -600,7 +600,7 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
        unsigned long length = old_end - old_start;
        unsigned long new_start = old_start - shift;
        unsigned long new_end = old_end - shift;
-       struct mmu_gather *tlb;
+       struct mmu_gather tlb;
 
        BUG_ON(new_start > new_end);
 
@@ -626,12 +626,12 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
                return -ENOMEM;
 
        lru_add_drain();
-       tlb = tlb_gather_mmu(mm, 0);
+       tlb_gather_mmu(&tlb, mm, 0);
        if (new_end > old_start) {
                /*
                 * when the old and new regions overlap clear from new_end.
                 */
-               free_pgd_range(tlb, new_end, old_end, new_end,
+               free_pgd_range(&tlb, new_end, old_end, new_end,
                        vma->vm_next ? vma->vm_next->vm_start : 0);
        } else {
                /*
@@ -640,10 +640,10 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
                 * have constraints on va-space that make this illegal (IA64) -
                 * for the others its just a little faster.
                 */
-               free_pgd_range(tlb, old_start, old_end, new_end,
+               free_pgd_range(&tlb, old_start, old_end, new_end,
                        vma->vm_next ? vma->vm_next->vm_start : 0);
        }
-       tlb_finish_mmu(tlb, new_end, old_end);
+       tlb_finish_mmu(&tlb, new_end, old_end);
 
        /*
         * Shrink the vma to just the new range.  Always succeeds.
index 48a18f184d5041b9f4909137898fe0fd51bc45d8..30afdfa7aec78b6a7e47ab791fbf9ec1198870d6 100644 (file)
@@ -33,8 +33,6 @@ void fscache_enqueue_operation(struct fscache_operation *op)
        _enter("{OBJ%x OP%x,%u}",
               op->object->debug_id, op->debug_id, atomic_read(&op->usage));
 
-       fscache_set_op_state(op, "EnQ");
-
        ASSERT(list_empty(&op->pend_link));
        ASSERT(op->processor != NULL);
        ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE);
@@ -66,8 +64,6 @@ EXPORT_SYMBOL(fscache_enqueue_operation);
 static void fscache_run_op(struct fscache_object *object,
                           struct fscache_operation *op)
 {
-       fscache_set_op_state(op, "Run");
-
        object->n_in_progress++;
        if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags))
                wake_up_bit(&op->flags, FSCACHE_OP_WAITING);
@@ -88,8 +84,6 @@ int fscache_submit_exclusive_op(struct fscache_object *object,
 
        _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id);
 
-       fscache_set_op_state(op, "SubmitX");
-
        spin_lock(&object->lock);
        ASSERTCMP(object->n_ops, >=, object->n_in_progress);
        ASSERTCMP(object->n_ops, >=, object->n_exclusive);
@@ -194,8 +188,6 @@ int fscache_submit_op(struct fscache_object *object,
 
        ASSERTCMP(atomic_read(&op->usage), >, 0);
 
-       fscache_set_op_state(op, "Submit");
-
        spin_lock(&object->lock);
        ASSERTCMP(object->n_ops, >=, object->n_in_progress);
        ASSERTCMP(object->n_ops, >=, object->n_exclusive);
@@ -335,8 +327,6 @@ void fscache_put_operation(struct fscache_operation *op)
        if (!atomic_dec_and_test(&op->usage))
                return;
 
-       fscache_set_op_state(op, "Put");
-
        _debug("PUT OP");
        if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags))
                BUG();
index 41c441c2058daad798aff3766cb5444c9961b44a..a2a5d19ece6adc92b3deda283bd6f5db1f2c701c 100644 (file)
@@ -155,11 +155,9 @@ static void fscache_attr_changed_op(struct fscache_operation *op)
        fscache_stat(&fscache_n_attr_changed_calls);
 
        if (fscache_object_is_active(object)) {
-               fscache_set_op_state(op, "CallFS");
                fscache_stat(&fscache_n_cop_attr_changed);
                ret = object->cache->ops->attr_changed(object);
                fscache_stat_d(&fscache_n_cop_attr_changed);
-               fscache_set_op_state(op, "Done");
                if (ret < 0)
                        fscache_abort_object(object);
        }
@@ -190,7 +188,6 @@ int __fscache_attr_changed(struct fscache_cookie *cookie)
 
        fscache_operation_init(op, fscache_attr_changed_op, NULL);
        op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE);
-       fscache_set_op_name(op, "Attr");
 
        spin_lock(&cookie->lock);
 
@@ -257,7 +254,6 @@ static struct fscache_retrieval *fscache_alloc_retrieval(
        op->context     = context;
        op->start_time  = jiffies;
        INIT_LIST_HEAD(&op->to_do);
-       fscache_set_op_name(&op->op, "Retr");
        return op;
 }
 
@@ -368,7 +364,6 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
                _leave(" = -ENOMEM");
                return -ENOMEM;
        }
-       fscache_set_op_name(&op->op, "RetrRA1");
 
        spin_lock(&cookie->lock);
 
@@ -487,7 +482,6 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
        op = fscache_alloc_retrieval(mapping, end_io_func, context);
        if (!op)
                return -ENOMEM;
-       fscache_set_op_name(&op->op, "RetrRAN");
 
        spin_lock(&cookie->lock);
 
@@ -589,7 +583,6 @@ int __fscache_alloc_page(struct fscache_cookie *cookie,
        op = fscache_alloc_retrieval(page->mapping, NULL, NULL);
        if (!op)
                return -ENOMEM;
-       fscache_set_op_name(&op->op, "RetrAL1");
 
        spin_lock(&cookie->lock);
 
@@ -662,8 +655,6 @@ static void fscache_write_op(struct fscache_operation *_op)
 
        _enter("{OP%x,%d}", op->op.debug_id, atomic_read(&op->op.usage));
 
-       fscache_set_op_state(&op->op, "GetPage");
-
        spin_lock(&object->lock);
        cookie = object->cookie;
 
@@ -698,15 +689,12 @@ static void fscache_write_op(struct fscache_operation *_op)
        spin_unlock(&cookie->stores_lock);
        spin_unlock(&object->lock);
 
-       fscache_set_op_state(&op->op, "Store");
        fscache_stat(&fscache_n_store_pages);
        fscache_stat(&fscache_n_cop_write_page);
        ret = object->cache->ops->write_page(op, page);
        fscache_stat_d(&fscache_n_cop_write_page);
-       fscache_set_op_state(&op->op, "EndWrite");
        fscache_end_page_write(object, page);
        if (ret < 0) {
-               fscache_set_op_state(&op->op, "Abort");
                fscache_abort_object(object);
        } else {
                fscache_enqueue_operation(&op->op);
@@ -778,7 +766,6 @@ int __fscache_write_page(struct fscache_cookie *cookie,
        fscache_operation_init(&op->op, fscache_write_op,
                               fscache_release_write_op);
        op->op.flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_WAITING);
-       fscache_set_op_name(&op->op, "Write1");
 
        ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM);
        if (ret < 0)
index a2a6abbccc070194c94dfeb37913291fb57be61a..2792a790e50ba9ae2eae255eccc68e47f39d9501 100644 (file)
@@ -1346,11 +1346,14 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret)
 }
 
 
-static int gfs2_shrink_glock_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int gfs2_shrink_glock_memory(struct shrinker *shrink,
+                                   struct shrink_control *sc)
 {
        struct gfs2_glock *gl;
        int may_demote;
        int nr_skipped = 0;
+       int nr = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
        LIST_HEAD(skipped);
 
        if (nr == 0)
index e23d9864c418d69c0abdce5d699a20904baa3779..42e8d23bc0472007aa0178b7d049d952175b2391 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
@@ -77,19 +78,20 @@ static LIST_HEAD(qd_lru_list);
 static atomic_t qd_lru_count = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(qd_lru_lock);
 
-int gfs2_shrink_qd_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+int gfs2_shrink_qd_memory(struct shrinker *shrink, struct shrink_control *sc)
 {
        struct gfs2_quota_data *qd;
        struct gfs2_sbd *sdp;
+       int nr_to_scan = sc->nr_to_scan;
 
-       if (nr == 0)
+       if (nr_to_scan == 0)
                goto out;
 
-       if (!(gfp_mask & __GFP_FS))
+       if (!(sc->gfp_mask & __GFP_FS))
                return -1;
 
        spin_lock(&qd_lru_lock);
-       while (nr && !list_empty(&qd_lru_list)) {
+       while (nr_to_scan && !list_empty(&qd_lru_list)) {
                qd = list_entry(qd_lru_list.next,
                                struct gfs2_quota_data, qd_reclaim);
                sdp = qd->qd_gl->gl_sbd;
@@ -110,7 +112,7 @@ int gfs2_shrink_qd_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
                spin_unlock(&qd_lru_lock);
                kmem_cache_free(gfs2_quotad_cachep, qd);
                spin_lock(&qd_lru_lock);
-               nr--;
+               nr_to_scan--;
        }
        spin_unlock(&qd_lru_lock);
 
index e7d236ca48bd28df49f8555fbaa9e1b90460fbd0..90bf1c302a983df6c74191f5c2341b8cf5c70f69 100644 (file)
@@ -12,6 +12,7 @@
 
 struct gfs2_inode;
 struct gfs2_sbd;
+struct shrink_control;
 
 #define NO_QUOTA_CHANGE ((u32)-1)
 
@@ -51,7 +52,8 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
        return ret;
 }
 
-extern int gfs2_shrink_qd_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask);
+extern int gfs2_shrink_qd_memory(struct shrinker *shrink,
+                                struct shrink_control *sc);
 extern const struct quotactl_ops gfs2_quotactl_ops;
 
 #endif /* __QUOTA_DOT_H__ */
index b9eeb1cd03ff540dc87aa31f43dc9eb03fbafb61..e7a035781b7dd30694acd0b3ee104758a3ffcf87 100644 (file)
@@ -412,10 +412,10 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset)
        pgoff = offset >> PAGE_SHIFT;
 
        i_size_write(inode, offset);
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        if (!prio_tree_empty(&mapping->i_mmap))
                hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff);
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        truncate_hugepages(inode, offset);
        return 0;
 }
index 05f4fa521325b071f7ad114354b30233b131ae48..990d284877a12472393a8d444b732ba9ec105c7c 100644 (file)
@@ -326,12 +326,11 @@ void address_space_init_once(struct address_space *mapping)
        memset(mapping, 0, sizeof(*mapping));
        INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC);
        spin_lock_init(&mapping->tree_lock);
-       spin_lock_init(&mapping->i_mmap_lock);
+       mutex_init(&mapping->i_mmap_mutex);
        INIT_LIST_HEAD(&mapping->private_list);
        spin_lock_init(&mapping->private_lock);
        INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap);
        INIT_LIST_HEAD(&mapping->i_mmap_nonlinear);
-       mutex_init(&mapping->unmap_mutex);
 }
 EXPORT_SYMBOL(address_space_init_once);
 
@@ -752,8 +751,12 @@ static void prune_icache(int nr_to_scan)
  * This function is passed the number of inodes to scan, and it returns the
  * total number of remaining possibly-reclaimable inodes.
  */
-static int shrink_icache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int shrink_icache_memory(struct shrinker *shrink,
+                               struct shrink_control *sc)
 {
+       int nr = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
+
        if (nr) {
                /*
                 * Nasty deadlock avoidance.  We may hold various FS locks,
index 2f174be065558500c1192cf401dbd6cc0e13c046..8c32ef3ba88e7ac25a197866a38c4590836f12be 100644 (file)
@@ -90,7 +90,8 @@ static DEFINE_SPINLOCK(mb_cache_spinlock);
  * What the mbcache registers as to get shrunk dynamically.
  */
 
-static int mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask);
+static int mb_cache_shrink_fn(struct shrinker *shrink,
+                             struct shrink_control *sc);
 
 static struct shrinker mb_cache_shrinker = {
        .shrink = mb_cache_shrink_fn,
@@ -156,18 +157,19 @@ forget:
  * gets low.
  *
  * @shrink: (ignored)
- * @nr_to_scan: Number of objects to scan
- * @gfp_mask: (ignored)
+ * @sc: shrink_control passed from reclaim
  *
  * Returns the number of objects which are present in the cache.
  */
 static int
-mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+mb_cache_shrink_fn(struct shrinker *shrink, struct shrink_control *sc)
 {
        LIST_HEAD(free_list);
        struct mb_cache *cache;
        struct mb_cache_entry *entry, *tmp;
        int count = 0;
+       int nr_to_scan = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        mb_debug("trying to free %d entries", nr_to_scan);
        spin_lock(&mb_cache_spinlock);
index 0250e4ce489347f0a23fdbd551cd216a7abe208a..202f370526a724979ed3a8af6d1d6156027e5a09 100644 (file)
@@ -461,7 +461,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
 #endif
        struct ncp_entry_info finfo;
 
-       data.wdog_pid = NULL;
+       memset(&data, 0, sizeof(data));
        server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
        if (!server)
                return -ENOMEM;
@@ -496,7 +496,6 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
                                struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
 
                                data.flags = md->flags;
-                               data.int_flags = 0;
                                data.mounted_uid = md->mounted_uid;
                                data.wdog_pid = find_get_pid(md->wdog_pid);
                                data.ncp_fd = md->ncp_fd;
@@ -507,7 +506,6 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
                                data.file_mode = md->file_mode;
                                data.dir_mode = md->dir_mode;
                                data.info_fd = -1;
-                               data.mounted_vol[0] = 0;
                        }
                        break;
                default:
index 7237672216c804769b945c9b09b1e57e1b3de202..424e47773a8436a40ac58737f383c1dc8bb28c42 100644 (file)
@@ -2042,11 +2042,14 @@ static void nfs_access_free_list(struct list_head *head)
        }
 }
 
-int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+int nfs_access_cache_shrinker(struct shrinker *shrink,
+                             struct shrink_control *sc)
 {
        LIST_HEAD(head);
        struct nfs_inode *nfsi, *next;
        struct nfs_access_entry *cache;
+       int nr_to_scan = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
                return (nr_to_scan == 0) ? 0 : -1;
index ce118ce885dd5e20276356011e288d8502c6ef11..2df6ca7b589895b14e4dc2d43aa23dd85d0afa17 100644 (file)
@@ -234,7 +234,7 @@ extern int nfs_init_client(struct nfs_client *clp,
 
 /* dir.c */
 extern int nfs_access_cache_shrinker(struct shrinker *shrink,
-                                       int nr_to_scan, gfp_t gfp_mask);
+                                       struct shrink_control *sc);
 
 /* inode.c */
 extern struct workqueue_struct *nfsiod_workqueue;
index d545e97d99c3390706894ff1b030c2491a2c0a38..8ed4d3433199fb233913c3f2e6e88afc149c062c 100644 (file)
@@ -255,7 +255,11 @@ ssize_t part_discard_alignment_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
        struct hd_struct *p = dev_to_part(dev);
-       return sprintf(buf, "%u\n", p->discard_alignment);
+       struct gendisk *disk = dev_to_disk(dev);
+
+       return sprintf(buf, "%u\n",
+                       queue_limit_discard_alignment(&disk->queue->limits,
+                                                       p->start_sect));
 }
 
 ssize_t part_stat_show(struct device *dev,
@@ -449,8 +453,6 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        p->start_sect = start;
        p->alignment_offset =
                queue_limit_alignment_offset(&disk->queue->limits, start);
-       p->discard_alignment =
-               queue_limit_discard_alignment(&disk->queue->limits, start);
        p->nr_sects = len;
        p->partno = partno;
        p->policy = get_disk_ro(disk);
index df434c5f28fbdce6fe676dcc2a6fe8ecb9e75ec6..c1c729335924803f92e5530d4197b1eb3bd4907c 100644 (file)
@@ -20,6 +20,7 @@ proc-y        += stat.o
 proc-y += uptime.o
 proc-y += version.o
 proc-y += softirqs.o
+proc-y += namespaces.o
 proc-$(CONFIG_PROC_SYSCTL)     += proc_sysctl.o
 proc-$(CONFIG_NET)             += proc_net.o
 proc-$(CONFIG_PROC_KCORE)      += kcore.o
index dfa532730e55788a7459095ca9c788dbb58d6af9..dc8bca72b002d9b01036bb7e659495eb972af322 100644 (file)
@@ -600,7 +600,7 @@ static int proc_fd_access_allowed(struct inode *inode)
        return allowed;
 }
 
-static int proc_setattr(struct dentry *dentry, struct iattr *attr)
+int proc_setattr(struct dentry *dentry, struct iattr *attr)
 {
        int error;
        struct inode *inode = dentry->d_inode;
@@ -1736,8 +1736,7 @@ static int task_dumpable(struct task_struct *task)
        return 0;
 }
 
-
-static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
+struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
 {
        struct inode * inode;
        struct proc_inode *ei;
@@ -1779,7 +1778,7 @@ out_unlock:
        return NULL;
 }
 
-static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 {
        struct inode *inode = dentry->d_inode;
        struct task_struct *task;
@@ -1820,7 +1819,7 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
  * made this apply to all per process world readable and executable
  * directories.
  */
-static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
+int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode;
        struct task_struct *task;
@@ -1862,7 +1861,7 @@ static int pid_delete_dentry(const struct dentry * dentry)
        return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
 }
 
-static const struct dentry_operations pid_dentry_operations =
+const struct dentry_operations pid_dentry_operations =
 {
        .d_revalidate   = pid_revalidate,
        .d_delete       = pid_delete_dentry,
@@ -1870,9 +1869,6 @@ static const struct dentry_operations pid_dentry_operations =
 
 /* Lookups */
 
-typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
-                               struct task_struct *, const void *);
-
 /*
  * Fill a directory entry.
  *
@@ -1885,8 +1881,8 @@ typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
  * reported by readdir in sync with the inode numbers reported
  * by stat.
  */
-static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
-       char *name, int len,
+int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       const char *name, int len,
        instantiate_t instantiate, struct task_struct *task, const void *ptr)
 {
        struct dentry *child, *dir = filp->f_path.dentry;
@@ -2820,6 +2816,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        DIR("task",       S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations),
        DIR("fd",         S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
        DIR("fdinfo",     S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
+       DIR("ns",         S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
 #ifdef CONFIG_NET
        DIR("net",        S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations),
 #endif
@@ -3168,6 +3165,7 @@ out_no_task:
 static const struct pid_entry tid_base_stuff[] = {
        DIR("fd",        S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
        DIR("fdinfo",    S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
+       DIR("ns",        S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
        REG("environ",   S_IRUSR, proc_environ_operations),
        INF("auxv",      S_IRUSR, proc_pid_auxv),
        ONE("status",    S_IRUGO, proc_pid_status),
index f1281339b6fadc27ab1237e2d0191f666b0ed5ce..f1637f17c37c8b39c353c455c040d63d6e3637ed 100644 (file)
@@ -674,6 +674,7 @@ struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
        }
        return ent;
 }
+EXPORT_SYMBOL(proc_mkdir_mode);
 
 struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
                struct proc_dir_entry *parent)
index d15aa1b1cc8fea9f9a7e702849035095e38f4613..74b48cfa1bb2d4be464180b6913c6cd28462eb5f 100644 (file)
@@ -28,6 +28,7 @@ static void proc_evict_inode(struct inode *inode)
 {
        struct proc_dir_entry *de;
        struct ctl_table_header *head;
+       const struct proc_ns_operations *ns_ops;
 
        truncate_inode_pages(&inode->i_data, 0);
        end_writeback(inode);
@@ -44,6 +45,10 @@ static void proc_evict_inode(struct inode *inode)
                rcu_assign_pointer(PROC_I(inode)->sysctl, NULL);
                sysctl_head_put(head);
        }
+       /* Release any associated namespace */
+       ns_ops = PROC_I(inode)->ns_ops;
+       if (ns_ops && ns_ops->put)
+               ns_ops->put(PROC_I(inode)->ns);
 }
 
 static struct kmem_cache * proc_inode_cachep;
@@ -62,6 +67,8 @@ static struct inode *proc_alloc_inode(struct super_block *sb)
        ei->pde = NULL;
        ei->sysctl = NULL;
        ei->sysctl_entry = NULL;
+       ei->ns = NULL;
+       ei->ns_ops = NULL;
        inode = &ei->vfs_inode;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        return inode;
index c03e8d3a3a5b550ef8b88bc60776b48b42795065..7838e5cfec145d4655d4af0e291a8d8bebad91cd 100644 (file)
@@ -61,6 +61,14 @@ extern const struct file_operations proc_pagemap_operations;
 extern const struct file_operations proc_net_operations;
 extern const struct inode_operations proc_net_inode_operations;
 
+struct proc_maps_private {
+       struct pid *pid;
+       struct task_struct *task;
+#ifdef CONFIG_MMU
+       struct vm_area_struct *tail_vma;
+#endif
+};
+
 void proc_init_inodecache(void);
 
 static inline struct pid *proc_pid(struct inode *inode)
@@ -119,3 +127,21 @@ struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *);
  */
 int proc_readdir(struct file *, void *, filldir_t);
 struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
+
+
+
+/* Lookups */
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
+                               struct task_struct *, const void *);
+int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       const char *name, int len,
+       instantiate_t instantiate, struct task_struct *task, const void *ptr);
+int pid_revalidate(struct dentry *dentry, struct nameidata *nd);
+struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task);
+extern const struct dentry_operations pid_dentry_operations;
+int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
+int proc_setattr(struct dentry *dentry, struct iattr *attr);
+
+extern const struct inode_operations proc_ns_dir_inode_operations;
+extern const struct file_operations proc_ns_dir_operations;
+
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
new file mode 100644 (file)
index 0000000..781dec5
--- /dev/null
@@ -0,0 +1,198 @@
+#include <linux/proc_fs.h>
+#include <linux/nsproxy.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fs_struct.h>
+#include <linux/mount.h>
+#include <linux/path.h>
+#include <linux/namei.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+#include <net/net_namespace.h>
+#include <linux/mnt_namespace.h>
+#include <linux/ipc_namespace.h>
+#include <linux/pid_namespace.h>
+#include "internal.h"
+
+
+static const struct proc_ns_operations *ns_entries[] = {
+#ifdef CONFIG_NET_NS
+       &netns_operations,
+#endif
+#ifdef CONFIG_UTS_NS
+       &utsns_operations,
+#endif
+#ifdef CONFIG_IPC_NS
+       &ipcns_operations,
+#endif
+};
+
+static const struct file_operations ns_file_operations = {
+       .llseek         = no_llseek,
+};
+
+static struct dentry *proc_ns_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, const void *ptr)
+{
+       const struct proc_ns_operations *ns_ops = ptr;
+       struct inode *inode;
+       struct proc_inode *ei;
+       struct dentry *error = ERR_PTR(-ENOENT);
+
+       inode = proc_pid_make_inode(dir->i_sb, task);
+       if (!inode)
+               goto out;
+
+       ei = PROC_I(inode);
+       inode->i_mode = S_IFREG|S_IRUSR;
+       inode->i_fop  = &ns_file_operations;
+       ei->ns_ops    = ns_ops;
+       ei->ns        = ns_ops->get(task);
+       if (!ei->ns)
+               goto out_iput;
+
+       dentry->d_op = &pid_dentry_operations;
+       d_add(dentry, inode);
+       /* Close the race of the process dying before we return the dentry */
+       if (pid_revalidate(dentry, NULL))
+               error = NULL;
+out:
+       return error;
+out_iput:
+       iput(inode);
+       goto out;
+}
+
+static int proc_ns_fill_cache(struct file *filp, void *dirent,
+       filldir_t filldir, struct task_struct *task,
+       const struct proc_ns_operations *ops)
+{
+       return proc_fill_cache(filp, dirent, filldir,
+                               ops->name, strlen(ops->name),
+                               proc_ns_instantiate, task, ops);
+}
+
+static int proc_ns_dir_readdir(struct file *filp, void *dirent,
+                               filldir_t filldir)
+{
+       int i;
+       struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *task = get_proc_task(inode);
+       const struct proc_ns_operations **entry, **last;
+       ino_t ino;
+       int ret;
+
+       ret = -ENOENT;
+       if (!task)
+               goto out_no_task;
+
+       ret = -EPERM;
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
+               goto out;
+
+       ret = 0;
+       i = filp->f_pos;
+       switch (i) {
+       case 0:
+               ino = inode->i_ino;
+               if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+                       goto out;
+               i++;
+               filp->f_pos++;
+               /* fall through */
+       case 1:
+               ino = parent_ino(dentry);
+               if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
+                       goto out;
+               i++;
+               filp->f_pos++;
+               /* fall through */
+       default:
+               i -= 2;
+               if (i >= ARRAY_SIZE(ns_entries)) {
+                       ret = 1;
+                       goto out;
+               }
+               entry = ns_entries + i;
+               last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
+               while (entry <= last) {
+                       if (proc_ns_fill_cache(filp, dirent, filldir,
+                                               task, *entry) < 0)
+                               goto out;
+                       filp->f_pos++;
+                       entry++;
+               }
+       }
+
+       ret = 1;
+out:
+       put_task_struct(task);
+out_no_task:
+       return ret;
+}
+
+const struct file_operations proc_ns_dir_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_ns_dir_readdir,
+};
+
+static struct dentry *proc_ns_dir_lookup(struct inode *dir,
+                               struct dentry *dentry, struct nameidata *nd)
+{
+       struct dentry *error;
+       struct task_struct *task = get_proc_task(dir);
+       const struct proc_ns_operations **entry, **last;
+       unsigned int len = dentry->d_name.len;
+
+       error = ERR_PTR(-ENOENT);
+
+       if (!task)
+               goto out_no_task;
+
+       error = ERR_PTR(-EPERM);
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
+               goto out;
+
+       last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
+       for (entry = ns_entries; entry <= last; entry++) {
+               if (strlen((*entry)->name) != len)
+                       continue;
+               if (!memcmp(dentry->d_name.name, (*entry)->name, len))
+                       break;
+       }
+       error = ERR_PTR(-ENOENT);
+       if (entry > last)
+               goto out;
+
+       error = proc_ns_instantiate(dir, dentry, task, *entry);
+out:
+       put_task_struct(task);
+out_no_task:
+       return error;
+}
+
+const struct inode_operations proc_ns_dir_inode_operations = {
+       .lookup         = proc_ns_dir_lookup,
+       .getattr        = pid_getattr,
+       .setattr        = proc_setattr,
+};
+
+struct file *proc_ns_fget(int fd)
+{
+       struct file *file;
+
+       file = fget(fd);
+       if (!file)
+               return ERR_PTR(-EBADF);
+
+       if (file->f_op != &ns_file_operations)
+               goto out_invalid;
+
+       return file;
+
+out_invalid:
+       fput(file);
+       return ERR_PTR(-EINVAL);
+}
+
index 318d8654989bf70479321fb8599b0dcf9ac29365..2c9db29ea3581d7ad79a250cea453411a0b4c9e9 100644 (file)
@@ -858,7 +858,192 @@ const struct file_operations proc_pagemap_operations = {
 #endif /* CONFIG_PROC_PAGE_MONITOR */
 
 #ifdef CONFIG_NUMA
-extern int show_numa_map(struct seq_file *m, void *v);
+
+struct numa_maps {
+       struct vm_area_struct *vma;
+       unsigned long pages;
+       unsigned long anon;
+       unsigned long active;
+       unsigned long writeback;
+       unsigned long mapcount_max;
+       unsigned long dirty;
+       unsigned long swapcache;
+       unsigned long node[MAX_NUMNODES];
+};
+
+struct numa_maps_private {
+       struct proc_maps_private proc_maps;
+       struct numa_maps md;
+};
+
+static void gather_stats(struct page *page, struct numa_maps *md, int pte_dirty)
+{
+       int count = page_mapcount(page);
+
+       md->pages++;
+       if (pte_dirty || PageDirty(page))
+               md->dirty++;
+
+       if (PageSwapCache(page))
+               md->swapcache++;
+
+       if (PageActive(page) || PageUnevictable(page))
+               md->active++;
+
+       if (PageWriteback(page))
+               md->writeback++;
+
+       if (PageAnon(page))
+               md->anon++;
+
+       if (count > md->mapcount_max)
+               md->mapcount_max = count;
+
+       md->node[page_to_nid(page)]++;
+}
+
+static int gather_pte_stats(pmd_t *pmd, unsigned long addr,
+               unsigned long end, struct mm_walk *walk)
+{
+       struct numa_maps *md;
+       spinlock_t *ptl;
+       pte_t *orig_pte;
+       pte_t *pte;
+
+       md = walk->private;
+       orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl);
+       do {
+               struct page *page;
+               int nid;
+
+               if (!pte_present(*pte))
+                       continue;
+
+               page = vm_normal_page(md->vma, addr, *pte);
+               if (!page)
+                       continue;
+
+               if (PageReserved(page))
+                       continue;
+
+               nid = page_to_nid(page);
+               if (!node_isset(nid, node_states[N_HIGH_MEMORY]))
+                       continue;
+
+               gather_stats(page, md, pte_dirty(*pte));
+
+       } while (pte++, addr += PAGE_SIZE, addr != end);
+       pte_unmap_unlock(orig_pte, ptl);
+       return 0;
+}
+#ifdef CONFIG_HUGETLB_PAGE
+static int gather_hugetbl_stats(pte_t *pte, unsigned long hmask,
+               unsigned long addr, unsigned long end, struct mm_walk *walk)
+{
+       struct numa_maps *md;
+       struct page *page;
+
+       if (pte_none(*pte))
+               return 0;
+
+       page = pte_page(*pte);
+       if (!page)
+               return 0;
+
+       md = walk->private;
+       gather_stats(page, md, pte_dirty(*pte));
+       return 0;
+}
+
+#else
+static int gather_hugetbl_stats(pte_t *pte, unsigned long hmask,
+               unsigned long addr, unsigned long end, struct mm_walk *walk)
+{
+       return 0;
+}
+#endif
+
+/*
+ * Display pages allocated per node and memory policy via /proc.
+ */
+static int show_numa_map(struct seq_file *m, void *v)
+{
+       struct numa_maps_private *numa_priv = m->private;
+       struct proc_maps_private *proc_priv = &numa_priv->proc_maps;
+       struct vm_area_struct *vma = v;
+       struct numa_maps *md = &numa_priv->md;
+       struct file *file = vma->vm_file;
+       struct mm_struct *mm = vma->vm_mm;
+       struct mm_walk walk = {};
+       struct mempolicy *pol;
+       int n;
+       char buffer[50];
+
+       if (!mm)
+               return 0;
+
+       /* Ensure we start with an empty set of numa_maps statistics. */
+       memset(md, 0, sizeof(*md));
+
+       md->vma = vma;
+
+       walk.hugetlb_entry = gather_hugetbl_stats;
+       walk.pmd_entry = gather_pte_stats;
+       walk.private = md;
+       walk.mm = mm;
+
+       pol = get_vma_policy(proc_priv->task, vma, vma->vm_start);
+       mpol_to_str(buffer, sizeof(buffer), pol, 0);
+       mpol_cond_put(pol);
+
+       seq_printf(m, "%08lx %s", vma->vm_start, buffer);
+
+       if (file) {
+               seq_printf(m, " file=");
+               seq_path(m, &file->f_path, "\n\t= ");
+       } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
+               seq_printf(m, " heap");
+       } else if (vma->vm_start <= mm->start_stack &&
+                       vma->vm_end >= mm->start_stack) {
+               seq_printf(m, " stack");
+       }
+
+       walk_page_range(vma->vm_start, vma->vm_end, &walk);
+
+       if (!md->pages)
+               goto out;
+
+       if (md->anon)
+               seq_printf(m, " anon=%lu", md->anon);
+
+       if (md->dirty)
+               seq_printf(m, " dirty=%lu", md->dirty);
+
+       if (md->pages != md->anon && md->pages != md->dirty)
+               seq_printf(m, " mapped=%lu", md->pages);
+
+       if (md->mapcount_max > 1)
+               seq_printf(m, " mapmax=%lu", md->mapcount_max);
+
+       if (md->swapcache)
+               seq_printf(m, " swapcache=%lu", md->swapcache);
+
+       if (md->active < md->pages && !is_vm_hugetlb_page(vma))
+               seq_printf(m, " active=%lu", md->active);
+
+       if (md->writeback)
+               seq_printf(m, " writeback=%lu", md->writeback);
+
+       for_each_node_state(n, N_HIGH_MEMORY)
+               if (md->node[n])
+                       seq_printf(m, " N%d=%lu", n, md->node[n]);
+out:
+       seq_putc(m, '\n');
+
+       if (m->count < m->size)
+               m->version = (vma != proc_priv->tail_vma) ? vma->vm_start : 0;
+       return 0;
+}
 
 static const struct seq_operations proc_pid_numa_maps_op = {
         .start  = m_start,
@@ -869,7 +1054,20 @@ static const struct seq_operations proc_pid_numa_maps_op = {
 
 static int numa_maps_open(struct inode *inode, struct file *file)
 {
-       return do_maps_open(inode, file, &proc_pid_numa_maps_op);
+       struct numa_maps_private *priv;
+       int ret = -ENOMEM;
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (priv) {
+               priv->proc_maps.pid = proc_pid(inode);
+               ret = seq_open(file, &proc_pid_numa_maps_op);
+               if (!ret) {
+                       struct seq_file *m = file->private_data;
+                       m->private = priv;
+               } else {
+                       kfree(priv);
+               }
+       }
+       return ret;
 }
 
 const struct file_operations proc_numa_maps_operations = {
@@ -878,4 +1076,4 @@ const struct file_operations proc_numa_maps_operations = {
        .llseek         = seq_lseek,
        .release        = seq_release_private,
 };
-#endif
+#endif /* CONFIG_NUMA */
index d3c032f5fa0aeb600e3d8801fb6fe80f89ad39df..5b572c89e6c4bcbb028b5faf417c098503cc2991 100644 (file)
@@ -691,8 +691,11 @@ static void prune_dqcache(int count)
  * This is called from kswapd when we think we need some
  * more memory
  */
-static int shrink_dqcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
+static int shrink_dqcache_memory(struct shrinker *shrink,
+                                struct shrink_control *sc)
 {
+       int nr = sc->nr_to_scan;
+
        if (nr) {
                spin_lock(&dq_list_lock);
                prune_dqcache(nr);
index 50a5d978da1698f68cf8d2d2eca97474887ea223..aa866d309695497c1c8925cb30c8af6884f20aaf 100644 (file)
@@ -162,6 +162,14 @@ static const struct pipe_buf_operations user_page_pipe_buf_ops = {
        .get = generic_pipe_buf_get,
 };
 
+static void wakeup_pipe_readers(struct pipe_inode_info *pipe)
+{
+       smp_mb();
+       if (waitqueue_active(&pipe->wait))
+               wake_up_interruptible(&pipe->wait);
+       kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
+}
+
 /**
  * splice_to_pipe - fill passed data into a pipe
  * @pipe:      pipe to fill
@@ -247,12 +255,8 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
 
        pipe_unlock(pipe);
 
-       if (do_wakeup) {
-               smp_mb();
-               if (waitqueue_active(&pipe->wait))
-                       wake_up_interruptible(&pipe->wait);
-               kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
-       }
+       if (do_wakeup)
+               wakeup_pipe_readers(pipe);
 
        while (page_nr < spd_pages)
                spd->spd_release(spd, page_nr++);
@@ -1892,12 +1896,9 @@ retry:
        /*
         * If we put data in the output pipe, wakeup any potential readers.
         */
-       if (ret > 0) {
-               smp_mb();
-               if (waitqueue_active(&opipe->wait))
-                       wake_up_interruptible(&opipe->wait);
-               kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
-       }
+       if (ret > 0)
+               wakeup_pipe_readers(opipe);
+
        if (input_wakeup)
                wakeup_pipe_writers(ipipe);
 
@@ -1976,12 +1977,8 @@ static int link_pipe(struct pipe_inode_info *ipipe,
        /*
         * If we put data in the output pipe, wakeup any potential readers.
         */
-       if (ret > 0) {
-               smp_mb();
-               if (waitqueue_active(&opipe->wait))
-                       wake_up_interruptible(&opipe->wait);
-               kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN);
-       }
+       if (ret > 0)
+               wakeup_pipe_readers(opipe);
 
        return ret;
 }
index 52b2b5da566e7ff801adda6b7c2f57147f39fc80..5e68099db2a5fdc97a284031e06a7f70fcea27cb 100644 (file)
@@ -1422,12 +1422,12 @@ restart:
 int
 xfs_buftarg_shrink(
        struct shrinker         *shrink,
-       int                     nr_to_scan,
-       gfp_t                   mask)
+       struct shrink_control   *sc)
 {
        struct xfs_buftarg      *btp = container_of(shrink,
                                        struct xfs_buftarg, bt_shrinker);
        struct xfs_buf          *bp;
+       int nr_to_scan = sc->nr_to_scan;
        LIST_HEAD(dispose);
 
        if (!nr_to_scan)
index cb1bb2080e44b7d3acc2803a275c290894fd3245..8ecad5ff9f9b0e0bdb5a4f76dd97b694147a5a55 100644 (file)
@@ -1032,13 +1032,14 @@ xfs_reclaim_inodes(
 static int
 xfs_reclaim_inode_shrink(
        struct shrinker *shrink,
-       int             nr_to_scan,
-       gfp_t           gfp_mask)
+       struct shrink_control *sc)
 {
        struct xfs_mount *mp;
        struct xfs_perag *pag;
        xfs_agnumber_t  ag;
        int             reclaimable;
+       int nr_to_scan = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        mp = container_of(shrink, struct xfs_mount, m_inode_shrink);
        if (nr_to_scan) {
index 69228aa8605a9f6e07d1f66845c0e4c0c7beff2c..b94dace4e7852333274cd3ca42f633aca98d33f9 100644 (file)
@@ -60,7 +60,7 @@ STATIC void   xfs_qm_list_destroy(xfs_dqlist_t *);
 
 STATIC int     xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int     xfs_qm_init_quotainfo(xfs_mount_t *);
-STATIC int     xfs_qm_shake(struct shrinker *, int, gfp_t);
+STATIC int     xfs_qm_shake(struct shrinker *, struct shrink_control *);
 
 static struct shrinker xfs_qm_shaker = {
        .shrink = xfs_qm_shake,
@@ -2009,10 +2009,10 @@ xfs_qm_shake_freelist(
 STATIC int
 xfs_qm_shake(
        struct shrinker *shrink,
-       int             nr_to_scan,
-       gfp_t           gfp_mask)
+       struct shrink_control *sc)
 {
        int     ndqused, nfree, n;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        if (!kmem_shake_allow(gfp_mask))
                return 0;
index bcbab3e4a3be6c802698fe0d1419f02b54a1eba3..89b73e5d0fd0ca626f7b99e5236f20247553ceaf 100644 (file)
@@ -1,4 +1,6 @@
+#ifdef __NR_chmod
 __NR_chmod,
+#endif
 __NR_fchmod,
 #ifdef __NR_chown
 __NR_chown,
@@ -20,7 +22,9 @@ __NR_chown32,
 __NR_fchown32,
 __NR_lchown32,
 #endif
+#ifdef __NR_link
 __NR_link,
+#endif
 #ifdef __NR_linkat
 __NR_linkat,
 #endif
index 6621bd82cbe82319dc075c42f557bfb3c663555a..7b61db4fe72b1cb610674038d8577c82a9f6224f 100644 (file)
@@ -1,13 +1,27 @@
+#ifdef __NR_rename
 __NR_rename,
+#endif
+#ifdef __NR_mkdir
 __NR_mkdir,
+#endif
+#ifdef __NR_rmdir
 __NR_rmdir,
+#endif
 #ifdef __NR_creat
 __NR_creat,
 #endif
+#ifdef __NR_link
 __NR_link,
+#endif
+#ifdef __NR_unlink
 __NR_unlink,
+#endif
+#ifdef __NR_symlink
 __NR_symlink,
+#endif
+#ifdef __NR_mknod
 __NR_mknod,
+#endif
 #ifdef __NR_mkdirat
 __NR_mkdirat,
 __NR_mknodat,
index 0e87464d98471a95a6823b9e215e83cc17fc169e..3b249cb857dc55dfb33dec433d4617318a7bc1ac 100644 (file)
@@ -1,4 +1,6 @@
+#ifdef __NR_readlink
 __NR_readlink,
+#endif
 __NR_quotactl,
 __NR_listxattr,
 __NR_llistxattr,
@@ -6,3 +8,6 @@ __NR_flistxattr,
 __NR_getxattr,
 __NR_lgetxattr,
 __NR_fgetxattr,
+#ifdef __NR_readlinkat
+__NR_readlinkat,
+#endif
index c5f1c2c920e26c033761d640a81256b0b13c13eb..e7020c57b13b8014ba8c28800e8b66dc9ea37cdb 100644 (file)
@@ -4,7 +4,9 @@ __NR_acct,
 __NR_swapon,
 #endif
 __NR_quotactl,
+#ifdef __NR_truncate
 __NR_truncate,
+#endif
 #ifdef __NR_truncate64
 __NR_truncate64,
 #endif
index e5a3f588000173d8e9da0f8ae00c98dc275d63b1..91784841e4079e35fe4fab89aaaf8a60c4e7b081 100644 (file)
@@ -162,9 +162,46 @@ extern void warn_slowpath_null(const char *file, const int line);
        unlikely(__ret_warn_once);                              \
 })
 
+#ifdef CONFIG_PRINTK
+
 #define WARN_ON_RATELIMIT(condition, state)                    \
                WARN_ON((condition) && __ratelimit(state))
 
+#define __WARN_RATELIMIT(condition, state, format...)          \
+({                                                             \
+       int rtn = 0;                                            \
+       if (unlikely(__ratelimit(state)))                       \
+               rtn = WARN(condition, format);                  \
+       rtn;                                                    \
+})
+
+#define WARN_RATELIMIT(condition, format...)                   \
+({                                                             \
+       static DEFINE_RATELIMIT_STATE(_rs,                      \
+                                     DEFAULT_RATELIMIT_INTERVAL,       \
+                                     DEFAULT_RATELIMIT_BURST); \
+       __WARN_RATELIMIT(condition, &_rs, format);              \
+})
+
+#else
+
+#define WARN_ON_RATELIMIT(condition, state)                    \
+       WARN_ON(condition)
+
+#define __WARN_RATELIMIT(condition, state, format...)          \
+({                                                             \
+       int rtn = WARN(condition, format);                      \
+       rtn;                                                    \
+})
+
+#define WARN_RATELIMIT(condition, format...)                   \
+({                                                             \
+       int rtn = WARN(condition, format);                      \
+       rtn;                                                    \
+})
+
+#endif
+
 /*
  * WARN_ON_SMP() is for cases that the warning is either
  * meaningless for !SMP or may even cause failures.
index 57b5c3c82e86a8e2e7b875e49dc1641ca20fb7aa..87bc536ccde3cedb139a892e692e83ee45a12cfe 100644 (file)
 #define flush_cache_vunmap(start, end)         do { } while (0)
 
 #define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-       memcpy(dst, src, len)
+       do { \
+               memcpy(dst, src, len); \
+               flush_icache_user_range(vma, page, vaddr, len); \
+       } while (0)
 #define copy_from_user_page(vma, page, vaddr, dst, src, len) \
        memcpy(dst, src, len)
 
index 587566f95f6ccd61eb3931097542b37a9c769138..61fa862fe08d61fb326bd66c20e31c567e3fb6f8 100644 (file)
@@ -78,7 +78,7 @@
        [RLIMIT_CORE]           = {              0,  RLIM_INFINITY },   \
        [RLIMIT_RSS]            = {  RLIM_INFINITY,  RLIM_INFINITY },   \
        [RLIMIT_NPROC]          = {              0,              0 },   \
-       [RLIMIT_NOFILE]         = {       INR_OPEN,       INR_OPEN },   \
+       [RLIMIT_NOFILE]         = {   INR_OPEN_CUR,   INR_OPEN_MAX },   \
        [RLIMIT_MEMLOCK]        = {    MLOCK_LIMIT,    MLOCK_LIMIT },   \
        [RLIMIT_AS]             = {  RLIM_INFINITY,  RLIM_INFINITY },   \
        [RLIMIT_LOCKS]          = {  RLIM_INFINITY,  RLIM_INFINITY },   \
index e43f9766259f301b2087e83d70a1e563e568edbd..e58fa777fa09abe91831026852bfe21bdfa4f8d4 100644 (file)
@@ -5,6 +5,8 @@
  * Copyright 2001 Red Hat, Inc.
  * Based on code from mm/memory.c Copyright Linus Torvalds and others.
  *
+ * Copyright 2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
 /*
- * For UP we don't need to worry about TLB flush
- * and page free order so much..
+ * Semi RCU freeing of the page directories.
+ *
+ * This is needed by some architectures to implement software pagetable walkers.
+ *
+ * gup_fast() and other software pagetable walkers do a lockless page-table
+ * walk and therefore needs some synchronization with the freeing of the page
+ * directories. The chosen means to accomplish that is by disabling IRQs over
+ * the walk.
+ *
+ * Architectures that use IPIs to flush TLBs will then automagically DTRT,
+ * since we unlink the page, flush TLBs, free the page. Since the disabling of
+ * IRQs delays the completion of the TLB flush we can never observe an already
+ * freed page.
+ *
+ * Architectures that do not have this (PPC) need to delay the freeing by some
+ * other means, this is that means.
+ *
+ * What we do is batch the freed directory pages (tables) and RCU free them.
+ * We use the sched RCU variant, as that guarantees that IRQ/preempt disabling
+ * holds off grace periods.
+ *
+ * However, in order to batch these pages we need to allocate storage, this
+ * allocation is deep inside the MM code and can thus easily fail on memory
+ * pressure. To guarantee progress we fall back to single table freeing, see
+ * the implementation of tlb_remove_table_one().
+ *
  */
-#ifdef CONFIG_SMP
-  #ifdef ARCH_FREE_PTR_NR
-    #define FREE_PTR_NR   ARCH_FREE_PTR_NR
-  #else
-    #define FREE_PTE_NR        506
-  #endif
-  #define tlb_fast_mode(tlb) ((tlb)->nr == ~0U)
-#else
-  #define FREE_PTE_NR  1
-  #define tlb_fast_mode(tlb) 1
+struct mmu_table_batch {
+       struct rcu_head         rcu;
+       unsigned int            nr;
+       void                    *tables[0];
+};
+
+#define MAX_TABLE_BATCH                \
+       ((PAGE_SIZE - sizeof(struct mmu_table_batch)) / sizeof(void *))
+
+extern void tlb_table_flush(struct mmu_gather *tlb);
+extern void tlb_remove_table(struct mmu_gather *tlb, void *table);
+
 #endif
 
-/* struct mmu_gather is an opaque type used by the mm code for passing around
- * any data needed by arch specific code for tlb_remove_page.
+/*
+ * If we can't allocate a page to make a big batch of page pointers
+ * to work on, then just handle a few from the on-stack structure.
  */
-struct mmu_gather {
-       struct mm_struct        *mm;
-       unsigned int            nr;     /* set to ~0U means fast mode */
-       unsigned int            need_flush;/* Really unmapped some ptes? */
-       unsigned int            fullmm; /* non-zero means full mm flush */
-       struct page *           pages[FREE_PTE_NR];
+#define MMU_GATHER_BUNDLE      8
+
+struct mmu_gather_batch {
+       struct mmu_gather_batch *next;
+       unsigned int            nr;
+       unsigned int            max;
+       struct page             *pages[0];
 };
 
-/* Users of the generic TLB shootdown code must declare this storage space. */
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
+#define MAX_GATHER_BATCH       \
+       ((PAGE_SIZE - sizeof(struct mmu_gather_batch)) / sizeof(void *))
 
-/* tlb_gather_mmu
- *     Return a pointer to an initialized struct mmu_gather.
+/* struct mmu_gather is an opaque type used by the mm code for passing around
+ * any data needed by arch specific code for tlb_remove_page.
  */
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
-{
-       struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
-       tlb->mm = mm;
+struct mmu_gather {
+       struct mm_struct        *mm;
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       struct mmu_table_batch  *batch;
+#endif
+       unsigned int            need_flush : 1, /* Did free PTEs */
+                               fast_mode  : 1; /* No batching   */
 
-       /* Use fast mode if only one CPU is online */
-       tlb->nr = num_online_cpus() > 1 ? 0U : ~0U;
+       unsigned int            fullmm;
 
-       tlb->fullmm = full_mm_flush;
+       struct mmu_gather_batch *active;
+       struct mmu_gather_batch local;
+       struct page             *__pages[MMU_GATHER_BUNDLE];
+};
 
-       return tlb;
-}
+#define HAVE_GENERIC_MMU_GATHER
 
-static inline void
-tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+static inline int tlb_fast_mode(struct mmu_gather *tlb)
 {
-       if (!tlb->need_flush)
-               return;
-       tlb->need_flush = 0;
-       tlb_flush(tlb);
-       if (!tlb_fast_mode(tlb)) {
-               free_pages_and_swap_cache(tlb->pages, tlb->nr);
-               tlb->nr = 0;
-       }
+#ifdef CONFIG_SMP
+       return tlb->fast_mode;
+#else
+       /*
+        * For UP we don't need to worry about TLB flush
+        * and page free order so much..
+        */
+       return 1;
+#endif
 }
 
-/* tlb_finish_mmu
- *     Called at the end of the shootdown operation to free up any resources
- *     that were required.
- */
-static inline void
-tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
-{
-       tlb_flush_mmu(tlb, start, end);
-
-       /* keep the page table cache within bounds */
-       check_pgt_cache();
-
-       put_cpu_var(mmu_gathers);
-}
+void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm);
+void tlb_flush_mmu(struct mmu_gather *tlb);
+void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end);
+int __tlb_remove_page(struct mmu_gather *tlb, struct page *page);
 
 /* tlb_remove_page
- *     Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while
- *     handling the additional races in SMP caused by other CPUs caching valid
- *     mappings in their TLBs.
+ *     Similar to __tlb_remove_page but will call tlb_flush_mmu() itself when
+ *     required.
  */
 static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 {
-       tlb->need_flush = 1;
-       if (tlb_fast_mode(tlb)) {
-               free_page_and_swap_cache(page);
-               return;
-       }
-       tlb->pages[tlb->nr++] = page;
-       if (tlb->nr >= FREE_PTE_NR)
-               tlb_flush_mmu(tlb, 0, 0);
+       if (!__tlb_remove_page(tlb, page))
+               tlb_flush_mmu(tlb);
 }
 
 /**
index 07c40d5149de41ee263a450db1141781f806f44b..33d5247048835bc610844a562177b064aa7a0562 100644 (file)
 #define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _64)
 #endif
 
+#ifdef __SYSCALL_COMPAT
+#define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _comp)
+#define __SC_COMP_3264(_nr, _32, _64, _comp) __SYSCALL(_nr, _comp)
+#else
+#define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _sys)
+#define __SC_COMP_3264(_nr, _32, _64, _comp) __SC_3264(_nr, _32, _64)
+#endif
+
 #define __NR_io_setup 0
-__SYSCALL(__NR_io_setup, sys_io_setup)
+__SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup)
 #define __NR_io_destroy 1
 __SYSCALL(__NR_io_destroy, sys_io_destroy)
 #define __NR_io_submit 2
-__SYSCALL(__NR_io_submit, sys_io_submit)
+__SC_COMP(__NR_io_submit, sys_io_submit, compat_sys_io_submit)
 #define __NR_io_cancel 3
 __SYSCALL(__NR_io_cancel, sys_io_cancel)
 #define __NR_io_getevents 4
-__SYSCALL(__NR_io_getevents, sys_io_getevents)
+__SC_COMP(__NR_io_getevents, sys_io_getevents, compat_sys_io_getevents)
 
 /* fs/xattr.c */
 #define __NR_setxattr 5
@@ -67,7 +75,7 @@ __SYSCALL(__NR_getcwd, sys_getcwd)
 
 /* fs/cookies.c */
 #define __NR_lookup_dcookie 18
-__SYSCALL(__NR_lookup_dcookie, sys_lookup_dcookie)
+__SC_COMP(__NR_lookup_dcookie, sys_lookup_dcookie, compat_sys_lookup_dcookie)
 
 /* fs/eventfd.c */
 #define __NR_eventfd2 19
@@ -79,7 +87,7 @@ __SYSCALL(__NR_epoll_create1, sys_epoll_create1)
 #define __NR_epoll_ctl 21
 __SYSCALL(__NR_epoll_ctl, sys_epoll_ctl)
 #define __NR_epoll_pwait 22
-__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
+__SC_COMP(__NR_epoll_pwait, sys_epoll_pwait, compat_sys_epoll_pwait)
 
 /* fs/fcntl.c */
 #define __NR_dup 23
@@ -87,7 +95,7 @@ __SYSCALL(__NR_dup, sys_dup)
 #define __NR_dup3 24
 __SYSCALL(__NR_dup3, sys_dup3)
 #define __NR3264_fcntl 25
-__SC_3264(__NR3264_fcntl, sys_fcntl64, sys_fcntl)
+__SC_COMP_3264(__NR3264_fcntl, sys_fcntl64, sys_fcntl, compat_sys_fcntl64)
 
 /* fs/inotify_user.c */
 #define __NR_inotify_init1 26
@@ -99,7 +107,7 @@ __SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch)
 
 /* fs/ioctl.c */
 #define __NR_ioctl 29
-__SYSCALL(__NR_ioctl, sys_ioctl)
+__SC_COMP(__NR_ioctl, sys_ioctl, compat_sys_ioctl)
 
 /* fs/ioprio.c */
 #define __NR_ioprio_set 30
@@ -129,26 +137,30 @@ __SYSCALL(__NR_renameat, sys_renameat)
 #define __NR_umount2 39
 __SYSCALL(__NR_umount2, sys_umount)
 #define __NR_mount 40
-__SYSCALL(__NR_mount, sys_mount)
+__SC_COMP(__NR_mount, sys_mount, compat_sys_mount)
 #define __NR_pivot_root 41
 __SYSCALL(__NR_pivot_root, sys_pivot_root)
 
 /* fs/nfsctl.c */
 #define __NR_nfsservctl 42
-__SYSCALL(__NR_nfsservctl, sys_nfsservctl)
+__SC_COMP(__NR_nfsservctl, sys_nfsservctl, compat_sys_nfsservctl)
 
 /* fs/open.c */
 #define __NR3264_statfs 43
-__SC_3264(__NR3264_statfs, sys_statfs64, sys_statfs)
+__SC_COMP_3264(__NR3264_statfs, sys_statfs64, sys_statfs, \
+              compat_sys_statfs64)
 #define __NR3264_fstatfs 44
-__SC_3264(__NR3264_fstatfs, sys_fstatfs64, sys_fstatfs)
+__SC_COMP_3264(__NR3264_fstatfs, sys_fstatfs64, sys_fstatfs, \
+              compat_sys_fstatfs64)
 #define __NR3264_truncate 45
-__SC_3264(__NR3264_truncate, sys_truncate64, sys_truncate)
+__SC_COMP_3264(__NR3264_truncate, sys_truncate64, sys_truncate, \
+              compat_sys_truncate64)
 #define __NR3264_ftruncate 46
-__SC_3264(__NR3264_ftruncate, sys_ftruncate64, sys_ftruncate)
+__SC_COMP_3264(__NR3264_ftruncate, sys_ftruncate64, sys_ftruncate, \
+              compat_sys_ftruncate64)
 
 #define __NR_fallocate 47
-__SYSCALL(__NR_fallocate, sys_fallocate)
+__SC_COMP(__NR_fallocate, sys_fallocate, compat_sys_fallocate)
 #define __NR_faccessat 48
 __SYSCALL(__NR_faccessat, sys_faccessat)
 #define __NR_chdir 49
@@ -166,7 +178,7 @@ __SYSCALL(__NR_fchownat, sys_fchownat)
 #define __NR_fchown 55
 __SYSCALL(__NR_fchown, sys_fchown)
 #define __NR_openat 56
-__SYSCALL(__NR_openat, sys_openat)
+__SC_COMP(__NR_openat, sys_openat, compat_sys_openat)
 #define __NR_close 57
 __SYSCALL(__NR_close, sys_close)
 #define __NR_vhangup 58
@@ -182,7 +194,7 @@ __SYSCALL(__NR_quotactl, sys_quotactl)
 
 /* fs/readdir.c */
 #define __NR_getdents64 61
-__SYSCALL(__NR_getdents64, sys_getdents64)
+__SC_COMP(__NR_getdents64, sys_getdents64, compat_sys_getdents64)
 
 /* fs/read_write.c */
 #define __NR3264_lseek 62
@@ -192,17 +204,17 @@ __SYSCALL(__NR_read, sys_read)
 #define __NR_write 64
 __SYSCALL(__NR_write, sys_write)
 #define __NR_readv 65
-__SYSCALL(__NR_readv, sys_readv)
+__SC_COMP(__NR_readv, sys_readv, compat_sys_readv)
 #define __NR_writev 66
-__SYSCALL(__NR_writev, sys_writev)
+__SC_COMP(__NR_writev, sys_writev, compat_sys_writev)
 #define __NR_pread64 67
-__SYSCALL(__NR_pread64, sys_pread64)
+__SC_COMP(__NR_pread64, sys_pread64, compat_sys_pread64)
 #define __NR_pwrite64 68
-__SYSCALL(__NR_pwrite64, sys_pwrite64)
+__SC_COMP(__NR_pwrite64, sys_pwrite64, compat_sys_pwrite64)
 #define __NR_preadv 69
-__SYSCALL(__NR_preadv, sys_preadv)
+__SC_COMP(__NR_preadv, sys_preadv, compat_sys_preadv)
 #define __NR_pwritev 70
-__SYSCALL(__NR_pwritev, sys_pwritev)
+__SC_COMP(__NR_pwritev, sys_pwritev, compat_sys_pwritev)
 
 /* fs/sendfile.c */
 #define __NR3264_sendfile 71
@@ -210,17 +222,17 @@ __SC_3264(__NR3264_sendfile, sys_sendfile64, sys_sendfile)
 
 /* fs/select.c */
 #define __NR_pselect6 72
-__SYSCALL(__NR_pselect6, sys_pselect6)
+__SC_COMP(__NR_pselect6, sys_pselect6, compat_sys_pselect6)
 #define __NR_ppoll 73
-__SYSCALL(__NR_ppoll, sys_ppoll)
+__SC_COMP(__NR_ppoll, sys_ppoll, compat_sys_ppoll)
 
 /* fs/signalfd.c */
 #define __NR_signalfd4 74
-__SYSCALL(__NR_signalfd4, sys_signalfd4)
+__SC_COMP(__NR_signalfd4, sys_signalfd4, compat_sys_signalfd4)
 
 /* fs/splice.c */
 #define __NR_vmsplice 75
-__SYSCALL(__NR_vmsplice, sys_vmsplice)
+__SC_COMP(__NR_vmsplice, sys_vmsplice, compat_sys_vmsplice)
 #define __NR_splice 76
 __SYSCALL(__NR_splice, sys_splice)
 #define __NR_tee 77
@@ -243,23 +255,27 @@ __SYSCALL(__NR_fsync, sys_fsync)
 __SYSCALL(__NR_fdatasync, sys_fdatasync)
 #ifdef __ARCH_WANT_SYNC_FILE_RANGE2
 #define __NR_sync_file_range2 84
-__SYSCALL(__NR_sync_file_range2, sys_sync_file_range2)
+__SC_COMP(__NR_sync_file_range2, sys_sync_file_range2, \
+         compat_sys_sync_file_range2)
 #else
 #define __NR_sync_file_range 84
-__SYSCALL(__NR_sync_file_range, sys_sync_file_range)
+__SC_COMP(__NR_sync_file_range, sys_sync_file_range, \
+         compat_sys_sync_file_range)
 #endif
 
 /* fs/timerfd.c */
 #define __NR_timerfd_create 85
 __SYSCALL(__NR_timerfd_create, sys_timerfd_create)
 #define __NR_timerfd_settime 86
-__SYSCALL(__NR_timerfd_settime, sys_timerfd_settime)
+__SC_COMP(__NR_timerfd_settime, sys_timerfd_settime, \
+         compat_sys_timerfd_settime)
 #define __NR_timerfd_gettime 87
-__SYSCALL(__NR_timerfd_gettime, sys_timerfd_gettime)
+__SC_COMP(__NR_timerfd_gettime, sys_timerfd_gettime, \
+         compat_sys_timerfd_gettime)
 
 /* fs/utimes.c */
 #define __NR_utimensat 88
-__SYSCALL(__NR_utimensat, sys_utimensat)
+__SC_COMP(__NR_utimensat, sys_utimensat, compat_sys_utimensat)
 
 /* kernel/acct.c */
 #define __NR_acct 89
@@ -281,7 +297,7 @@ __SYSCALL(__NR_exit, sys_exit)
 #define __NR_exit_group 94
 __SYSCALL(__NR_exit_group, sys_exit_group)
 #define __NR_waitid 95
-__SYSCALL(__NR_waitid, sys_waitid)
+__SC_COMP(__NR_waitid, sys_waitid, compat_sys_waitid)
 
 /* kernel/fork.c */
 #define __NR_set_tid_address 96
@@ -291,25 +307,27 @@ __SYSCALL(__NR_unshare, sys_unshare)
 
 /* kernel/futex.c */
 #define __NR_futex 98
-__SYSCALL(__NR_futex, sys_futex)
+__SC_COMP(__NR_futex, sys_futex, compat_sys_futex)
 #define __NR_set_robust_list 99
-__SYSCALL(__NR_set_robust_list, sys_set_robust_list)
+__SC_COMP(__NR_set_robust_list, sys_set_robust_list, \
+         compat_sys_set_robust_list)
 #define __NR_get_robust_list 100
-__SYSCALL(__NR_get_robust_list, sys_get_robust_list)
+__SC_COMP(__NR_get_robust_list, sys_get_robust_list, \
+         compat_sys_get_robust_list)
 
 /* kernel/hrtimer.c */
 #define __NR_nanosleep 101
-__SYSCALL(__NR_nanosleep, sys_nanosleep)
+__SC_COMP(__NR_nanosleep, sys_nanosleep, compat_sys_nanosleep)
 
 /* kernel/itimer.c */
 #define __NR_getitimer 102
-__SYSCALL(__NR_getitimer, sys_getitimer)
+__SC_COMP(__NR_getitimer, sys_getitimer, compat_sys_getitimer)
 #define __NR_setitimer 103
-__SYSCALL(__NR_setitimer, sys_setitimer)
+__SC_COMP(__NR_setitimer, sys_setitimer, compat_sys_setitimer)
 
 /* kernel/kexec.c */
 #define __NR_kexec_load 104
-__SYSCALL(__NR_kexec_load, sys_kexec_load)
+__SC_COMP(__NR_kexec_load, sys_kexec_load, compat_sys_kexec_load)
 
 /* kernel/module.c */
 #define __NR_init_module 105
@@ -319,23 +337,24 @@ __SYSCALL(__NR_delete_module, sys_delete_module)
 
 /* kernel/posix-timers.c */
 #define __NR_timer_create 107
-__SYSCALL(__NR_timer_create, sys_timer_create)
+__SC_COMP(__NR_timer_create, sys_timer_create, compat_sys_timer_create)
 #define __NR_timer_gettime 108
-__SYSCALL(__NR_timer_gettime, sys_timer_gettime)
+__SC_COMP(__NR_timer_gettime, sys_timer_gettime, compat_sys_timer_gettime)
 #define __NR_timer_getoverrun 109
 __SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun)
 #define __NR_timer_settime 110
-__SYSCALL(__NR_timer_settime, sys_timer_settime)
+__SC_COMP(__NR_timer_settime, sys_timer_settime, compat_sys_timer_settime)
 #define __NR_timer_delete 111
 __SYSCALL(__NR_timer_delete, sys_timer_delete)
 #define __NR_clock_settime 112
-__SYSCALL(__NR_clock_settime, sys_clock_settime)
+__SC_COMP(__NR_clock_settime, sys_clock_settime, compat_sys_clock_settime)
 #define __NR_clock_gettime 113
-__SYSCALL(__NR_clock_gettime, sys_clock_gettime)
+__SC_COMP(__NR_clock_gettime, sys_clock_gettime, compat_sys_clock_gettime)
 #define __NR_clock_getres 114
-__SYSCALL(__NR_clock_getres, sys_clock_getres)
+__SC_COMP(__NR_clock_getres, sys_clock_getres, compat_sys_clock_getres)
 #define __NR_clock_nanosleep 115
-__SYSCALL(__NR_clock_nanosleep, sys_clock_nanosleep)
+__SC_COMP(__NR_clock_nanosleep, sys_clock_nanosleep, \
+         compat_sys_clock_nanosleep)
 
 /* kernel/printk.c */
 #define __NR_syslog 116
@@ -355,9 +374,11 @@ __SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler)
 #define __NR_sched_getparam 121
 __SYSCALL(__NR_sched_getparam, sys_sched_getparam)
 #define __NR_sched_setaffinity 122
-__SYSCALL(__NR_sched_setaffinity, sys_sched_setaffinity)
+__SC_COMP(__NR_sched_setaffinity, sys_sched_setaffinity, \
+         compat_sys_sched_setaffinity)
 #define __NR_sched_getaffinity 123
-__SYSCALL(__NR_sched_getaffinity, sys_sched_getaffinity)
+__SC_COMP(__NR_sched_getaffinity, sys_sched_getaffinity, \
+         compat_sys_sched_getaffinity)
 #define __NR_sched_yield 124
 __SYSCALL(__NR_sched_yield, sys_sched_yield)
 #define __NR_sched_get_priority_max 125
@@ -365,7 +386,8 @@ __SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max)
 #define __NR_sched_get_priority_min 126
 __SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min)
 #define __NR_sched_rr_get_interval 127
-__SYSCALL(__NR_sched_rr_get_interval, sys_sched_rr_get_interval)
+__SC_COMP(__NR_sched_rr_get_interval, sys_sched_rr_get_interval, \
+         compat_sys_sched_rr_get_interval)
 
 /* kernel/signal.c */
 #define __NR_restart_syscall 128
@@ -377,21 +399,23 @@ __SYSCALL(__NR_tkill, sys_tkill)
 #define __NR_tgkill 131
 __SYSCALL(__NR_tgkill, sys_tgkill)
 #define __NR_sigaltstack 132
-__SYSCALL(__NR_sigaltstack, sys_sigaltstack)
+__SC_COMP(__NR_sigaltstack, sys_sigaltstack, compat_sys_sigaltstack)
 #define __NR_rt_sigsuspend 133
-__SYSCALL(__NR_rt_sigsuspend, sys_rt_sigsuspend) /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
+__SC_COMP(__NR_rt_sigsuspend, sys_rt_sigsuspend, compat_sys_rt_sigsuspend)
 #define __NR_rt_sigaction 134
-__SYSCALL(__NR_rt_sigaction, sys_rt_sigaction) /* __ARCH_WANT_SYS_RT_SIGACTION */
+__SC_COMP(__NR_rt_sigaction, sys_rt_sigaction, compat_sys_rt_sigaction)
 #define __NR_rt_sigprocmask 135
 __SYSCALL(__NR_rt_sigprocmask, sys_rt_sigprocmask)
 #define __NR_rt_sigpending 136
 __SYSCALL(__NR_rt_sigpending, sys_rt_sigpending)
 #define __NR_rt_sigtimedwait 137
-__SYSCALL(__NR_rt_sigtimedwait, sys_rt_sigtimedwait)
+__SC_COMP(__NR_rt_sigtimedwait, sys_rt_sigtimedwait, \
+         compat_sys_rt_sigtimedwait)
 #define __NR_rt_sigqueueinfo 138
-__SYSCALL(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo)
+__SC_COMP(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo, \
+         compat_sys_rt_sigqueueinfo)
 #define __NR_rt_sigreturn 139
-__SYSCALL(__NR_rt_sigreturn, sys_rt_sigreturn) /* sys_rt_sigreturn_wrapper, */
+__SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn)
 
 /* kernel/sys.c */
 #define __NR_setpriority 140
@@ -421,7 +445,7 @@ __SYSCALL(__NR_setfsuid, sys_setfsuid)
 #define __NR_setfsgid 152
 __SYSCALL(__NR_setfsgid, sys_setfsgid)
 #define __NR_times 153
-__SYSCALL(__NR_times, sys_times)
+__SC_COMP(__NR_times, sys_times, compat_sys_times)
 #define __NR_setpgid 154
 __SYSCALL(__NR_setpgid, sys_setpgid)
 #define __NR_getpgid 155
@@ -441,11 +465,11 @@ __SYSCALL(__NR_sethostname, sys_sethostname)
 #define __NR_setdomainname 162
 __SYSCALL(__NR_setdomainname, sys_setdomainname)
 #define __NR_getrlimit 163
-__SYSCALL(__NR_getrlimit, sys_getrlimit)
+__SC_COMP(__NR_getrlimit, sys_getrlimit, compat_sys_getrlimit)
 #define __NR_setrlimit 164
-__SYSCALL(__NR_setrlimit, sys_setrlimit)
+__SC_COMP(__NR_setrlimit, sys_setrlimit, compat_sys_setrlimit)
 #define __NR_getrusage 165
-__SYSCALL(__NR_getrusage, sys_getrusage)
+__SC_COMP(__NR_getrusage, sys_getrusage, compat_sys_getrusage)
 #define __NR_umask 166
 __SYSCALL(__NR_umask, sys_umask)
 #define __NR_prctl 167
@@ -455,11 +479,11 @@ __SYSCALL(__NR_getcpu, sys_getcpu)
 
 /* kernel/time.c */
 #define __NR_gettimeofday 169
-__SYSCALL(__NR_gettimeofday, sys_gettimeofday)
+__SC_COMP(__NR_gettimeofday, sys_gettimeofday, compat_sys_gettimeofday)
 #define __NR_settimeofday 170
-__SYSCALL(__NR_settimeofday, sys_settimeofday)
+__SC_COMP(__NR_settimeofday, sys_settimeofday, compat_sys_settimeofday)
 #define __NR_adjtimex 171
-__SYSCALL(__NR_adjtimex, sys_adjtimex)
+__SC_COMP(__NR_adjtimex, sys_adjtimex, compat_sys_adjtimex)
 
 /* kernel/timer.c */
 #define __NR_getpid 172
@@ -477,39 +501,40 @@ __SYSCALL(__NR_getegid, sys_getegid)
 #define __NR_gettid 178
 __SYSCALL(__NR_gettid, sys_gettid)
 #define __NR_sysinfo 179
-__SYSCALL(__NR_sysinfo, sys_sysinfo)
+__SC_COMP(__NR_sysinfo, sys_sysinfo, compat_sys_sysinfo)
 
 /* ipc/mqueue.c */
 #define __NR_mq_open 180
-__SYSCALL(__NR_mq_open, sys_mq_open)
+__SC_COMP(__NR_mq_open, sys_mq_open, compat_sys_mq_open)
 #define __NR_mq_unlink 181
 __SYSCALL(__NR_mq_unlink, sys_mq_unlink)
 #define __NR_mq_timedsend 182
-__SYSCALL(__NR_mq_timedsend, sys_mq_timedsend)
+__SC_COMP(__NR_mq_timedsend, sys_mq_timedsend, compat_sys_mq_timedsend)
 #define __NR_mq_timedreceive 183
-__SYSCALL(__NR_mq_timedreceive, sys_mq_timedreceive)
+__SC_COMP(__NR_mq_timedreceive, sys_mq_timedreceive, \
+         compat_sys_mq_timedreceive)
 #define __NR_mq_notify 184
-__SYSCALL(__NR_mq_notify, sys_mq_notify)
+__SC_COMP(__NR_mq_notify, sys_mq_notify, compat_sys_mq_notify)
 #define __NR_mq_getsetattr 185
-__SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
+__SC_COMP(__NR_mq_getsetattr, sys_mq_getsetattr, compat_sys_mq_getsetattr)
 
 /* ipc/msg.c */
 #define __NR_msgget 186
 __SYSCALL(__NR_msgget, sys_msgget)
 #define __NR_msgctl 187
-__SYSCALL(__NR_msgctl, sys_msgctl)
+__SC_COMP(__NR_msgctl, sys_msgctl, compat_sys_msgctl)
 #define __NR_msgrcv 188
-__SYSCALL(__NR_msgrcv, sys_msgrcv)
+__SC_COMP(__NR_msgrcv, sys_msgrcv, compat_sys_msgrcv)
 #define __NR_msgsnd 189
-__SYSCALL(__NR_msgsnd, sys_msgsnd)
+__SC_COMP(__NR_msgsnd, sys_msgsnd, compat_sys_msgsnd)
 
 /* ipc/sem.c */
 #define __NR_semget 190
 __SYSCALL(__NR_semget, sys_semget)
 #define __NR_semctl 191
-__SYSCALL(__NR_semctl, sys_semctl)
+__SC_COMP(__NR_semctl, sys_semctl, compat_sys_semctl)
 #define __NR_semtimedop 192
-__SYSCALL(__NR_semtimedop, sys_semtimedop)
+__SC_COMP(__NR_semtimedop, sys_semtimedop, compat_sys_semtimedop)
 #define __NR_semop 193
 __SYSCALL(__NR_semop, sys_semop)
 
@@ -517,9 +542,9 @@ __SYSCALL(__NR_semop, sys_semop)
 #define __NR_shmget 194
 __SYSCALL(__NR_shmget, sys_shmget)
 #define __NR_shmctl 195
-__SYSCALL(__NR_shmctl, sys_shmctl)
+__SC_COMP(__NR_shmctl, sys_shmctl, compat_sys_shmctl)
 #define __NR_shmat 196
-__SYSCALL(__NR_shmat, sys_shmat)
+__SC_COMP(__NR_shmat, sys_shmat, compat_sys_shmat)
 #define __NR_shmdt 197
 __SYSCALL(__NR_shmdt, sys_shmdt)
 
@@ -543,21 +568,21 @@ __SYSCALL(__NR_getpeername, sys_getpeername)
 #define __NR_sendto 206
 __SYSCALL(__NR_sendto, sys_sendto)
 #define __NR_recvfrom 207
-__SYSCALL(__NR_recvfrom, sys_recvfrom)
+__SC_COMP(__NR_recvfrom, sys_recvfrom, compat_sys_recvfrom)
 #define __NR_setsockopt 208
-__SYSCALL(__NR_setsockopt, sys_setsockopt)
+__SC_COMP(__NR_setsockopt, sys_setsockopt, compat_sys_setsockopt)
 #define __NR_getsockopt 209
-__SYSCALL(__NR_getsockopt, sys_getsockopt)
+__SC_COMP(__NR_getsockopt, sys_getsockopt, compat_sys_getsockopt)
 #define __NR_shutdown 210
 __SYSCALL(__NR_shutdown, sys_shutdown)
 #define __NR_sendmsg 211
-__SYSCALL(__NR_sendmsg, sys_sendmsg)
+__SC_COMP(__NR_sendmsg, sys_sendmsg, compat_sys_sendmsg)
 #define __NR_recvmsg 212
-__SYSCALL(__NR_recvmsg, sys_recvmsg)
+__SC_COMP(__NR_recvmsg, sys_recvmsg, compat_sys_recvmsg)
 
 /* mm/filemap.c */
 #define __NR_readahead 213
-__SYSCALL(__NR_readahead, sys_readahead)
+__SC_COMP(__NR_readahead, sys_readahead, compat_sys_readahead)
 
 /* mm/nommu.c, also with MMU */
 #define __NR_brk 214
@@ -573,19 +598,19 @@ __SYSCALL(__NR_add_key, sys_add_key)
 #define __NR_request_key 218
 __SYSCALL(__NR_request_key, sys_request_key)
 #define __NR_keyctl 219
-__SYSCALL(__NR_keyctl, sys_keyctl)
+__SC_COMP(__NR_keyctl, sys_keyctl, compat_sys_keyctl)
 
 /* arch/example/kernel/sys_example.c */
 #define __NR_clone 220
-__SYSCALL(__NR_clone, sys_clone)       /* .long sys_clone_wrapper */
+__SYSCALL(__NR_clone, sys_clone)
 #define __NR_execve 221
-__SYSCALL(__NR_execve, sys_execve)     /* .long sys_execve_wrapper */
+__SC_COMP(__NR_execve, sys_execve, compat_sys_execve)
 
 #define __NR3264_mmap 222
 __SC_3264(__NR3264_mmap, sys_mmap2, sys_mmap)
 /* mm/fadvise.c */
 #define __NR3264_fadvise64 223
-__SYSCALL(__NR3264_fadvise64, sys_fadvise64_64)
+__SC_COMP(__NR3264_fadvise64, sys_fadvise64_64, compat_sys_fadvise64_64)
 
 /* mm/, CONFIG_MMU only */
 #ifndef __ARCH_NOMMU
@@ -612,25 +637,26 @@ __SYSCALL(__NR_madvise, sys_madvise)
 #define __NR_remap_file_pages 234
 __SYSCALL(__NR_remap_file_pages, sys_remap_file_pages)
 #define __NR_mbind 235
-__SYSCALL(__NR_mbind, sys_mbind)
+__SC_COMP(__NR_mbind, sys_mbind, compat_sys_mbind)
 #define __NR_get_mempolicy 236
-__SYSCALL(__NR_get_mempolicy, sys_get_mempolicy)
+__SC_COMP(__NR_get_mempolicy, sys_get_mempolicy, compat_sys_get_mempolicy)
 #define __NR_set_mempolicy 237
-__SYSCALL(__NR_set_mempolicy, sys_set_mempolicy)
+__SC_COMP(__NR_set_mempolicy, sys_set_mempolicy, compat_sys_set_mempolicy)
 #define __NR_migrate_pages 238
-__SYSCALL(__NR_migrate_pages, sys_migrate_pages)
+__SC_COMP(__NR_migrate_pages, sys_migrate_pages, compat_sys_migrate_pages)
 #define __NR_move_pages 239
-__SYSCALL(__NR_move_pages, sys_move_pages)
+__SC_COMP(__NR_move_pages, sys_move_pages, compat_sys_move_pages)
 #endif
 
 #define __NR_rt_tgsigqueueinfo 240
-__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
+__SC_COMP(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo, \
+         compat_sys_rt_tgsigqueueinfo)
 #define __NR_perf_event_open 241
 __SYSCALL(__NR_perf_event_open, sys_perf_event_open)
 #define __NR_accept4 242
 __SYSCALL(__NR_accept4, sys_accept4)
 #define __NR_recvmmsg 243
-__SYSCALL(__NR_recvmmsg, sys_recvmmsg)
+__SC_COMP(__NR_recvmmsg, sys_recvmmsg, compat_sys_recvmmsg)
 
 /*
  * Architectures may provide up to 16 syscalls of their own
@@ -639,19 +665,20 @@ __SYSCALL(__NR_recvmmsg, sys_recvmmsg)
 #define __NR_arch_specific_syscall 244
 
 #define __NR_wait4 260
-__SYSCALL(__NR_wait4, sys_wait4)
+__SC_COMP(__NR_wait4, sys_wait4, compat_sys_wait4)
 #define __NR_prlimit64 261
 __SYSCALL(__NR_prlimit64, sys_prlimit64)
 #define __NR_fanotify_init 262
 __SYSCALL(__NR_fanotify_init, sys_fanotify_init)
 #define __NR_fanotify_mark 263
 __SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
-#define __NR_name_to_handle_at         264
+#define __NR_name_to_handle_at         264
 __SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
-#define __NR_open_by_handle_at         265
-__SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
+#define __NR_open_by_handle_at         265
+__SC_COMP(__NR_open_by_handle_at, sys_open_by_handle_at, \
+         compat_sys_open_by_handle_at)
 #define __NR_clock_adjtime 266
-__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
+__SC_COMP(__NR_clock_adjtime, sys_clock_adjtime, compat_sys_clock_adjtime)
 #define __NR_syncfs 267
 __SYSCALL(__NR_syncfs, sys_syncfs)
 
index cb1ded2bd54520f2f26f82ea786653f110c9d01d..01f6362750570e19e01c01d5fbc22f50f63cbed6 100644 (file)
@@ -4,6 +4,7 @@ header-y += caif/
 header-y += dvb/
 header-y += hdlc/
 header-y += isdn/
+header-y += mmc/
 header-y += nfsd/
 header-y += raid/
 header-y += spi/
@@ -302,6 +303,7 @@ header-y += ppp-comp.h
 header-y += ppp_defs.h
 header-y += pps.h
 header-y += prctl.h
+header-y += ptp_clock.h
 header-y += ptrace.h
 header-y += qnx4_fs.h
 header-y += qnxtypes.h
index daf8c480c7867e9a60f3cdd715e9b4a8c030942c..dcafe0bf0005ac11e10dbcb0f3cc6f756221e60e 100644 (file)
@@ -55,7 +55,8 @@
  * bitmap_parse(buf, buflen, dst, nbits)       Parse bitmap dst from kernel buf
  * bitmap_parse_user(ubuf, ulen, dst, nbits)   Parse bitmap dst from user buf
  * bitmap_scnlistprintf(buf, len, src, nbits)  Print bitmap src as list to buf
- * bitmap_parselist(buf, dst, nbits)           Parse bitmap dst from list
+ * bitmap_parselist(buf, dst, nbits)           Parse bitmap dst from kernel buf
+ * bitmap_parselist_user(buf, dst, nbits)      Parse bitmap dst from user buf
  * bitmap_find_free_region(bitmap, bits, order)        Find and allocate bit region
  * bitmap_release_region(bitmap, pos, order)   Free specified bit region
  * bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
@@ -129,6 +130,8 @@ extern int bitmap_scnlistprintf(char *buf, unsigned int len,
                        const unsigned long *src, int nbits);
 extern int bitmap_parselist(const char *buf, unsigned long *maskp,
                        int nmaskbits);
+extern int bitmap_parselist_user(const char __user *ubuf, unsigned int ulen,
+                       unsigned long *dst, int nbits);
 extern void bitmap_remap(unsigned long *dst, const unsigned long *src,
                const unsigned long *old, const unsigned long *new, int bits);
 extern int bitmap_bitremap(int oldbit,
index be50d9e70a7d45577782c90050384252db735bd8..2a7cea53ca0d3d047617d1fff5f6e3848493a60f 100644 (file)
@@ -151,7 +151,6 @@ enum rq_flag_bits {
        __REQ_IO_STAT,          /* account I/O stat */
        __REQ_MIXED_MERGE,      /* merge of different types, fail separately */
        __REQ_SECURE,           /* secure discard (used with __REQ_DISCARD) */
-       __REQ_ON_PLUG,          /* on plug list */
        __REQ_NR_BITS,          /* stops here */
 };
 
@@ -192,6 +191,5 @@ enum rq_flag_bits {
 #define REQ_IO_STAT            (1 << __REQ_IO_STAT)
 #define REQ_MIXED_MERGE                (1 << __REQ_MIXED_MERGE)
 #define REQ_SECURE             (1 << __REQ_SECURE)
-#define REQ_ON_PLUG            (1 << __REQ_ON_PLUG)
 
 #endif /* __LINUX_BLK_TYPES_H */
index 2ad95fa1d130f8c8f5cfd68e5fe7a0108aec31d9..ae9091a684807ffcc95fa6c0fb6de3233383d4cf 100644 (file)
@@ -257,7 +257,7 @@ struct queue_limits {
        unsigned char           misaligned;
        unsigned char           discard_misaligned;
        unsigned char           cluster;
-       signed char             discard_zeroes_data;
+       unsigned char           discard_zeroes_data;
 };
 
 struct request_queue
@@ -364,6 +364,8 @@ struct request_queue
         * for flush operations
         */
        unsigned int            flush_flags;
+       unsigned int            flush_not_queueable:1;
+       unsigned int            flush_queue_delayed:1;
        unsigned int            flush_pending_idx:1;
        unsigned int            flush_running_idx:1;
        unsigned long           flush_pending_since;
@@ -843,6 +845,7 @@ extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *);
 extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *);
 extern void blk_queue_rq_timeout(struct request_queue *, unsigned int);
 extern void blk_queue_flush(struct request_queue *q, unsigned int flush);
+extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
@@ -1066,13 +1069,16 @@ static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector
 {
        unsigned int alignment = (sector << 9) & (lim->discard_granularity - 1);
 
+       if (!lim->max_discard_sectors)
+               return 0;
+
        return (lim->discard_granularity + lim->discard_alignment - alignment)
                & (lim->discard_granularity - 1);
 }
 
 static inline unsigned int queue_discard_zeroes_data(struct request_queue *q)
 {
-       if (q->limits.discard_zeroes_data == 1)
+       if (q->limits.max_discard_sectors && q->limits.discard_zeroes_data == 1)
                return 1;
 
        return 0;
@@ -1111,6 +1117,11 @@ static inline unsigned int block_size(struct block_device *bdev)
        return bdev->bd_block_size;
 }
 
+static inline bool queue_flush_queueable(struct request_queue *q)
+{
+       return !q->flush_not_queueable;
+}
+
 typedef struct {struct page *v;} Sector;
 
 unsigned char *read_dev_sector(struct block_device *, sector_t, Sector *);
index 01eca1794e148efb906d3aa9fe0327abb49cbd8a..ab344a52110571b6600c8bbb37871960fa8d67f0 100644 (file)
@@ -99,24 +99,31 @@ extern void *__alloc_bootmem_low_node(pg_data_t *pgdat,
                                      unsigned long align,
                                      unsigned long goal);
 
+#ifdef CONFIG_NO_BOOTMEM
+/* We are using top down, so it is safe to use 0 here */
+#define BOOTMEM_LOW_LIMIT 0
+#else
+#define BOOTMEM_LOW_LIMIT __pa(MAX_DMA_ADDRESS)
+#endif
+
 #define alloc_bootmem(x) \
-       __alloc_bootmem(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_align(x, align) \
-       __alloc_bootmem(x, align, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem(x, align, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_nopanic(x) \
-       __alloc_bootmem_nopanic(x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_nopanic(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_pages(x) \
-       __alloc_bootmem(x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_pages_nopanic(x) \
-       __alloc_bootmem_nopanic(x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_nopanic(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_node(pgdat, x) \
-       __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_node_nopanic(pgdat, x) \
-       __alloc_bootmem_node_nopanic(pgdat, x, SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_node_nopanic(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_pages_node(pgdat, x) \
-       __alloc_bootmem_node(pgdat, x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_node(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
 #define alloc_bootmem_pages_node_nopanic(pgdat, x) \
-       __alloc_bootmem_node_nopanic(pgdat, x, PAGE_SIZE, __pa(MAX_DMA_ADDRESS))
+       __alloc_bootmem_node_nopanic(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT)
 
 #define alloc_bootmem_low(x) \
        __alloc_bootmem_low(x, SMP_CACHE_BYTES, 0)
index 2a5cd867c365c3fd4e7f776ceb7e6d42d4e255f9..a2f7d7413f30534f039f902405faaf8be7e4a921 100644 (file)
@@ -60,9 +60,6 @@ struct c2port_ops {
  * Exported functions
  */
 
-#define to_class_dev(obj) container_of((obj), struct class_device, kobj)
-#define to_c2port_device(obj) container_of((obj), struct c2port_device, class)
-
 extern struct c2port_device *c2port_device_register(char *name,
                                        struct c2port_ops *ops, void *devdata);
 extern void c2port_device_unregister(struct c2port_device *dev);
index b8e995fbd8670a2c7303d590432dc2a5e1f62b0d..b8c60694b2b0977d4ecdb982d8bcaea5f0ef2673 100644 (file)
@@ -313,6 +313,7 @@ enum {
        CEPH_MDS_OP_GETATTR    = 0x00101,
        CEPH_MDS_OP_LOOKUPHASH = 0x00102,
        CEPH_MDS_OP_LOOKUPPARENT = 0x00103,
+       CEPH_MDS_OP_LOOKUPINO  = 0x00104,
 
        CEPH_MDS_OP_SETXATTR   = 0x01105,
        CEPH_MDS_OP_RMXATTR    = 0x01106,
index 5778b559d59c3222ee825897b7430523aa96c353..ddcb7db38e67cc1f822d9cca89c7253a0883a63e 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/sem.h>
 #include <linux/socket.h>
 #include <linux/if.h>
+#include <linux/fs.h>
+#include <linux/aio_abi.h>     /* for aio_context_t */
 
 #include <asm/compat.h>
 #include <asm/siginfo.h>
@@ -26,7 +28,7 @@ typedef __compat_gid32_t      compat_gid_t;
 struct compat_sel_arg_struct;
 struct rusage;
 
-struct compat_itimerspec { 
+struct compat_itimerspec {
        struct compat_timespec it_interval;
        struct compat_timespec it_value;
 };
@@ -70,9 +72,9 @@ struct compat_timex {
        compat_long_t stbcnt;
        compat_int_t tai;
 
-       compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
-       compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
-       compat_int_t :32; compat_int_t :32; compat_int_t :32;
+       compat_int_t:32; compat_int_t:32; compat_int_t:32; compat_int_t:32;
+       compat_int_t:32; compat_int_t:32; compat_int_t:32; compat_int_t:32;
+       compat_int_t:32; compat_int_t:32; compat_int_t:32;
 };
 
 #define _COMPAT_NSIG_WORDS     (_COMPAT_NSIG / _COMPAT_NSIG_BPW)
@@ -81,8 +83,10 @@ typedef struct {
        compat_sigset_word      sig[_COMPAT_NSIG_WORDS];
 } compat_sigset_t;
 
-extern int get_compat_timespec(struct timespec *, const struct compat_timespec __user *);
-extern int put_compat_timespec(const struct timespec *, struct compat_timespec __user *);
+extern int get_compat_timespec(struct timespec *,
+                              const struct compat_timespec __user *);
+extern int put_compat_timespec(const struct timespec *,
+                              struct compat_timespec __user *);
 
 struct compat_iovec {
        compat_uptr_t   iov_base;
@@ -113,7 +117,8 @@ struct compat_rusage {
        compat_long_t   ru_nivcsw;
 };
 
-extern int put_compat_rusage(const struct rusage *, struct compat_rusage __user *);
+extern int put_compat_rusage(const struct rusage *,
+                            struct compat_rusage __user *);
 
 struct compat_siginfo;
 
@@ -166,8 +171,7 @@ struct compat_ifmap {
        unsigned char port;
 };
 
-struct compat_if_settings
-{
+struct compat_if_settings {
        unsigned int type;      /* Type of physical device or protocol */
        unsigned int size;      /* Size of the data allocated by the caller */
        compat_uptr_t ifs_ifsu; /* union of pointers */
@@ -195,8 +199,8 @@ struct compat_ifreq {
 };
 
 struct compat_ifconf {
-        compat_int_t   ifc_len;                        /* size of buffer       */
-        compat_caddr_t  ifcbuf;
+       compat_int_t    ifc_len;                /* size of buffer */
+       compat_caddr_t  ifcbuf;
 };
 
 struct compat_robust_list {
@@ -209,6 +213,18 @@ struct compat_robust_list_head {
        compat_uptr_t                   list_op_pending;
 };
 
+struct compat_statfs;
+struct compat_statfs64;
+struct compat_old_linux_dirent;
+struct compat_linux_dirent;
+struct linux_dirent64;
+struct compat_msghdr;
+struct compat_mmsghdr;
+struct compat_sysinfo;
+struct compat_sysctl_args;
+struct compat_kexec_segment;
+struct compat_mq_attr;
+
 extern void compat_exit_robust_list(struct task_struct *curr);
 
 asmlinkage long
@@ -243,8 +259,8 @@ asmlinkage ssize_t compat_sys_pwritev(unsigned long fd,
                const struct compat_iovec __user *vec,
                unsigned long vlen, u32 pos_low, u32 pos_high);
 
-int compat_do_execve(char * filename, compat_uptr_t __user *argv,
-               compat_uptr_t __user *envp, struct pt_regs * regs);
+int compat_do_execve(char *filename, compat_uptr_t __user *argv,
+                    compat_uptr_t __user *envp, struct pt_regs *regs);
 
 asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
                compat_ulong_t __user *outp, compat_ulong_t __user *exp,
@@ -331,12 +347,18 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
                        const compat_sigset_t __user *sigmask,
                        compat_size_t sigsetsize);
 
-asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filename,
-                               struct compat_timespec __user *t, int flags);
+asmlinkage long compat_sys_utime(const char __user *filename,
+                                struct compat_utimbuf __user *t);
+asmlinkage long compat_sys_utimensat(unsigned int dfd,
+                                    const char __user *filename,
+                                    struct compat_timespec __user *t,
+                                    int flags);
 
+asmlinkage long compat_sys_time(compat_time_t __user *tloc);
+asmlinkage long compat_sys_stime(compat_time_t __user *tptr);
 asmlinkage long compat_sys_signalfd(int ufd,
-                               const compat_sigset_t __user *sigmask,
-                                compat_size_t sigsetsize);
+                                   const compat_sigset_t __user *sigmask,
+                                   compat_size_t sigsetsize);
 asmlinkage long compat_sys_timerfd_settime(int ufd, int flags,
                                   const struct compat_itimerspec __user *utmr,
                                   struct compat_itimerspec __user *otmr);
@@ -348,16 +370,190 @@ asmlinkage long compat_sys_move_pages(pid_t pid, unsigned long nr_page,
                                      const int __user *nodes,
                                      int __user *status,
                                      int flags);
-asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filename,
+asmlinkage long compat_sys_futimesat(unsigned int dfd,
+                                    const char __user *filename,
                                     struct compat_timeval __user *t);
-asmlinkage long compat_sys_newfstatat(unsigned int dfd, const char __user * filename,
+asmlinkage long compat_sys_utimes(const char __user *filename,
+                                 struct compat_timeval __user *t);
+asmlinkage long compat_sys_newstat(const char __user *filename,
+                                  struct compat_stat __user *statbuf);
+asmlinkage long compat_sys_newlstat(const char __user *filename,
+                                   struct compat_stat __user *statbuf);
+asmlinkage long compat_sys_newfstatat(unsigned int dfd,
+                                     const char __user *filename,
                                      struct compat_stat __user *statbuf,
                                      int flag);
+asmlinkage long compat_sys_newfstat(unsigned int fd,
+                                   struct compat_stat __user *statbuf);
+asmlinkage long compat_sys_statfs(const char __user *pathname,
+                                 struct compat_statfs __user *buf);
+asmlinkage long compat_sys_fstatfs(unsigned int fd,
+                                  struct compat_statfs __user *buf);
+asmlinkage long compat_sys_statfs64(const char __user *pathname,
+                                   compat_size_t sz,
+                                   struct compat_statfs64 __user *buf);
+asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz,
+                                    struct compat_statfs64 __user *buf);
+asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd,
+                                  unsigned long arg);
+asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd,
+                                unsigned long arg);
+asmlinkage long compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p);
+asmlinkage long compat_sys_io_getevents(aio_context_t ctx_id,
+                                       unsigned long min_nr,
+                                       unsigned long nr,
+                                       struct io_event __user *events,
+                                       struct compat_timespec __user *timeout);
+asmlinkage long compat_sys_io_submit(aio_context_t ctx_id, int nr,
+                                    u32 __user *iocb);
+asmlinkage long compat_sys_mount(const char __user *dev_name,
+                                const char __user *dir_name,
+                                const char __user *type, unsigned long flags,
+                                const void __user *data);
+asmlinkage long compat_sys_old_readdir(unsigned int fd,
+                                      struct compat_old_linux_dirent __user *,
+                                      unsigned int count);
+asmlinkage long compat_sys_getdents(unsigned int fd,
+                                   struct compat_linux_dirent __user *dirent,
+                                   unsigned int count);
+asmlinkage long compat_sys_getdents64(unsigned int fd,
+                                     struct linux_dirent64 __user *dirent,
+                                     unsigned int count);
+asmlinkage long compat_sys_vmsplice(int fd, const struct compat_iovec __user *,
+                                   unsigned int nr_segs, unsigned int flags);
+asmlinkage long compat_sys_open(const char __user *filename, int flags,
+                               int mode);
 asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename,
                                  int flags, int mode);
+asmlinkage long compat_sys_open_by_handle_at(int mountdirfd,
+                                            struct file_handle __user *handle,
+                                            int flags);
+asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp,
+                                   compat_ulong_t __user *outp,
+                                   compat_ulong_t __user *exp,
+                                   struct compat_timespec __user *tsp,
+                                   void __user *sig);
+asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
+                                unsigned int nfds,
+                                struct compat_timespec __user *tsp,
+                                const compat_sigset_t __user *sigmask,
+                                compat_size_t sigsetsize);
+#if (defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)) && \
+       !defined(CONFIG_NFSD_DEPRECATED)
+union compat_nfsctl_res;
+struct compat_nfsctl_arg;
+asmlinkage long compat_sys_nfsservctl(int cmd,
+                                     struct compat_nfsctl_arg __user *arg,
+                                     union compat_nfsctl_res __user *res);
+#else
+asmlinkage long compat_sys_nfsservctl(int cmd, void *notused, void *notused2);
+#endif
+asmlinkage long compat_sys_signalfd4(int ufd,
+                                    const compat_sigset_t __user *sigmask,
+                                    compat_size_t sigsetsize, int flags);
+asmlinkage long compat_sys_get_mempolicy(int __user *policy,
+                                        compat_ulong_t __user *nmask,
+                                        compat_ulong_t maxnode,
+                                        compat_ulong_t addr,
+                                        compat_ulong_t flags);
+asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask,
+                                        compat_ulong_t maxnode);
+asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
+                                compat_ulong_t mode,
+                                compat_ulong_t __user *nmask,
+                                compat_ulong_t maxnode, compat_ulong_t flags);
+
+asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
+                                     char __user *optval, unsigned int optlen);
+asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg,
+                                  unsigned flags);
+asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg,
+                                  unsigned int flags);
+asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len,
+                               unsigned flags);
+asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
+                           unsigned flags, struct sockaddr __user *addr,
+                           int __user *addrlen);
+asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
+                                   unsigned vlen, unsigned int flags,
+                                   struct compat_timespec __user *timeout);
+asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp,
+                                    struct compat_timespec __user *rmtp);
+asmlinkage long compat_sys_getitimer(int which,
+                                    struct compat_itimerval __user *it);
+asmlinkage long compat_sys_setitimer(int which,
+                                    struct compat_itimerval __user *in,
+                                    struct compat_itimerval __user *out);
+asmlinkage long compat_sys_times(struct compat_tms __user *tbuf);
+asmlinkage long compat_sys_setrlimit(unsigned int resource,
+                                    struct compat_rlimit __user *rlim);
+asmlinkage long compat_sys_getrlimit(unsigned int resource,
+                                    struct compat_rlimit __user *rlim);
+asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru);
+asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid,
+                                    unsigned int len,
+                                    compat_ulong_t __user *user_mask_ptr);
+asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid,
+                                    unsigned int len,
+                                    compat_ulong_t __user *user_mask_ptr);
+asmlinkage long compat_sys_timer_create(clockid_t which_clock,
+                       struct compat_sigevent __user *timer_event_spec,
+                       timer_t __user *created_timer_id);
+asmlinkage long compat_sys_timer_settime(timer_t timer_id, int flags,
+                                        struct compat_itimerspec __user *new,
+                                        struct compat_itimerspec __user *old);
+asmlinkage long compat_sys_timer_gettime(timer_t timer_id,
+                                struct compat_itimerspec __user *setting);
+asmlinkage long compat_sys_clock_settime(clockid_t which_clock,
+                                        struct compat_timespec __user *tp);
+asmlinkage long compat_sys_clock_gettime(clockid_t which_clock,
+                                        struct compat_timespec __user *tp);
+asmlinkage long compat_sys_clock_adjtime(clockid_t which_clock,
+                                        struct compat_timex __user *tp);
+asmlinkage long compat_sys_clock_getres(clockid_t which_clock,
+                                       struct compat_timespec __user *tp);
+asmlinkage long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
+                                          struct compat_timespec __user *rqtp,
+                                          struct compat_timespec __user *rmtp);
+asmlinkage long compat_sys_rt_sigtimedwait(compat_sigset_t __user *uthese,
+               struct compat_siginfo __user *uinfo,
+               struct compat_timespec __user *uts, compat_size_t sigsetsize);
+asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset,
+                                        compat_size_t sigsetsize);
+asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info);
+asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
+                                unsigned long arg);
+asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
+               struct compat_timespec __user *utime, u32 __user *uaddr2,
+               u32 val3);
+asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
+                                     char __user *optval, int __user *optlen);
+asmlinkage long compat_sys_kexec_load(unsigned long entry,
+                                     unsigned long nr_segments,
+                                     struct compat_kexec_segment __user *,
+                                     unsigned long flags);
+asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
+                       const struct compat_mq_attr __user *u_mqstat,
+                       struct compat_mq_attr __user *u_omqstat);
+asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
+                       const struct compat_sigevent __user *u_notification);
+asmlinkage long compat_sys_mq_open(const char __user *u_name,
+                       int oflag, compat_mode_t mode,
+                       struct compat_mq_attr __user *u_attr);
+asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
+                       const char __user *u_msg_ptr,
+                       size_t msg_len, unsigned int msg_prio,
+                       const struct compat_timespec __user *u_abs_timeout);
+asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
+                       char __user *u_msg_ptr,
+                       size_t msg_len, unsigned int __user *u_msg_prio,
+                       const struct compat_timespec __user *u_abs_timeout);
+asmlinkage long compat_sys_socketcall(int call, u32 __user *args);
+asmlinkage long compat_sys_sysctl(struct compat_sysctl_args __user *args);
 
 extern ssize_t compat_rw_copy_check_uvector(int type,
-               const struct compat_iovec __user *uvector, unsigned long nr_segs,
+               const struct compat_iovec __user *uvector,
+               unsigned long nr_segs,
                unsigned long fast_segs, struct iovec *fast_pointer,
                struct iovec **ret_pointer);
 
index cb4c1eb7778e4f776bf9343f93d5f9c8636ab148..59e4028e833d0ffe7c1fa11844cc5ebd027886f9 100644 (file)
     __asm__ ("" : "=r"(__ptr) : "0"(ptr));             \
     (typeof(ptr)) (__ptr + (off)); })
 
+#ifdef __CHECKER__
+#define __must_be_array(arr) 0
+#else
 /* &a[0] degrades to a pointer: a different type from an array */
 #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
+#endif
 
 /*
  * Force always-inline if the user requests it so via the .config,
index 64b7c003fd7a50c056d98f0a2aa412da067a753d..dfadc96e9d63851c334885f0ec7761c8d6cfe3ff 100644 (file)
@@ -51,7 +51,7 @@
 #if __GNUC_MINOR__ > 0
 #define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
 #endif
-#if __GNUC_MINOR__ >= 4
+#if __GNUC_MINOR__ >= 4 && !defined(__CHECKER__)
 #define __compiletime_warning(message) __attribute__((warning(message)))
 #define __compiletime_error(message) __attribute__((error(message)))
 #endif
index bae6fe24d1f9de103d75d40b6439f7e17a406b2a..b24ac56477b46bea69e7e748c04896cc564eda43 100644 (file)
@@ -546,6 +546,21 @@ static inline int cpumask_parse_user(const char __user *buf, int len,
        return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpumask_bits);
 }
 
+/**
+ * cpumask_parselist_user - extract a cpumask from a user string
+ * @buf: the buffer to extract from
+ * @len: the length of the buffer
+ * @dstp: the cpumask to set.
+ *
+ * Returns -errno, or 0 for success.
+ */
+static inline int cpumask_parselist_user(const char __user *buf, int len,
+                                    struct cpumask *dstp)
+{
+       return bitmap_parselist_user(buf, len, cpumask_bits(dstp),
+                                                       nr_cpumask_bits);
+}
+
 /**
  * cpulist_scnprintf - print a cpumask into a string as comma-separated list
  * @buf: the buffer to sprintf into
index cec467f5d6768ae92f958058ab93f20edba28ec6..9e5f5607eba36b918db8beb8a3bf0c1a807e9ecc 100644 (file)
@@ -38,7 +38,7 @@
 
 /* Although 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
+   architecture as of Linux-2.6.24-rc4 where the bitfields' endianness
    does not match the generic endianness. */
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -53,7 +53,7 @@
 
 
 extern const char *drbd_buildtag(void);
-#define REL_VERSION "8.3.10"
+#define REL_VERSION "8.3.11"
 #define API_VERSION 88
 #define PRO_VERSION_MIN 86
 #define PRO_VERSION_MAX 96
@@ -195,7 +195,7 @@ enum drbd_conns {
        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_STARTING_SYNC_T,  /* starting full sync by admin request. */
        C_WF_BITMAP_S,
        C_WF_BITMAP_T,
        C_WF_SYNC_UUID,
@@ -236,7 +236,7 @@ union drbd_state {
  * 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.
+ * on different endianness.
  */
        struct {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
@@ -266,7 +266,7 @@ union drbd_state {
                unsigned peer:2 ;   /* 3/4       primary/secondary/unknown */
                unsigned role:2 ;   /* 3/4       primary/secondary/unknown */
 #else
-# error "this endianess is not supported"
+# error "this endianness is not supported"
 #endif
        };
        unsigned int i;
index f14a165e82dc162ef0306d6dc8d9d7266a816387..0695431905162cdc1c50aad7b23efa2e5f0810ec 100644 (file)
@@ -30,7 +30,7 @@ enum packet_types {
        int tag_and_len ## member;
 #include "linux/drbd_nl.h"
 
-/* declate tag-list-sizes */
+/* declare 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
index cdf9495df204aa917605613b220c852349528b54..3f9d3251790d081529e51870a073682260b2212b 100644 (file)
@@ -23,7 +23,8 @@
 
 /* Fixed constants first: */
 #undef NR_OPEN
-#define INR_OPEN 1024          /* Initial setting for nfile rlimits */
+#define INR_OPEN_CUR 1024      /* Initial setting for nfile rlimits */
+#define INR_OPEN_MAX 4096      /* Hard limit for nfile rlimits */
 
 #define BLOCK_SIZE_BITS 10
 #define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
@@ -634,8 +635,7 @@ struct address_space {
        unsigned int            i_mmap_writable;/* count VM_SHARED mappings */
        struct prio_tree_root   i_mmap;         /* tree of private and shared mappings */
        struct list_head        i_mmap_nonlinear;/*list VM_NONLINEAR mappings */
-       spinlock_t              i_mmap_lock;    /* protect tree, count, list */
-       unsigned int            truncate_count; /* Cover race condition with truncate */
+       struct mutex            i_mmap_mutex;   /* protect tree, count, list */
        unsigned long           nrpages;        /* number of total pages */
        pgoff_t                 writeback_index;/* writeback starts here */
        const struct address_space_operations *a_ops;   /* methods */
@@ -644,7 +644,6 @@ struct address_space {
        spinlock_t              private_lock;   /* for use by the address_space */
        struct list_head        private_list;   /* ditto */
        struct address_space    *assoc_mapping; /* ditto */
-       struct mutex            unmap_mutex;    /* to protect unmapping */
 } __attribute__((aligned(sizeof(long))));
        /*
         * On most architectures that alignment is already the case; but
index 76427e688d1581f590478fcf8447a4443223901f..af095b54502e35471cad25d0e74e042fb50ecc4f 100644 (file)
@@ -100,17 +100,6 @@ struct fscache_operation {
 
        /* operation releaser */
        fscache_operation_release_t release;
-
-#ifdef CONFIG_WORKQUEUE_DEBUGFS
-       struct work_struct put_work;    /* work to delay operation put */
-       const char *name;               /* operation name */
-       const char *state;              /* operation state */
-#define fscache_set_op_name(OP, N)     do { (OP)->name  = (N); } while(0)
-#define fscache_set_op_state(OP, S)    do { (OP)->state = (S); } while(0)
-#else
-#define fscache_set_op_name(OP, N)     do { } while(0)
-#define fscache_set_op_state(OP, S)    do { } while(0)
-#endif
 };
 
 extern atomic_t fscache_op_debug_id;
@@ -137,7 +126,6 @@ static inline void fscache_operation_init(struct fscache_operation *op,
        op->processor = processor;
        op->release = release;
        INIT_LIST_HEAD(&op->pend_link);
-       fscache_set_op_state(op, "Init");
 }
 
 /*
index 9869ef3674acbfe0f1a8fbad4fd20286c092c3be..5bbebda78b025d8bc63b2c24e960d20733fa2613 100644 (file)
@@ -9,6 +9,8 @@
  */
 
 
+#ifndef __GENALLOC_H__
+#define __GENALLOC_H__
 /*
  *  General purpose special memory pool descriptor.
  */
@@ -24,13 +26,34 @@ struct gen_pool {
 struct gen_pool_chunk {
        spinlock_t lock;
        struct list_head next_chunk;    /* next chunk in pool */
+       phys_addr_t phys_addr;          /* physical starting address of memory chunk */
        unsigned long start_addr;       /* starting address of memory chunk */
        unsigned long end_addr;         /* ending address of memory chunk */
        unsigned long bits[0];          /* bitmap for allocating memory chunk */
 };
 
 extern struct gen_pool *gen_pool_create(int, int);
-extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int);
+extern phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long);
+extern int gen_pool_add_virt(struct gen_pool *, unsigned long, phys_addr_t,
+                            size_t, int);
+/**
+ * gen_pool_add - add a new chunk of special memory to the pool
+ * @pool: pool to add new memory chunk to
+ * @addr: starting address of memory chunk to add to pool
+ * @size: size in bytes of the memory chunk to add to pool
+ * @nid: node id of the node the chunk structure and bitmap should be
+ *       allocated on, or -1
+ *
+ * Add a new chunk of special memory to the specified pool.
+ *
+ * Returns 0 on success or a -ve errno on failure.
+ */
+static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,
+                              size_t size, int nid)
+{
+       return gen_pool_add_virt(pool, addr, -1, size, nid);
+}
 extern void gen_pool_destroy(struct gen_pool *);
 extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
 extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
+#endif /* __GENALLOC_H__ */
index d764a426e9fdbf5b5086542e3eeb6c6a2e6d3c8a..b78956b3c2e749076078cf74e439144c447c9058 100644 (file)
@@ -100,7 +100,6 @@ struct hd_struct {
        sector_t start_sect;
        sector_t nr_sects;
        sector_t alignment_offset;
-       unsigned int discard_alignment;
        struct device __dev;
        struct kobject *holder_dir;
        int policy, partno;
@@ -127,6 +126,7 @@ struct hd_struct {
 #define GENHD_FL_SUPPRESS_PARTITION_INFO       32
 #define GENHD_FL_EXT_DEVT                      64 /* allow extended devt */
 #define GENHD_FL_NATIVE_CAPACITY               128
+#define GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE    256
 
 enum {
        DISK_EVENT_MEDIA_CHANGE                 = 1 << 0, /* media changed */
index 56d8fc87fbbc70e8f1d5de07aa0bd7aaccd6887c..cb4089254f01feb22fa7db68841f81e7e6b2569c 100644 (file)
@@ -249,14 +249,7 @@ static inline enum zone_type gfp_zone(gfp_t flags)
 
        z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) &
                                         ((1 << ZONES_SHIFT) - 1);
-
-       if (__builtin_constant_p(bit))
-               BUILD_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
-       else {
-#ifdef CONFIG_DEBUG_VM
-               BUG_ON((GFP_ZONE_BAD >> bit) & 1);
-#endif
-       }
+       VM_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
        return z;
 }
 
index 8847c8c29791c8c078dedaf0db9ff6dce85faa23..48c32ebf65a77a2c19b35fe900bc28daf3f64e86 100644 (file)
@@ -92,12 +92,8 @@ extern void __split_huge_page_pmd(struct mm_struct *mm, pmd_t *pmd);
 #define wait_split_huge_page(__anon_vma, __pmd)                                \
        do {                                                            \
                pmd_t *____pmd = (__pmd);                               \
-               spin_unlock_wait(&(__anon_vma)->root->lock);            \
-               /*                                                      \
-                * spin_unlock_wait() is just a loop in C and so the    \
-                * CPU can reorder anything around it.                  \
-                */                                                     \
-               smp_mb();                                               \
+               anon_vma_lock(__anon_vma);                              \
+               anon_vma_unlock(__anon_vma);                            \
                BUG_ON(pmd_trans_splitting(*____pmd) ||                 \
                       pmd_trans_huge(*____pmd));                       \
        } while (0)
index f1e3ff5880a9f1d6d505f2e1102aeceef10fdb47..a6c652ef516d559dc405cefe5607d08772436e63 100644 (file)
@@ -409,7 +409,7 @@ void i2c_unlock_adapter(struct i2c_adapter *);
 /* i2c adapter classes (bitmask) */
 #define I2C_CLASS_HWMON                (1<<0)  /* lm_sensors, ... */
 #define I2C_CLASS_DDC          (1<<3)  /* DDC bus on graphics adapters */
-#define I2C_CLASS_SPD          (1<<7)  /* SPD EEPROMs and similar */
+#define I2C_CLASS_SPD          (1<<7)  /* Memory modules */
 
 /* Internal numbers to terminate lists */
 #define I2C_CLIENT_END         0xfffeU
index f4a2e6b1b864c5d8d83caffd2343c2cf12fe3b84..0ee969a5593d0fe0defc15089dc8c8515933836e 100644 (file)
@@ -136,6 +136,7 @@ enum {
        IFLA_PORT_SELF,
        IFLA_AF_SPEC,
        IFLA_GROUP,             /* Group the device belongs to */
+       IFLA_NET_NS_FD,
        __IFLA_MAX
 };
 
index 290bd8ac94cfe461f71eaf12bc4bdafc4fc993ce..dc01681fbb42d5dc689d58c239d6b20a1ae7992f 100644 (file)
@@ -110,6 +110,11 @@ static inline void vlan_group_set_device(struct vlan_group *vg,
        array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] = dev;
 }
 
+static inline int is_vlan_dev(struct net_device *dev)
+{
+        return dev->priv_flags & IFF_802_1Q_VLAN;
+}
+
 #define vlan_tx_tag_present(__skb)     ((__skb)->vlan_tci & VLAN_TAG_PRESENT)
 #define vlan_tx_tag_get(__skb)         ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
 
index f37ba716ef8b7fe81f73a586289286a879404609..fb0e7329fee1a5ad370b2e5284ceb681670c7395 100644 (file)
@@ -248,6 +248,37 @@ int __must_check kstrtos16(const char *s, unsigned int base, s16 *res);
 int __must_check kstrtou8(const char *s, unsigned int base, u8 *res);
 int __must_check kstrtos8(const char *s, unsigned int base, s8 *res);
 
+int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res);
+int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res);
+int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res);
+int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res);
+int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res);
+int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res);
+int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res);
+int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res);
+int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res);
+int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res);
+
+static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res)
+{
+       return kstrtoull_from_user(s, count, base, res);
+}
+
+static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res)
+{
+       return kstrtoll_from_user(s, count, base, res);
+}
+
+static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res)
+{
+       return kstrtouint_from_user(s, count, base, res);
+}
+
+static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res)
+{
+       return kstrtoint_from_user(s, count, base, res);
+}
+
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
@@ -638,6 +669,13 @@ struct sysinfo {
        char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */
 };
 
+#ifdef __CHECKER__
+#define BUILD_BUG_ON_NOT_POWER_OF_2(n)
+#define BUILD_BUG_ON_ZERO(e)
+#define BUILD_BUG_ON_NULL(e)
+#define BUILD_BUG_ON(condition)
+#else /* __CHECKER__ */
+
 /* Force a compilation error if a constant expression is not a power of 2 */
 #define BUILD_BUG_ON_NOT_POWER_OF_2(n)                 \
        BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
@@ -674,6 +712,7 @@ extern int __build_bug_on_failed;
                if (condition) __build_bug_on_failed = 1;       \
        } while(0)
 #endif
+#endif /* __CHECKER__ */
 
 /* Trap pasters of __FUNCTION__ at compile-time */
 #define __FUNCTION__ (__func__)
index f158eb1149aa8b6cd0029ca92ac2645a672a3928..b8d6fffed4d801c938e69bf7aa99fe3ad98085cb 100644 (file)
@@ -25,7 +25,7 @@ enum pca9532_state {
 };
 
 enum pca9532_type { PCA9532_TYPE_NONE, PCA9532_TYPE_LED,
-       PCA9532_TYPE_N2100_BEEP };
+       PCA9532_TYPE_N2100_BEEP, PCA9532_TYPE_GPIO };
 
 struct pca9532_led {
        u8 id;
@@ -41,6 +41,7 @@ struct pca9532_platform_data {
        struct pca9532_led leds[16];
        u8 pwm[2];
        u8 psc[2];
+       int gpio_base;
 };
 
 #endif /* __LINUX_PCA9532_H */
index 61e0340a4b770c3675787130afdc8174eb902262..5884def15a24872a2b4be5ef9abe815fad233388 100644 (file)
@@ -207,5 +207,7 @@ struct gpio_led_platform_data {
                                        unsigned long *delay_off);
 };
 
+struct platform_device *gpio_led_register_device(
+               int id, const struct gpio_led_platform_data *pdata);
 
 #endif         /* __LINUX_LEDS_H_INCLUDED */
index 4aef1dda64065e90bd846cd553b3c26fc93c594e..ef820a3c378bb421a51fb0920f289571f8f96382 100644 (file)
@@ -487,12 +487,15 @@ static inline void print_irqtrace_events(struct task_struct *curr)
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 # ifdef CONFIG_PROVE_LOCKING
 #  define mutex_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 2, NULL, i)
+#  define mutex_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 2, n, i)
 # else
 #  define mutex_acquire(l, s, t, i)            lock_acquire(l, s, t, 0, 1, NULL, i)
+#  define mutex_acquire_nest(l, s, t, n, i)    lock_acquire(l, s, t, 0, 1, n, i)
 # endif
 # define mutex_release(l, n, i)                        lock_release(l, n, i)
 #else
 # define mutex_acquire(l, s, t, i)             do { } while (0)
+# define mutex_acquire_nest(l, s, t, n, i)     do { } while (0)
 # define mutex_release(l, n, i)                        do { } while (0)
 #endif
 
index 6a4fab7c6e0902e261c3decc4b725cda0589b5d8..7a71ffad037c7ebd07aa79d7e23c08b6b38554bb 100644 (file)
@@ -139,9 +139,9 @@ write intent log information, three of which are mentioned here.
  * .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),
+ *          (lc_refcnt == 0, lc_number != LC_FREE),
  *    free: unused but ready to be recycled
- *          (ts_refcnt == 0, lc_number == LC_FREE),
+ *          (lc_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.
@@ -160,8 +160,8 @@ 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" */
+       /* back "pointer" into lc_cache->element[index],
+        * for paranoia, and for "lc_element_to_index" */
        unsigned lc_index;
        /* if we want to track a larger set of objects,
         * it needs to become arch independend u64 */
@@ -190,8 +190,8 @@ struct lru_cache {
        /* 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. */
+        * This also limits the maximum value of lc_element.lc_index, allowing the
+        * 8 high bits of .lc_index to be overloaded with flags in the future. */
 #define LC_MAX_ACTIVE  (1<<24)
 
        /* statistics */
index 62a10c2a11f2dc6a68f5bf4b1e30bbb23149ce6a..7525e38c434d64fa690c454922d99df75d75c983 100644 (file)
@@ -2,6 +2,8 @@
 #define _LINUX_MEMBLOCK_H
 #ifdef __KERNEL__
 
+#define MEMBLOCK_ERROR 0
+
 #ifdef CONFIG_HAVE_MEMBLOCK
 /*
  * Logical memory blocks.
@@ -20,7 +22,6 @@
 #include <asm/memblock.h>
 
 #define INIT_MEMBLOCK_REGIONS  128
-#define MEMBLOCK_ERROR         0
 
 struct memblock_region {
        phys_addr_t base;
@@ -160,6 +161,12 @@ static inline unsigned long memblock_region_reserved_end_pfn(const struct memblo
 #define __initdata_memblock
 #endif
 
+#else
+static inline phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align)
+{
+       return MEMBLOCK_ERROR;
+}
+
 #endif /* CONFIG_HAVE_MEMBLOCK */
 
 #endif /* __KERNEL__ */
index 31ac26ca4acf1afbe2e0afe343a5ca974acb49cc..7978eec1b7d9964420c2e854afba51a8f9cbf8f5 100644 (file)
@@ -199,6 +199,9 @@ void mpol_free_shared_policy(struct shared_policy *p);
 struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,
                                            unsigned long idx);
 
+struct mempolicy *get_vma_policy(struct task_struct *tsk,
+               struct vm_area_struct *vma, unsigned long addr);
+
 extern void numa_default_policy(void);
 extern void numa_policy_init(void);
 extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
@@ -228,10 +231,10 @@ int do_migrate_pages(struct mm_struct *mm,
 
 #ifdef CONFIG_TMPFS
 extern int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context);
+#endif
 
 extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
                        int no_context);
-#endif
 
 /* Check if a vma is migratable */
 static inline int vma_migratable(struct vm_area_struct *vma)
@@ -368,13 +371,13 @@ static inline int mpol_parse_str(char *str, struct mempolicy **mpol,
 {
        return 1;       /* error */
 }
+#endif
 
 static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
                                int no_context)
 {
        return 0;
 }
-#endif
 
 #endif /* CONFIG_NUMA */
 #endif /* __KERNEL__ */
diff --git a/include/linux/mfd/db5500-prcmu.h b/include/linux/mfd/db5500-prcmu.h
new file mode 100644 (file)
index 0000000..f097798
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * U5500 PRCMU API.
+ */
+#ifndef __MACH_PRCMU_U5500_H
+#define __MACH_PRCMU_U5500_H
+
+#ifdef CONFIG_UX500_SOC_DB5500
+
+void db5500_prcmu_early_init(void);
+
+int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+
+#else /* !CONFIG_UX500_SOC_DB5500 */
+
+static inline void db5500_prcmu_early_init(void)
+{
+}
+
+static inline int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       return -ENOSYS;
+}
+
+static inline int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       return -ENOSYS;
+}
+
+#endif /* CONFIG_UX500_SOC_DB5500 */
+
+static inline int db5500_prcmu_config_abb_event_readout(u32 abb_events)
+{
+#ifdef CONFIG_MACH_U5500_SIMULATOR
+       return 0;
+#else
+       return -1;
+#endif
+}
+
+#endif /* __MACH_PRCMU_U5500_H */
diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h
new file mode 100644 (file)
index 0000000..917dbca
--- /dev/null
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ *
+ * PRCMU f/w APIs
+ */
+#ifndef __MFD_DB8500_PRCMU_H
+#define __MFD_DB8500_PRCMU_H
+
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+
+/* This portion previously known as <mach/prcmu-fw-defs_v1.h> */
+
+/**
+ * enum state - ON/OFF state definition
+ * @OFF: State is ON
+ * @ON: State is OFF
+ *
+ */
+enum state {
+       OFF = 0x0,
+       ON  = 0x1,
+};
+
+/**
+ * enum ret_state - general purpose On/Off/Retention states
+ *
+ */
+enum ret_state {
+       OFFST = 0,
+       ONST  = 1,
+       RETST = 2
+};
+
+/**
+ * enum clk_arm - ARM Cortex A9 clock schemes
+ * @A9_OFF:
+ * @A9_BOOT:
+ * @A9_OPPT1:
+ * @A9_OPPT2:
+ * @A9_EXTCLK:
+ */
+enum clk_arm {
+       A9_OFF,
+       A9_BOOT,
+       A9_OPPT1,
+       A9_OPPT2,
+       A9_EXTCLK
+};
+
+/**
+ * enum clk_gen - GEN#0/GEN#1 clock schemes
+ * @GEN_OFF:
+ * @GEN_BOOT:
+ * @GEN_OPPT1:
+ */
+enum clk_gen {
+       GEN_OFF,
+       GEN_BOOT,
+       GEN_OPPT1,
+};
+
+/* some information between arm and xp70 */
+
+/**
+ * enum romcode_write - Romcode message written by A9 AND read by XP70
+ * @RDY_2_DS: Value set when ApDeepSleep state can be executed by XP70
+ * @RDY_2_XP70_RST: Value set when 0x0F has been successfully polled by the
+ *                 romcode. The xp70 will go into self-reset
+ */
+enum romcode_write {
+       RDY_2_DS = 0x09,
+       RDY_2_XP70_RST = 0x10
+};
+
+/**
+ * enum romcode_read - Romcode message written by XP70 and read by A9
+ * @INIT: Init value when romcode field is not used
+ * @FS_2_DS: Value set when power state is going from ApExecute to
+ *          ApDeepSleep
+ * @END_DS: Value set when ApDeepSleep power state is reached coming from
+ *         ApExecute state
+ * @DS_TO_FS: Value set when power state is going from ApDeepSleep to
+ *           ApExecute
+ * @END_FS: Value set when ApExecute power state is reached coming from
+ *         ApDeepSleep state
+ * @SWR: Value set when power state is going to ApReset
+ * @END_SWR: Value set when the xp70 finished executing ApReset actions and
+ *          waits for romcode acknowledgment to go to self-reset
+ */
+enum romcode_read {
+       INIT = 0x00,
+       FS_2_DS = 0x0A,
+       END_DS = 0x0B,
+       DS_TO_FS = 0x0C,
+       END_FS = 0x0D,
+       SWR = 0x0E,
+       END_SWR = 0x0F
+};
+
+/**
+ * enum ap_pwrst - current power states defined in PRCMU firmware
+ * @NO_PWRST: Current power state init
+ * @AP_BOOT: Current power state is apBoot
+ * @AP_EXECUTE: Current power state is apExecute
+ * @AP_DEEP_SLEEP: Current power state is apDeepSleep
+ * @AP_SLEEP: Current power state is apSleep
+ * @AP_IDLE: Current power state is apIdle
+ * @AP_RESET: Current power state is apReset
+ */
+enum ap_pwrst {
+       NO_PWRST = 0x00,
+       AP_BOOT = 0x01,
+       AP_EXECUTE = 0x02,
+       AP_DEEP_SLEEP = 0x03,
+       AP_SLEEP = 0x04,
+       AP_IDLE = 0x05,
+       AP_RESET = 0x06
+};
+
+/**
+ * enum ap_pwrst_trans - Transition states defined in PRCMU firmware
+ * @NO_TRANSITION: No power state transition
+ * @APEXECUTE_TO_APSLEEP: Power state transition from ApExecute to ApSleep
+ * @APIDLE_TO_APSLEEP: Power state transition from ApIdle to ApSleep
+ * @APBOOT_TO_APEXECUTE: Power state transition from ApBoot to ApExecute
+ * @APEXECUTE_TO_APDEEPSLEEP: Power state transition from ApExecute to
+ *                          ApDeepSleep
+ * @APEXECUTE_TO_APIDLE: Power state transition from ApExecute to ApIdle
+ */
+enum ap_pwrst_trans {
+       NO_TRANSITION                   = 0x00,
+       APEXECUTE_TO_APSLEEP            = 0x01,
+       APIDLE_TO_APSLEEP               = 0x02, /* To be removed */
+       PRCMU_AP_SLEEP                  = 0x01,
+       APBOOT_TO_APEXECUTE             = 0x03,
+       APEXECUTE_TO_APDEEPSLEEP        = 0x04, /* To be removed */
+       PRCMU_AP_DEEP_SLEEP             = 0x04,
+       APEXECUTE_TO_APIDLE             = 0x05, /* To be removed */
+       PRCMU_AP_IDLE                   = 0x05,
+       PRCMU_AP_DEEP_IDLE              = 0x07,
+};
+
+/**
+ * enum ddr_pwrst - DDR power states definition
+ * @DDR_PWR_STATE_UNCHANGED: SDRAM and DDR controller state is unchanged
+ * @DDR_PWR_STATE_ON:
+ * @DDR_PWR_STATE_OFFLOWLAT:
+ * @DDR_PWR_STATE_OFFHIGHLAT:
+ */
+enum ddr_pwrst {
+       DDR_PWR_STATE_UNCHANGED     = 0x00,
+       DDR_PWR_STATE_ON            = 0x01,
+       DDR_PWR_STATE_OFFLOWLAT     = 0x02,
+       DDR_PWR_STATE_OFFHIGHLAT    = 0x03
+};
+
+/**
+ * enum arm_opp - ARM OPP states definition
+ * @ARM_OPP_INIT:
+ * @ARM_NO_CHANGE: The ARM operating point is unchanged
+ * @ARM_100_OPP: The new ARM operating point is arm100opp
+ * @ARM_50_OPP: The new ARM operating point is arm50opp
+ * @ARM_MAX_OPP: Operating point is "max" (more than 100)
+ * @ARM_MAX_FREQ100OPP: Set max opp if available, else 100
+ * @ARM_EXTCLK: The new ARM operating point is armExtClk
+ */
+enum arm_opp {
+       ARM_OPP_INIT = 0x00,
+       ARM_NO_CHANGE = 0x01,
+       ARM_100_OPP = 0x02,
+       ARM_50_OPP = 0x03,
+       ARM_MAX_OPP = 0x04,
+       ARM_MAX_FREQ100OPP = 0x05,
+       ARM_EXTCLK = 0x07
+};
+
+/**
+ * enum ape_opp - APE OPP states definition
+ * @APE_OPP_INIT:
+ * @APE_NO_CHANGE: The APE operating point is unchanged
+ * @APE_100_OPP: The new APE operating point is ape100opp
+ * @APE_50_OPP: 50%
+ */
+enum ape_opp {
+       APE_OPP_INIT = 0x00,
+       APE_NO_CHANGE = 0x01,
+       APE_100_OPP = 0x02,
+       APE_50_OPP = 0x03
+};
+
+/**
+ * enum hw_acc_state - State definition for hardware accelerator
+ * @HW_NO_CHANGE: The hardware accelerator state must remain unchanged
+ * @HW_OFF: The hardware accelerator must be switched off
+ * @HW_OFF_RAMRET: The hardware accelerator must be switched off with its
+ *               internal RAM in retention
+ * @HW_ON: The hwa hardware accelerator hwa must be switched on
+ *
+ * NOTE! Deprecated, to be removed when all users switched over to use the
+ * regulator API.
+ */
+enum hw_acc_state {
+       HW_NO_CHANGE = 0x00,
+       HW_OFF = 0x01,
+       HW_OFF_RAMRET = 0x02,
+       HW_ON = 0x04
+};
+
+/**
+ * enum  mbox_2_arm_stat - Status messages definition for mbox_arm
+ * @BOOT_TO_EXECUTEOK: The apBoot to apExecute state transition has been
+ *                    completed
+ * @DEEPSLEEPOK: The apExecute to apDeepSleep state transition has been
+ *              completed
+ * @SLEEPOK: The apExecute to apSleep state transition has been completed
+ * @IDLEOK: The apExecute to apIdle state transition has been completed
+ * @SOFTRESETOK: The A9 watchdog/ SoftReset state has been completed
+ * @SOFTRESETGO : The A9 watchdog/SoftReset state is on going
+ * @BOOT_TO_EXECUTE: The apBoot to apExecute state transition is on going
+ * @EXECUTE_TO_DEEPSLEEP: The apExecute to apDeepSleep state transition is on
+ *                       going
+ * @DEEPSLEEP_TO_EXECUTE: The apDeepSleep to apExecute state transition is on
+ *                       going
+ * @DEEPSLEEP_TO_EXECUTEOK: The apDeepSleep to apExecute state transition has
+ *                         been completed
+ * @EXECUTE_TO_SLEEP: The apExecute to apSleep state transition is on going
+ * @SLEEP_TO_EXECUTE: The apSleep to apExecute state transition is on going
+ * @SLEEP_TO_EXECUTEOK: The apSleep to apExecute state transition has been
+ *                     completed
+ * @EXECUTE_TO_IDLE: The apExecute to apIdle state transition is on going
+ * @IDLE_TO_EXECUTE: The apIdle to apExecute state transition is on going
+ * @IDLE_TO_EXECUTEOK: The apIdle to apExecute state transition has been
+ *                    completed
+ * @INIT_STATUS: Status init
+ */
+enum ap_pwrsttr_status {
+       BOOT_TO_EXECUTEOK = 0xFF,
+       DEEPSLEEPOK = 0xFE,
+       SLEEPOK = 0xFD,
+       IDLEOK = 0xFC,
+       SOFTRESETOK = 0xFB,
+       SOFTRESETGO = 0xFA,
+       BOOT_TO_EXECUTE = 0xF9,
+       EXECUTE_TO_DEEPSLEEP = 0xF8,
+       DEEPSLEEP_TO_EXECUTE = 0xF7,
+       DEEPSLEEP_TO_EXECUTEOK = 0xF6,
+       EXECUTE_TO_SLEEP = 0xF5,
+       SLEEP_TO_EXECUTE = 0xF4,
+       SLEEP_TO_EXECUTEOK = 0xF3,
+       EXECUTE_TO_IDLE = 0xF2,
+       IDLE_TO_EXECUTE = 0xF1,
+       IDLE_TO_EXECUTEOK = 0xF0,
+       RDYTODS_RETURNTOEXE    = 0xEF,
+       NORDYTODS_RETURNTOEXE  = 0xEE,
+       EXETOSLEEP_RETURNTOEXE = 0xED,
+       EXETOIDLE_RETURNTOEXE  = 0xEC,
+       INIT_STATUS = 0xEB,
+
+       /*error messages */
+       INITERROR                     = 0x00,
+       PLLARMLOCKP_ER                = 0x01,
+       PLLDDRLOCKP_ER                = 0x02,
+       PLLSOCLOCKP_ER                = 0x03,
+       PLLSOCK1LOCKP_ER              = 0x04,
+       ARMWFI_ER                     = 0x05,
+       SYSCLKOK_ER                   = 0x06,
+       I2C_NACK_DATA_ER              = 0x07,
+       BOOT_ER                       = 0x08,
+       I2C_STATUS_ALWAYS_1           = 0x0A,
+       I2C_NACK_REG_ADDR_ER          = 0x0B,
+       I2C_NACK_DATA0123_ER          = 0x1B,
+       I2C_NACK_ADDR_ER              = 0x1F,
+       CURAPPWRSTISNOT_BOOT          = 0x20,
+       CURAPPWRSTISNOT_EXECUTE       = 0x21,
+       CURAPPWRSTISNOT_SLEEPMODE     = 0x22,
+       CURAPPWRSTISNOT_CORRECTFORIT10 = 0x23,
+       FIFO4500WUISNOT_WUPEVENT      = 0x24,
+       PLL32KLOCKP_ER                = 0x29,
+       DDRDEEPSLEEPOK_ER             = 0x2A,
+       ROMCODEREADY_ER               = 0x50,
+       WUPBEFOREDS                   = 0x51,
+       DDRCONFIG_ER                  = 0x52,
+       WUPBEFORESLEEP                = 0x53,
+       WUPBEFOREIDLE                 = 0x54
+};  /* earlier called as  mbox_2_arm_stat */
+
+/**
+ * enum dvfs_stat - DVFS status messages definition
+ * @DVFS_GO: A state transition DVFS is on going
+ * @DVFS_ARM100OPPOK: The state transition DVFS has been completed for 100OPP
+ * @DVFS_ARM50OPPOK: The state transition DVFS has been completed for 50OPP
+ * @DVFS_ARMEXTCLKOK: The state transition DVFS has been completed for EXTCLK
+ * @DVFS_NOCHGTCLKOK: The state transition DVFS has been completed for
+ *                   NOCHGCLK
+ * @DVFS_INITSTATUS: Value init
+ */
+enum dvfs_stat {
+       DVFS_GO = 0xFF,
+       DVFS_ARM100OPPOK = 0xFE,
+       DVFS_ARM50OPPOK = 0xFD,
+       DVFS_ARMEXTCLKOK = 0xFC,
+       DVFS_NOCHGTCLKOK = 0xFB,
+       DVFS_INITSTATUS = 0x00
+};
+
+/**
+ * enum sva_mmdsp_stat - SVA MMDSP status messages
+ * @SVA_MMDSP_GO: SVAMMDSP interrupt has happened
+ * @SVA_MMDSP_INIT: Status init
+ */
+enum sva_mmdsp_stat {
+       SVA_MMDSP_GO = 0xFF,
+       SVA_MMDSP_INIT = 0x00
+};
+
+/**
+ * enum sia_mmdsp_stat - SIA MMDSP status messages
+ * @SIA_MMDSP_GO: SIAMMDSP interrupt has happened
+ * @SIA_MMDSP_INIT: Status init
+ */
+enum sia_mmdsp_stat {
+       SIA_MMDSP_GO = 0xFF,
+       SIA_MMDSP_INIT = 0x00
+};
+
+/**
+ * enum  mbox_to_arm_err - Error messages definition
+ * @INIT_ERR: Init value
+ * @PLLARMLOCKP_ERR: PLLARM has not been correctly locked in given time
+ * @PLLDDRLOCKP_ERR: PLLDDR has not been correctly locked in the given time
+ * @PLLSOC0LOCKP_ERR: PLLSOC0 has not been correctly locked in the given time
+ * @PLLSOC1LOCKP_ERR: PLLSOC1 has not been correctly locked in the given time
+ * @ARMWFI_ERR: The ARM WFI has not been correctly executed in the given time
+ * @SYSCLKOK_ERR: The SYSCLK is not available in the given time
+ * @BOOT_ERR: Romcode has not validated the XP70 self reset in the given time
+ * @ROMCODESAVECONTEXT: The Romcode didn.t correctly save it secure context
+ * @VARMHIGHSPEEDVALTO_ERR: The ARM high speed supply value transfered
+ *          through I2C has not been correctly executed in the given time
+ * @VARMHIGHSPEEDACCESS_ERR: The command value of VarmHighSpeedVal transfered
+ *             through I2C has not been correctly executed in the given time
+ * @VARMLOWSPEEDVALTO_ERR:The ARM low speed supply value transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VARMLOWSPEEDACCESS_ERR: The command value of VarmLowSpeedVal transfered
+ *             through I2C has not been correctly executed in the given time
+ * @VARMRETENTIONVALTO_ERR: The ARM retention supply value transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VARMRETENTIONACCESS_ERR: The command value of VarmRetentionVal transfered
+ *             through I2C has not been correctly executed in the given time
+ * @VAPEHIGHSPEEDVALTO_ERR: The APE highspeed supply value transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VSAFEHPVALTO_ERR: The SAFE high power supply value transfered through I2C
+ *                         has not been correctly executed in the given time
+ * @VMODSEL1VALTO_ERR: The MODEM sel1 supply value transfered through I2C has
+ *                             not been correctly executed in the given time
+ * @VMODSEL2VALTO_ERR: The MODEM sel2 supply value transfered through I2C has
+ *                             not been correctly executed in the given time
+ * @VARMOFFACCESS_ERR: The command value of Varm ON/OFF transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VAPEOFFACCESS_ERR: The command value of Vape ON/OFF transfered through
+ *                     I2C has not been correctly executed in the given time
+ * @VARMRETACCES_ERR: The command value of Varm retention ON/OFF transfered
+ *             through I2C has not been correctly executed in the given time
+ * @CURAPPWRSTISNOTBOOT:Generated when Arm want to do power state transition
+ *             ApBoot to ApExecute but the power current state is not Apboot
+ * @CURAPPWRSTISNOTEXECUTE: Generated when Arm want to do power state
+ *              transition from ApExecute to others power state but the
+ *              power current state is not ApExecute
+ * @CURAPPWRSTISNOTSLEEPMODE: Generated when wake up events are transmitted
+ *             but the power current state is not ApDeepSleep/ApSleep/ApIdle
+ * @CURAPPWRSTISNOTCORRECTDBG:  Generated when wake up events are transmitted
+ *              but the power current state is not correct
+ * @ARMREGU1VALTO_ERR:The ArmRegu1 value transferred through I2C has not
+ *                    been correctly executed in the given time
+ * @ARMREGU2VALTO_ERR: The ArmRegu2 value transferred through I2C has not
+ *                    been correctly executed in the given time
+ * @VAPEREGUVALTO_ERR: The VApeRegu value transfered through I2C has not
+ *                    been correctly executed in the given time
+ * @VSMPS3REGUVALTO_ERR: The VSmps3Regu value transfered through I2C has not
+ *                      been correctly executed in the given time
+ * @VMODREGUVALTO_ERR: The VModemRegu value transfered through I2C has not
+ *                    been correctly executed in the given time
+ */
+enum mbox_to_arm_err {
+       INIT_ERR = 0x00,
+       PLLARMLOCKP_ERR = 0x01,
+       PLLDDRLOCKP_ERR = 0x02,
+       PLLSOC0LOCKP_ERR = 0x03,
+       PLLSOC1LOCKP_ERR = 0x04,
+       ARMWFI_ERR = 0x05,
+       SYSCLKOK_ERR = 0x06,
+       BOOT_ERR = 0x07,
+       ROMCODESAVECONTEXT = 0x08,
+       VARMHIGHSPEEDVALTO_ERR = 0x10,
+       VARMHIGHSPEEDACCESS_ERR = 0x11,
+       VARMLOWSPEEDVALTO_ERR = 0x12,
+       VARMLOWSPEEDACCESS_ERR = 0x13,
+       VARMRETENTIONVALTO_ERR = 0x14,
+       VARMRETENTIONACCESS_ERR = 0x15,
+       VAPEHIGHSPEEDVALTO_ERR = 0x16,
+       VSAFEHPVALTO_ERR = 0x17,
+       VMODSEL1VALTO_ERR = 0x18,
+       VMODSEL2VALTO_ERR = 0x19,
+       VARMOFFACCESS_ERR = 0x1A,
+       VAPEOFFACCESS_ERR = 0x1B,
+       VARMRETACCES_ERR = 0x1C,
+       CURAPPWRSTISNOTBOOT = 0x20,
+       CURAPPWRSTISNOTEXECUTE = 0x21,
+       CURAPPWRSTISNOTSLEEPMODE = 0x22,
+       CURAPPWRSTISNOTCORRECTDBG = 0x23,
+       ARMREGU1VALTO_ERR = 0x24,
+       ARMREGU2VALTO_ERR = 0x25,
+       VAPEREGUVALTO_ERR = 0x26,
+       VSMPS3REGUVALTO_ERR = 0x27,
+       VMODREGUVALTO_ERR = 0x28
+};
+
+enum hw_acc {
+       SVAMMDSP = 0,
+       SVAPIPE = 1,
+       SIAMMDSP = 2,
+       SIAPIPE = 3,
+       SGA = 4,
+       B2R2MCDE = 5,
+       ESRAM12 = 6,
+       ESRAM34 = 7,
+};
+
+enum cs_pwrmgt {
+       PWRDNCS0  = 0,
+       WKUPCS0   = 1,
+       PWRDNCS1  = 2,
+       WKUPCS1   = 3
+};
+
+/* Defs related to autonomous power management */
+
+/**
+ * enum sia_sva_pwr_policy - Power policy
+ * @NO_CHGT:   No change
+ * @DSPOFF_HWPOFF:
+ * @DSPOFFRAMRET_HWPOFF:
+ * @DSPCLKOFF_HWPOFF:
+ * @DSPCLKOFF_HWPCLKOFF:
+ *
+ */
+enum sia_sva_pwr_policy {
+       NO_CHGT                 = 0x0,
+       DSPOFF_HWPOFF           = 0x1,
+       DSPOFFRAMRET_HWPOFF     = 0x2,
+       DSPCLKOFF_HWPOFF        = 0x3,
+       DSPCLKOFF_HWPCLKOFF     = 0x4,
+};
+
+/**
+ * enum auto_enable - Auto Power enable
+ * @AUTO_OFF:
+ * @AUTO_ON:
+ *
+ */
+enum auto_enable {
+       AUTO_OFF        = 0x0,
+       AUTO_ON         = 0x1,
+};
+
+/* End of file previously known as prcmu-fw-defs_v1.h */
+
+/* PRCMU Wakeup defines */
+enum prcmu_wakeup_index {
+       PRCMU_WAKEUP_INDEX_RTC,
+       PRCMU_WAKEUP_INDEX_RTT0,
+       PRCMU_WAKEUP_INDEX_RTT1,
+       PRCMU_WAKEUP_INDEX_HSI0,
+       PRCMU_WAKEUP_INDEX_HSI1,
+       PRCMU_WAKEUP_INDEX_USB,
+       PRCMU_WAKEUP_INDEX_ABB,
+       PRCMU_WAKEUP_INDEX_ABB_FIFO,
+       PRCMU_WAKEUP_INDEX_ARM,
+       NUM_PRCMU_WAKEUP_INDICES
+};
+#define PRCMU_WAKEUP(_name) (BIT(PRCMU_WAKEUP_INDEX_##_name))
+
+/* PRCMU QoS APE OPP class */
+#define PRCMU_QOS_APE_OPP 1
+#define PRCMU_QOS_DDR_OPP 2
+#define PRCMU_QOS_DEFAULT_VALUE -1
+
+/**
+ * enum hw_acc_dev - enum for hw accelerators
+ * @HW_ACC_SVAMMDSP: for SVAMMDSP
+ * @HW_ACC_SVAPIPE:  for SVAPIPE
+ * @HW_ACC_SIAMMDSP: for SIAMMDSP
+ * @HW_ACC_SIAPIPE: for SIAPIPE
+ * @HW_ACC_SGA: for SGA
+ * @HW_ACC_B2R2: for B2R2
+ * @HW_ACC_MCDE: for MCDE
+ * @HW_ACC_ESRAM1: for ESRAM1
+ * @HW_ACC_ESRAM2: for ESRAM2
+ * @HW_ACC_ESRAM3: for ESRAM3
+ * @HW_ACC_ESRAM4: for ESRAM4
+ * @NUM_HW_ACC: number of hardware accelerators
+ *
+ * Different hw accelerators which can be turned ON/
+ * OFF or put into retention (MMDSPs and ESRAMs).
+ * Used with EPOD API.
+ *
+ * NOTE! Deprecated, to be removed when all users switched over to use the
+ * regulator API.
+ */
+enum hw_acc_dev {
+       HW_ACC_SVAMMDSP,
+       HW_ACC_SVAPIPE,
+       HW_ACC_SIAMMDSP,
+       HW_ACC_SIAPIPE,
+       HW_ACC_SGA,
+       HW_ACC_B2R2,
+       HW_ACC_MCDE,
+       HW_ACC_ESRAM1,
+       HW_ACC_ESRAM2,
+       HW_ACC_ESRAM3,
+       HW_ACC_ESRAM4,
+       NUM_HW_ACC
+};
+
+/*
+ * Ids for all EPODs (power domains)
+ * - EPOD_ID_SVAMMDSP: power domain for SVA MMDSP
+ * - EPOD_ID_SVAPIPE: power domain for SVA pipe
+ * - EPOD_ID_SIAMMDSP: power domain for SIA MMDSP
+ * - EPOD_ID_SIAPIPE: power domain for SIA pipe
+ * - EPOD_ID_SGA: power domain for SGA
+ * - EPOD_ID_B2R2_MCDE: power domain for B2R2 and MCDE
+ * - EPOD_ID_ESRAM12: power domain for ESRAM 1 and 2
+ * - EPOD_ID_ESRAM34: power domain for ESRAM 3 and 4
+ * - NUM_EPOD_ID: number of power domains
+ */
+#define EPOD_ID_SVAMMDSP       0
+#define EPOD_ID_SVAPIPE                1
+#define EPOD_ID_SIAMMDSP       2
+#define EPOD_ID_SIAPIPE                3
+#define EPOD_ID_SGA            4
+#define EPOD_ID_B2R2_MCDE      5
+#define EPOD_ID_ESRAM12                6
+#define EPOD_ID_ESRAM34                7
+#define NUM_EPOD_ID            8
+
+/*
+ * state definition for EPOD (power domain)
+ * - EPOD_STATE_NO_CHANGE: The EPOD should remain unchanged
+ * - EPOD_STATE_OFF: The EPOD is switched off
+ * - EPOD_STATE_RAMRET: The EPOD is switched off with its internal RAM in
+ *                         retention
+ * - EPOD_STATE_ON_CLK_OFF: The EPOD is switched on, clock is still off
+ * - EPOD_STATE_ON: Same as above, but with clock enabled
+ */
+#define EPOD_STATE_NO_CHANGE   0x00
+#define EPOD_STATE_OFF         0x01
+#define EPOD_STATE_RAMRET      0x02
+#define EPOD_STATE_ON_CLK_OFF  0x03
+#define EPOD_STATE_ON          0x04
+
+/*
+ * CLKOUT sources
+ */
+#define PRCMU_CLKSRC_CLK38M            0x00
+#define PRCMU_CLKSRC_ACLK              0x01
+#define PRCMU_CLKSRC_SYSCLK            0x02
+#define PRCMU_CLKSRC_LCDCLK            0x03
+#define PRCMU_CLKSRC_SDMMCCLK          0x04
+#define PRCMU_CLKSRC_TVCLK             0x05
+#define PRCMU_CLKSRC_TIMCLK            0x06
+#define PRCMU_CLKSRC_CLK009            0x07
+/* These are only valid for CLKOUT1: */
+#define PRCMU_CLKSRC_SIAMMDSPCLK       0x40
+#define PRCMU_CLKSRC_I2CCLK            0x41
+#define PRCMU_CLKSRC_MSP02CLK          0x42
+#define PRCMU_CLKSRC_ARMPLL_OBSCLK     0x43
+#define PRCMU_CLKSRC_HSIRXCLK          0x44
+#define PRCMU_CLKSRC_HSITXCLK          0x45
+#define PRCMU_CLKSRC_ARMCLKFIX         0x46
+#define PRCMU_CLKSRC_HDMICLK           0x47
+
+/*
+ * Definitions for autonomous power management configuration.
+ */
+
+#define PRCMU_AUTO_PM_OFF 0
+#define PRCMU_AUTO_PM_ON 1
+
+#define PRCMU_AUTO_PM_POWER_ON_HSEM BIT(0)
+#define PRCMU_AUTO_PM_POWER_ON_ABB_FIFO_IT BIT(1)
+
+enum prcmu_auto_pm_policy {
+       PRCMU_AUTO_PM_POLICY_NO_CHANGE,
+       PRCMU_AUTO_PM_POLICY_DSP_OFF_HWP_OFF,
+       PRCMU_AUTO_PM_POLICY_DSP_OFF_RAMRET_HWP_OFF,
+       PRCMU_AUTO_PM_POLICY_DSP_CLK_OFF_HWP_OFF,
+       PRCMU_AUTO_PM_POLICY_DSP_CLK_OFF_HWP_CLK_OFF,
+};
+
+/**
+ * struct prcmu_auto_pm_config - Autonomous power management configuration.
+ * @sia_auto_pm_enable: SIA autonomous pm enable. (PRCMU_AUTO_PM_{OFF,ON})
+ * @sia_power_on:       SIA power ON enable. (PRCMU_AUTO_PM_POWER_ON_* bitmask)
+ * @sia_policy:         SIA power policy. (enum prcmu_auto_pm_policy)
+ * @sva_auto_pm_enable: SVA autonomous pm enable. (PRCMU_AUTO_PM_{OFF,ON})
+ * @sva_power_on:       SVA power ON enable. (PRCMU_AUTO_PM_POWER_ON_* bitmask)
+ * @sva_policy:         SVA power policy. (enum prcmu_auto_pm_policy)
+ */
+struct prcmu_auto_pm_config {
+       u8 sia_auto_pm_enable;
+       u8 sia_power_on;
+       u8 sia_policy;
+       u8 sva_auto_pm_enable;
+       u8 sva_power_on;
+       u8 sva_policy;
+};
+
+/**
+ * enum ddr_opp - DDR OPP states definition
+ * @DDR_100_OPP: The new DDR operating point is ddr100opp
+ * @DDR_50_OPP: The new DDR operating point is ddr50opp
+ * @DDR_25_OPP: The new DDR operating point is ddr25opp
+ */
+enum ddr_opp {
+       DDR_100_OPP = 0x00,
+       DDR_50_OPP = 0x01,
+       DDR_25_OPP = 0x02,
+};
+
+/*
+ * Clock identifiers.
+ */
+enum prcmu_clock {
+       PRCMU_SGACLK,
+       PRCMU_UARTCLK,
+       PRCMU_MSP02CLK,
+       PRCMU_MSP1CLK,
+       PRCMU_I2CCLK,
+       PRCMU_SDMMCCLK,
+       PRCMU_SLIMCLK,
+       PRCMU_PER1CLK,
+       PRCMU_PER2CLK,
+       PRCMU_PER3CLK,
+       PRCMU_PER5CLK,
+       PRCMU_PER6CLK,
+       PRCMU_PER7CLK,
+       PRCMU_LCDCLK,
+       PRCMU_BMLCLK,
+       PRCMU_HSITXCLK,
+       PRCMU_HSIRXCLK,
+       PRCMU_HDMICLK,
+       PRCMU_APEATCLK,
+       PRCMU_APETRACECLK,
+       PRCMU_MCDECLK,
+       PRCMU_IPI2CCLK,
+       PRCMU_DSIALTCLK,
+       PRCMU_DMACLK,
+       PRCMU_B2R2CLK,
+       PRCMU_TVCLK,
+       PRCMU_SSPCLK,
+       PRCMU_RNGCLK,
+       PRCMU_UICCCLK,
+       PRCMU_NUM_REG_CLOCKS,
+       PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
+       PRCMU_TIMCLK,
+};
+
+/*
+ * Definitions for controlling ESRAM0 in deep sleep.
+ */
+#define ESRAM0_DEEP_SLEEP_STATE_OFF 1
+#define ESRAM0_DEEP_SLEEP_STATE_RET 2
+
+#ifdef CONFIG_MFD_DB8500_PRCMU
+void __init prcmu_early_init(void);
+int prcmu_set_display_clocks(void);
+int prcmu_disable_dsipll(void);
+int prcmu_enable_dsipll(void);
+#else
+static inline void __init prcmu_early_init(void) {}
+#endif
+
+#ifdef CONFIG_MFD_DB8500_PRCMU
+
+int prcmu_set_rc_a2p(enum romcode_write);
+enum romcode_read prcmu_get_rc_p2a(void);
+enum ap_pwrst prcmu_get_xp70_current_state(void);
+int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll);
+
+void prcmu_enable_wakeups(u32 wakeups);
+static inline void prcmu_disable_wakeups(void)
+{
+       prcmu_enable_wakeups(0);
+}
+
+void prcmu_config_abb_event_readout(u32 abb_events);
+void prcmu_get_abb_event_buffer(void __iomem **buf);
+int prcmu_set_arm_opp(u8 opp);
+int prcmu_get_arm_opp(void);
+bool prcmu_has_arm_maxopp(void);
+bool prcmu_is_u8400(void);
+int prcmu_set_ape_opp(u8 opp);
+int prcmu_get_ape_opp(void);
+int prcmu_request_ape_opp_100_voltage(bool enable);
+int prcmu_release_usb_wakeup_state(void);
+int prcmu_set_ddr_opp(u8 opp);
+int prcmu_get_ddr_opp(void);
+unsigned long prcmu_qos_get_cpufreq_opp_delay(void);
+void prcmu_qos_set_cpufreq_opp_delay(unsigned long);
+/* NOTE! Use regulator framework instead */
+int prcmu_set_hwacc(u16 hw_acc_dev, u8 state);
+int prcmu_set_epod(u16 epod_id, u8 epod_state);
+void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
+       struct prcmu_auto_pm_config *idle);
+bool prcmu_is_auto_pm_enabled(void);
+
+int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
+int prcmu_request_clock(u8 clock, bool enable);
+int prcmu_set_clock_divider(u8 clock, u8 divider);
+int prcmu_config_esram0_deep_sleep(u8 state);
+int prcmu_config_hotdog(u8 threshold);
+int prcmu_config_hotmon(u8 low, u8 high);
+int prcmu_start_temp_sense(u16 cycles32k);
+int prcmu_stop_temp_sense(void);
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+
+void prcmu_ac_wake_req(void);
+void prcmu_ac_sleep_req(void);
+void prcmu_system_reset(u16 reset_code);
+void prcmu_modem_reset(void);
+bool prcmu_is_ac_wake_requested(void);
+void prcmu_enable_spi2(void);
+void prcmu_disable_spi2(void);
+
+#else /* !CONFIG_MFD_DB8500_PRCMU */
+
+static inline int prcmu_set_rc_a2p(enum romcode_write code)
+{
+       return 0;
+}
+
+static inline enum romcode_read prcmu_get_rc_p2a(void)
+{
+       return INIT;
+}
+
+static inline enum ap_pwrst prcmu_get_xp70_current_state(void)
+{
+       return AP_EXECUTE;
+}
+
+static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
+       bool keep_ap_pll)
+{
+       return 0;
+}
+
+static inline void prcmu_enable_wakeups(u32 wakeups) {}
+
+static inline void prcmu_disable_wakeups(void) {}
+
+static inline void prcmu_config_abb_event_readout(u32 abb_events) {}
+
+static inline int prcmu_set_arm_opp(u8 opp)
+{
+       return 0;
+}
+
+static inline int prcmu_get_arm_opp(void)
+{
+       return ARM_100_OPP;
+}
+
+static bool prcmu_has_arm_maxopp(void)
+{
+       return false;
+}
+
+static bool prcmu_is_u8400(void)
+{
+       return false;
+}
+
+static inline int prcmu_set_ape_opp(u8 opp)
+{
+       return 0;
+}
+
+static inline int prcmu_get_ape_opp(void)
+{
+       return APE_100_OPP;
+}
+
+static inline int prcmu_request_ape_opp_100_voltage(bool enable)
+{
+       return 0;
+}
+
+static inline int prcmu_release_usb_wakeup_state(void)
+{
+       return 0;
+}
+
+static inline int prcmu_set_ddr_opp(u8 opp)
+{
+       return 0;
+}
+
+static inline int prcmu_get_ddr_opp(void)
+{
+       return DDR_100_OPP;
+}
+
+static inline unsigned long prcmu_qos_get_cpufreq_opp_delay(void)
+{
+       return 0;
+}
+
+static inline void prcmu_qos_set_cpufreq_opp_delay(unsigned long n) {}
+
+static inline int prcmu_set_hwacc(u16 hw_acc_dev, u8 state)
+{
+       return 0;
+}
+
+static inline void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
+       struct prcmu_auto_pm_config *idle)
+{
+}
+
+static inline bool prcmu_is_auto_pm_enabled(void)
+{
+       return false;
+}
+
+static inline int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
+{
+       return 0;
+}
+
+static inline int prcmu_request_clock(u8 clock, bool enable)
+{
+       return 0;
+}
+
+static inline int prcmu_set_clock_divider(u8 clock, u8 divider)
+{
+       return 0;
+}
+
+int prcmu_config_esram0_deep_sleep(u8 state)
+{
+       return 0;
+}
+
+static inline int prcmu_config_hotdog(u8 threshold)
+{
+       return 0;
+}
+
+static inline int prcmu_config_hotmon(u8 low, u8 high)
+{
+       return 0;
+}
+
+static inline int prcmu_start_temp_sense(u16 cycles32k)
+{
+       return 0;
+}
+
+static inline int prcmu_stop_temp_sense(void)
+{
+       return 0;
+}
+
+static inline int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       return -ENOSYS;
+}
+
+static inline int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       return -ENOSYS;
+}
+
+static inline void prcmu_ac_wake_req(void) {}
+
+static inline void prcmu_ac_sleep_req(void) {}
+
+static inline void prcmu_system_reset(u16 reset_code) {}
+
+static inline void prcmu_modem_reset(void) {}
+
+static inline bool prcmu_is_ac_wake_requested(void)
+{
+       return false;
+}
+
+#ifndef CONFIG_UX500_SOC_DB5500
+static inline int prcmu_set_display_clocks(void)
+{
+       return 0;
+}
+
+static inline int prcmu_disable_dsipll(void)
+{
+       return 0;
+}
+
+static inline int prcmu_enable_dsipll(void)
+{
+       return 0;
+}
+#endif
+
+static inline int prcmu_enable_spi2(void)
+{
+       return 0;
+}
+
+static inline int prcmu_disable_spi2(void)
+{
+       return 0;
+}
+
+#endif /* !CONFIG_MFD_DB8500_PRCMU */
+
+#ifdef CONFIG_UX500_PRCMU_QOS_POWER
+int prcmu_qos_requirement(int pm_qos_class);
+int prcmu_qos_add_requirement(int pm_qos_class, char *name, s32 value);
+int prcmu_qos_update_requirement(int pm_qos_class, char *name, s32 new_value);
+void prcmu_qos_remove_requirement(int pm_qos_class, char *name);
+int prcmu_qos_add_notifier(int prcmu_qos_class,
+                          struct notifier_block *notifier);
+int prcmu_qos_remove_notifier(int prcmu_qos_class,
+                             struct notifier_block *notifier);
+#else
+static inline int prcmu_qos_requirement(int prcmu_qos_class)
+{
+       return 0;
+}
+
+static inline int prcmu_qos_add_requirement(int prcmu_qos_class,
+                                           char *name, s32 value)
+{
+       return 0;
+}
+
+static inline int prcmu_qos_update_requirement(int prcmu_qos_class,
+                                              char *name, s32 new_value)
+{
+       return 0;
+}
+
+static inline void prcmu_qos_remove_requirement(int prcmu_qos_class, char *name)
+{
+}
+
+static inline int prcmu_qos_add_notifier(int prcmu_qos_class,
+                                        struct notifier_block *notifier)
+{
+       return 0;
+}
+static inline int prcmu_qos_remove_notifier(int prcmu_qos_class,
+                                           struct notifier_block *notifier)
+{
+       return 0;
+}
+
+#endif
+
+#endif /* __MFD_DB8500_PRCMU_H */
index 8e70310ee9453c6d5abdcd514345479055d8d684..5a90266c3a5a7061a0e3639082d106ffbe72ff01 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/fb.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #define tmio_ioread8(addr) readb(addr)
 #define tmio_ioread16(addr) readw(addr)
  * Some controllers can support SDIO IRQ signalling.
  */
 #define TMIO_MMC_SDIO_IRQ              (1 << 2)
+/*
+ * Some platforms can detect card insertion events with controller powered
+ * down, in which case they have to call tmio_mmc_cd_wakeup() to power up the
+ * controller and report the event to the driver.
+ */
+#define TMIO_MMC_HAS_COLD_CD           (1 << 3)
 
 int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base);
 int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
@@ -82,11 +89,21 @@ struct tmio_mmc_data {
        unsigned long                   flags;
        u32                             ocr_mask;       /* available voltages */
        struct tmio_mmc_dma             *dma;
+       struct device                   *dev;
+       bool                            power;
        void (*set_pwr)(struct platform_device *host, int state);
        void (*set_clk_div)(struct platform_device *host, int state);
        int (*get_cd)(struct platform_device *host);
 };
 
+static inline void tmio_mmc_cd_wakeup(struct tmio_mmc_data *pdata)
+{
+       if (pdata && !pdata->power) {
+               pdata->power = true;
+               pm_runtime_get(pdata->dev);
+       }
+}
+
 /*
  * data for the NAND controller
  */
index 6507dde38b16602a1b819492088f6ce5ea8fba40..8eb969ebf90450c19414af90118c083388002f88 100644 (file)
@@ -153,6 +153,7 @@ extern pgprot_t protection_map[16];
 #define FAULT_FLAG_MKWRITE     0x04    /* Fault was mkwrite of existing pte */
 #define FAULT_FLAG_ALLOW_RETRY 0x08    /* Retry fault if blocking */
 #define FAULT_FLAG_RETRY_NOWAIT        0x10    /* Don't drop mmap_sem and wait when retrying */
+#define FAULT_FLAG_KILLABLE    0x20    /* The fault task is in SIGKILL killable region */
 
 /*
  * This interface is used by x86 PAT code to identify a pfn mapping that is
@@ -604,10 +605,6 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
 #define NODE_NOT_IN_PAGE_FLAGS
 #endif
 
-#ifndef PFN_SECTION_SHIFT
-#define PFN_SECTION_SHIFT 0
-#endif
-
 /*
  * Define the bit shifts to access each section.  For non-existent
  * sections we define the shift as 0; that plus a 0 mask ensures
@@ -681,6 +678,12 @@ static inline struct zone *page_zone(struct page *page)
 }
 
 #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
+static inline void set_page_section(struct page *page, unsigned long section)
+{
+       page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT);
+       page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
+}
+
 static inline unsigned long page_to_section(struct page *page)
 {
        return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
@@ -699,18 +702,14 @@ static inline void set_page_node(struct page *page, unsigned long node)
        page->flags |= (node & NODES_MASK) << NODES_PGSHIFT;
 }
 
-static inline void set_page_section(struct page *page, unsigned long section)
-{
-       page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT);
-       page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
-}
-
 static inline void set_page_links(struct page *page, enum zone_type zone,
        unsigned long node, unsigned long pfn)
 {
        set_page_zone(page, zone);
        set_page_node(page, node);
+#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
        set_page_section(page, pfn_to_section_nr(pfn));
+#endif
 }
 
 /*
@@ -862,26 +861,18 @@ extern void pagefault_out_of_memory(void);
 #define offset_in_page(p)      ((unsigned long)(p) & ~PAGE_MASK)
 
 /*
- * Flags passed to show_mem() and __show_free_areas() to suppress output in
+ * Flags passed to show_mem() and show_free_areas() to suppress output in
  * various contexts.
  */
 #define SHOW_MEM_FILTER_NODES  (0x0001u)       /* filter disallowed nodes */
 
-extern void show_free_areas(void);
-extern void __show_free_areas(unsigned int flags);
+extern void show_free_areas(unsigned int flags);
+extern bool skip_free_areas_node(unsigned int flags, int nid);
 
 int shmem_lock(struct file *file, int lock, struct user_struct *user);
 struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags);
 int shmem_zero_setup(struct vm_area_struct *);
 
-#ifndef CONFIG_MMU
-extern unsigned long shmem_get_unmapped_area(struct file *file,
-                                            unsigned long addr,
-                                            unsigned long len,
-                                            unsigned long pgoff,
-                                            unsigned long flags);
-#endif
-
 extern int can_do_mlock(void);
 extern int user_shm_lock(size_t, struct user_struct *);
 extern void user_shm_unlock(size_t, struct user_struct *);
@@ -894,8 +885,6 @@ struct zap_details {
        struct address_space *check_mapping;    /* Check page->mapping if set */
        pgoff_t first_index;                    /* Lowest page->index to unmap */
        pgoff_t last_index;                     /* Highest page->index to unmap */
-       spinlock_t *i_mmap_lock;                /* For unmap_mapping_range: */
-       unsigned long truncate_count;           /* Compare vm_truncate_count */
 };
 
 struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
@@ -905,7 +894,7 @@ int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
                unsigned long size);
 unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
                unsigned long size, struct zap_details *);
-unsigned long unmap_vmas(struct mmu_gather **tlb,
+unsigned long unmap_vmas(struct mmu_gather *tlb,
                struct vm_area_struct *start_vma, unsigned long start_addr,
                unsigned long end_addr, unsigned long *nr_accounted,
                struct zap_details *);
@@ -1056,65 +1045,35 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
 /*
  * per-process(per-mm_struct) statistics.
  */
-#if defined(SPLIT_RSS_COUNTING)
-/*
- * The mm counters are not protected by its page_table_lock,
- * so must be incremented atomically.
- */
 static inline void set_mm_counter(struct mm_struct *mm, int member, long value)
 {
        atomic_long_set(&mm->rss_stat.count[member], value);
 }
 
+#if defined(SPLIT_RSS_COUNTING)
 unsigned long get_mm_counter(struct mm_struct *mm, int member);
-
-static inline void add_mm_counter(struct mm_struct *mm, int member, long value)
-{
-       atomic_long_add(value, &mm->rss_stat.count[member]);
-}
-
-static inline void inc_mm_counter(struct mm_struct *mm, int member)
-{
-       atomic_long_inc(&mm->rss_stat.count[member]);
-}
-
-static inline void dec_mm_counter(struct mm_struct *mm, int member)
-{
-       atomic_long_dec(&mm->rss_stat.count[member]);
-}
-
-#else  /* !USE_SPLIT_PTLOCKS */
-/*
- * The mm counters are protected by its page_table_lock,
- * so can be incremented directly.
- */
-static inline void set_mm_counter(struct mm_struct *mm, int member, long value)
-{
-       mm->rss_stat.count[member] = value;
-}
-
+#else
 static inline unsigned long get_mm_counter(struct mm_struct *mm, int member)
 {
-       return mm->rss_stat.count[member];
+       return atomic_long_read(&mm->rss_stat.count[member]);
 }
+#endif
 
 static inline void add_mm_counter(struct mm_struct *mm, int member, long value)
 {
-       mm->rss_stat.count[member] += value;
+       atomic_long_add(value, &mm->rss_stat.count[member]);
 }
 
 static inline void inc_mm_counter(struct mm_struct *mm, int member)
 {
-       mm->rss_stat.count[member]++;
+       atomic_long_inc(&mm->rss_stat.count[member]);
 }
 
 static inline void dec_mm_counter(struct mm_struct *mm, int member)
 {
-       mm->rss_stat.count[member]--;
+       atomic_long_dec(&mm->rss_stat.count[member]);
 }
 
-#endif /* !USE_SPLIT_PTLOCKS */
-
 static inline unsigned long get_mm_rss(struct mm_struct *mm)
 {
        return get_mm_counter(mm, MM_FILEPAGES) +
@@ -1162,14 +1121,25 @@ static inline void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
 }
 #endif
 
+/*
+ * This struct is used to pass information from page reclaim to the shrinkers.
+ * We consolidate the values for easier extention later.
+ */
+struct shrink_control {
+       gfp_t gfp_mask;
+
+       /* How many slab objects shrinker() should scan and try to reclaim */
+       unsigned long nr_to_scan;
+};
+
 /*
  * A callback you can register to apply pressure to ageable caches.
  *
- * 'shrink' is passed a count 'nr_to_scan' and a 'gfpmask'.  It should
- * look through the least-recently-used 'nr_to_scan' entries and
- * attempt to free them up.  It should return the number of objects
- * which remain in the cache.  If it returns -1, it means it cannot do
- * any scanning at this time (eg. there is a risk of deadlock).
+ * 'sc' is passed shrink_control which includes a count 'nr_to_scan'
+ * and a 'gfpmask'.  It should look through the least-recently-used
+ * 'nr_to_scan' entries and attempt to free them up.  It should return
+ * the number of objects which remain in the cache.  If it returns -1, it means
+ * it cannot do any scanning at this time (eg. there is a risk of deadlock).
  *
  * The 'gfpmask' refers to the allocation we are currently trying to
  * fulfil.
@@ -1178,7 +1148,7 @@ static inline void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
  * querying the cache size, so a fastpath for that case is appropriate.
  */
 struct shrinker {
-       int (*shrink)(struct shrinker *, int nr_to_scan, gfp_t gfp_mask);
+       int (*shrink)(struct shrinker *, struct shrink_control *sc);
        int seeks;      /* seeks to recreate an obj */
 
        /* These are for internal use */
@@ -1380,7 +1350,7 @@ extern void set_dma_reserve(unsigned long new_dma_reserve);
 extern void memmap_init_zone(unsigned long, int, unsigned long,
                                unsigned long, enum memmap_context);
 extern void setup_per_zone_wmarks(void);
-extern void calculate_zone_inactive_ratio(struct zone *zone);
+extern int __meminit init_per_zone_wmark_min(void);
 extern void mem_init(void);
 extern void __init mmap_init(void);
 extern void show_mem(unsigned int flags);
@@ -1388,6 +1358,8 @@ extern void si_meminfo(struct sysinfo * val);
 extern void si_meminfo_node(struct sysinfo *val, int nid);
 extern int after_bootmem;
 
+extern void warn_alloc_failed(gfp_t gfp_mask, int order, const char *fmt, ...);
+
 extern void setup_per_cpu_pageset(void);
 
 extern void zone_pcp_update(struct zone *zone);
@@ -1517,15 +1489,17 @@ unsigned long ra_submit(struct file_ra_state *ra,
                        struct address_space *mapping,
                        struct file *filp);
 
-/* Do stack extension */
+/* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */
 extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
+
+/* CONFIG_STACK_GROWSUP still needs to to grow downwards at some places */
+extern int expand_downwards(struct vm_area_struct *vma,
+               unsigned long address);
 #if VM_GROWSUP
 extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
 #else
   #define expand_upwards(vma, address) do { } while (0)
 #endif
-extern int expand_stack_downwards(struct vm_area_struct *vma,
-                                 unsigned long address);
 
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
 extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
@@ -1627,8 +1601,9 @@ int in_gate_area_no_mm(unsigned long addr);
 
 int drop_caches_sysctl_handler(struct ctl_table *, int,
                                        void __user *, size_t *, loff_t *);
-unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
-                       unsigned long lru_pages);
+unsigned long shrink_slab(struct shrink_control *shrink,
+                         unsigned long nr_pages_scanned,
+                         unsigned long lru_pages);
 
 #ifndef CONFIG_MMU
 #define randomize_va_space 0
index 02aa5619709b9bab0a40d183fc3b0b017b8bd50c..071d459e866bdccf55541c0b6147d73c3acd2670 100644 (file)
@@ -175,7 +175,6 @@ struct vm_area_struct {
                                           units, *not* PAGE_CACHE_SIZE */
        struct file * vm_file;          /* File we map to (can be NULL). */
        void * vm_private_data;         /* was vm_pte (shared mem) */
-       unsigned long vm_truncate_count;/* truncate_count or restart_addr */
 
 #ifndef CONFIG_MMU
        struct vm_region *vm_region;    /* NOMMU mapping region */
@@ -205,19 +204,16 @@ enum {
 
 #if USE_SPLIT_PTLOCKS && defined(CONFIG_MMU)
 #define SPLIT_RSS_COUNTING
-struct mm_rss_stat {
-       atomic_long_t count[NR_MM_COUNTERS];
-};
 /* per-thread cached information, */
 struct task_rss_stat {
        int events;     /* for synchronization threshold */
        int count[NR_MM_COUNTERS];
 };
-#else  /* !USE_SPLIT_PTLOCKS */
+#endif /* USE_SPLIT_PTLOCKS */
+
 struct mm_rss_stat {
-       unsigned long count[NR_MM_COUNTERS];
+       atomic_long_t count[NR_MM_COUNTERS];
 };
-#endif /* !USE_SPLIT_PTLOCKS */
 
 struct mm_struct {
        struct vm_area_struct * mmap;           /* list of VMAs */
@@ -266,8 +262,6 @@ struct mm_struct {
 
        struct linux_binfmt *binfmt;
 
-       cpumask_t cpu_vm_mask;
-
        /* Architecture-specific MM context */
        mm_context_t context;
 
@@ -317,9 +311,14 @@ struct mm_struct {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
        pgtable_t pmd_huge_pte; /* protected by page_table_lock */
 #endif
+
+       cpumask_var_t cpu_vm_mask_var;
 };
 
 /* Future-safe accessor for struct mm_struct's cpu_vm_mask. */
-#define mm_cpumask(mm) (&(mm)->cpu_vm_mask)
+static inline cpumask_t *mm_cpumask(struct mm_struct *mm)
+{
+       return mm->cpu_vm_mask_var;
+}
 
 #endif /* _LINUX_MM_TYPES_H */
diff --git a/include/linux/mmc/Kbuild b/include/linux/mmc/Kbuild
new file mode 100644 (file)
index 0000000..1fb2644
--- /dev/null
@@ -0,0 +1 @@
+header-y += ioctl.h
index adb4888248be9a06219f71f39dceb06c60edd15d..c6927a4d157fd3cfb9f4a963065353c730364b99 100644 (file)
@@ -11,6 +11,7 @@
 #define LINUX_MMC_CARD_H
 
 #include <linux/mmc/core.h>
+#include <linux/mod_devicetable.h>
 
 struct mmc_cid {
        unsigned int            manfid;
@@ -29,6 +30,7 @@ struct mmc_csd {
        unsigned short          cmdclass;
        unsigned short          tacc_clks;
        unsigned int            tacc_ns;
+       unsigned int            c_size;
        unsigned int            r2w_factor;
        unsigned int            max_dtr;
        unsigned int            erase_size;             /* In sectors */
@@ -45,6 +47,10 @@ struct mmc_ext_csd {
        u8                      rev;
        u8                      erase_group_def;
        u8                      sec_feature_support;
+       u8                      rel_sectors;
+       u8                      rel_param;
+       u8                      part_config;
+       unsigned int            part_time;              /* Units: ms */
        unsigned int            sa_timeout;             /* Units: 100ns */
        unsigned int            hs_max_dtr;
        unsigned int            sectors;
@@ -57,13 +63,18 @@ struct mmc_ext_csd {
        bool                    enhanced_area_en;       /* enable bit */
        unsigned long long      enhanced_area_offset;   /* Units: Byte */
        unsigned int            enhanced_area_size;     /* Units: KB */
+       unsigned int            boot_size;              /* in bytes */
 };
 
 struct sd_scr {
        unsigned char           sda_vsn;
+       unsigned char           sda_spec3;
        unsigned char           bus_widths;
 #define SD_SCR_BUS_WIDTH_1     (1<<0)
 #define SD_SCR_BUS_WIDTH_4     (1<<2)
+       unsigned char           cmds;
+#define SD_SCR_CMD20_SUPPORT   (1<<0)
+#define SD_SCR_CMD23_SUPPORT   (1<<1)
 };
 
 struct sd_ssr {
@@ -74,6 +85,39 @@ struct sd_ssr {
 
 struct sd_switch_caps {
        unsigned int            hs_max_dtr;
+       unsigned int            uhs_max_dtr;
+#define UHS_SDR104_MAX_DTR     208000000
+#define UHS_SDR50_MAX_DTR      100000000
+#define UHS_DDR50_MAX_DTR      50000000
+#define UHS_SDR25_MAX_DTR      UHS_DDR50_MAX_DTR
+#define UHS_SDR12_MAX_DTR      25000000
+       unsigned int            sd3_bus_mode;
+#define UHS_SDR12_BUS_SPEED    0
+#define UHS_SDR25_BUS_SPEED    1
+#define UHS_SDR50_BUS_SPEED    2
+#define UHS_SDR104_BUS_SPEED   3
+#define UHS_DDR50_BUS_SPEED    4
+
+#define SD_MODE_UHS_SDR12      (1 << UHS_SDR12_BUS_SPEED)
+#define SD_MODE_UHS_SDR25      (1 << UHS_SDR25_BUS_SPEED)
+#define SD_MODE_UHS_SDR50      (1 << UHS_SDR50_BUS_SPEED)
+#define SD_MODE_UHS_SDR104     (1 << UHS_SDR104_BUS_SPEED)
+#define SD_MODE_UHS_DDR50      (1 << UHS_DDR50_BUS_SPEED)
+       unsigned int            sd3_drv_type;
+#define SD_DRIVER_TYPE_B       0x01
+#define SD_DRIVER_TYPE_A       0x02
+#define SD_DRIVER_TYPE_C       0x04
+#define SD_DRIVER_TYPE_D       0x08
+       unsigned int            sd3_curr_limit;
+#define SD_SET_CURRENT_LIMIT_200       0
+#define SD_SET_CURRENT_LIMIT_400       1
+#define SD_SET_CURRENT_LIMIT_600       2
+#define SD_SET_CURRENT_LIMIT_800       3
+
+#define SD_MAX_CURRENT_200     (1 << SD_SET_CURRENT_LIMIT_200)
+#define SD_MAX_CURRENT_400     (1 << SD_SET_CURRENT_LIMIT_400)
+#define SD_MAX_CURRENT_600     (1 << SD_SET_CURRENT_LIMIT_600)
+#define SD_MAX_CURRENT_800     (1 << SD_SET_CURRENT_LIMIT_800)
 };
 
 struct sdio_cccr {
@@ -118,6 +162,8 @@ struct mmc_card {
 #define MMC_STATE_HIGHSPEED    (1<<2)          /* card is in high speed mode */
 #define MMC_STATE_BLOCKADDR    (1<<3)          /* card uses block-addressing */
 #define MMC_STATE_HIGHSPEED_DDR (1<<4)         /* card is in high speed mode */
+#define MMC_STATE_ULTRAHIGHSPEED (1<<5)                /* card is in ultra high speed mode */
+#define MMC_CARD_SDXC          (1<<6)          /* card is SDXC */
        unsigned int            quirks;         /* card quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
@@ -125,6 +171,10 @@ struct mmc_card {
 #define MMC_QUIRK_NONSTD_SDIO  (1<<2)          /* non-standard SDIO card attached */
                                                /* (missing CIA registers) */
 #define MMC_QUIRK_BROKEN_CLK_GATING (1<<3)     /* clock gating the sdio bus will make card fail */
+#define MMC_QUIRK_NONSTD_FUNC_IF (1<<4)                /* SDIO card has nonstd function interfaces */
+#define MMC_QUIRK_DISABLE_CD   (1<<5)          /* disconnect CD/DAT[3] resistor */
+#define MMC_QUIRK_INAND_CMD38  (1<<6)          /* iNAND devices have broken CMD38 */
+#define MMC_QUIRK_BLK_NO_CMD23 (1<<7)          /* Avoid CMD23 for regular multiblock */
 
        unsigned int            erase_size;     /* erase size in sectors */
        unsigned int            erase_shift;    /* if erase unit is power 2 */
@@ -145,14 +195,100 @@ struct mmc_card {
        struct sdio_cccr        cccr;           /* common card info */
        struct sdio_cis         cis;            /* common tuple info */
        struct sdio_func        *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
+       struct sdio_func        *sdio_single_irq; /* SDIO function when only one IRQ active */
        unsigned                num_info;       /* number of info strings */
        const char              **info;         /* info strings */
        struct sdio_func_tuple  *tuples;        /* unknown common tuples */
 
+       unsigned int            sd_bus_speed;   /* Bus Speed Mode set for the card */
+
        struct dentry           *debugfs_root;
 };
 
-void mmc_fixup_device(struct mmc_card *dev);
+/*
+ *  The world is not perfect and supplies us with broken mmc/sdio devices.
+ *  For at least some of these bugs we need a work-around.
+ */
+
+struct mmc_fixup {
+       /* CID-specific fields. */
+       const char *name;
+
+       /* Valid revision range */
+       u64 rev_start, rev_end;
+
+       unsigned int manfid;
+       unsigned short oemid;
+
+       /* SDIO-specfic fields. You can use SDIO_ANY_ID here of course */
+       u16 cis_vendor, cis_device;
+
+       void (*vendor_fixup)(struct mmc_card *card, int data);
+       int data;
+};
+
+#define CID_MANFID_ANY (-1u)
+#define CID_OEMID_ANY ((unsigned short) -1)
+#define CID_NAME_ANY (NULL)
+
+#define END_FIXUP { 0 }
+
+#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end,       \
+                  _cis_vendor, _cis_device,                            \
+                  _fixup, _data)                                       \
+       {                                                  \
+               .name = (_name),                           \
+               .manfid = (_manfid),                       \
+               .oemid = (_oemid),                         \
+               .rev_start = (_rev_start),                 \
+               .rev_end = (_rev_end),                     \
+               .cis_vendor = (_cis_vendor),               \
+               .cis_device = (_cis_device),               \
+               .vendor_fixup = (_fixup),                  \
+               .data = (_data),                           \
+        }
+
+#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end,    \
+                     _fixup, _data)                                    \
+       _FIXUP_EXT(_name, _manfid,                                      \
+                  _oemid, _rev_start, _rev_end,                        \
+                  SDIO_ANY_ID, SDIO_ANY_ID,                            \
+                  _fixup, _data)                                       \
+
+#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \
+       MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data)
+
+#define SDIO_FIXUP(_vendor, _device, _fixup, _data)                    \
+       _FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY,                        \
+                   CID_OEMID_ANY, 0, -1ull,                            \
+                  _vendor, _device,                                    \
+                  _fixup, _data)                                       \
+
+#define cid_rev(hwrev, fwrev, year, month)     \
+       (((u64) hwrev) << 40 |                  \
+        ((u64) fwrev) << 32 |                  \
+        ((u64) year) << 16 |                   \
+        ((u64) month))
+
+#define cid_rev_card(card)               \
+       cid_rev(card->cid.hwrev,          \
+                   card->cid.fwrev,      \
+                   card->cid.year,       \
+                   card->cid.month)
+
+/*
+ * Unconditionally quirk add/remove.
+ */
+
+static inline void __maybe_unused add_quirk(struct mmc_card *card, int data)
+{
+       card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
+{
+       card->quirks &= ~data;
+}
 
 #define mmc_card_mmc(c)                ((c)->type == MMC_TYPE_MMC)
 #define mmc_card_sd(c)         ((c)->type == MMC_TYPE_SD)
@@ -163,12 +299,50 @@ void mmc_fixup_device(struct mmc_card *dev);
 #define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
+#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
+#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
+#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
+#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+
+/*
+ * Quirk add/remove for MMC products.
+ */
+
+static inline void __maybe_unused add_quirk_mmc(struct mmc_card *card, int data)
+{
+       if (mmc_card_mmc(card))
+               card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk_mmc(struct mmc_card *card,
+                                                  int data)
+{
+       if (mmc_card_mmc(card))
+               card->quirks &= ~data;
+}
+
+/*
+ * Quirk add/remove for SD products.
+ */
+
+static inline void __maybe_unused add_quirk_sd(struct mmc_card *card, int data)
+{
+       if (mmc_card_sd(card))
+               card->quirks |= data;
+}
+
+static inline void __maybe_unused remove_quirk_sd(struct mmc_card *card,
+                                                  int data)
+{
+       if (mmc_card_sd(card))
+               card->quirks &= ~data;
+}
 
 static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
 {
@@ -180,6 +354,16 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
        return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
 }
 
+static inline int mmc_card_disable_cd(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_DISABLE_CD;
+}
+
+static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
+{
+       return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
+}
+
 #define mmc_card_name(c)       ((c)->cid.prod_name)
 #define mmc_card_id(c)         (dev_name(&(c)->dev))
 
@@ -203,4 +387,7 @@ struct mmc_driver {
 extern int mmc_register_driver(struct mmc_driver *);
 extern void mmc_unregister_driver(struct mmc_driver *);
 
+extern void mmc_fixup_device(struct mmc_card *card,
+                            const struct mmc_fixup *table);
+
 #endif
index 07f27af4dba5221b1139206cc2bd33858a3b38ef..b6718e549a510780e0f8c9a3be17e64753d6c2f5 100644 (file)
@@ -92,7 +92,7 @@ struct mmc_command {
  *              actively failing requests
  */
 
-       unsigned int            erase_timeout;  /* in milliseconds */
+       unsigned int            cmd_timeout_ms; /* in milliseconds */
 
        struct mmc_data         *data;          /* data segment associated with cmd */
        struct mmc_request      *mrq;           /* associated request */
@@ -120,6 +120,7 @@ struct mmc_data {
 };
 
 struct mmc_request {
+       struct mmc_command      *sbc;           /* SET_BLOCK_COUNT for multiblock */
        struct mmc_command      *cmd;
        struct mmc_data         *data;
        struct mmc_command      *stop;
@@ -133,8 +134,10 @@ struct mmc_card;
 
 extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
 extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
 extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
        struct mmc_command *, int);
+extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
 
 #define MMC_ERASE_ARG          0x00000000
 #define MMC_SECURE_ERASE_ARG   0x80000000
index bcb793ec7374f61d2552cca43f573bdd1f100ece..1ee4424462ebcf98f2e81082b65c7211d64a248e 100644 (file)
@@ -50,12 +50,30 @@ struct mmc_ios {
 #define MMC_TIMING_LEGACY      0
 #define MMC_TIMING_MMC_HS      1
 #define MMC_TIMING_SD_HS       2
+#define MMC_TIMING_UHS_SDR12   MMC_TIMING_LEGACY
+#define MMC_TIMING_UHS_SDR25   MMC_TIMING_SD_HS
+#define MMC_TIMING_UHS_SDR50   3
+#define MMC_TIMING_UHS_SDR104  4
+#define MMC_TIMING_UHS_DDR50   5
 
        unsigned char   ddr;                    /* dual data rate used */
 
 #define MMC_SDR_MODE           0
 #define MMC_1_2V_DDR_MODE      1
 #define MMC_1_8V_DDR_MODE      2
+
+       unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
+
+#define MMC_SIGNAL_VOLTAGE_330 0
+#define MMC_SIGNAL_VOLTAGE_180 1
+#define MMC_SIGNAL_VOLTAGE_120 2
+
+       unsigned char   drv_type;               /* driver type (A, B, C, D) */
+
+#define MMC_SET_DRIVER_TYPE_B  0
+#define MMC_SET_DRIVER_TYPE_A  1
+#define MMC_SET_DRIVER_TYPE_C  2
+#define MMC_SET_DRIVER_TYPE_D  3
 };
 
 struct mmc_host_ops {
@@ -117,6 +135,10 @@ struct mmc_host_ops {
 
        /* optional callback for HC quirks */
        void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
+
+       int     (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
+       int     (*execute_tuning)(struct mmc_host *host);
+       void    (*enable_preset_value)(struct mmc_host *host, bool enable);
 };
 
 struct mmc_card;
@@ -173,6 +195,22 @@ struct mmc_host {
                                                /* DDR mode at 1.2V */
 #define MMC_CAP_POWER_OFF_CARD (1 << 13)       /* Can power off after boot */
 #define MMC_CAP_BUS_WIDTH_TEST (1 << 14)       /* CMD14/CMD19 bus width ok */
+#define MMC_CAP_UHS_SDR12      (1 << 15)       /* Host supports UHS SDR12 mode */
+#define MMC_CAP_UHS_SDR25      (1 << 16)       /* Host supports UHS SDR25 mode */
+#define MMC_CAP_UHS_SDR50      (1 << 17)       /* Host supports UHS SDR50 mode */
+#define MMC_CAP_UHS_SDR104     (1 << 18)       /* Host supports UHS SDR104 mode */
+#define MMC_CAP_UHS_DDR50      (1 << 19)       /* Host supports UHS DDR50 mode */
+#define MMC_CAP_SET_XPC_330    (1 << 20)       /* Host supports >150mA current at 3.3V */
+#define MMC_CAP_SET_XPC_300    (1 << 21)       /* Host supports >150mA current at 3.0V */
+#define MMC_CAP_SET_XPC_180    (1 << 22)       /* Host supports >150mA current at 1.8V */
+#define MMC_CAP_DRIVER_TYPE_A  (1 << 23)       /* Host supports Driver Type A */
+#define MMC_CAP_DRIVER_TYPE_C  (1 << 24)       /* Host supports Driver Type C */
+#define MMC_CAP_DRIVER_TYPE_D  (1 << 25)       /* Host supports Driver Type D */
+#define MMC_CAP_MAX_CURRENT_200        (1 << 26)       /* Host max current limit is 200mA */
+#define MMC_CAP_MAX_CURRENT_400        (1 << 27)       /* Host max current limit is 400mA */
+#define MMC_CAP_MAX_CURRENT_600        (1 << 28)       /* Host max current limit is 600mA */
+#define MMC_CAP_MAX_CURRENT_800        (1 << 29)       /* Host max current limit is 800mA */
+#define MMC_CAP_CMD23          (1 << 30)       /* CMD23 supported. */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
@@ -321,10 +359,19 @@ static inline int mmc_card_is_removable(struct mmc_host *host)
        return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable;
 }
 
-static inline int mmc_card_is_powered_resumed(struct mmc_host *host)
+static inline int mmc_card_keep_power(struct mmc_host *host)
 {
        return host->pm_flags & MMC_PM_KEEP_POWER;
 }
 
+static inline int mmc_card_wake_sdio_irq(struct mmc_host *host)
+{
+       return host->pm_flags & MMC_PM_WAKE_SDIO_IRQ;
+}
+
+static inline int mmc_host_cmd23(struct mmc_host *host)
+{
+       return host->caps & MMC_CAP_CMD23;
+}
 #endif
 
diff --git a/include/linux/mmc/ioctl.h b/include/linux/mmc/ioctl.h
new file mode 100644 (file)
index 0000000..5baf298
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef LINUX_MMC_IOCTL_H
+#define LINUX_MMC_IOCTL_H
+struct mmc_ioc_cmd {
+       /* Implies direction of data.  true = write, false = read */
+       int write_flag;
+
+       /* Application-specific command.  true = precede with CMD55 */
+       int is_acmd;
+
+       __u32 opcode;
+       __u32 arg;
+       __u32 response[4];  /* CMD response */
+       unsigned int flags;
+       unsigned int blksz;
+       unsigned int blocks;
+
+       /*
+        * Sleep at least postsleep_min_us useconds, and at most
+        * postsleep_max_us useconds *after* issuing command.  Needed for
+        * some read commands for which cards have no other way of indicating
+        * they're ready for the next command (i.e. there is no equivalent of
+        * a "busy" indicator for read operations).
+        */
+       unsigned int postsleep_min_us;
+       unsigned int postsleep_max_us;
+
+       /*
+        * Override driver-computed timeouts.  Note the difference in units!
+        */
+       unsigned int data_timeout_ns;
+       unsigned int cmd_timeout_ms;
+
+       /*
+        * For 64-bit machines, the next member, ``__u64 data_ptr``, wants to
+        * be 8-byte aligned.  Make sure this struct is the same size when
+        * built for 32-bit.
+        */
+       __u32 __pad;
+
+       /* DAT buffer */
+       __u64 data_ptr;
+};
+#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr
+
+#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
+
+/*
+ * Since this ioctl is only meant to enhance (and not replace) normal access
+ * to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES
+ * is enforced per ioctl call.  For larger data transfers, use the normal
+ * block device operations.
+ */
+#define MMC_IOC_MAX_BYTES  (512L * 256)
+#endif  /* LINUX_MMC_IOCTL_H */
index 264ba5451e3b98449832d94693d167792cec1f7b..ac26a685cca8a82e55f2b6eba31ee1321ff70727 100644 (file)
@@ -50,6 +50,7 @@
 #define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
 #define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
 #define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
+#define MMC_SEND_TUNING_BLOCK    19   /* adtc                    R1  */
 
   /* class 3 */
 #define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
 #define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
 #define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1  */
 
+static inline bool mmc_op_multi(u32 opcode)
+{
+       return opcode == MMC_WRITE_MULTIPLE_BLOCK ||
+              opcode == MMC_READ_MULTIPLE_BLOCK;
+}
+
 /*
  * MMC_SWITCH argument format:
  *
@@ -255,18 +262,23 @@ struct _mmc_csd {
 
 #define EXT_CSD_PARTITION_ATTRIBUTE    156     /* R/W */
 #define EXT_CSD_PARTITION_SUPPORT      160     /* RO */
+#define EXT_CSD_WR_REL_PARAM           166     /* RO */
 #define EXT_CSD_ERASE_GROUP_DEF                175     /* R/W */
+#define EXT_CSD_PART_CONFIG            179     /* R/W */
 #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
 #define EXT_CSD_BUS_WIDTH              183     /* R/W */
 #define EXT_CSD_HS_TIMING              185     /* R/W */
 #define EXT_CSD_REV                    192     /* RO */
 #define EXT_CSD_STRUCTURE              194     /* RO */
 #define EXT_CSD_CARD_TYPE              196     /* RO */
+#define EXT_CSD_PART_SWITCH_TIME        199     /* RO */
 #define EXT_CSD_SEC_CNT                        212     /* RO, 4 bytes */
 #define EXT_CSD_S_A_TIMEOUT            217     /* RO */
+#define EXT_CSD_REL_WR_SEC_C           222     /* RO */
 #define EXT_CSD_HC_WP_GRP_SIZE         221     /* RO */
 #define EXT_CSD_ERASE_TIMEOUT_MULT     223     /* RO */
 #define EXT_CSD_HC_ERASE_GRP_SIZE      224     /* RO */
+#define EXT_CSD_BOOT_MULT              226     /* RO */
 #define EXT_CSD_SEC_TRIM_MULT          229     /* RO */
 #define EXT_CSD_SEC_ERASE_MULT         230     /* RO */
 #define EXT_CSD_SEC_FEATURE_SUPPORT    231     /* RO */
@@ -276,6 +288,12 @@ struct _mmc_csd {
  * EXT_CSD field definitions
  */
 
+#define EXT_CSD_WR_REL_PARAM_EN                (1<<2)
+
+#define EXT_CSD_PART_CONFIG_ACC_MASK   (0x7)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT0  (0x1)
+#define EXT_CSD_PART_CONFIG_ACC_BOOT1  (0x2)
+
 #define EXT_CSD_CMD_SET_NORMAL         (1<<0)
 #define EXT_CSD_CMD_SET_SECURE         (1<<1)
 #define EXT_CSD_CMD_SET_CPSECURE       (1<<2)
index 3fd85e088cc3fd7547f3f7a6b31b8df1a2e86a3c..7d35d52c3df374a2a19ad7d9089381992f88317c 100644 (file)
@@ -17,6 +17,7 @@
 /* This is basically the same command as for MMC with some quirks. */
 #define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
 #define SD_SEND_IF_COND           8   /* bcr  [11:0] See below   R7  */
+#define SD_SWITCH_VOLTAGE         11  /* ac                      R1  */
 
   /* class 10 */
 #define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */
 #define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
 #define SD_APP_SEND_SCR          51   /* adtc                    R1  */
 
+/* OCR bit definitions */
+#define SD_OCR_S18R            (1 << 24)    /* 1.8V switching request */
+#define SD_ROCR_S18A           SD_OCR_S18R  /* 1.8V switching accepted by card */
+#define SD_OCR_XPC             (1 << 28)    /* SDXC power control */
+#define SD_OCR_CCS             (1 << 30)    /* Card Capacity Status */
+
 /*
  * SD_SWITCH argument format:
  *
@@ -59,7 +66,7 @@
 
 #define SCR_SPEC_VER_0         0       /* Implements system specification 1.0 - 1.01 */
 #define SCR_SPEC_VER_1         1       /* Implements system specification 1.10 */
-#define SCR_SPEC_VER_2         2       /* Implements system specification 2.00 */
+#define SCR_SPEC_VER_2         2       /* Implements system specification 2.00-3.0X */
 
 /*
  * SD bus widths
index 83bd9f76709aa90b32ad76a175a408bf7725b468..6a68c4eb4e444b55137d0e561275aad5f80f1910 100644 (file)
@@ -85,6 +85,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK_NO_HISPD_BIT                       (1<<29)
 /* Controller treats ADMA descriptors with length 0000h incorrectly */
 #define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC           (1<<30)
+/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */
+#define SDHCI_QUIRK_UNSTABLE_RO_DETECT                 (1<<31)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
@@ -109,11 +111,16 @@ struct sdhci_host {
 #define SDHCI_USE_ADMA         (1<<1)  /* Host is ADMA capable */
 #define SDHCI_REQ_USE_DMA      (1<<2)  /* Use DMA for this req. */
 #define SDHCI_DEVICE_DEAD      (1<<3)  /* Device unresponsive */
+#define SDHCI_SDR50_NEEDS_TUNING (1<<4)        /* SDR50 needs tuning */
+#define SDHCI_NEEDS_RETUNING   (1<<5)  /* Host needs retuning */
+#define SDHCI_AUTO_CMD12       (1<<6)  /* Auto CMD12 support */
+#define SDHCI_AUTO_CMD23       (1<<7)  /* Auto CMD23 support */
 
        unsigned int version;   /* SDHCI spec. version */
 
        unsigned int max_clk;   /* Max possible freq (MHz) */
        unsigned int timeout_clk;       /* Timeout freq (KHz) */
+       unsigned int clk_mul;   /* Clock Muliplier value */
 
        unsigned int clock;     /* Current clock (MHz) */
        u8 pwr;                 /* Current voltage */
@@ -145,6 +152,14 @@ struct sdhci_host {
        unsigned int            ocr_avail_sd;
        unsigned int            ocr_avail_mmc;
 
+       wait_queue_head_t       buf_ready_int;  /* Waitqueue for Buffer Read Ready interrupt */
+       unsigned int            tuning_done;    /* Condition flag set when CMD19 succeeds */
+
+       unsigned int            tuning_count;   /* Timer count for re-tuning */
+       unsigned int            tuning_mode;    /* Re-tuning mode supported by host */
+#define SDHCI_TUNING_MODE_1    0
+       struct timer_list       tuning_timer;   /* Timer for tuning */
+
        unsigned long private[0] ____cacheline_aligned;
 };
 #endif /* __SDHCI_H */
index c981b959760f717ffff9e88895900bb6e46321bf..faf32b6ec18517dc3948497fd6919f17239348f8 100644 (file)
@@ -3,12 +3,16 @@
 
 #include <linux/types.h>
 
+struct platform_device;
+struct tmio_mmc_data;
+
 struct sh_mobile_sdhi_info {
        int dma_slave_tx;
        int dma_slave_rx;
        unsigned long tmio_flags;
        unsigned long tmio_caps;
        u32 tmio_ocr_mask;      /* available MMC voltages */
+       struct tmio_mmc_data *pdata;
        void (*set_pwr)(struct platform_device *pdev, int state);
        int (*get_cd)(struct platform_device *pdev);
 };
index cc2e7dfea9d7f6a57661155cb88ca487863e66af..1d1b1e13f79fbc13c0f2abfec525c8026a286b8f 100644 (file)
@@ -150,7 +150,7 @@ struct mmu_notifier_ops {
  * Therefore notifier chains can only be traversed when either
  *
  * 1. mmap_sem is held.
- * 2. One of the reverse map locks is held (i_mmap_lock or anon_vma->lock).
+ * 2. One of the reverse map locks is held (i_mmap_mutex or anon_vma->mutex).
  * 3. No other concurrent thread can access the list (release)
  */
 struct mmu_notifier {
index e56f835274c9becd407fe28705fd81f09f5bbc3d..261f299c94412be90e5b24e6b2406bc9815ee608 100644 (file)
@@ -928,9 +928,6 @@ static inline unsigned long early_pfn_to_nid(unsigned long pfn)
 #define pfn_to_nid(pfn)                (0)
 #endif
 
-#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT)
-#define section_nr_to_pfn(sec) ((sec) << PFN_SECTION_SHIFT)
-
 #ifdef CONFIG_SPARSEMEM
 
 /*
@@ -956,6 +953,12 @@ static inline unsigned long early_pfn_to_nid(unsigned long pfn)
 #error Allocator MAX_ORDER exceeds SECTION_SIZE
 #endif
 
+#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT)
+#define section_nr_to_pfn(sec) ((sec) << PFN_SECTION_SHIFT)
+
+#define SECTION_ALIGN_UP(pfn)  (((pfn) + PAGES_PER_SECTION - 1) & PAGE_SECTION_MASK)
+#define SECTION_ALIGN_DOWN(pfn)        ((pfn) & PAGE_SECTION_MASK)
+
 struct page;
 struct page_cgroup;
 struct mem_section {
@@ -1053,12 +1056,14 @@ static inline struct mem_section *__pfn_to_section(unsigned long pfn)
        return __nr_to_section(pfn_to_section_nr(pfn));
 }
 
+#ifndef CONFIG_HAVE_ARCH_PFN_VALID
 static inline int pfn_valid(unsigned long pfn)
 {
        if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
                return 0;
        return valid_section(__nr_to_section(pfn_to_section_nr(pfn)));
 }
+#endif
 
 static inline int pfn_present(unsigned long pfn)
 {
index c75471db576ef0d500eb5a363b607819f38b869b..a940fe435acac1e6b48774686cdd39c9f0cd652d 100644 (file)
@@ -132,6 +132,7 @@ static inline int mutex_is_locked(struct mutex *lock)
  */
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
+extern void _mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *nest_lock);
 extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
                                        unsigned int subclass);
 extern int __must_check mutex_lock_killable_nested(struct mutex *lock,
@@ -140,6 +141,13 @@ extern int __must_check mutex_lock_killable_nested(struct mutex *lock,
 #define mutex_lock(lock) mutex_lock_nested(lock, 0)
 #define mutex_lock_interruptible(lock) mutex_lock_interruptible_nested(lock, 0)
 #define mutex_lock_killable(lock) mutex_lock_killable_nested(lock, 0)
+
+#define mutex_lock_nest_lock(lock, nest_lock)                          \
+do {                                                                   \
+       typecheck(struct lockdep_map *, &(nest_lock)->dep_map);         \
+       _mutex_lock_nest_lock(lock, &(nest_lock)->dep_map);             \
+} while (0)
+
 #else
 extern void mutex_lock(struct mutex *lock);
 extern int __must_check mutex_lock_interruptible(struct mutex *lock);
@@ -148,6 +156,7 @@ extern int __must_check mutex_lock_killable(struct mutex *lock);
 # define mutex_lock_nested(lock, subclass) mutex_lock(lock)
 # define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
 # define mutex_lock_killable_nested(lock, subclass) mutex_lock_killable(lock)
+# define mutex_lock_nest_lock(lock, nest_lock) mutex_lock(lock)
 #endif
 
 /*
index 5e3aa8311c5ed40f2598ccd814162bef5173030e..4952fb874ad3dadd631b3e10f0ae35eb0df59135 100644 (file)
@@ -40,6 +40,8 @@ enum oom_constraint {
        CONSTRAINT_MEMCG,
 };
 
+extern int test_set_oom_score_adj(int new_val);
+
 extern unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
                        const nodemask_t *nodemask, unsigned long totalpages);
 extern int try_set_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_flags);
index c119506526467d204b2c78a7d47bc0a7152129a4..716875e53520ecb4afe8ae7edd1e39a7eb75032a 100644 (file)
@@ -219,6 +219,12 @@ static inline struct page *page_cache_alloc_cold(struct address_space *x)
        return __page_cache_alloc(mapping_gfp_mask(x)|__GFP_COLD);
 }
 
+static inline struct page *page_cache_alloc_readahead(struct address_space *x)
+{
+       return __page_cache_alloc(mapping_gfp_mask(x) |
+                                 __GFP_COLD | __GFP_NORETRY | __GFP_NOWARN);
+}
+
 typedef int filler_t(void *, struct page *);
 
 extern struct page * find_get_page(struct address_space *mapping,
@@ -357,6 +363,15 @@ static inline int lock_page_or_retry(struct page *page, struct mm_struct *mm,
  */
 extern void wait_on_page_bit(struct page *page, int bit_nr);
 
+extern int wait_on_page_bit_killable(struct page *page, int bit_nr);
+
+static inline int wait_on_page_locked_killable(struct page *page)
+{
+       if (PageLocked(page))
+               return wait_on_page_bit_killable(page, PG_locked);
+       return 0;
+}
+
 /* 
  * Wait for a page to be unlocked.
  *
index 46f6ba56fa9139909c04acbad98383b7ed88babb..5edc9014263aca9e10cfda70dc4c5e3e8a94f8bb 100644 (file)
@@ -75,7 +75,7 @@ static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
        barrier();              /* Prevent reloads of fbc->count */
        if (ret >= 0)
                return ret;
-       return 1;
+       return 0;
 }
 
 static inline int percpu_counter_initialized(struct percpu_counter *fbc)
@@ -133,6 +133,10 @@ static inline s64 percpu_counter_read(struct percpu_counter *fbc)
        return fbc->count;
 }
 
+/*
+ * percpu_counter is intended to track positive numbers. In the UP case the
+ * number should never be negative.
+ */
 static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
 {
        return fbc->count;
index 808227d40a645a7cabf83cb0d0c10cc04e2ac86d..959c14132f465f8f3d0f5f61cd6d2701c252ae30 100644 (file)
@@ -82,6 +82,7 @@ struct k_itimer {
                        unsigned long expires;
                } mmtimer;
                struct alarm alarmtimer;
+               struct rcu_head rcu;
        } it;
 };
 
index ee048e77e1ae092f178e9d88675ea6cb1ae33019..0101d55d9651f3cc1dc48858ba0ca1b301ec6425 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __KERNEL_PRINTK__
 #define __KERNEL_PRINTK__
 
+#include <linux/init.h>
+
 extern const char linux_banner[];
 extern const char linux_proc_banner[];
 
@@ -113,6 +115,7 @@ extern int dmesg_restrict;
 extern int kptr_restrict;
 
 void log_buf_kexec_setup(void);
+void __init setup_log_buf(int early);
 #else
 static inline __attribute__ ((format (printf, 1, 0)))
 int vprintk(const char *s, va_list args)
@@ -137,6 +140,10 @@ static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies,
 static inline void log_buf_kexec_setup(void)
 {
 }
+
+static inline void setup_log_buf(int early)
+{
+}
 #endif
 
 extern void dump_stack(void) __cold;
index eaf4350c0f905bfb5e2dfa6380118fe805b1b785..648c9c58add7ccafd511d1864cd78f1c5b80df79 100644 (file)
@@ -179,6 +179,8 @@ extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
 extern struct file *get_mm_exe_file(struct mm_struct *mm);
 extern void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm);
 
+extern struct file *proc_ns_fget(int fd);
+
 #else
 
 #define proc_net_fops_create(net, name, mode, fops)  ({ (void)(mode), NULL; })
@@ -241,6 +243,11 @@ static inline void dup_mm_exe_file(struct mm_struct *oldmm,
                                   struct mm_struct *newmm)
 {}
 
+static inline struct file *proc_ns_fget(int fd)
+{
+       return ERR_PTR(-EINVAL);
+}
+
 #endif /* CONFIG_PROC_FS */
 
 #if !defined(CONFIG_PROC_KCORE)
@@ -252,6 +259,18 @@ kclist_add(struct kcore_list *new, void *addr, size_t size, int type)
 extern void kclist_add(struct kcore_list *, void *, size_t, int type);
 #endif
 
+struct nsproxy;
+struct proc_ns_operations {
+       const char *name;
+       int type;
+       void *(*get)(struct task_struct *task);
+       void (*put)(void *ns);
+       int (*install)(struct nsproxy *nsproxy, void *ns);
+};
+extern const struct proc_ns_operations netns_operations;
+extern const struct proc_ns_operations utsns_operations;
+extern const struct proc_ns_operations ipcns_operations;
+
 union proc_op {
        int (*proc_get_link)(struct inode *, struct path *);
        int (*proc_read)(struct task_struct *task, char *page);
@@ -270,6 +289,8 @@ struct proc_inode {
        struct proc_dir_entry *pde;
        struct ctl_table_header *sysctl;
        struct ctl_table *sysctl_entry;
+       void *ns;
+       const struct proc_ns_operations *ns_ops;
        struct inode vfs_inode;
 };
 
@@ -288,12 +309,4 @@ static inline struct net *PDE_NET(struct proc_dir_entry *pde)
        return pde->parent->data;
 }
 
-struct proc_maps_private {
-       struct pid *pid;
-       struct task_struct *task;
-#ifdef CONFIG_MMU
-       struct vm_area_struct *tail_vma;
-#endif
-};
-
 #endif /* _LINUX_PROC_FS_H */
index 943a85ab0020a289895d6069650a6d94867deb06..e07e2742a865a46d13740934a830b35dbde17af5 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
+#include <linux/ip.h>
 #include <linux/filter.h>
 #ifdef __KERNEL__
 #include <linux/in.h>
 #define OFF_NEXT       6
 #define OFF_UDP_DST    2
 
+#define OFF_PTP_SOURCE_UUID    22 /* PTPv1 only */
+#define OFF_PTP_SEQUENCE_ID    30
+#define OFF_PTP_CONTROL                32 /* PTPv1 only */
+
+#define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2)
+
 #define IP6_HLEN       40
 #define UDP_HLEN       8
 
diff --git a/include/linux/ptp_clock.h b/include/linux/ptp_clock.h
new file mode 100644 (file)
index 0000000..94e981f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * PTP 1588 clock support - user space interface
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PTP_CLOCK_H_
+#define _PTP_CLOCK_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* PTP_xxx bits, for the flags field within the request structures. */
+#define PTP_ENABLE_FEATURE (1<<0)
+#define PTP_RISING_EDGE    (1<<1)
+#define PTP_FALLING_EDGE   (1<<2)
+
+/*
+ * struct ptp_clock_time - represents a time value
+ *
+ * The sign of the seconds field applies to the whole value. The
+ * nanoseconds field is always unsigned. The reserved field is
+ * included for sub-nanosecond resolution, should the demand for
+ * this ever appear.
+ *
+ */
+struct ptp_clock_time {
+       __s64 sec;  /* seconds */
+       __u32 nsec; /* nanoseconds */
+       __u32 reserved;
+};
+
+struct ptp_clock_caps {
+       int max_adj;   /* Maximum frequency adjustment in parts per billon. */
+       int n_alarm;   /* Number of programmable alarms. */
+       int n_ext_ts;  /* Number of external time stamp channels. */
+       int n_per_out; /* Number of programmable periodic signals. */
+       int pps;       /* Whether the clock supports a PPS callback. */
+       int rsv[15];   /* Reserved for future use. */
+};
+
+struct ptp_extts_request {
+       unsigned int index;  /* Which channel to configure. */
+       unsigned int flags;  /* Bit field for PTP_xxx flags. */
+       unsigned int rsv[2]; /* Reserved for future use. */
+};
+
+struct ptp_perout_request {
+       struct ptp_clock_time start;  /* Absolute start time. */
+       struct ptp_clock_time period; /* Desired period, zero means disable. */
+       unsigned int index;           /* Which channel to configure. */
+       unsigned int flags;           /* Reserved for future use. */
+       unsigned int rsv[4];          /* Reserved for future use. */
+};
+
+#define PTP_CLK_MAGIC '='
+
+#define PTP_CLOCK_GETCAPS  _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps)
+#define PTP_EXTTS_REQUEST  _IOW(PTP_CLK_MAGIC, 2, struct ptp_extts_request)
+#define PTP_PEROUT_REQUEST _IOW(PTP_CLK_MAGIC, 3, struct ptp_perout_request)
+#define PTP_ENABLE_PPS     _IOW(PTP_CLK_MAGIC, 4, int)
+
+struct ptp_extts_event {
+       struct ptp_clock_time t; /* Time event occured. */
+       unsigned int index;      /* Which channel produced the event. */
+       unsigned int flags;      /* Reserved for future use. */
+       unsigned int rsv[2];     /* Reserved for future use. */
+};
+
+#endif
diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h
new file mode 100644 (file)
index 0000000..dd2e44f
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * PTP 1588 clock support
+ *
+ * Copyright (C) 2010 OMICRON electronics GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PTP_CLOCK_KERNEL_H_
+#define _PTP_CLOCK_KERNEL_H_
+
+#include <linux/ptp_clock.h>
+
+
+struct ptp_clock_request {
+       enum {
+               PTP_CLK_REQ_EXTTS,
+               PTP_CLK_REQ_PEROUT,
+               PTP_CLK_REQ_PPS,
+       } type;
+       union {
+               struct ptp_extts_request extts;
+               struct ptp_perout_request perout;
+       };
+};
+
+/**
+ * struct ptp_clock_info - decribes a PTP hardware clock
+ *
+ * @owner:     The clock driver should set to THIS_MODULE.
+ * @name:      A short name to identify the clock.
+ * @max_adj:   The maximum possible frequency adjustment, in parts per billon.
+ * @n_alarm:   The number of programmable alarms.
+ * @n_ext_ts:  The number of external time stamp channels.
+ * @n_per_out: The number of programmable periodic signals.
+ * @pps:       Indicates whether the clock supports a PPS callback.
+ *
+ * clock operations
+ *
+ * @adjfreq:  Adjusts the frequency of the hardware clock.
+ *            parameter delta: Desired period change in parts per billion.
+ *
+ * @adjtime:  Shifts the time of the hardware clock.
+ *            parameter delta: Desired change in nanoseconds.
+ *
+ * @gettime:  Reads the current time from the hardware clock.
+ *            parameter ts: Holds the result.
+ *
+ * @settime:  Set the current time on the hardware clock.
+ *            parameter ts: Time value to set.
+ *
+ * @enable:   Request driver to enable or disable an ancillary feature.
+ *            parameter request: Desired resource to enable or disable.
+ *            parameter on: Caller passes one to enable or zero to disable.
+ *
+ * Drivers should embed their ptp_clock_info within a private
+ * structure, obtaining a reference to it using container_of().
+ *
+ * The callbacks must all return zero on success, non-zero otherwise.
+ */
+
+struct ptp_clock_info {
+       struct module *owner;
+       char name[16];
+       s32 max_adj;
+       int n_alarm;
+       int n_ext_ts;
+       int n_per_out;
+       int pps;
+       int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta);
+       int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
+       int (*gettime)(struct ptp_clock_info *ptp, struct timespec *ts);
+       int (*settime)(struct ptp_clock_info *ptp, const struct timespec *ts);
+       int (*enable)(struct ptp_clock_info *ptp,
+                     struct ptp_clock_request *request, int on);
+};
+
+struct ptp_clock;
+
+/**
+ * ptp_clock_register() - register a PTP hardware clock driver
+ *
+ * @info:  Structure describing the new clock.
+ */
+
+extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info);
+
+/**
+ * ptp_clock_unregister() - unregister a PTP hardware clock driver
+ *
+ * @ptp:  The clock to remove from service.
+ */
+
+extern int ptp_clock_unregister(struct ptp_clock *ptp);
+
+
+enum ptp_clock_events {
+       PTP_CLOCK_ALARM,
+       PTP_CLOCK_EXTTS,
+       PTP_CLOCK_PPS,
+};
+
+/**
+ * struct ptp_clock_event - decribes a PTP hardware clock event
+ *
+ * @type:  One of the ptp_clock_events enumeration values.
+ * @index: Identifies the source of the event.
+ * @timestamp: When the event occured.
+ */
+
+struct ptp_clock_event {
+       int type;
+       int index;
+       u64 timestamp;
+};
+
+/**
+ * ptp_clock_event() - notify the PTP layer about an event
+ *
+ * @ptp:    The clock obtained from ptp_clock_register().
+ * @event:  Message structure describing the event.
+ */
+
+extern void ptp_clock_event(struct ptp_clock *ptp,
+                           struct ptp_clock_event *event);
+
+#endif
diff --git a/include/linux/regulator/db8500-prcmu.h b/include/linux/regulator/db8500-prcmu.h
new file mode 100644 (file)
index 0000000..6120623
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Interface to power domain regulators on DB8500
+ */
+
+#ifndef __REGULATOR_H__
+#define __REGULATOR_H__
+
+/* Number of DB8500 regulators and regulator enumeration */
+enum db8500_regulator_id {
+       DB8500_REGULATOR_VAPE,
+       DB8500_REGULATOR_VARM,
+       DB8500_REGULATOR_VMODEM,
+       DB8500_REGULATOR_VPLL,
+       DB8500_REGULATOR_VSMPS1,
+       DB8500_REGULATOR_VSMPS2,
+       DB8500_REGULATOR_VSMPS3,
+       DB8500_REGULATOR_VRF1,
+       DB8500_REGULATOR_SWITCH_SVAMMDSP,
+       DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
+       DB8500_REGULATOR_SWITCH_SVAPIPE,
+       DB8500_REGULATOR_SWITCH_SIAMMDSP,
+       DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
+       DB8500_REGULATOR_SWITCH_SIAPIPE,
+       DB8500_REGULATOR_SWITCH_SGA,
+       DB8500_REGULATOR_SWITCH_B2R2_MCDE,
+       DB8500_REGULATOR_SWITCH_ESRAM12,
+       DB8500_REGULATOR_SWITCH_ESRAM12RET,
+       DB8500_REGULATOR_SWITCH_ESRAM34,
+       DB8500_REGULATOR_SWITCH_ESRAM34RET,
+       DB8500_NUM_REGULATORS
+};
+
+/*
+ * Exported interface for CPUIdle only. This function is called with all
+ * interrupts turned off.
+ */
+int power_state_active_is_enabled(void);
+
+#endif
diff --git a/include/linux/rfkill-gpio.h b/include/linux/rfkill-gpio.h
new file mode 100644 (file)
index 0000000..a175d05
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#ifndef __RFKILL_GPIO_H
+#define __RFKILL_GPIO_H
+
+#include <linux/types.h>
+#include <linux/rfkill.h>
+
+/**
+ * struct rfkill_gpio_platform_data - platform data for rfkill gpio device.
+ * for unused gpio's, the expected value is -1.
+ * @name:              name for the gpio rf kill instance
+ * @reset_gpio:                GPIO which is used for reseting rfkill switch
+ * @shutdown_gpio:     GPIO which is used for shutdown of rfkill switch
+ * @power_clk_name:    [optional] name of clk to turn off while blocked
+ */
+
+struct rfkill_gpio_platform_data {
+       char                    *name;
+       int                     reset_gpio;
+       int                     shutdown_gpio;
+       const char              *power_clk_name;
+       enum rfkill_type        type;
+};
+
+#endif /* __RFKILL_GPIO_H */
index 830e65dc01ee1f264e715632f2f99fd95c7bd529..2148b122779b5a2fd8421c5e15cfc9ca91ea85ff 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/memcontrol.h>
 
 /*
@@ -26,7 +26,7 @@
  */
 struct anon_vma {
        struct anon_vma *root;  /* Root of this anon_vma tree */
-       spinlock_t lock;        /* Serialize access to vma list */
+       struct mutex mutex;     /* Serialize access to vma list */
        /*
         * The refcount is taken on an anon_vma when there is no
         * guarantee that the vma of page tables will exist for
@@ -64,7 +64,7 @@ struct anon_vma_chain {
        struct vm_area_struct *vma;
        struct anon_vma *anon_vma;
        struct list_head same_vma;   /* locked by mmap_sem & page_table_lock */
-       struct list_head same_anon_vma; /* locked by anon_vma->lock */
+       struct list_head same_anon_vma; /* locked by anon_vma->mutex */
 };
 
 #ifdef CONFIG_MMU
@@ -93,24 +93,24 @@ static inline void vma_lock_anon_vma(struct vm_area_struct *vma)
 {
        struct anon_vma *anon_vma = vma->anon_vma;
        if (anon_vma)
-               spin_lock(&anon_vma->root->lock);
+               mutex_lock(&anon_vma->root->mutex);
 }
 
 static inline void vma_unlock_anon_vma(struct vm_area_struct *vma)
 {
        struct anon_vma *anon_vma = vma->anon_vma;
        if (anon_vma)
-               spin_unlock(&anon_vma->root->lock);
+               mutex_unlock(&anon_vma->root->mutex);
 }
 
 static inline void anon_vma_lock(struct anon_vma *anon_vma)
 {
-       spin_lock(&anon_vma->root->lock);
+       mutex_lock(&anon_vma->root->mutex);
 }
 
 static inline void anon_vma_unlock(struct anon_vma *anon_vma)
 {
-       spin_unlock(&anon_vma->root->lock);
+       mutex_unlock(&anon_vma->root->mutex);
 }
 
 /*
@@ -218,20 +218,7 @@ int try_to_munlock(struct page *);
 /*
  * Called by memory-failure.c to kill processes.
  */
-struct anon_vma *__page_lock_anon_vma(struct page *page);
-
-static inline struct anon_vma *page_lock_anon_vma(struct page *page)
-{
-       struct anon_vma *anon_vma;
-
-       __cond_lock(RCU, anon_vma = __page_lock_anon_vma(page));
-
-       /* (void) is needed to make gcc happy */
-       (void) __cond_lock(&anon_vma->root->lock, anon_vma);
-
-       return anon_vma;
-}
-
+struct anon_vma *page_lock_anon_vma(struct page *page);
 void page_unlock_anon_vma(struct anon_vma *anon_vma);
 int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma);
 
index aaf71e08222ca70e0984e374bfe2e4ee66a4ce7c..f18300eddfcb51041eb833eeefb1284288e7f2c9 100644 (file)
@@ -1753,7 +1753,6 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define PF_FROZEN      0x00010000      /* frozen for system suspend */
 #define PF_FSTRANS     0x00020000      /* inside a filesystem transaction */
 #define PF_KSWAPD      0x00040000      /* I am kswapd */
-#define PF_OOM_ORIGIN  0x00080000      /* Allocating much memory to others */
 #define PF_LESS_THROTTLE 0x00100000    /* Throttle me less: I clean memory */
 #define PF_KTHREAD     0x00200000      /* I am a kernel thread */
 #define PF_RANDOMIZE   0x00400000      /* randomize virtual address space */
@@ -2177,6 +2176,7 @@ static inline void mmdrop(struct mm_struct * mm)
        if (unlikely(atomic_dec_and_test(&mm->mm_count)))
                __mmdrop(mm);
 }
+extern int mm_init_cpumask(struct mm_struct *mm, struct mm_struct *oldmm);
 
 /* mmput gets rid of the mappings and all user-space */
 extern void mmput(struct mm_struct *);
index 399be5ad2f996cb0124412d68a9f1b191cc1e685..2b7fec840517ff00ae46d14b0662bbf85bb4dc62 100644 (file)
@@ -9,6 +9,8 @@
 
 #define SHMEM_NR_DIRECT 16
 
+#define SHMEM_SYMLINK_INLINE_LEN (SHMEM_NR_DIRECT * sizeof(swp_entry_t))
+
 struct shmem_inode_info {
        spinlock_t              lock;
        unsigned long           flags;
@@ -17,8 +19,12 @@ struct shmem_inode_info {
        unsigned long           next_index;     /* highest alloced index + 1 */
        struct shared_policy    policy;         /* NUMA memory alloc policy */
        struct page             *i_indirect;    /* top indirect blocks page */
-       swp_entry_t             i_direct[SHMEM_NR_DIRECT]; /* first blocks */
+       union {
+               swp_entry_t     i_direct[SHMEM_NR_DIRECT]; /* first blocks */
+               char            inline_symlink[SHMEM_SYMLINK_INLINE_LEN];
+       };
        struct list_head        swaplist;       /* chain of maybes on swap */
+       struct list_head        xattr_list;     /* list of shmem_xattr */
        struct inode            vfs_inode;
 };
 
index ab71447d0c5ad7d470751b856cb4869960ad1fee..8c03b98df5f93d196d523c60f31a850ffe9a22e4 100644 (file)
@@ -846,4 +846,5 @@ asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name,
 asmlinkage long sys_open_by_handle_at(int mountdirfd,
                                      struct file_handle __user *handle,
                                      int flags);
+asmlinkage long sys_setns(int fd, int nstype);
 #endif
index 2b3831b58aa4312a754c41b2608431db85e31887..51359837511ae4180ec22ac0ac71b625475dfaab 100644 (file)
@@ -261,6 +261,7 @@ extern void dec_zone_state(struct zone *, enum zone_stat_item);
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
 
 void refresh_cpu_vm_stats(int);
+void refresh_zone_stat_thresholds(void);
 
 int calculate_pressure_threshold(struct zone *zone);
 int calculate_normal_threshold(struct zone *zone);
@@ -313,6 +314,10 @@ static inline void __dec_zone_page_state(struct page *page,
 #define set_pgdat_percpu_threshold(pgdat, callback) { }
 
 static inline void refresh_cpu_vm_stats(int cpu) { }
-#endif
+static inline void refresh_zone_stat_thresholds(void) { }
+
+#endif         /* CONFIG_SMP */
+
+extern const char * const vmstat_text[];
 
 #endif /* _LINUX_VMSTAT_H */
index 6050783005bd9839ceaa1df692b526afd14982fc..aed54c50aa665b89e61bf007c6715e65a26cbefb 100644 (file)
 #define XATTR_CREATE   0x1     /* set value, fail if attr already exists */
 #define XATTR_REPLACE  0x2     /* set value, fail if attr does not exist */
 
-#ifdef  __KERNEL__
-
-#include <linux/types.h>
-
 /* Namespaces */
 #define XATTR_OS2_PREFIX "os2."
 #define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1)
 #define XATTR_CAPS_SUFFIX "capability"
 #define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX
 
+#ifdef  __KERNEL__
+
+#include <linux/types.h>
+
 struct inode;
 struct dentry;
 
index d2df55b0c2134a35044a583429ac34e01b37f065..008711e8e78f265d512105d788aad6877c016a07 100644 (file)
@@ -241,10 +241,10 @@ enum p9_open_mode_t {
 
 /**
  * enum p9_perm_t - 9P permissions
- * @P9_DMDIR: mode bite for directories
+ * @P9_DMDIR: mode bit for directories
  * @P9_DMAPPEND: mode bit for is append-only
  * @P9_DMEXCL: mode bit for excluse use (only one open handle allowed)
- * @P9_DMMOUNT: mode bite for mount points
+ * @P9_DMMOUNT: mode bit for mount points
  * @P9_DMAUTH: mode bit for authentication file
  * @P9_DMTMP: mode bit for non-backed-up files
  * @P9_DMSYMLINK: mode bit for symbolic links (9P2000.u)
@@ -362,7 +362,7 @@ struct p9_qid {
 };
 
 /**
- * struct p9_stat - file system metadata information
+ * struct p9_wstat - file system metadata information
  * @size: length prefix for this stat structure instance
  * @type: the type of the server (equivalent to a major number)
  * @dev: the sub-type of the server (equivalent to a minor number)
@@ -687,10 +687,10 @@ struct p9_rwstat {
  * @size: prefixed length of the structure
  * @id: protocol operating identifier of type &p9_msg_t
  * @tag: transaction id of the request
- * @offset: used by marshalling routines to track currentposition in buffer
+ * @offset: used by marshalling routines to track current position in buffer
  * @capacity: used by marshalling routines to track total malloc'd capacity
  * @pubuf: Payload user buffer given by the caller
- * @pubuf: Payload kernel buffer given by the caller
+ * @pkbuf: Payload kernel buffer given by the caller
  * @pbuf_size: pubuf/pkbuf(only one will be !NULL) size to be read/write.
  * @private: For transport layer's use.
  * @sdata: payload
@@ -714,7 +714,7 @@ struct p9_fcall {
        size_t pbuf_size;
        void *private;
 
-       uint8_t *sdata;
+       u8 *sdata;
 };
 
 struct p9_idpool;
@@ -728,7 +728,6 @@ void p9_idpool_put(int id, struct p9_idpool *p);
 int p9_idpool_check(int id, struct p9_idpool *p);
 
 int p9_error_init(void);
-int p9_errstr2errno(char *, int);
 int p9_trans_fd_init(void);
 void p9_trans_fd_exit(void);
 #endif /* NET_9P_H */
index 051a99f79769a59021fdcb958a6f850e1f2ddc71..d26d5e98a1737e85e9e2004f30d5fa17f4f007ae 100644 (file)
@@ -60,7 +60,7 @@ enum p9_trans_status {
 };
 
 /**
- * enum p9_req_status_t - virtio request status
+ * enum p9_req_status_t - status of a request
  * @REQ_STATUS_IDLE: request slot unused
  * @REQ_STATUS_ALLOC: request has been allocated but not sent
  * @REQ_STATUS_UNSENT: request waiting to be sent
index 8f08c736c4c3c22a86988c89c9f5fec77e68ff7b..d8549fb9c742209369f324db5953fd5904aa36dd 100644 (file)
@@ -41,6 +41,7 @@
  * @pref: Preferences of this transport
  * @def: set if this transport should be considered the default
  * @create: member function to create a new connection on this transport
+ * @close: member function to discard a connection on this transport
  * @request: member function to issue a request to the transport
  * @cancel: member function to cancel a request (if it hasn't been sent)
  *
@@ -48,7 +49,7 @@
  * transport module with the 9P core network module and used by the client
  * to instantiate a new connection on a transport.
  *
- * BUGS: the transport module list isn't protected.
+ * The transport module list is protected by v9fs_trans_lock.
  */
 
 struct p9_trans_module {
index bfd6557946beca9f5cf2525cf7931be4a2c51cbe..0589f554788aea2dd5dc28c9a372ee10637e3eb6 100644 (file)
@@ -531,6 +531,7 @@ struct sta_bss_parameters {
  * @tx_retries: cumulative retry counts
  * @tx_failed: number of failed transmissions (retries exceeded, no ACK)
  * @rx_dropped_misc:  Dropped for un-specified reason.
+ * @bss_param: current BSS parameters
  * @generation: generation number for nl80211 dumps.
  *     This number should increase every time the list of stations
  *     changes, i.e. when a station is added or removed, so that
@@ -1537,7 +1538,7 @@ struct cfg80211_ops {
  * @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
  * @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing
  *     auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH.
- * @WIPHY_FLAG_SCHED_SCAN: The device supports scheduled scans.
+ * @WIPHY_FLAG_SUPPORTS_SCHED_SCAN: The device supports scheduled scans.
  */
 enum wiphy_flags {
        WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
@@ -2878,6 +2879,7 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
  * cfg80211_roamed - notify cfg80211 of roaming
  *
  * @dev: network device
+ * @channel: the channel of the new AP
  * @bssid: the BSSID of the new AP
  * @req_ie: association request IEs (maybe be %NULL)
  * @req_ie_len: association request IEs length
@@ -2888,7 +2890,9 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
  * 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,
+void cfg80211_roamed(struct net_device *dev,
+                    struct ieee80211_channel *channel,
+                    const u8 *bssid,
                     const u8 *req_ie, size_t req_ie_len,
                     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp);
 
index 07a0402c52e6b3cec976652d7aa0c3d4a101d955..7d15d238b6ecc4f3d4c47af4389525ead0f7a2c7 100644 (file)
@@ -111,6 +111,8 @@ static inline u32 *dst_metrics_write_ptr(struct dst_entry *dst)
 {
        unsigned long p = dst->_metrics;
 
+       BUG_ON(!p);
+
        if (p & DST_METRICS_READ_ONLY)
                return dst->ops->cow_metrics(dst, p);
        return __DST_METRICS_PTR(p);
index 3ae491932bc80305909f278864c370e0f6e689df..dcc8f5749d3fa5d799e9bc7acff9ab279b864ca3 100644 (file)
@@ -119,6 +119,7 @@ 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);
+extern struct net *get_net_ns_by_fd(int pid);
 
 #ifdef CONFIG_NET_NS
 extern void __put_net(struct net *net);
similarity index 86%
rename from arch/arm/plat-omap/include/plat/panel-generic-dpi.h
rename to include/video/omap-panel-generic-dpi.h
index 790619734bcd920eafdcc523dc35a682733d44b7..127e3f20328e59e17d6f2b4b7de8f3eba2d5fee8 100644 (file)
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
-#define __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H
+#ifndef __OMAP_PANEL_GENERIC_DPI_H
+#define __OMAP_PANEL_GENERIC_DPI_H
 
-#include "display.h"
+struct omap_dss_device;
 
 /**
  * struct panel_generic_dpi_data - panel driver configuration data
@@ -34,4 +34,4 @@ struct panel_generic_dpi_data {
        void (*platform_disable)(struct omap_dss_device *dssdev);
 };
 
-#endif /* __ARCH_ARM_PLAT_OMAP_PANEL_GENERIC_DPI_H */
+#endif /* __OMAP_PANEL_GENERIC_DPI_H */
similarity index 65%
rename from arch/arm/plat-omap/include/plat/nokia-dsi-panel.h
rename to include/video/omap-panel-nokia-dsi.h
index 01ab6572ccbbb35c19f9e16db3d806f1701f6f63..921ae9327228cb7592b1f908fc4de2ed3eba4192 100644 (file)
@@ -1,14 +1,15 @@
-#ifndef __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H
-#define __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H
+#ifndef __OMAP_NOKIA_DSI_PANEL_H
+#define __OMAP_NOKIA_DSI_PANEL_H
 
-#include "display.h"
+struct omap_dss_device;
 
 /**
  * struct nokia_dsi_panel_data - Nokia DSI panel driver configuration
  * @name: panel name
  * @use_ext_te: use external TE
  * @ext_te_gpio: external TE GPIO
- * @use_esd_check: perform ESD checks
+ * @esd_interval: interval of ESD checks, 0 = disabled (ms)
+ * @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
  * @max_backlight_level: maximum backlight level
  * @set_backlight: pointer to backlight set function
  * @get_backlight: pointer to backlight get function
@@ -21,11 +22,12 @@ struct nokia_dsi_panel_data {
        bool use_ext_te;
        int ext_te_gpio;
 
-       bool use_esd_check;
+       unsigned esd_interval;
+       unsigned ulps_timeout;
 
        int max_backlight_level;
        int (*set_backlight)(struct omap_dss_device *dssdev, int level);
        int (*get_backlight)(struct omap_dss_device *dssdev);
 };
 
-#endif /* __ARCH_ARM_PLAT_OMAP_NOKIA_DSI_PANEL_H */
+#endif /* __OMAP_NOKIA_DSI_PANEL_H */
similarity index 85%
rename from arch/arm/plat-omap/include/plat/display.h
rename to include/video/omapdss.h
index 5e04ddc18fa8c512fbafb205e6818d1b064e2335..892b97f8e1576f969821688820350a0020762641 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * linux/include/asm-arm/arch-omap/display.h
- *
  * Copyright (C) 2008 Nokia Corporation
  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
  *
@@ -17,8 +15,8 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef __ASM_ARCH_OMAP_DISPLAY_H
-#define __ASM_ARCH_OMAP_DISPLAY_H
+#ifndef __OMAP_OMAPDSS_H
+#define __OMAP_OMAPDSS_H
 
 #include <linux/list.h>
 #include <linux/kobject.h>
@@ -88,6 +86,11 @@ enum omap_color_mode {
        OMAP_DSS_COLOR_ARGB32   = 1 << 11, /* ARGB32 */
        OMAP_DSS_COLOR_RGBA32   = 1 << 12, /* RGBA32 */
        OMAP_DSS_COLOR_RGBX32   = 1 << 13, /* RGBx32 */
+       OMAP_DSS_COLOR_NV12             = 1 << 14, /* NV12 format: YUV 4:2:0 */
+       OMAP_DSS_COLOR_RGBA16           = 1 << 15, /* RGBA16 - 4444 */
+       OMAP_DSS_COLOR_RGBX16           = 1 << 16, /* RGBx16 - 4444 */
+       OMAP_DSS_COLOR_ARGB16_1555      = 1 << 17, /* ARGB16 - 1555 */
+       OMAP_DSS_COLOR_XRGB16_1555      = 1 << 18, /* xRGB16 - 1555 */
 };
 
 enum omap_lcd_display_type {
@@ -174,6 +177,17 @@ enum omap_overlay_manager_caps {
        OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0,
 };
 
+enum omap_dss_clk_source {
+       OMAP_DSS_CLK_SRC_FCK = 0,               /* OMAP2/3: DSS1_ALWON_FCLK
+                                                * OMAP4: DSS_FCLK */
+       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC,   /* OMAP3: DSI1_PLL_FCLK
+                                                * OMAP4: PLL1_CLK1 */
+       OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI,     /* OMAP3: DSI2_PLL_FCLK
+                                                * OMAP4: PLL1_CLK2 */
+       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC,  /* OMAP4: PLL2_CLK1 */
+       OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI,    /* OMAP4: PLL2_CLK2 */
+};
+
 /* RFBI */
 
 struct rfbi_timings {
@@ -205,20 +219,30 @@ int omap_rfbi_enable_te(bool enable, unsigned line);
 int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
                             unsigned hs_pulse_time, unsigned vs_pulse_time,
                             int hs_pol_inv, int vs_pol_inv, int extif_div);
+void rfbi_bus_lock(void);
+void rfbi_bus_unlock(void);
 
 /* DSI */
-void dsi_bus_lock(void);
-void dsi_bus_unlock(void);
-int dsi_vc_dcs_write(int channel, u8 *data, int len);
-int dsi_vc_dcs_write_0(int channel, u8 dcs_cmd);
-int dsi_vc_dcs_write_1(int channel, u8 dcs_cmd, u8 param);
-int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len);
-int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen);
-int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data);
-int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2);
-int dsi_vc_set_max_rx_packet_size(int channel, u16 len);
-int dsi_vc_send_null(int channel);
-int dsi_vc_send_bta_sync(int channel);
+void dsi_bus_lock(struct omap_dss_device *dssdev);
+void dsi_bus_unlock(struct omap_dss_device *dssdev);
+int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data,
+               int len);
+int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel,
+               u8 dcs_cmd);
+int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 param);
+int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel,
+               u8 *data, int len);
+int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *buf, int buflen);
+int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *data);
+int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd,
+               u8 *data1, u8 *data2);
+int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel,
+               u16 len);
+int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
+int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel);
 
 /* Board specific data */
 struct omap_dss_board_info {
@@ -226,6 +250,7 @@ struct omap_dss_board_info {
        int num_devices;
        struct omap_dss_device **devices;
        struct omap_dss_device *default_device;
+       void (*dsi_mux_pads)(bool enable);
 };
 
 #if defined(CONFIG_OMAP2_DSS_MODULE) || defined(CONFIG_OMAP2_DSS)
@@ -280,6 +305,7 @@ struct omap_overlay_info {
 
        u32 paddr;
        void __iomem *vaddr;
+       u32 p_uv_addr;  /* for NV12 format */
        u16 screen_width;
        u16 width;
        u16 height;
@@ -400,18 +426,12 @@ struct omap_dss_device {
                        u8 data1_pol;
                        u8 data2_lane;
                        u8 data2_pol;
+                       u8 data3_lane;
+                       u8 data3_pol;
+                       u8 data4_lane;
+                       u8 data4_pol;
 
-                       struct {
-                               u16 regn;
-                               u16 regm;
-                               u16 regm_dispc;
-                               u16 regm_dsi;
-
-                               u16 lp_clk_div;
-
-                               u16 lck_div;
-                               u16 pck_div;
-                       } div;
+                       int module;
 
                        bool ext_te;
                        u8 ext_te_gpio;
@@ -423,6 +443,33 @@ struct omap_dss_device {
                } venc;
        } phy;
 
+       struct {
+               struct {
+                       struct {
+                               u16 lck_div;
+                               u16 pck_div;
+                               enum omap_dss_clk_source lcd_clk_src;
+                       } channel;
+
+                       enum omap_dss_clk_source dispc_fclk_src;
+               } dispc;
+
+               struct {
+                       u16 regn;
+                       u16 regm;
+                       u16 regm_dispc;
+                       u16 regm_dsi;
+
+                       u16 lp_clk_div;
+                       enum omap_dss_clk_source dsi_fclk_src;
+               } dsi;
+
+               struct {
+                       u16 regn;
+                       u16 regm2;
+               } hdmi;
+       } clocks;
+
        struct {
                struct omap_video_timings timings;
 
@@ -503,6 +550,8 @@ struct omap_dss_driver {
 
        void (*get_resolution)(struct omap_dss_device *dssdev,
                        u16 *xres, u16 *yres);
+       void (*get_dimensions)(struct omap_dss_device *dssdev,
+                       u32 *width, u32 *height);
        int (*get_recommended_bpp)(struct omap_dss_device *dssdev);
 
        int (*check_timings)(struct omap_dss_device *dssdev,
@@ -519,9 +568,6 @@ struct omap_dss_driver {
 int omap_dss_register_driver(struct omap_dss_driver *);
 void omap_dss_unregister_driver(struct omap_dss_driver *);
 
-int omap_dss_register_device(struct omap_dss_device *);
-void omap_dss_unregister_device(struct omap_dss_device *);
-
 void omap_dss_get_device(struct omap_dss_device *dssdev);
 void omap_dss_put_device(struct omap_dss_device *dssdev);
 #define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
@@ -553,7 +599,8 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
 #define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver)
 #define to_dss_device(x) container_of((x), struct omap_dss_device, dev)
 
-void omapdss_dsi_vc_enable_hs(int channel, bool enable);
+void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel,
+               bool enable);
 int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable);
 
 int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
@@ -568,7 +615,8 @@ int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id);
 void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel);
 
 int omapdss_dsi_display_enable(struct omap_dss_device *dssdev);
-void omapdss_dsi_display_disable(struct omap_dss_device *dssdev);
+void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
+               bool disconnect_lanes, bool enter_ulps);
 
 int omapdss_dpi_display_enable(struct omap_dss_device *dssdev);
 void omapdss_dpi_display_disable(struct omap_dss_device *dssdev);
@@ -587,5 +635,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
 int omap_rfbi_update(struct omap_dss_device *dssdev,
                u16 x, u16 y, u16 w, u16 h,
                void (*callback)(void *), void *data);
+int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size,
+               int data_lines);
 
 #endif
index 2c8d369190b3af142bacb5796bb53d48ead04c81..d964e68fc61dab119e504f3f8feb1a5d0a44d36d 100644 (file)
@@ -2,6 +2,7 @@
 #define __ASM_SH_MOBILE_LCDC_H__
 
 #include <linux/fb.h>
+#include <video/sh_mobile_meram.h>
 
 enum {
        RGB8,   /* 24bpp, 8:8:8 */
@@ -87,11 +88,13 @@ struct sh_mobile_lcdc_chan_cfg {
        struct sh_mobile_lcdc_bl_info bl_info;
        struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */
        int nonstd;
+       struct sh_mobile_meram_cfg *meram_cfg;
 };
 
 struct sh_mobile_lcdc_info {
        int clock_source;
        struct sh_mobile_lcdc_chan_cfg ch[2];
+       struct sh_mobile_meram_info *meram_dev;
 };
 
 #endif /* __ASM_SH_MOBILE_LCDC_H__ */
diff --git a/include/video/sh_mobile_meram.h b/include/video/sh_mobile_meram.h
new file mode 100644 (file)
index 0000000..af602d6
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __VIDEO_SH_MOBILE_MERAM_H__
+#define __VIDEO_SH_MOBILE_MERAM_H__
+
+/* For sh_mobile_meram_info.addr_mode */
+enum {
+       SH_MOBILE_MERAM_MODE0 = 0,
+       SH_MOBILE_MERAM_MODE1
+};
+
+enum {
+       SH_MOBILE_MERAM_PF_NV = 0,
+       SH_MOBILE_MERAM_PF_RGB,
+       SH_MOBILE_MERAM_PF_NV24
+};
+
+
+struct sh_mobile_meram_priv;
+struct sh_mobile_meram_ops;
+
+struct sh_mobile_meram_info {
+       int                             addr_mode;
+       struct sh_mobile_meram_ops      *ops;
+       struct sh_mobile_meram_priv     *priv;
+       struct platform_device          *pdev;
+};
+
+/* icb config */
+struct sh_mobile_meram_icb {
+       int marker_icb;         /* ICB # for Marker ICB */
+       int cache_icb;          /* ICB # for Cache ICB */
+       int meram_offset;       /* MERAM Buffer Offset to use */
+       int meram_size;         /* MERAM Buffer Size to use */
+
+       int cache_unit;         /* bytes to cache per ICB */
+};
+
+struct sh_mobile_meram_cfg {
+       struct sh_mobile_meram_icb      icb[2];
+       int                             pixelformat;
+       int                             current_reg;
+};
+
+struct module;
+struct sh_mobile_meram_ops {
+       struct module   *module;
+       /* register usage of meram */
+       int (*meram_register)(struct sh_mobile_meram_info *meram_dev,
+                             struct sh_mobile_meram_cfg *cfg,
+                             int xres, int yres, int pixelformat,
+                             unsigned long base_addr_y,
+                             unsigned long base_addr_c,
+                             unsigned long *icb_addr_y,
+                             unsigned long *icb_addr_c, int *pitch);
+
+       /* unregister usage of meram */
+       int (*meram_unregister)(struct sh_mobile_meram_info *meram_dev,
+                               struct sh_mobile_meram_cfg *cfg);
+
+       /* update meram settings */
+       int (*meram_update)(struct sh_mobile_meram_info *meram_dev,
+                           struct sh_mobile_meram_cfg *cfg,
+                           unsigned long base_addr_y,
+                           unsigned long base_addr_c,
+                           unsigned long *icb_addr_y,
+                           unsigned long *icb_addr_c);
+};
+
+#endif /* __VIDEO_SH_MOBILE_MERAM_H__  */
index 61e523af3c46c8311c354a4fb22e36048ebf2a0a..3d5d6db864fe9781e2fc79214474f7101c84187c 100644 (file)
@@ -44,6 +44,19 @@ typedef uint64_t blkif_sector_t;
  */
 #define BLKIF_OP_WRITE_BARRIER     2
 
+/*
+ * Recognised if "feature-flush-cache" is present in backend xenbus
+ * info.  A flush will ask the underlying storage hardware to flush its
+ * non-volatile caches as appropriate.  The "feature-flush-cache" node
+ * contains a boolean indicating whether flush requests are likely to
+ * succeed or fail. Either way, a flush request may fail at any time
+ * with BLKIF_RSP_EOPNOTSUPP if it is unsupported by the underlying
+ * block-device hardware. The boolean simply indicates whether or not it
+ * is worthwhile for the frontend to attempt flushes.  If a backend does
+ * not recognise BLKIF_OP_WRITE_FLUSH_CACHE, it should *not* create the
+ * "feature-flush-cache" node!
+ */
+#define BLKIF_OP_FLUSH_DISKCACHE   3
 /*
  * Maximum scatter/gather segments per request.
  * This is carefully chosen so that sizeof(struct blkif_ring) <= PAGE_SIZE.
index 76ac9194cbc437911e2394f8e94f4530eff716c8..cfd7000c9d7108085b337876893fa6e91910dc04 100644 (file)
@@ -38,6 +38,9 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
        unsigned long timer_rate_min, timer_rate_max;
        unsigned long good_timer_sum = 0;
        unsigned long good_timer_count = 0;
+       unsigned long measured_times[MAX_DIRECT_CALIBRATION_RETRIES];
+       int max = -1; /* index of measured_times with max/min values or not set */
+       int min = -1;
        int i;
 
        if (read_current_timer(&pre_start) < 0 )
@@ -90,18 +93,78 @@ static unsigned long __cpuinit calibrate_delay_direct(void)
                 * If the upper limit and lower limit of the timer_rate is
                 * >= 12.5% apart, redo calibration.
                 */
-               if (pre_start != 0 && pre_end != 0 &&
+               printk(KERN_DEBUG "calibrate_delay_direct() timer_rate_max=%lu "
+                           "timer_rate_min=%lu pre_start=%lu pre_end=%lu\n",
+                         timer_rate_max, timer_rate_min, pre_start, pre_end);
+               if (start >= post_end)
+                       printk(KERN_NOTICE "calibrate_delay_direct() ignoring "
+                                       "timer_rate as we had a TSC wrap around"
+                                       " start=%lu >=post_end=%lu\n",
+                               start, post_end);
+               if (start < post_end && pre_start != 0 && pre_end != 0 &&
                    (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) {
                        good_timer_count++;
                        good_timer_sum += timer_rate_max;
-               }
+                       measured_times[i] = timer_rate_max;
+                       if (max < 0 || timer_rate_max > measured_times[max])
+                               max = i;
+                       if (min < 0 || timer_rate_max < measured_times[min])
+                               min = i;
+               } else
+                       measured_times[i] = 0;
+
        }
 
-       if (good_timer_count)
-               return (good_timer_sum/good_timer_count);
+       /*
+        * Find the maximum & minimum - if they differ too much throw out the
+        * one with the largest difference from the mean and try again...
+        */
+       while (good_timer_count > 1) {
+               unsigned long estimate;
+               unsigned long maxdiff;
+
+               /* compute the estimate */
+               estimate = (good_timer_sum/good_timer_count);
+               maxdiff = estimate >> 3;
+
+               /* if range is within 12% let's take it */
+               if ((measured_times[max] - measured_times[min]) < maxdiff)
+                       return estimate;
+
+               /* ok - drop the worse value and try again... */
+               good_timer_sum = 0;
+               good_timer_count = 0;
+               if ((measured_times[max] - estimate) <
+                               (estimate - measured_times[min])) {
+                       printk(KERN_NOTICE "calibrate_delay_direct() dropping "
+                                       "min bogoMips estimate %d = %lu\n",
+                               min, measured_times[min]);
+                       measured_times[min] = 0;
+                       min = max;
+               } else {
+                       printk(KERN_NOTICE "calibrate_delay_direct() dropping "
+                                       "max bogoMips estimate %d = %lu\n",
+                               max, measured_times[max]);
+                       measured_times[max] = 0;
+                       max = min;
+               }
+
+               for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) {
+                       if (measured_times[i] == 0)
+                               continue;
+                       good_timer_count++;
+                       good_timer_sum += measured_times[i];
+                       if (measured_times[i] < measured_times[min])
+                               min = i;
+                       if (measured_times[i] > measured_times[max])
+                               max = i;
+               }
+
+       }
 
-       printk(KERN_WARNING "calibrate_delay_direct() failed to get a good "
-              "estimate for loops_per_jiffy.\nProbably due to long platform interrupts. Consider using \"lpj=\" boot option.\n");
+       printk(KERN_NOTICE "calibrate_delay_direct() failed to get a good "
+              "estimate for loops_per_jiffy.\nProbably due to long platform "
+               "interrupts. Consider using \"lpj=\" boot option.\n");
        return 0;
 }
 #else
index 48df882d51d2e709eaf5e79be55e806d75b6d6c5..d2f1e086bf337d064aaeef6baa0865ca6ba5fd31 100644 (file)
@@ -504,11 +504,14 @@ asmlinkage void __init start_kernel(void)
         * These use large bootmem allocations and must precede
         * kmem_cache_init()
         */
+       setup_log_buf(0);
        pidhash_init();
        vfs_caches_init_early();
        sort_main_extable();
        trap_init();
        mm_init();
+       BUG_ON(mm_init_cpumask(&init_mm, 0));
+
        /*
         * Set up the scheduler prior starting any interrupts (such as the
         * timer interrupt). Full topology setup happens at smp_init()
index 8054c8e5faf1da309ef7b44d9ecebd4000883277..ce0a647869b1e8797290930770bbfc9557d19fab 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/fs.h>
 #include <linux/mount.h>
 #include <linux/user_namespace.h>
+#include <linux/proc_fs.h>
 
 #include "util.h"
 
@@ -140,3 +141,39 @@ void put_ipc_ns(struct ipc_namespace *ns)
                free_ipc_ns(ns);
        }
 }
+
+static void *ipcns_get(struct task_struct *task)
+{
+       struct ipc_namespace *ns = NULL;
+       struct nsproxy *nsproxy;
+
+       rcu_read_lock();
+       nsproxy = task_nsproxy(task);
+       if (nsproxy)
+               ns = get_ipc_ns(nsproxy->ipc_ns);
+       rcu_read_unlock();
+
+       return ns;
+}
+
+static void ipcns_put(void *ns)
+{
+       return put_ipc_ns(ns);
+}
+
+static int ipcns_install(struct nsproxy *nsproxy, void *ns)
+{
+       /* Ditch state from the old ipc namespace */
+       exit_sem(current);
+       put_ipc_ns(nsproxy->ipc_ns);
+       nsproxy->ipc_ns = get_ipc_ns(ns);
+       return 0;
+}
+
+const struct proc_ns_operations ipcns_operations = {
+       .name           = "ipc",
+       .type           = CLONE_NEWIPC,
+       .get            = ipcns_get,
+       .put            = ipcns_put,
+       .install        = ipcns_install,
+};
index 9214dcd087b7369fb754e6391015918db6d6ed3f..fc9eb093acd5fc006e9f296b1a6c92b7a39d53ff 100644 (file)
@@ -293,6 +293,8 @@ asmlinkage long compat_sys_times(struct compat_tms __user *tbuf)
        return compat_jiffies_to_clock_t(jiffies);
 }
 
+#ifdef __ARCH_WANT_SYS_SIGPENDING
+
 /*
  * Assumption: old_sigset_t and compat_old_sigset_t are both
  * types that can be passed to put_user()/get_user().
@@ -312,6 +314,10 @@ asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set)
        return ret;
 }
 
+#endif
+
+#ifdef __ARCH_WANT_SYS_SIGPROCMASK
+
 asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
                compat_old_sigset_t __user *oset)
 {
@@ -333,6 +339,8 @@ asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *set,
        return ret;
 }
 
+#endif
+
 asmlinkage long compat_sys_setrlimit(unsigned int resource,
                struct compat_rlimit __user *rlim)
 {
index 2b44d82b8237f6fb8e98cef8cff1c5cb84620efb..8e7e135d08177e9f99e3ecf2c8142d56a1989c85 100644 (file)
@@ -383,15 +383,14 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
                        get_file(file);
                        if (tmp->vm_flags & VM_DENYWRITE)
                                atomic_dec(&inode->i_writecount);
-                       spin_lock(&mapping->i_mmap_lock);
+                       mutex_lock(&mapping->i_mmap_mutex);
                        if (tmp->vm_flags & VM_SHARED)
                                mapping->i_mmap_writable++;
-                       tmp->vm_truncate_count = mpnt->vm_truncate_count;
                        flush_dcache_mmap_lock(mapping);
                        /* insert tmp into the share list, just after mpnt */
                        vma_prio_tree_add(tmp, mpnt);
                        flush_dcache_mmap_unlock(mapping);
-                       spin_unlock(&mapping->i_mmap_lock);
+                       mutex_unlock(&mapping->i_mmap_mutex);
                }
 
                /*
@@ -486,6 +485,20 @@ static void mm_init_aio(struct mm_struct *mm)
 #endif
 }
 
+int mm_init_cpumask(struct mm_struct *mm, struct mm_struct *oldmm)
+{
+#ifdef CONFIG_CPUMASK_OFFSTACK
+       if (!alloc_cpumask_var(&mm->cpu_vm_mask_var, GFP_KERNEL))
+               return -ENOMEM;
+
+       if (oldmm)
+               cpumask_copy(mm_cpumask(mm), mm_cpumask(oldmm));
+       else
+               memset(mm_cpumask(mm), 0, cpumask_size());
+#endif
+       return 0;
+}
+
 static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
 {
        atomic_set(&mm->mm_users, 1);
@@ -522,10 +535,20 @@ struct mm_struct * mm_alloc(void)
        struct mm_struct * mm;
 
        mm = allocate_mm();
-       if (mm) {
-               memset(mm, 0, sizeof(*mm));
-               mm = mm_init(mm, current);
+       if (!mm)
+               return NULL;
+
+       memset(mm, 0, sizeof(*mm));
+       mm = mm_init(mm, current);
+       if (!mm)
+               return NULL;
+
+       if (mm_init_cpumask(mm, NULL)) {
+               mm_free_pgd(mm);
+               free_mm(mm);
+               return NULL;
        }
+
        return mm;
 }
 
@@ -537,6 +560,7 @@ struct mm_struct * mm_alloc(void)
 void __mmdrop(struct mm_struct *mm)
 {
        BUG_ON(mm == &init_mm);
+       free_cpumask_var(mm->cpu_vm_mask_var);
        mm_free_pgd(mm);
        destroy_context(mm);
        mmu_notifier_mm_destroy(mm);
@@ -691,6 +715,9 @@ struct mm_struct *dup_mm(struct task_struct *tsk)
        if (!mm_init(mm, tsk))
                goto fail_nomem;
 
+       if (mm_init_cpumask(mm, oldmm))
+               goto fail_nocpumask;
+
        if (init_new_context(tsk, mm))
                goto fail_nocontext;
 
@@ -717,6 +744,9 @@ fail_nomem:
        return NULL;
 
 fail_nocontext:
+       free_cpumask_var(mm->cpu_vm_mask_var);
+
+fail_nocpumask:
        /*
         * If init_new_context() failed, we cannot use mmput() to free the mm
         * because it calls destroy_context()
index c541ee527ecb72443dc598764ede707b664a4b79..a9205e32a059cde761f924c498d2984b0aacb36c 100644 (file)
@@ -748,7 +748,7 @@ static inline void retrigger_next_event(void *arg) { }
  */
 void clock_was_set(void)
 {
-#ifdef CONFIG_HIGHRES_TIMERS
+#ifdef CONFIG_HIGH_RES_TIMERS
        /* Retrigger the CPU local events everywhere */
        on_each_cpu(retrigger_next_event, NULL, 1);
 #endif
index 834899f2500fc550d3da66306d31386eb80baf91..64e3df6ab1efdd32b9ea8088b4b565d536548b0c 100644 (file)
@@ -19,7 +19,7 @@ static struct proc_dir_entry *root_irq_dir;
 
 #ifdef CONFIG_SMP
 
-static int irq_affinity_proc_show(struct seq_file *m, void *v)
+static int show_irq_affinity(int type, struct seq_file *m, void *v)
 {
        struct irq_desc *desc = irq_to_desc((long)m->private);
        const struct cpumask *mask = desc->irq_data.affinity;
@@ -28,7 +28,10 @@ static int irq_affinity_proc_show(struct seq_file *m, void *v)
        if (irqd_is_setaffinity_pending(&desc->irq_data))
                mask = desc->pending_mask;
 #endif
-       seq_cpumask(m, mask);
+       if (type)
+               seq_cpumask_list(m, mask);
+       else
+               seq_cpumask(m, mask);
        seq_putc(m, '\n');
        return 0;
 }
@@ -59,7 +62,18 @@ static int irq_affinity_hint_proc_show(struct seq_file *m, void *v)
 #endif
 
 int no_irq_affinity;
-static ssize_t irq_affinity_proc_write(struct file *file,
+static int irq_affinity_proc_show(struct seq_file *m, void *v)
+{
+       return show_irq_affinity(0, m, v);
+}
+
+static int irq_affinity_list_proc_show(struct seq_file *m, void *v)
+{
+       return show_irq_affinity(1, m, v);
+}
+
+
+static ssize_t write_irq_affinity(int type, struct file *file,
                const char __user *buffer, size_t count, loff_t *pos)
 {
        unsigned int irq = (int)(long)PDE(file->f_path.dentry->d_inode)->data;
@@ -72,7 +86,10 @@ static ssize_t irq_affinity_proc_write(struct file *file,
        if (!alloc_cpumask_var(&new_value, GFP_KERNEL))
                return -ENOMEM;
 
-       err = cpumask_parse_user(buffer, count, new_value);
+       if (type)
+               err = cpumask_parselist_user(buffer, count, new_value);
+       else
+               err = cpumask_parse_user(buffer, count, new_value);
        if (err)
                goto free_cpumask;
 
@@ -100,11 +117,28 @@ free_cpumask:
        return err;
 }
 
+static ssize_t irq_affinity_proc_write(struct file *file,
+               const char __user *buffer, size_t count, loff_t *pos)
+{
+       return write_irq_affinity(0, file, buffer, count, pos);
+}
+
+static ssize_t irq_affinity_list_proc_write(struct file *file,
+               const char __user *buffer, size_t count, loff_t *pos)
+{
+       return write_irq_affinity(1, file, buffer, count, pos);
+}
+
 static int irq_affinity_proc_open(struct inode *inode, struct file *file)
 {
        return single_open(file, irq_affinity_proc_show, PDE(inode)->data);
 }
 
+static int irq_affinity_list_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, irq_affinity_list_proc_show, PDE(inode)->data);
+}
+
 static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file)
 {
        return single_open(file, irq_affinity_hint_proc_show, PDE(inode)->data);
@@ -125,6 +159,14 @@ static const struct file_operations irq_affinity_hint_proc_fops = {
        .release        = single_release,
 };
 
+static const struct file_operations irq_affinity_list_proc_fops = {
+       .open           = irq_affinity_list_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = irq_affinity_list_proc_write,
+};
+
 static int default_affinity_show(struct seq_file *m, void *v)
 {
        seq_cpumask(m, irq_default_affinity);
@@ -289,6 +331,10 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
        proc_create_data("affinity_hint", 0400, desc->dir,
                         &irq_affinity_hint_proc_fops, (void *)(long)irq);
 
+       /* create /proc/irq/<irq>/smp_affinity_list */
+       proc_create_data("smp_affinity_list", 0600, desc->dir,
+                        &irq_affinity_list_proc_fops, (void *)(long)irq);
+
        proc_create_data("node", 0444, desc->dir,
                         &irq_node_proc_fops, (void *)(long)irq);
 #endif
index 2c938e2337cd36f3e627bb5758186aa7b4e0a327..d607ed5dd4416b5a688a271d788d7c2e51190662 100644 (file)
@@ -131,14 +131,14 @@ EXPORT_SYMBOL(mutex_unlock);
  */
 static inline int __sched
 __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
-               unsigned long ip)
+                   struct lockdep_map *nest_lock, unsigned long ip)
 {
        struct task_struct *task = current;
        struct mutex_waiter waiter;
        unsigned long flags;
 
        preempt_disable();
-       mutex_acquire(&lock->dep_map, subclass, 0, ip);
+       mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
 
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
        /*
@@ -269,16 +269,25 @@ void __sched
 mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, _RET_IP_);
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, NULL, _RET_IP_);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_nested);
 
+void __sched
+_mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *nest)
+{
+       might_sleep();
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, nest, _RET_IP_);
+}
+
+EXPORT_SYMBOL_GPL(_mutex_lock_nest_lock);
+
 int __sched
 mutex_lock_killable_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
-       return __mutex_lock_common(lock, TASK_KILLABLE, subclass, _RET_IP_);
+       return __mutex_lock_common(lock, TASK_KILLABLE, subclass, NULL, _RET_IP_);
 }
 EXPORT_SYMBOL_GPL(mutex_lock_killable_nested);
 
@@ -287,7 +296,7 @@ mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass)
 {
        might_sleep();
        return __mutex_lock_common(lock, TASK_INTERRUPTIBLE,
-                                  subclass, _RET_IP_);
+                                  subclass, NULL, _RET_IP_);
 }
 
 EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested);
@@ -393,7 +402,7 @@ __mutex_lock_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
 
-       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, _RET_IP_);
+       __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, NULL, _RET_IP_);
 }
 
 static noinline int __sched
@@ -401,7 +410,7 @@ __mutex_lock_killable_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
 
-       return __mutex_lock_common(lock, TASK_KILLABLE, 0, _RET_IP_);
+       return __mutex_lock_common(lock, TASK_KILLABLE, 0, NULL, _RET_IP_);
 }
 
 static noinline int __sched
@@ -409,7 +418,7 @@ __mutex_lock_interruptible_slowpath(atomic_t *lock_count)
 {
        struct mutex *lock = container_of(lock_count, struct mutex, count);
 
-       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0, _RET_IP_);
+       return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0, NULL, _RET_IP_);
 }
 #endif
 
index a05d191ffdd903bd2efc5e10d783021ef1b29a98..5424e37673ed0fc5df510c5a03db31e50fba5dae 100644 (file)
@@ -22,6 +22,9 @@
 #include <linux/pid_namespace.h>
 #include <net/net_namespace.h>
 #include <linux/ipc_namespace.h>
+#include <linux/proc_fs.h>
+#include <linux/file.h>
+#include <linux/syscalls.h>
 
 static struct kmem_cache *nsproxy_cachep;
 
@@ -233,6 +236,45 @@ void exit_task_namespaces(struct task_struct *p)
        switch_task_namespaces(p, NULL);
 }
 
+SYSCALL_DEFINE2(setns, int, fd, int, nstype)
+{
+       const struct proc_ns_operations *ops;
+       struct task_struct *tsk = current;
+       struct nsproxy *new_nsproxy;
+       struct proc_inode *ei;
+       struct file *file;
+       int err;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       file = proc_ns_fget(fd);
+       if (IS_ERR(file))
+               return PTR_ERR(file);
+
+       err = -EINVAL;
+       ei = PROC_I(file->f_dentry->d_inode);
+       ops = ei->ns_ops;
+       if (nstype && (ops->type != nstype))
+               goto out;
+
+       new_nsproxy = create_new_namespaces(0, tsk, tsk->fs);
+       if (IS_ERR(new_nsproxy)) {
+               err = PTR_ERR(new_nsproxy);
+               goto out;
+       }
+
+       err = ops->install(new_nsproxy, ei->ns);
+       if (err) {
+               free_nsproxy(new_nsproxy);
+               goto out;
+       }
+       switch_task_namespaces(tsk, new_nsproxy);
+out:
+       fput(file);
+       return err;
+}
+
 static int __init nsproxy_cache_init(void)
 {
        nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC);
index a1b5edf1bf92b6890f0bcb2b872e6bcc001d728e..4556182527f38fe88dba74dd753cec5ed0112785 100644 (file)
@@ -491,6 +491,13 @@ static struct k_itimer * alloc_posix_timer(void)
        return tmr;
 }
 
+static void k_itimer_rcu_free(struct rcu_head *head)
+{
+       struct k_itimer *tmr = container_of(head, struct k_itimer, it.rcu);
+
+       kmem_cache_free(posix_timers_cache, tmr);
+}
+
 #define IT_ID_SET      1
 #define IT_ID_NOT_SET  0
 static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
@@ -503,7 +510,7 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
        }
        put_pid(tmr->it_pid);
        sigqueue_free(tmr->sigq);
-       kmem_cache_free(posix_timers_cache, tmr);
+       call_rcu(&tmr->it.rcu, k_itimer_rcu_free);
 }
 
 static struct k_clock *clockid_to_kclock(const clockid_t id)
@@ -631,22 +638,18 @@ out:
 static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)
 {
        struct k_itimer *timr;
-       /*
-        * Watch out here.  We do a irqsave on the idr_lock and pass the
-        * flags part over to the timer lock.  Must not let interrupts in
-        * while we are moving the lock.
-        */
-       spin_lock_irqsave(&idr_lock, *flags);
+
+       rcu_read_lock();
        timr = idr_find(&posix_timers_id, (int)timer_id);
        if (timr) {
-               spin_lock(&timr->it_lock);
+               spin_lock_irqsave(&timr->it_lock, *flags);
                if (timr->it_signal == current->signal) {
-                       spin_unlock(&idr_lock);
+                       rcu_read_unlock();
                        return timr;
                }
-               spin_unlock(&timr->it_lock);
+               spin_unlock_irqrestore(&timr->it_lock, *flags);
        }
-       spin_unlock_irqrestore(&idr_lock, *flags);
+       rcu_read_unlock();
 
        return NULL;
 }
index da8ca817eae3b817d037f3f2d4b9666e52569b35..35185392173f5af5fc39fff30cadc115b92114e8 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/smp.h>
 #include <linux/security.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/syscalls.h>
 #include <linux/kexec.h>
 #include <linux/kdb.h>
@@ -167,46 +168,74 @@ void log_buf_kexec_setup(void)
 }
 #endif
 
+/* requested log_buf_len from kernel cmdline */
+static unsigned long __initdata new_log_buf_len;
+
+/* save requested log_buf_len since it's too early to process it */
 static int __init log_buf_len_setup(char *str)
 {
        unsigned size = memparse(str, &str);
-       unsigned long flags;
 
        if (size)
                size = roundup_pow_of_two(size);
-       if (size > log_buf_len) {
-               unsigned start, dest_idx, offset;
-               char *new_log_buf;
+       if (size > log_buf_len)
+               new_log_buf_len = size;
 
-               new_log_buf = alloc_bootmem(size);
-               if (!new_log_buf) {
-                       printk(KERN_WARNING "log_buf_len: allocation failed\n");
-                       goto out;
-               }
+       return 0;
+}
+early_param("log_buf_len", log_buf_len_setup);
 
-               spin_lock_irqsave(&logbuf_lock, flags);
-               log_buf_len = size;
-               log_buf = new_log_buf;
-
-               offset = start = min(con_start, log_start);
-               dest_idx = 0;
-               while (start != log_end) {
-                       log_buf[dest_idx] = __log_buf[start & (__LOG_BUF_LEN - 1)];
-                       start++;
-                       dest_idx++;
-               }
-               log_start -= offset;
-               con_start -= offset;
-               log_end -= offset;
-               spin_unlock_irqrestore(&logbuf_lock, flags);
+void __init setup_log_buf(int early)
+{
+       unsigned long flags;
+       unsigned start, dest_idx, offset;
+       char *new_log_buf;
+       int free;
+
+       if (!new_log_buf_len)
+               return;
+
+       if (early) {
+               unsigned long mem;
 
-               printk(KERN_NOTICE "log_buf_len: %d\n", log_buf_len);
+               mem = memblock_alloc(new_log_buf_len, PAGE_SIZE);
+               if (mem == MEMBLOCK_ERROR)
+                       return;
+               new_log_buf = __va(mem);
+       } else {
+               new_log_buf = alloc_bootmem_nopanic(new_log_buf_len);
        }
-out:
-       return 1;
-}
 
-__setup("log_buf_len=", log_buf_len_setup);
+       if (unlikely(!new_log_buf)) {
+               pr_err("log_buf_len: %ld bytes not available\n",
+                       new_log_buf_len);
+               return;
+       }
+
+       spin_lock_irqsave(&logbuf_lock, flags);
+       log_buf_len = new_log_buf_len;
+       log_buf = new_log_buf;
+       new_log_buf_len = 0;
+       free = __LOG_BUF_LEN - log_end;
+
+       offset = start = min(con_start, log_start);
+       dest_idx = 0;
+       while (start != log_end) {
+               unsigned log_idx_mask = start & (__LOG_BUF_LEN - 1);
+
+               log_buf[dest_idx] = __log_buf[log_idx_mask];
+               start++;
+               dest_idx++;
+       }
+       log_start -= offset;
+       con_start -= offset;
+       log_end -= offset;
+       spin_unlock_irqrestore(&logbuf_lock, flags);
+
+       pr_info("log_buf_len: %d\n", log_buf_len);
+       pr_info("early log buf free: %d(%d%%)\n",
+               free, (free * 100) / __LOG_BUF_LEN);
+}
 
 #ifdef CONFIG_BOOT_PRINTK_DELAY
 
index 7a81fc0713442590c6643e411c77da127bc2520e..2df115790cd9e1ab6a1128603697ce5b6ed255d9 100644 (file)
@@ -562,7 +562,7 @@ static int ptrace_resume(struct task_struct *child, long request,
        }
 
        child->exit_code = data;
-       wake_up_process(child);
+       wake_up_state(child, __TASK_TRACED);
 
        return 0;
 }
index ad5e818baacc43fb5e4046926bf52dde55acacfa..86c32b884f8efbb8f071b6343b3c37667b4e8fa3 100644 (file)
@@ -3023,8 +3023,10 @@ SYSCALL_DEFINE2(signal, int, sig, __sighandler_t, handler)
 
 SYSCALL_DEFINE0(pause)
 {
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
+       while (!signal_pending(current)) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+       }
        return -ERESTARTNOHAND;
 }
 
index 4bffd62c2f13beff38787b8a3e625932492a965f..4fc92445a29c920405935176b473485af8140f17 100644 (file)
@@ -1506,7 +1506,7 @@ static struct ctl_table fs_table[] = {
 
 static struct ctl_table debug_table[] = {
 #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \
-    defined(CONFIG_S390)
+    defined(CONFIG_S390) || defined(CONFIG_TILE)
        {
                .procname       = "exception-trace",
                .data           = &show_unhandled_signals,
index 44646179eabae8e8fd848174869f7d1782c90be8..bff131b9510a425452428005afda0acf7c979507 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/user_namespace.h>
+#include <linux/proc_fs.h>
 
 static struct uts_namespace *create_uts_ns(void)
 {
@@ -79,3 +80,41 @@ void free_uts_ns(struct kref *kref)
        put_user_ns(ns->user_ns);
        kfree(ns);
 }
+
+static void *utsns_get(struct task_struct *task)
+{
+       struct uts_namespace *ns = NULL;
+       struct nsproxy *nsproxy;
+
+       rcu_read_lock();
+       nsproxy = task_nsproxy(task);
+       if (nsproxy) {
+               ns = nsproxy->uts_ns;
+               get_uts_ns(ns);
+       }
+       rcu_read_unlock();
+
+       return ns;
+}
+
+static void utsns_put(void *ns)
+{
+       put_uts_ns(ns);
+}
+
+static int utsns_install(struct nsproxy *nsproxy, void *ns)
+{
+       get_uts_ns(ns);
+       put_uts_ns(nsproxy->uts_ns);
+       nsproxy->uts_ns = ns;
+       return 0;
+}
+
+const struct proc_ns_operations utsns_operations = {
+       .name           = "uts",
+       .type           = CLONE_NEWUTS,
+       .get            = utsns_get,
+       .put            = utsns_put,
+       .install        = utsns_install,
+};
+
index 0efcdca9751ac7f24d05ab8a828f0c0f2c757069..28afa4c5333c121e8a9feac719892fb17e5ef9a0 100644 (file)
@@ -670,6 +670,15 @@ config STACKTRACE
        bool
        depends on STACKTRACE_SUPPORT
 
+config DEBUG_STACK_USAGE
+       bool "Stack utilization instrumentation"
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
 config DEBUG_KOBJECT
        bool "kobject debugging"
        depends on DEBUG_KERNEL
@@ -983,6 +992,17 @@ config DEBUG_FORCE_WEAK_PER_CPU
          To ensure that generic code follows the above rules, this
          option forces all percpu variables to be defined as weak.
 
+config DEBUG_PER_CPU_MAPS
+       bool "Debug access to per_cpu maps"
+       depends on DEBUG_KERNEL
+       depends on SMP
+       help
+         Say Y to verify that the per_cpu map being accessed has
+         been set up. This adds a fair amount of code to kernel memory
+         and decreases performance.
+
+         Say N if unsure.
+
 config LKDTM
        tristate "Linux Kernel Dump Test Tool Module"
        depends on DEBUG_FS
index 8e7dc1c63aa9b1d5ce1fcdc8fa5796578b93aaed..76bbed4a20e55d85ebdfc32881d436ee98592f4f 100644 (file)
@@ -36,8 +36,10 @@ int audit_classify_arch(int arch)
 int audit_classify_syscall(int abi, unsigned syscall)
 {
        switch(syscall) {
+#ifdef __NR_open
        case __NR_open:
                return 2;
+#endif
 #ifdef __NR_openat
        case __NR_openat:
                return 3;
index 91e0ccfdb4241b1651d70d8b8bd2e4c903a4599e..41baf02924e64cc926ef3b2560a8f02c76c1bbf0 100644 (file)
@@ -571,8 +571,11 @@ int bitmap_scnlistprintf(char *buf, unsigned int buflen,
 EXPORT_SYMBOL(bitmap_scnlistprintf);
 
 /**
- * bitmap_parselist - convert list format ASCII string to bitmap
+ * __bitmap_parselist - convert list format ASCII string to bitmap
  * @bp: read nul-terminated user string from this buffer
+ * @buflen: buffer size in bytes.  If string is smaller than this
+ *    then it must be terminated with a \0.
+ * @is_user: location of buffer, 0 indicates kernel space
  * @maskp: write resulting mask here
  * @nmaskbits: number of bits in mask to be written
  *
@@ -587,20 +590,63 @@ EXPORT_SYMBOL(bitmap_scnlistprintf);
  *    %-EINVAL: invalid character in string
  *    %-ERANGE: bit number specified too large for mask
  */
-int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
+static int __bitmap_parselist(const char *buf, unsigned int buflen,
+               int is_user, unsigned long *maskp,
+               int nmaskbits)
 {
        unsigned a, b;
+       int c, old_c, totaldigits;
+       const char __user *ubuf = buf;
+       int exp_digit, in_range;
 
+       totaldigits = c = 0;
        bitmap_zero(maskp, nmaskbits);
        do {
-               if (!isdigit(*bp))
-                       return -EINVAL;
-               b = a = simple_strtoul(bp, (char **)&bp, BASEDEC);
-               if (*bp == '-') {
-                       bp++;
-                       if (!isdigit(*bp))
+               exp_digit = 1;
+               in_range = 0;
+               a = b = 0;
+
+               /* Get the next cpu# or a range of cpu#'s */
+               while (buflen) {
+                       old_c = c;
+                       if (is_user) {
+                               if (__get_user(c, ubuf++))
+                                       return -EFAULT;
+                       } else
+                               c = *buf++;
+                       buflen--;
+                       if (isspace(c))
+                               continue;
+
+                       /*
+                        * If the last character was a space and the current
+                        * character isn't '\0', we've got embedded whitespace.
+                        * This is a no-no, so throw an error.
+                        */
+                       if (totaldigits && c && isspace(old_c))
+                               return -EINVAL;
+
+                       /* A '\0' or a ',' signal the end of a cpu# or range */
+                       if (c == '\0' || c == ',')
+                               break;
+
+                       if (c == '-') {
+                               if (exp_digit || in_range)
+                                       return -EINVAL;
+                               b = 0;
+                               in_range = 1;
+                               exp_digit = 1;
+                               continue;
+                       }
+
+                       if (!isdigit(c))
                                return -EINVAL;
-                       b = simple_strtoul(bp, (char **)&bp, BASEDEC);
+
+                       b = b * 10 + (c - '0');
+                       if (!in_range)
+                               a = b;
+                       exp_digit = 0;
+                       totaldigits++;
                }
                if (!(a <= b))
                        return -EINVAL;
@@ -610,13 +656,52 @@ int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
                        set_bit(a, maskp);
                        a++;
                }
-               if (*bp == ',')
-                       bp++;
-       } while (*bp != '\0' && *bp != '\n');
+       } while (buflen && c == ',');
        return 0;
 }
+
+int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits)
+{
+       char *nl  = strchr(bp, '\n');
+       int len;
+
+       if (nl)
+               len = nl - bp;
+       else
+               len = strlen(bp);
+
+       return __bitmap_parselist(bp, len, 0, maskp, nmaskbits);
+}
 EXPORT_SYMBOL(bitmap_parselist);
 
+
+/**
+ * bitmap_parselist_user()
+ *
+ * @ubuf: pointer to user buffer containing string.
+ * @ulen: buffer size in bytes.  If string is smaller than this
+ *    then it must be terminated with a \0.
+ * @maskp: pointer to bitmap array that will contain result.
+ * @nmaskbits: size of bitmap, in bits.
+ *
+ * Wrapper for bitmap_parselist(), providing it with user buffer.
+ *
+ * We cannot have this as an inline function in bitmap.h because it needs
+ * linux/uaccess.h to get the access_ok() declaration and this causes
+ * cyclic dependencies.
+ */
+int bitmap_parselist_user(const char __user *ubuf,
+                       unsigned int ulen, unsigned long *maskp,
+                       int nmaskbits)
+{
+       if (!access_ok(VERIFY_READ, ubuf, ulen))
+               return -EFAULT;
+       return __bitmap_parselist((const char *)ubuf,
+                                       ulen, 1, maskp, nmaskbits);
+}
+EXPORT_SYMBOL(bitmap_parselist_user);
+
+
 /**
  * bitmap_pos_to_ord - find ordinal of set bit at given position in bitmap
  *     @buf: pointer to a bitmap
index 1923f1490e72618b36756b326bbd2e280d71bd49..577ddf8059758b05ecf9871c2409e3c8d346b5c6 100644 (file)
@@ -39,17 +39,20 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
 EXPORT_SYMBOL(gen_pool_create);
 
 /**
- * gen_pool_add - add a new chunk of special memory to the pool
+ * gen_pool_add_virt - add a new chunk of special memory to the pool
  * @pool: pool to add new memory chunk to
- * @addr: starting address of memory chunk to add to pool
+ * @virt: virtual starting address of memory chunk to add to pool
+ * @phys: physical starting address of memory chunk to add to pool
  * @size: size in bytes of the memory chunk to add to pool
  * @nid: node id of the node the chunk structure and bitmap should be
  *       allocated on, or -1
  *
  * Add a new chunk of special memory to the specified pool.
+ *
+ * Returns 0 on success or a -ve errno on failure.
  */
-int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
-                int nid)
+int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,
+                size_t size, int nid)
 {
        struct gen_pool_chunk *chunk;
        int nbits = size >> pool->min_alloc_order;
@@ -58,11 +61,12 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
 
        chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid);
        if (unlikely(chunk == NULL))
-               return -1;
+               return -ENOMEM;
 
        spin_lock_init(&chunk->lock);
-       chunk->start_addr = addr;
-       chunk->end_addr = addr + size;
+       chunk->phys_addr = phys;
+       chunk->start_addr = virt;
+       chunk->end_addr = virt + size;
 
        write_lock(&pool->lock);
        list_add(&chunk->next_chunk, &pool->chunks);
@@ -70,7 +74,32 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
 
        return 0;
 }
-EXPORT_SYMBOL(gen_pool_add);
+EXPORT_SYMBOL(gen_pool_add_virt);
+
+/**
+ * gen_pool_virt_to_phys - return the physical address of memory
+ * @pool: pool to allocate from
+ * @addr: starting address of memory
+ *
+ * Returns the physical address on success, or -1 on error.
+ */
+phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
+{
+       struct list_head *_chunk;
+       struct gen_pool_chunk *chunk;
+
+       read_lock(&pool->lock);
+       list_for_each(_chunk, &pool->chunks) {
+               chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+
+               if (addr >= chunk->start_addr && addr < chunk->end_addr)
+                       return chunk->phys_addr + addr - chunk->start_addr;
+       }
+       read_unlock(&pool->lock);
+
+       return -1;
+}
+EXPORT_SYMBOL(gen_pool_virt_to_phys);
 
 /**
  * gen_pool_destroy - destroy a special memory pool
index a235f3cc471c6d427fd4c2e713a701fa0b1e7e1b..2dbae88090ac3232f591f98289521fa3c9f3b3dd 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <asm/uaccess.h>
 
 static inline char _tolower(const char c)
 {
@@ -222,3 +223,28 @@ int kstrtos8(const char *s, unsigned int base, s8 *res)
        return 0;
 }
 EXPORT_SYMBOL(kstrtos8);
+
+#define kstrto_from_user(f, g, type)                                   \
+int f(const char __user *s, size_t count, unsigned int base, type *res)        \
+{                                                                      \
+       /* sign, base 2 representation, newline, terminator */          \
+       char buf[1 + sizeof(type) * 8 + 1 + 1];                         \
+                                                                       \
+       count = min(count, sizeof(buf) - 1);                            \
+       if (copy_from_user(buf, s, count))                              \
+               return -EFAULT;                                         \
+       buf[count] = '\0';                                              \
+       return g(buf, base, res);                                       \
+}                                                                      \
+EXPORT_SYMBOL(f)
+
+kstrto_from_user(kstrtoull_from_user,  kstrtoull,      unsigned long long);
+kstrto_from_user(kstrtoll_from_user,   kstrtoll,       long long);
+kstrto_from_user(kstrtoul_from_user,   kstrtoul,       unsigned long);
+kstrto_from_user(kstrtol_from_user,    kstrtol,        long);
+kstrto_from_user(kstrtouint_from_user, kstrtouint,     unsigned int);
+kstrto_from_user(kstrtoint_from_user,  kstrtoint,      int);
+kstrto_from_user(kstrtou16_from_user,  kstrtou16,      u16);
+kstrto_from_user(kstrtos16_from_user,  kstrtos16,      s16);
+kstrto_from_user(kstrtou8_from_user,   kstrtou8,       u8);
+kstrto_from_user(kstrtos8_from_user,   kstrtos8,       s8);
index 270de9d31b8c1a04940489e6bdd60b06480179b2..a07e7268d7ed4aa446f590076fed5a86aab96877 100644 (file)
@@ -84,7 +84,7 @@ struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
        if (e_count > LC_MAX_ACTIVE)
                return NULL;
 
-       slot = kzalloc(e_count * sizeof(struct hlist_head*), GFP_KERNEL);
+       slot = kcalloc(e_count, sizeof(struct hlist_head), GFP_KERNEL);
        if (!slot)
                goto out_fail;
        element = kzalloc(e_count * sizeof(struct lc_element *), GFP_KERNEL);
index 90cbe4bb5960fc480eaf45273638159ac48d2aa7..4407f8c9b1f71046d8b4aec0519734491b8bdd2a 100644 (file)
@@ -16,7 +16,7 @@ void show_mem(unsigned int filter)
                nonshared = 0, highmem = 0;
 
        printk("Mem-Info:\n");
-       __show_free_areas(filter);
+       show_free_areas(filter);
 
        for_each_online_pgdat(pgdat) {
                unsigned long i, flags;
index 1d659d7bb0f8ed595156f9863f773c476fe68d23..c11205688fb4d4ff070409557b633cf05c2d7c07 100644 (file)
@@ -898,7 +898,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
        case 'U':
                return uuid_string(buf, end, ptr, spec, fmt);
        case 'V':
-               return buf + vsnprintf(buf, end - buf,
+               return buf + vsnprintf(buf, end > buf ? end - buf : 0,
                                       ((struct va_format *)ptr)->fmt,
                                       *(((struct va_format *)ptr)->va));
        case 'K':
index befc87531e4fe0f7630f65195f00806d1feaaeef..f032e6e1e09af069bbaab3537a6169827237189d 100644 (file)
@@ -63,10 +63,10 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
        unsigned long background_thresh;
        unsigned long dirty_thresh;
        unsigned long bdi_thresh;
-       unsigned long nr_dirty, nr_io, nr_more_io, nr_wb;
+       unsigned long nr_dirty, nr_io, nr_more_io;
        struct inode *inode;
 
-       nr_wb = nr_dirty = nr_io = nr_more_io = 0;
+       nr_dirty = nr_io = nr_more_io = 0;
        spin_lock(&inode_wb_list_lock);
        list_for_each_entry(inode, &wb->b_dirty, i_wb_list)
                nr_dirty++;
index c641edf553a9373dd3f2c3a20c584fa3dcb2c957..68e782b3d3de0c0f1da75750dd57374cf1a03e89 100644 (file)
 /*
  * Lock ordering:
  *
- *  ->i_mmap_lock              (truncate_pagecache)
+ *  ->i_mmap_mutex             (truncate_pagecache)
  *    ->private_lock           (__free_pte->__set_page_dirty_buffers)
  *      ->swap_lock            (exclusive_swap_page, others)
  *        ->mapping->tree_lock
  *
  *  ->i_mutex
- *    ->i_mmap_lock            (truncate->unmap_mapping_range)
+ *    ->i_mmap_mutex           (truncate->unmap_mapping_range)
  *
  *  ->mmap_sem
- *    ->i_mmap_lock
+ *    ->i_mmap_mutex
  *      ->page_table_lock or pte_lock  (various, mainly in memory.c)
  *        ->mapping->tree_lock (arch-dependent flush_dcache_mmap_lock)
  *
@@ -84,7 +84,7 @@
  *    sb_lock                  (fs/fs-writeback.c)
  *    ->mapping->tree_lock     (__sync_single_inode)
  *
- *  ->i_mmap_lock
+ *  ->i_mmap_mutex
  *    ->anon_vma.lock          (vma_adjust)
  *
  *  ->anon_vma.lock
  *
  *  (code doesn't rely on that order, so you could switch it around)
  *  ->tasklist_lock             (memory_failure, collect_procs_ao)
- *    ->i_mmap_lock
+ *    ->i_mmap_mutex
  */
 
 /*
@@ -562,6 +562,17 @@ void wait_on_page_bit(struct page *page, int bit_nr)
 }
 EXPORT_SYMBOL(wait_on_page_bit);
 
+int wait_on_page_bit_killable(struct page *page, int bit_nr)
+{
+       DEFINE_WAIT_BIT(wait, &page->flags, bit_nr);
+
+       if (!test_bit(bit_nr, &page->flags))
+               return 0;
+
+       return __wait_on_bit(page_waitqueue(page), &wait,
+                            sleep_on_page_killable, TASK_KILLABLE);
+}
+
 /**
  * add_page_wait_queue - Add an arbitrary waiter to a page's wait queue
  * @page: Page defining the wait queue of interest
@@ -643,15 +654,32 @@ EXPORT_SYMBOL_GPL(__lock_page_killable);
 int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
                         unsigned int flags)
 {
-       if (!(flags & FAULT_FLAG_ALLOW_RETRY)) {
-               __lock_page(page);
-               return 1;
-       } else {
-               if (!(flags & FAULT_FLAG_RETRY_NOWAIT)) {
-                       up_read(&mm->mmap_sem);
+       if (flags & FAULT_FLAG_ALLOW_RETRY) {
+               /*
+                * CAUTION! In this case, mmap_sem is not released
+                * even though return 0.
+                */
+               if (flags & FAULT_FLAG_RETRY_NOWAIT)
+                       return 0;
+
+               up_read(&mm->mmap_sem);
+               if (flags & FAULT_FLAG_KILLABLE)
+                       wait_on_page_locked_killable(page);
+               else
                        wait_on_page_locked(page);
-               }
                return 0;
+       } else {
+               if (flags & FAULT_FLAG_KILLABLE) {
+                       int ret;
+
+                       ret = __lock_page_killable(page);
+                       if (ret) {
+                               up_read(&mm->mmap_sem);
+                               return 0;
+                       }
+               } else
+                       __lock_page(page);
+               return 1;
        }
 }
 
@@ -1528,15 +1556,17 @@ static void do_sync_mmap_readahead(struct vm_area_struct *vma,
        /* If we don't want any read-ahead, don't bother */
        if (VM_RandomReadHint(vma))
                return;
+       if (!ra->ra_pages)
+               return;
 
-       if (VM_SequentialReadHint(vma) ||
-                       offset - 1 == (ra->prev_pos >> PAGE_CACHE_SHIFT)) {
+       if (VM_SequentialReadHint(vma)) {
                page_cache_sync_readahead(mapping, ra, file, offset,
                                          ra->ra_pages);
                return;
        }
 
-       if (ra->mmap_miss < INT_MAX)
+       /* Avoid banging the cache line if not needed */
+       if (ra->mmap_miss < MMAP_LOTSAMISS * 10)
                ra->mmap_miss++;
 
        /*
@@ -1550,12 +1580,10 @@ static void do_sync_mmap_readahead(struct vm_area_struct *vma,
         * mmap read-around
         */
        ra_pages = max_sane_readahead(ra->ra_pages);
-       if (ra_pages) {
-               ra->start = max_t(long, 0, offset - ra_pages/2);
-               ra->size = ra_pages;
-               ra->async_size = 0;
-               ra_submit(ra, mapping, file);
-       }
+       ra->start = max_t(long, 0, offset - ra_pages / 2);
+       ra->size = ra_pages;
+       ra->async_size = ra_pages / 4;
+       ra_submit(ra, mapping, file);
 }
 
 /*
@@ -1660,7 +1688,6 @@ retry_find:
                return VM_FAULT_SIGBUS;
        }
 
-       ra->prev_pos = (loff_t)offset << PAGE_CACHE_SHIFT;
        vmf->page = page;
        return ret | VM_FAULT_LOCKED;
 
index 83364df74a33811ea7aea971412bfe91d4fe9c17..93356cd12828a40eb4d635a9e0e0bea3d6ba0790 100644 (file)
@@ -183,7 +183,7 @@ __xip_unmap (struct address_space * mapping,
                return;
 
 retry:
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                mm = vma->vm_mm;
                address = vma->vm_start +
@@ -201,7 +201,7 @@ retry:
                        page_cache_release(page);
                }
        }
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
 
        if (locked) {
                mutex_unlock(&xip_sparse_mutex);
index ec520c7b28dffedb5027de6b27834831938671cd..7f4123056e0603ce3bae84c3fea05a7444160dc8 100644 (file)
@@ -211,13 +211,13 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
                        }
                        goto out;
                }
-               spin_lock(&mapping->i_mmap_lock);
+               mutex_lock(&mapping->i_mmap_mutex);
                flush_dcache_mmap_lock(mapping);
                vma->vm_flags |= VM_NONLINEAR;
                vma_prio_tree_remove(vma, &mapping->i_mmap);
                vma_nonlinear_insert(vma, &mapping->i_mmap_nonlinear);
                flush_dcache_mmap_unlock(mapping);
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
        }
 
        if (vma->vm_flags & VM_LOCKED) {
index 83326ad66d9b15df1027a0274d92886c85386394..615d9743a3cbad1ca19d745c45115eecb1c463f4 100644 (file)
@@ -1139,7 +1139,7 @@ static int __split_huge_page_splitting(struct page *page,
                 * We can't temporarily set the pmd to null in order
                 * to split it, the pmd must remain marked huge at all
                 * times or the VM won't take the pmd_trans_huge paths
-                * and it won't wait on the anon_vma->root->lock to
+                * and it won't wait on the anon_vma->root->mutex to
                 * serialize against split_huge_page*.
                 */
                pmdp_splitting_flush_notify(vma, address, pmd);
@@ -1333,7 +1333,7 @@ static int __split_huge_page_map(struct page *page,
        return ret;
 }
 
-/* must be called with anon_vma->root->lock hold */
+/* must be called with anon_vma->root->mutex hold */
 static void __split_huge_page(struct page *page,
                              struct anon_vma *anon_vma)
 {
@@ -1771,12 +1771,9 @@ static void collapse_huge_page(struct mm_struct *mm,
 
        VM_BUG_ON(address & ~HPAGE_PMD_MASK);
 #ifndef CONFIG_NUMA
+       up_read(&mm->mmap_sem);
        VM_BUG_ON(!*hpage);
        new_page = *hpage;
-       if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
-               up_read(&mm->mmap_sem);
-               return;
-       }
 #else
        VM_BUG_ON(*hpage);
        /*
@@ -1791,22 +1788,26 @@ static void collapse_huge_page(struct mm_struct *mm,
         */
        new_page = alloc_hugepage_vma(khugepaged_defrag(), vma, address,
                                      node, __GFP_OTHER_NODE);
+
+       /*
+        * After allocating the hugepage, release the mmap_sem read lock in
+        * preparation for taking it in write mode.
+        */
+       up_read(&mm->mmap_sem);
        if (unlikely(!new_page)) {
-               up_read(&mm->mmap_sem);
                count_vm_event(THP_COLLAPSE_ALLOC_FAILED);
                *hpage = ERR_PTR(-ENOMEM);
                return;
        }
+#endif
+
        count_vm_event(THP_COLLAPSE_ALLOC);
        if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
-               up_read(&mm->mmap_sem);
+#ifdef CONFIG_NUMA
                put_page(new_page);
+#endif
                return;
        }
-#endif
-
-       /* after allocating the hugepage upgrade to mmap_sem write mode */
-       up_read(&mm->mmap_sem);
 
        /*
         * Prevent all access to pagetables with the exception of
index bbb4a5bbb9582055945237692b8938a731c5492a..5fd68b95c671bafd2687ab696e04a0ae73a17012 100644 (file)
@@ -2205,7 +2205,7 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
        unsigned long sz = huge_page_size(h);
 
        /*
-        * A page gathering list, protected by per file i_mmap_lock. The
+        * A page gathering list, protected by per file i_mmap_mutex. The
         * lock is used to avoid list corruption from multiple unmapping
         * of the same page since we are using page->lru.
         */
@@ -2274,9 +2274,9 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
 void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
                          unsigned long end, struct page *ref_page)
 {
-       spin_lock(&vma->vm_file->f_mapping->i_mmap_lock);
+       mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex);
        __unmap_hugepage_range(vma, start, end, ref_page);
-       spin_unlock(&vma->vm_file->f_mapping->i_mmap_lock);
+       mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
 }
 
 /*
@@ -2308,7 +2308,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
         * this mapping should be shared between all the VMAs,
         * __unmap_hugepage_range() is called as the lock is already held
         */
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(iter_vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                /* Do not unmap the current VMA */
                if (iter_vma == vma)
@@ -2326,7 +2326,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
                                address, address + huge_page_size(h),
                                page);
        }
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
 
        return 1;
 }
@@ -2810,7 +2810,7 @@ void hugetlb_change_protection(struct vm_area_struct *vma,
        BUG_ON(address >= end);
        flush_cache_range(vma, address, end);
 
-       spin_lock(&vma->vm_file->f_mapping->i_mmap_lock);
+       mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex);
        spin_lock(&mm->page_table_lock);
        for (; address < end; address += huge_page_size(h)) {
                ptep = huge_pte_offset(mm, address);
@@ -2825,7 +2825,7 @@ void hugetlb_change_protection(struct vm_area_struct *vma,
                }
        }
        spin_unlock(&mm->page_table_lock);
-       spin_unlock(&vma->vm_file->f_mapping->i_mmap_lock);
+       mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
 
        flush_tlb_range(vma, start, end);
 }
index 1d29cdfe8ebb6b2c21f1b0fafe68509bba14b2ab..4019979b263722098b8231391e9a7ae82dc153f6 100644 (file)
@@ -21,6 +21,5 @@ struct mm_struct init_mm = {
        .mmap_sem       = __RWSEM_INITIALIZER(init_mm.mmap_sem),
        .page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
        .mmlist         = LIST_HEAD_INIT(init_mm.mmlist),
-       .cpu_vm_mask    = CPU_MASK_ALL,
        INIT_MM_CONTEXT(init_mm)
 };
index 9d0ced8e505e9276dabb42e129a4b918966a2421..d071d380fb498ab36ac6700343bf86485463bdbe 100644 (file)
@@ -66,6 +66,10 @@ static inline unsigned long page_order(struct page *page)
        return page_private(page);
 }
 
+/* mm/util.c */
+void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
+               struct vm_area_struct *prev, struct rb_node *rb_parent);
+
 #ifdef CONFIG_MMU
 extern long mlock_vma_pages_range(struct vm_area_struct *vma,
                        unsigned long start, unsigned long end);
index 942dfc73a2ff89c3c7c96b3f9b1838c99ec16d02..d708b3ef2260282a3d6e5784a60c1fb003339f8e 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -35,6 +35,7 @@
 #include <linux/ksm.h>
 #include <linux/hash.h>
 #include <linux/freezer.h>
+#include <linux/oom.h>
 
 #include <asm/tlbflush.h>
 #include "internal.h"
@@ -1894,9 +1895,11 @@ static ssize_t run_store(struct kobject *kobj, struct kobj_attribute *attr,
        if (ksm_run != flags) {
                ksm_run = flags;
                if (flags & KSM_RUN_UNMERGE) {
-                       current->flags |= PF_OOM_ORIGIN;
+                       int oom_score_adj;
+
+                       oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX);
                        err = unmerge_and_remove_all_rmap_items();
-                       current->flags &= ~PF_OOM_ORIGIN;
+                       test_set_oom_score_adj(oom_score_adj);
                        if (err) {
                                ksm_run = KSM_RUN_STOP;
                                count = err;
index 010f9166fa6ea099b7ab7b5ccdefe7af8cf033f4..d5fd3dcd3f2e1f38278a73d8131cd80d7f6adc6d 100644 (file)
@@ -5169,19 +5169,12 @@ struct cgroup_subsys mem_cgroup_subsys = {
 static int __init enable_swap_account(char *s)
 {
        /* consider enabled if no parameter or 1 is given */
-       if (!(*s) || !strcmp(s, "=1"))
+       if (!strcmp(s, "1"))
                really_do_swap_account = 1;
-       else if (!strcmp(s, "=0"))
+       else if (!strcmp(s, "0"))
                really_do_swap_account = 0;
        return 1;
 }
-__setup("swapaccount", enable_swap_account);
+__setup("swapaccount=", enable_swap_account);
 
-static int __init disable_swap_account(char *s)
-{
-       printk_once("noswapaccount is deprecated and will be removed in 2.6.40. Use swapaccount=0 instead\n");
-       enable_swap_account("=0");
-       return 1;
-}
-__setup("noswapaccount", disable_swap_account);
 #endif
index 2b9a5eef39e0661d48e7a9976780345587aff80c..5c8f7e08928d5faba209a0392b4b2befe17a67e3 100644 (file)
@@ -239,7 +239,11 @@ void shake_page(struct page *p, int access)
        if (access) {
                int nr;
                do {
-                       nr = shrink_slab(1000, GFP_KERNEL, 1000);
+                       struct shrink_control shrink = {
+                               .gfp_mask = GFP_KERNEL,
+                       };
+
+                       nr = shrink_slab(&shrink, 1000, 1000);
                        if (page_count(p) == 1)
                                break;
                } while (nr > 10);
@@ -429,7 +433,7 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
         */
 
        read_lock(&tasklist_lock);
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        for_each_process(tsk) {
                pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
 
@@ -449,7 +453,7 @@ static void collect_procs_file(struct page *page, struct list_head *to_kill,
                                add_to_kill(tsk, page, vma, to_kill, tkc);
                }
        }
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        read_unlock(&tasklist_lock);
 }
 
@@ -1440,16 +1444,12 @@ int soft_offline_page(struct page *page, int flags)
         */
        ret = invalidate_inode_page(page);
        unlock_page(page);
-
        /*
-        * Drop count because page migration doesn't like raised
-        * counts. The page could get re-allocated, but if it becomes
-        * LRU the isolation will just fail.
         * RED-PEN would be better to keep it isolated here, but we
         * would need to fix isolation locking first.
         */
-       put_page(page);
        if (ret == 1) {
+               put_page(page);
                ret = 0;
                pr_info("soft_offline: %#lx: invalidated\n", pfn);
                goto done;
@@ -1461,6 +1461,11 @@ int soft_offline_page(struct page *page, int flags)
         * handles a large number of cases for us.
         */
        ret = isolate_lru_page(page);
+       /*
+        * Drop page reference which is came from get_any_page()
+        * successful isolate_lru_page() already took another one.
+        */
+       put_page(page);
        if (!ret) {
                LIST_HEAD(pagelist);
 
index 61e66f026563b4b473fc73922d58a984c490c827..b73f677f0bb1dac6dc18e8b14765da0167cc3f11 100644 (file)
@@ -182,7 +182,7 @@ void sync_mm_rss(struct task_struct *task, struct mm_struct *mm)
 {
        __sync_task_rss_stat(task, mm);
 }
-#else
+#else /* SPLIT_RSS_COUNTING */
 
 #define inc_mm_counter_fast(mm, member) inc_mm_counter(mm, member)
 #define dec_mm_counter_fast(mm, member) dec_mm_counter(mm, member)
@@ -191,8 +191,205 @@ static void check_sync_rss_stat(struct task_struct *task)
 {
 }
 
+#endif /* SPLIT_RSS_COUNTING */
+
+#ifdef HAVE_GENERIC_MMU_GATHER
+
+static int tlb_next_batch(struct mmu_gather *tlb)
+{
+       struct mmu_gather_batch *batch;
+
+       batch = tlb->active;
+       if (batch->next) {
+               tlb->active = batch->next;
+               return 1;
+       }
+
+       batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
+       if (!batch)
+               return 0;
+
+       batch->next = NULL;
+       batch->nr   = 0;
+       batch->max  = MAX_GATHER_BATCH;
+
+       tlb->active->next = batch;
+       tlb->active = batch;
+
+       return 1;
+}
+
+/* tlb_gather_mmu
+ *     Called to initialize an (on-stack) mmu_gather structure for page-table
+ *     tear-down from @mm. The @fullmm argument is used when @mm is without
+ *     users and we're going to destroy the full address space (exit/execve).
+ */
+void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm)
+{
+       tlb->mm = mm;
+
+       tlb->fullmm     = fullmm;
+       tlb->need_flush = 0;
+       tlb->fast_mode  = (num_possible_cpus() == 1);
+       tlb->local.next = NULL;
+       tlb->local.nr   = 0;
+       tlb->local.max  = ARRAY_SIZE(tlb->__pages);
+       tlb->active     = &tlb->local;
+
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       tlb->batch = NULL;
+#endif
+}
+
+void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+       struct mmu_gather_batch *batch;
+
+       if (!tlb->need_flush)
+               return;
+       tlb->need_flush = 0;
+       tlb_flush(tlb);
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+       tlb_table_flush(tlb);
 #endif
 
+       if (tlb_fast_mode(tlb))
+               return;
+
+       for (batch = &tlb->local; batch; batch = batch->next) {
+               free_pages_and_swap_cache(batch->pages, batch->nr);
+               batch->nr = 0;
+       }
+       tlb->active = &tlb->local;
+}
+
+/* tlb_finish_mmu
+ *     Called at the end of the shootdown operation to free up any resources
+ *     that were required.
+ */
+void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+{
+       struct mmu_gather_batch *batch, *next;
+
+       tlb_flush_mmu(tlb);
+
+       /* keep the page table cache within bounds */
+       check_pgt_cache();
+
+       for (batch = tlb->local.next; batch; batch = next) {
+               next = batch->next;
+               free_pages((unsigned long)batch, 0);
+       }
+       tlb->local.next = NULL;
+}
+
+/* __tlb_remove_page
+ *     Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while
+ *     handling the additional races in SMP caused by other CPUs caching valid
+ *     mappings in their TLBs. Returns the number of free page slots left.
+ *     When out of page slots we must call tlb_flush_mmu().
+ */
+int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+       struct mmu_gather_batch *batch;
+
+       tlb->need_flush = 1;
+
+       if (tlb_fast_mode(tlb)) {
+               free_page_and_swap_cache(page);
+               return 1; /* avoid calling tlb_flush_mmu() */
+       }
+
+       batch = tlb->active;
+       batch->pages[batch->nr++] = page;
+       if (batch->nr == batch->max) {
+               if (!tlb_next_batch(tlb))
+                       return 0;
+       }
+       VM_BUG_ON(batch->nr > batch->max);
+
+       return batch->max - batch->nr;
+}
+
+#endif /* HAVE_GENERIC_MMU_GATHER */
+
+#ifdef CONFIG_HAVE_RCU_TABLE_FREE
+
+/*
+ * See the comment near struct mmu_table_batch.
+ */
+
+static void tlb_remove_table_smp_sync(void *arg)
+{
+       /* Simply deliver the interrupt */
+}
+
+static void tlb_remove_table_one(void *table)
+{
+       /*
+        * This isn't an RCU grace period and hence the page-tables cannot be
+        * assumed to be actually RCU-freed.
+        *
+        * It is however sufficient for software page-table walkers that rely on
+        * IRQ disabling. See the comment near struct mmu_table_batch.
+        */
+       smp_call_function(tlb_remove_table_smp_sync, NULL, 1);
+       __tlb_remove_table(table);
+}
+
+static void tlb_remove_table_rcu(struct rcu_head *head)
+{
+       struct mmu_table_batch *batch;
+       int i;
+
+       batch = container_of(head, struct mmu_table_batch, rcu);
+
+       for (i = 0; i < batch->nr; i++)
+               __tlb_remove_table(batch->tables[i]);
+
+       free_page((unsigned long)batch);
+}
+
+void tlb_table_flush(struct mmu_gather *tlb)
+{
+       struct mmu_table_batch **batch = &tlb->batch;
+
+       if (*batch) {
+               call_rcu_sched(&(*batch)->rcu, tlb_remove_table_rcu);
+               *batch = NULL;
+       }
+}
+
+void tlb_remove_table(struct mmu_gather *tlb, void *table)
+{
+       struct mmu_table_batch **batch = &tlb->batch;
+
+       tlb->need_flush = 1;
+
+       /*
+        * When there's less then two users of this mm there cannot be a
+        * concurrent page-table walk.
+        */
+       if (atomic_read(&tlb->mm->mm_users) < 2) {
+               __tlb_remove_table(table);
+               return;
+       }
+
+       if (*batch == NULL) {
+               *batch = (struct mmu_table_batch *)__get_free_page(GFP_NOWAIT | __GFP_NOWARN);
+               if (*batch == NULL) {
+                       tlb_remove_table_one(table);
+                       return;
+               }
+               (*batch)->nr = 0;
+       }
+       (*batch)->tables[(*batch)->nr++] = table;
+       if ((*batch)->nr == MAX_TABLE_BATCH)
+               tlb_table_flush(tlb);
+}
+
+#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
+
 /*
  * If a p?d_bad entry is found while walking page tables, report
  * the error, before resetting entry to p?d_none.  Usually (but
@@ -909,26 +1106,24 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 static unsigned long zap_pte_range(struct mmu_gather *tlb,
                                struct vm_area_struct *vma, pmd_t *pmd,
                                unsigned long addr, unsigned long end,
-                               long *zap_work, struct zap_details *details)
+                               struct zap_details *details)
 {
        struct mm_struct *mm = tlb->mm;
-       pte_t *pte;
-       spinlock_t *ptl;
+       int force_flush = 0;
        int rss[NR_MM_COUNTERS];
+       spinlock_t *ptl;
+       pte_t *pte;
 
+again:
        init_rss_vec(rss);
-
        pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
        arch_enter_lazy_mmu_mode();
        do {
                pte_t ptent = *pte;
                if (pte_none(ptent)) {
-                       (*zap_work)--;
                        continue;
                }
 
-               (*zap_work) -= PAGE_SIZE;
-
                if (pte_present(ptent)) {
                        struct page *page;
 
@@ -974,7 +1169,9 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
                        page_remove_rmap(page);
                        if (unlikely(page_mapcount(page) < 0))
                                print_bad_pte(vma, addr, ptent, page);
-                       tlb_remove_page(tlb, page);
+                       force_flush = !__tlb_remove_page(tlb, page);
+                       if (force_flush)
+                               break;
                        continue;
                }
                /*
@@ -995,19 +1192,31 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
                                print_bad_pte(vma, addr, ptent, NULL);
                }
                pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
-       } while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0));
+       } while (pte++, addr += PAGE_SIZE, addr != end);
 
        add_mm_rss_vec(mm, rss);
        arch_leave_lazy_mmu_mode();
        pte_unmap_unlock(pte - 1, ptl);
 
+       /*
+        * mmu_gather ran out of room to batch pages, we break out of
+        * the PTE lock to avoid doing the potential expensive TLB invalidate
+        * and page-free while holding it.
+        */
+       if (force_flush) {
+               force_flush = 0;
+               tlb_flush_mmu(tlb);
+               if (addr != end)
+                       goto again;
+       }
+
        return addr;
 }
 
 static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
                                struct vm_area_struct *vma, pud_t *pud,
                                unsigned long addr, unsigned long end,
-                               long *zap_work, struct zap_details *details)
+                               struct zap_details *details)
 {
        pmd_t *pmd;
        unsigned long next;
@@ -1019,19 +1228,15 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
                        if (next-addr != HPAGE_PMD_SIZE) {
                                VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem));
                                split_huge_page_pmd(vma->vm_mm, pmd);
-                       } else if (zap_huge_pmd(tlb, vma, pmd)) {
-                               (*zap_work)--;
+                       } else if (zap_huge_pmd(tlb, vma, pmd))
                                continue;
-                       }
                        /* fall through */
                }
-               if (pmd_none_or_clear_bad(pmd)) {
-                       (*zap_work)--;
+               if (pmd_none_or_clear_bad(pmd))
                        continue;
-               }
-               next = zap_pte_range(tlb, vma, pmd, addr, next,
-                                               zap_work, details);
-       } while (pmd++, addr = next, (addr != end && *zap_work > 0));
+               next = zap_pte_range(tlb, vma, pmd, addr, next, details);
+               cond_resched();
+       } while (pmd++, addr = next, addr != end);
 
        return addr;
 }
@@ -1039,7 +1244,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
 static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
                                struct vm_area_struct *vma, pgd_t *pgd,
                                unsigned long addr, unsigned long end,
-                               long *zap_work, struct zap_details *details)
+                               struct zap_details *details)
 {
        pud_t *pud;
        unsigned long next;
@@ -1047,13 +1252,10 @@ static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
        pud = pud_offset(pgd, addr);
        do {
                next = pud_addr_end(addr, end);
-               if (pud_none_or_clear_bad(pud)) {
-                       (*zap_work)--;
+               if (pud_none_or_clear_bad(pud))
                        continue;
-               }
-               next = zap_pmd_range(tlb, vma, pud, addr, next,
-                                               zap_work, details);
-       } while (pud++, addr = next, (addr != end && *zap_work > 0));
+               next = zap_pmd_range(tlb, vma, pud, addr, next, details);
+       } while (pud++, addr = next, addr != end);
 
        return addr;
 }
@@ -1061,7 +1263,7 @@ static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
 static unsigned long unmap_page_range(struct mmu_gather *tlb,
                                struct vm_area_struct *vma,
                                unsigned long addr, unsigned long end,
-                               long *zap_work, struct zap_details *details)
+                               struct zap_details *details)
 {
        pgd_t *pgd;
        unsigned long next;
@@ -1075,13 +1277,10 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb,
        pgd = pgd_offset(vma->vm_mm, addr);
        do {
                next = pgd_addr_end(addr, end);
-               if (pgd_none_or_clear_bad(pgd)) {
-                       (*zap_work)--;
+               if (pgd_none_or_clear_bad(pgd))
                        continue;
-               }
-               next = zap_pud_range(tlb, vma, pgd, addr, next,
-                                               zap_work, details);
-       } while (pgd++, addr = next, (addr != end && *zap_work > 0));
+               next = zap_pud_range(tlb, vma, pgd, addr, next, details);
+       } while (pgd++, addr = next, addr != end);
        tlb_end_vma(tlb, vma);
        mem_cgroup_uncharge_end();
 
@@ -1121,17 +1320,12 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb,
  * ensure that any thus-far unmapped pages are flushed before unmap_vmas()
  * drops the lock and schedules.
  */
-unsigned long unmap_vmas(struct mmu_gather **tlbp,
+unsigned long unmap_vmas(struct mmu_gather *tlb,
                struct vm_area_struct *vma, unsigned long start_addr,
                unsigned long end_addr, unsigned long *nr_accounted,
                struct zap_details *details)
 {
-       long zap_work = ZAP_BLOCK_SIZE;
-       unsigned long tlb_start = 0;    /* For tlb_finish_mmu */
-       int tlb_start_valid = 0;
        unsigned long start = start_addr;
-       spinlock_t *i_mmap_lock = details? details->i_mmap_lock: NULL;
-       int fullmm = (*tlbp)->fullmm;
        struct mm_struct *mm = vma->vm_mm;
 
        mmu_notifier_invalidate_range_start(mm, start_addr, end_addr);
@@ -1152,11 +1346,6 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp,
                        untrack_pfn_vma(vma, 0, 0);
 
                while (start != end) {
-                       if (!tlb_start_valid) {
-                               tlb_start = start;
-                               tlb_start_valid = 1;
-                       }
-
                        if (unlikely(is_vm_hugetlb_page(vma))) {
                                /*
                                 * It is undesirable to test vma->vm_file as it
@@ -1169,39 +1358,15 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp,
                                 * Since no pte has actually been setup, it is
                                 * safe to do nothing in this case.
                                 */
-                               if (vma->vm_file) {
+                               if (vma->vm_file)
                                        unmap_hugepage_range(vma, start, end, NULL);
-                                       zap_work -= (end - start) /
-                                       pages_per_huge_page(hstate_vma(vma));
-                               }
 
                                start = end;
                        } else
-                               start = unmap_page_range(*tlbp, vma,
-                                               start, end, &zap_work, details);
-
-                       if (zap_work > 0) {
-                               BUG_ON(start != end);
-                               break;
-                       }
-
-                       tlb_finish_mmu(*tlbp, tlb_start, start);
-
-                       if (need_resched() ||
-                               (i_mmap_lock && spin_needbreak(i_mmap_lock))) {
-                               if (i_mmap_lock) {
-                                       *tlbp = NULL;
-                                       goto out;
-                               }
-                               cond_resched();
-                       }
-
-                       *tlbp = tlb_gather_mmu(vma->vm_mm, fullmm);
-                       tlb_start_valid = 0;
-                       zap_work = ZAP_BLOCK_SIZE;
+                               start = unmap_page_range(tlb, vma, start, end, details);
                }
        }
-out:
+
        mmu_notifier_invalidate_range_end(mm, start_addr, end_addr);
        return start;   /* which is now the end (or restart) address */
 }
@@ -1217,16 +1382,15 @@ unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address,
                unsigned long size, struct zap_details *details)
 {
        struct mm_struct *mm = vma->vm_mm;
-       struct mmu_gather *tlb;
+       struct mmu_gather tlb;
        unsigned long end = address + size;
        unsigned long nr_accounted = 0;
 
        lru_add_drain();
-       tlb = tlb_gather_mmu(mm, 0);
+       tlb_gather_mmu(&tlb, mm, 0);
        update_hiwater_rss(mm);
        end = unmap_vmas(&tlb, vma, address, end, &nr_accounted, details);
-       if (tlb)
-               tlb_finish_mmu(tlb, address, end);
+       tlb_finish_mmu(&tlb, address, end);
        return end;
 }
 
@@ -2535,96 +2699,11 @@ unwritable_page:
        return ret;
 }
 
-/*
- * Helper functions for unmap_mapping_range().
- *
- * __ Notes on dropping i_mmap_lock to reduce latency while unmapping __
- *
- * We have to restart searching the prio_tree whenever we drop the lock,
- * since the iterator is only valid while the lock is held, and anyway
- * a later vma might be split and reinserted earlier while lock dropped.
- *
- * The list of nonlinear vmas could be handled more efficiently, using
- * a placeholder, but handle it in the same way until a need is shown.
- * It is important to search the prio_tree before nonlinear list: a vma
- * may become nonlinear and be shifted from prio_tree to nonlinear list
- * while the lock is dropped; but never shifted from list to prio_tree.
- *
- * In order to make forward progress despite restarting the search,
- * vm_truncate_count is used to mark a vma as now dealt with, so we can
- * quickly skip it next time around.  Since the prio_tree search only
- * shows us those vmas affected by unmapping the range in question, we
- * can't efficiently keep all vmas in step with mapping->truncate_count:
- * so instead reset them all whenever it wraps back to 0 (then go to 1).
- * mapping->truncate_count and vma->vm_truncate_count are protected by
- * i_mmap_lock.
- *
- * In order to make forward progress despite repeatedly restarting some
- * large vma, note the restart_addr from unmap_vmas when it breaks out:
- * and restart from that address when we reach that vma again.  It might
- * have been split or merged, shrunk or extended, but never shifted: so
- * restart_addr remains valid so long as it remains in the vma's range.
- * unmap_mapping_range forces truncate_count to leap over page-aligned
- * values so we can save vma's restart_addr in its truncate_count field.
- */
-#define is_restart_addr(truncate_count) (!((truncate_count) & ~PAGE_MASK))
-
-static void reset_vma_truncate_counts(struct address_space *mapping)
-{
-       struct vm_area_struct *vma;
-       struct prio_tree_iter iter;
-
-       vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, 0, ULONG_MAX)
-               vma->vm_truncate_count = 0;
-       list_for_each_entry(vma, &mapping->i_mmap_nonlinear, shared.vm_set.list)
-               vma->vm_truncate_count = 0;
-}
-
-static int unmap_mapping_range_vma(struct vm_area_struct *vma,
+static void unmap_mapping_range_vma(struct vm_area_struct *vma,
                unsigned long start_addr, unsigned long end_addr,
                struct zap_details *details)
 {
-       unsigned long restart_addr;
-       int need_break;
-
-       /*
-        * files that support invalidating or truncating portions of the
-        * file from under mmaped areas must have their ->fault function
-        * return a locked page (and set VM_FAULT_LOCKED in the return).
-        * This provides synchronisation against concurrent unmapping here.
-        */
-
-again:
-       restart_addr = vma->vm_truncate_count;
-       if (is_restart_addr(restart_addr) && start_addr < restart_addr) {
-               start_addr = restart_addr;
-               if (start_addr >= end_addr) {
-                       /* Top of vma has been split off since last time */
-                       vma->vm_truncate_count = details->truncate_count;
-                       return 0;
-               }
-       }
-
-       restart_addr = zap_page_range(vma, start_addr,
-                                       end_addr - start_addr, details);
-       need_break = need_resched() || spin_needbreak(details->i_mmap_lock);
-
-       if (restart_addr >= end_addr) {
-               /* We have now completed this vma: mark it so */
-               vma->vm_truncate_count = details->truncate_count;
-               if (!need_break)
-                       return 0;
-       } else {
-               /* Note restart_addr in vma's truncate_count field */
-               vma->vm_truncate_count = restart_addr;
-               if (!need_break)
-                       goto again;
-       }
-
-       spin_unlock(details->i_mmap_lock);
-       cond_resched();
-       spin_lock(details->i_mmap_lock);
-       return -EINTR;
+       zap_page_range(vma, start_addr, end_addr - start_addr, details);
 }
 
 static inline void unmap_mapping_range_tree(struct prio_tree_root *root,
@@ -2634,12 +2713,8 @@ static inline void unmap_mapping_range_tree(struct prio_tree_root *root,
        struct prio_tree_iter iter;
        pgoff_t vba, vea, zba, zea;
 
-restart:
        vma_prio_tree_foreach(vma, &iter, root,
                        details->first_index, details->last_index) {
-               /* Skip quickly over those we have already dealt with */
-               if (vma->vm_truncate_count == details->truncate_count)
-                       continue;
 
                vba = vma->vm_pgoff;
                vea = vba + ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) - 1;
@@ -2651,11 +2726,10 @@ restart:
                if (zea > vea)
                        zea = vea;
 
-               if (unmap_mapping_range_vma(vma,
+               unmap_mapping_range_vma(vma,
                        ((zba - vba) << PAGE_SHIFT) + vma->vm_start,
                        ((zea - vba + 1) << PAGE_SHIFT) + vma->vm_start,
-                               details) < 0)
-                       goto restart;
+                               details);
        }
 }
 
@@ -2670,15 +2744,9 @@ static inline void unmap_mapping_range_list(struct list_head *head,
         * across *all* the pages in each nonlinear VMA, not just the pages
         * whose virtual address lies outside the file truncation point.
         */
-restart:
        list_for_each_entry(vma, head, shared.vm_set.list) {
-               /* Skip quickly over those we have already dealt with */
-               if (vma->vm_truncate_count == details->truncate_count)
-                       continue;
                details->nonlinear_vma = vma;
-               if (unmap_mapping_range_vma(vma, vma->vm_start,
-                                       vma->vm_end, details) < 0)
-                       goto restart;
+               unmap_mapping_range_vma(vma, vma->vm_start, vma->vm_end, details);
        }
 }
 
@@ -2717,26 +2785,14 @@ void unmap_mapping_range(struct address_space *mapping,
        details.last_index = hba + hlen - 1;
        if (details.last_index < details.first_index)
                details.last_index = ULONG_MAX;
-       details.i_mmap_lock = &mapping->i_mmap_lock;
 
-       mutex_lock(&mapping->unmap_mutex);
-       spin_lock(&mapping->i_mmap_lock);
-
-       /* Protect against endless unmapping loops */
-       mapping->truncate_count++;
-       if (unlikely(is_restart_addr(mapping->truncate_count))) {
-               if (mapping->truncate_count == 0)
-                       reset_vma_truncate_counts(mapping);
-               mapping->truncate_count++;
-       }
-       details.truncate_count = mapping->truncate_count;
 
+       mutex_lock(&mapping->i_mmap_mutex);
        if (unlikely(!prio_tree_empty(&mapping->i_mmap)))
                unmap_mapping_range_tree(&mapping->i_mmap, &details);
        if (unlikely(!list_empty(&mapping->i_mmap_nonlinear)))
                unmap_mapping_range_list(&mapping->i_mmap_nonlinear, &details);
-       spin_unlock(&mapping->i_mmap_lock);
-       mutex_unlock(&mapping->unmap_mutex);
+       mutex_unlock(&mapping->i_mmap_mutex);
 }
 EXPORT_SYMBOL(unmap_mapping_range);
 
@@ -2966,7 +3022,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo
                if (prev && prev->vm_end == address)
                        return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM;
 
-               expand_stack(vma, address - PAGE_SIZE);
+               expand_downwards(vma, address - PAGE_SIZE);
        }
        if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) {
                struct vm_area_struct *next = vma->vm_next;
index 9ca1d604f7cd74aab7a897de22e0784a8c0bcb45..9f646374e32f5ec7704b86ad653c2794037b830a 100644 (file)
@@ -374,10 +374,6 @@ void online_page(struct page *page)
                totalhigh_pages++;
 #endif
 
-#ifdef CONFIG_FLATMEM
-       max_mapnr = max(pfn, max_mapnr);
-#endif
-
        ClearPageReserved(page);
        init_page_count(page);
        __free_page(page);
@@ -400,7 +396,7 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
 }
 
 
-int online_pages(unsigned long pfn, unsigned long nr_pages)
+int __ref online_pages(unsigned long pfn, unsigned long nr_pages)
 {
        unsigned long onlined_pages = 0;
        struct zone *zone;
@@ -459,8 +455,9 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
                zone_pcp_update(zone);
 
        mutex_unlock(&zonelists_mutex);
-       setup_per_zone_wmarks();
-       calculate_zone_inactive_ratio(zone);
+
+       init_per_zone_wmark_min();
+
        if (onlined_pages) {
                kswapd_run(zone_to_nid(zone));
                node_set_state(zone_to_nid(zone), N_HIGH_MEMORY);
@@ -705,7 +702,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                if (!pfn_valid(pfn))
                        continue;
                page = pfn_to_page(pfn);
-               if (!page_count(page))
+               if (!get_page_unless_zero(page))
                        continue;
                /*
                 * We can skip free pages. And we can only deal with pages on
@@ -713,6 +710,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                 */
                ret = isolate_lru_page(page);
                if (!ret) { /* Success */
+                       put_page(page);
                        list_add_tail(&page->lru, &source);
                        move_pages--;
                        inc_zone_page_state(page, NR_ISOLATED_ANON +
@@ -724,6 +722,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                               pfn);
                        dump_page(page);
 #endif
+                       put_page(page);
                        /* Because we don't have big zone->lock. we should
                           check this again here. */
                        if (page_count(page)) {
@@ -795,7 +794,7 @@ check_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
        return offlined;
 }
 
-static int offline_pages(unsigned long start_pfn,
+static int __ref offline_pages(unsigned long start_pfn,
                  unsigned long end_pfn, unsigned long timeout)
 {
        unsigned long pfn, nr_pages, expire;
@@ -893,8 +892,8 @@ repeat:
        zone->zone_pgdat->node_present_pages -= offlined_pages;
        totalram_pages -= offlined_pages;
 
-       setup_per_zone_wmarks();
-       calculate_zone_inactive_ratio(zone);
+       init_per_zone_wmark_min();
+
        if (!node_present_pages(node)) {
                node_clear_state(node, N_HIGH_MEMORY);
                kswapd_stop(node);
index 959a8b8c7350c28ffa6cacced61b4c24977479da..e7fb9d25c54eb80a62a987fbfd5cb08c4ae8e055 100644 (file)
@@ -99,7 +99,6 @@
 /* Internal flags */
 #define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0)   /* Skip checks for continuous vmas */
 #define MPOL_MF_INVERT (MPOL_MF_INTERNAL << 1)         /* Invert check for nodemask */
-#define MPOL_MF_STATS (MPOL_MF_INTERNAL << 2)          /* Gather statistics */
 
 static struct kmem_cache *policy_cache;
 static struct kmem_cache *sn_cache;
@@ -457,7 +456,6 @@ static const struct mempolicy_operations mpol_ops[MPOL_MAX] = {
        },
 };
 
-static void gather_stats(struct page *, void *, int pte_dirty);
 static void migrate_page_add(struct page *page, struct list_head *pagelist,
                                unsigned long flags);
 
@@ -492,9 +490,7 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT))
                        continue;
 
-               if (flags & MPOL_MF_STATS)
-                       gather_stats(page, private, pte_dirty(*pte));
-               else if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
+               if (flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL))
                        migrate_page_add(page, private, flags);
                else
                        break;
@@ -1489,7 +1485,7 @@ asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len,
  * freeing by another task.  It is the caller's responsibility to free the
  * extra reference for shared policies.
  */
-static struct mempolicy *get_vma_policy(struct task_struct *task,
+struct mempolicy *get_vma_policy(struct task_struct *task,
                struct vm_area_struct *vma, unsigned long addr)
 {
        struct mempolicy *pol = task->mempolicy;
@@ -2529,159 +2525,3 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol, int no_context)
        }
        return p - buffer;
 }
-
-struct numa_maps {
-       unsigned long pages;
-       unsigned long anon;
-       unsigned long active;
-       unsigned long writeback;
-       unsigned long mapcount_max;
-       unsigned long dirty;
-       unsigned long swapcache;
-       unsigned long node[MAX_NUMNODES];
-};
-
-static void gather_stats(struct page *page, void *private, int pte_dirty)
-{
-       struct numa_maps *md = private;
-       int count = page_mapcount(page);
-
-       md->pages++;
-       if (pte_dirty || PageDirty(page))
-               md->dirty++;
-
-       if (PageSwapCache(page))
-               md->swapcache++;
-
-       if (PageActive(page) || PageUnevictable(page))
-               md->active++;
-
-       if (PageWriteback(page))
-               md->writeback++;
-
-       if (PageAnon(page))
-               md->anon++;
-
-       if (count > md->mapcount_max)
-               md->mapcount_max = count;
-
-       md->node[page_to_nid(page)]++;
-}
-
-#ifdef CONFIG_HUGETLB_PAGE
-static void check_huge_range(struct vm_area_struct *vma,
-               unsigned long start, unsigned long end,
-               struct numa_maps *md)
-{
-       unsigned long addr;
-       struct page *page;
-       struct hstate *h = hstate_vma(vma);
-       unsigned long sz = huge_page_size(h);
-
-       for (addr = start; addr < end; addr += sz) {
-               pte_t *ptep = huge_pte_offset(vma->vm_mm,
-                                               addr & huge_page_mask(h));
-               pte_t pte;
-
-               if (!ptep)
-                       continue;
-
-               pte = *ptep;
-               if (pte_none(pte))
-                       continue;
-
-               page = pte_page(pte);
-               if (!page)
-                       continue;
-
-               gather_stats(page, md, pte_dirty(*ptep));
-       }
-}
-#else
-static inline void check_huge_range(struct vm_area_struct *vma,
-               unsigned long start, unsigned long end,
-               struct numa_maps *md)
-{
-}
-#endif
-
-/*
- * Display pages allocated per node and memory policy via /proc.
- */
-int show_numa_map(struct seq_file *m, void *v)
-{
-       struct proc_maps_private *priv = m->private;
-       struct vm_area_struct *vma = v;
-       struct numa_maps *md;
-       struct file *file = vma->vm_file;
-       struct mm_struct *mm = vma->vm_mm;
-       struct mempolicy *pol;
-       int n;
-       char buffer[50];
-
-       if (!mm)
-               return 0;
-
-       md = kzalloc(sizeof(struct numa_maps), GFP_KERNEL);
-       if (!md)
-               return 0;
-
-       pol = get_vma_policy(priv->task, vma, vma->vm_start);
-       mpol_to_str(buffer, sizeof(buffer), pol, 0);
-       mpol_cond_put(pol);
-
-       seq_printf(m, "%08lx %s", vma->vm_start, buffer);
-
-       if (file) {
-               seq_printf(m, " file=");
-               seq_path(m, &file->f_path, "\n\t= ");
-       } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
-               seq_printf(m, " heap");
-       } else if (vma->vm_start <= mm->start_stack &&
-                       vma->vm_end >= mm->start_stack) {
-               seq_printf(m, " stack");
-       }
-
-       if (is_vm_hugetlb_page(vma)) {
-               check_huge_range(vma, vma->vm_start, vma->vm_end, md);
-               seq_printf(m, " huge");
-       } else {
-               check_pgd_range(vma, vma->vm_start, vma->vm_end,
-                       &node_states[N_HIGH_MEMORY], MPOL_MF_STATS, md);
-       }
-
-       if (!md->pages)
-               goto out;
-
-       if (md->anon)
-               seq_printf(m," anon=%lu",md->anon);
-
-       if (md->dirty)
-               seq_printf(m," dirty=%lu",md->dirty);
-
-       if (md->pages != md->anon && md->pages != md->dirty)
-               seq_printf(m, " mapped=%lu", md->pages);
-
-       if (md->mapcount_max > 1)
-               seq_printf(m, " mapmax=%lu", md->mapcount_max);
-
-       if (md->swapcache)
-               seq_printf(m," swapcache=%lu", md->swapcache);
-
-       if (md->active < md->pages && !is_vm_hugetlb_page(vma))
-               seq_printf(m," active=%lu", md->active);
-
-       if (md->writeback)
-               seq_printf(m," writeback=%lu", md->writeback);
-
-       for_each_node_state(n, N_HIGH_MEMORY)
-               if (md->node[n])
-                       seq_printf(m, " N%d=%lu", n, md->node[n]);
-out:
-       seq_putc(m, '\n');
-       kfree(md);
-
-       if (m->count < m->size)
-               m->version = (vma != priv->tail_vma) ? vma->vm_start : 0;
-       return 0;
-}
index 34132f8e9109e1b2af4c92fdd74c5df7ef073392..e4a5c912983df5352d701bce82fb691160c2e657 100644 (file)
@@ -721,15 +721,11 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                 * Only page_lock_anon_vma() understands the subtleties of
                 * getting a hold on an anon_vma from outside one of its mms.
                 */
-               anon_vma = page_lock_anon_vma(page);
+               anon_vma = page_get_anon_vma(page);
                if (anon_vma) {
                        /*
-                        * Take a reference count on the anon_vma if the
-                        * page is mapped so that it is guaranteed to
-                        * exist when the page is remapped later
+                        * Anon page
                         */
-                       get_anon_vma(anon_vma);
-                       page_unlock_anon_vma(anon_vma);
                } else if (PageSwapCache(page)) {
                        /*
                         * We cannot be sure that the anon_vma of an unmapped
@@ -857,13 +853,8 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
                lock_page(hpage);
        }
 
-       if (PageAnon(hpage)) {
-               anon_vma = page_lock_anon_vma(hpage);
-               if (anon_vma) {
-                       get_anon_vma(anon_vma);
-                       page_unlock_anon_vma(anon_vma);
-               }
-       }
+       if (PageAnon(hpage))
+               anon_vma = page_get_anon_vma(hpage);
 
        try_to_unmap(hpage, TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS);
 
index 772140c53ab185ebc76d1f185d6feb9fb8935c15..ac2631b7477f7b773431df0375ee59075b6e1e20 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -84,10 +84,14 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags)
 }
 EXPORT_SYMBOL(vm_get_page_prot);
 
-int sysctl_overcommit_memory = OVERCOMMIT_GUESS;  /* heuristic overcommit */
-int sysctl_overcommit_ratio = 50;      /* default is 50% */
+int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS;  /* heuristic overcommit */
+int sysctl_overcommit_ratio __read_mostly = 50;        /* default is 50% */
 int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
-struct percpu_counter vm_committed_as;
+/*
+ * Make sure vm_committed_as in one cacheline and not cacheline shared with
+ * other variables. It can be updated by several CPUs frequently.
+ */
+struct percpu_counter vm_committed_as ____cacheline_aligned_in_smp;
 
 /*
  * Check that a process has enough memory to allocate a new virtual
@@ -190,7 +194,7 @@ error:
 }
 
 /*
- * Requires inode->i_mapping->i_mmap_lock
+ * Requires inode->i_mapping->i_mmap_mutex
  */
 static void __remove_shared_vm_struct(struct vm_area_struct *vma,
                struct file *file, struct address_space *mapping)
@@ -218,9 +222,9 @@ void unlink_file_vma(struct vm_area_struct *vma)
 
        if (file) {
                struct address_space *mapping = file->f_mapping;
-               spin_lock(&mapping->i_mmap_lock);
+               mutex_lock(&mapping->i_mmap_mutex);
                __remove_shared_vm_struct(vma, file, mapping);
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
        }
 }
 
@@ -394,29 +398,6 @@ find_vma_prepare(struct mm_struct *mm, unsigned long addr,
        return vma;
 }
 
-static inline void
-__vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
-               struct vm_area_struct *prev, struct rb_node *rb_parent)
-{
-       struct vm_area_struct *next;
-
-       vma->vm_prev = prev;
-       if (prev) {
-               next = prev->vm_next;
-               prev->vm_next = vma;
-       } else {
-               mm->mmap = vma;
-               if (rb_parent)
-                       next = rb_entry(rb_parent,
-                                       struct vm_area_struct, vm_rb);
-               else
-                       next = NULL;
-       }
-       vma->vm_next = next;
-       if (next)
-               next->vm_prev = vma;
-}
-
 void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma,
                struct rb_node **rb_link, struct rb_node *rb_parent)
 {
@@ -464,16 +445,14 @@ static void vma_link(struct mm_struct *mm, struct vm_area_struct *vma,
        if (vma->vm_file)
                mapping = vma->vm_file->f_mapping;
 
-       if (mapping) {
-               spin_lock(&mapping->i_mmap_lock);
-               vma->vm_truncate_count = mapping->truncate_count;
-       }
+       if (mapping)
+               mutex_lock(&mapping->i_mmap_mutex);
 
        __vma_link(mm, vma, prev, rb_link, rb_parent);
        __vma_link_file(vma);
 
        if (mapping)
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
 
        mm->map_count++;
        validate_mm(mm);
@@ -576,17 +555,8 @@ again:                     remove_next = 1 + (end > next->vm_end);
                mapping = file->f_mapping;
                if (!(vma->vm_flags & VM_NONLINEAR))
                        root = &mapping->i_mmap;
-               spin_lock(&mapping->i_mmap_lock);
-               if (importer &&
-                   vma->vm_truncate_count != next->vm_truncate_count) {
-                       /*
-                        * unmap_mapping_range might be in progress:
-                        * ensure that the expanding vma is rescanned.
-                        */
-                       importer->vm_truncate_count = 0;
-               }
+               mutex_lock(&mapping->i_mmap_mutex);
                if (insert) {
-                       insert->vm_truncate_count = vma->vm_truncate_count;
                        /*
                         * Put into prio_tree now, so instantiated pages
                         * are visible to arm/parisc __flush_dcache_page
@@ -605,7 +575,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
         * lock may be shared between many sibling processes.  Skipping
         * the lock for brk adjustments makes a difference sometimes.
         */
-       if (vma->anon_vma && (insert || importer || start != vma->vm_start)) {
+       if (vma->anon_vma && (importer || start != vma->vm_start)) {
                anon_vma = vma->anon_vma;
                anon_vma_lock(anon_vma);
        }
@@ -652,7 +622,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
        if (anon_vma)
                anon_vma_unlock(anon_vma);
        if (mapping)
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
 
        if (remove_next) {
                if (file) {
@@ -699,9 +669,17 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma,
 }
 
 static inline int is_mergeable_anon_vma(struct anon_vma *anon_vma1,
-                                       struct anon_vma *anon_vma2)
+                                       struct anon_vma *anon_vma2,
+                                       struct vm_area_struct *vma)
 {
-       return !anon_vma1 || !anon_vma2 || (anon_vma1 == anon_vma2);
+       /*
+        * The list_is_singular() test is to avoid merging VMA cloned from
+        * parents. This can improve scalability caused by anon_vma lock.
+        */
+       if ((!anon_vma1 || !anon_vma2) && (!vma ||
+               list_is_singular(&vma->anon_vma_chain)))
+               return 1;
+       return anon_vma1 == anon_vma2;
 }
 
 /*
@@ -720,7 +698,7 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
        struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
 {
        if (is_mergeable_vma(vma, file, vm_flags) &&
-           is_mergeable_anon_vma(anon_vma, vma->anon_vma)) {
+           is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
                if (vma->vm_pgoff == vm_pgoff)
                        return 1;
        }
@@ -739,7 +717,7 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
        struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff)
 {
        if (is_mergeable_vma(vma, file, vm_flags) &&
-           is_mergeable_anon_vma(anon_vma, vma->anon_vma)) {
+           is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
                pgoff_t vm_pglen;
                vm_pglen = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
                if (vma->vm_pgoff + vm_pglen == vm_pgoff)
@@ -817,7 +795,7 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
                                can_vma_merge_before(next, vm_flags,
                                        anon_vma, file, pgoff+pglen) &&
                                is_mergeable_anon_vma(prev->anon_vma,
-                                                     next->anon_vma)) {
+                                                     next->anon_vma, NULL)) {
                                                        /* cases 1, 6 */
                        err = vma_adjust(prev, prev->vm_start,
                                next->vm_end, prev->vm_pgoff, NULL);
@@ -1785,7 +1763,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
 /*
  * vma is the first one with address < vma->vm_start.  Have to extend vma.
  */
-static int expand_downwards(struct vm_area_struct *vma,
+int expand_downwards(struct vm_area_struct *vma,
                                   unsigned long address)
 {
        int error;
@@ -1832,11 +1810,6 @@ static int expand_downwards(struct vm_area_struct *vma,
        return error;
 }
 
-int expand_stack_downwards(struct vm_area_struct *vma, unsigned long address)
-{
-       return expand_downwards(vma, address);
-}
-
 #ifdef CONFIG_STACK_GROWSUP
 int expand_stack(struct vm_area_struct *vma, unsigned long address)
 {
@@ -1919,17 +1892,17 @@ static void unmap_region(struct mm_struct *mm,
                unsigned long start, unsigned long end)
 {
        struct vm_area_struct *next = prev? prev->vm_next: mm->mmap;
-       struct mmu_gather *tlb;
+       struct mmu_gather tlb;
        unsigned long nr_accounted = 0;
 
        lru_add_drain();
-       tlb = tlb_gather_mmu(mm, 0);
+       tlb_gather_mmu(&tlb, mm, 0);
        update_hiwater_rss(mm);
        unmap_vmas(&tlb, vma, start, end, &nr_accounted, NULL);
        vm_unacct_memory(nr_accounted);
-       free_pgtables(tlb, vma, prev? prev->vm_end: FIRST_USER_ADDRESS,
-                                next? next->vm_start: 0);
-       tlb_finish_mmu(tlb, start, end);
+       free_pgtables(&tlb, vma, prev ? prev->vm_end : FIRST_USER_ADDRESS,
+                                next ? next->vm_start : 0);
+       tlb_finish_mmu(&tlb, start, end);
 }
 
 /*
@@ -2271,7 +2244,7 @@ EXPORT_SYMBOL(do_brk);
 /* Release all mmaps. */
 void exit_mmap(struct mm_struct *mm)
 {
-       struct mmu_gather *tlb;
+       struct mmu_gather tlb;
        struct vm_area_struct *vma;
        unsigned long nr_accounted = 0;
        unsigned long end;
@@ -2296,14 +2269,14 @@ void exit_mmap(struct mm_struct *mm)
 
        lru_add_drain();
        flush_cache_mm(mm);
-       tlb = tlb_gather_mmu(mm, 1);
+       tlb_gather_mmu(&tlb, mm, 1);
        /* update_hiwater_rss(mm) here? but nobody should be looking */
        /* Use -1 here to ensure all VMAs in the mm are unmapped */
        end = unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL);
        vm_unacct_memory(nr_accounted);
 
-       free_pgtables(tlb, vma, FIRST_USER_ADDRESS, 0);
-       tlb_finish_mmu(tlb, 0, end);
+       free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0);
+       tlb_finish_mmu(&tlb, 0, end);
 
        /*
         * Walk the list again, actually closing and freeing it,
@@ -2317,7 +2290,7 @@ void exit_mmap(struct mm_struct *mm)
 
 /* Insert vm structure into process list sorted by address
  * and into the inode's i_mmap tree.  If vm_file is non-NULL
- * then i_mmap_lock is taken here.
+ * then i_mmap_mutex is taken here.
  */
 int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
 {
@@ -2529,15 +2502,15 @@ static void vm_lock_anon_vma(struct mm_struct *mm, struct anon_vma *anon_vma)
                 * The LSB of head.next can't change from under us
                 * because we hold the mm_all_locks_mutex.
                 */
-               spin_lock_nest_lock(&anon_vma->root->lock, &mm->mmap_sem);
+               mutex_lock_nest_lock(&anon_vma->root->mutex, &mm->mmap_sem);
                /*
                 * We can safely modify head.next after taking the
-                * anon_vma->root->lock. If some other vma in this mm shares
+                * anon_vma->root->mutex. If some other vma in this mm shares
                 * the same anon_vma we won't take it again.
                 *
                 * No need of atomic instructions here, head.next
                 * can't change from under us thanks to the
-                * anon_vma->root->lock.
+                * anon_vma->root->mutex.
                 */
                if (__test_and_set_bit(0, (unsigned long *)
                                       &anon_vma->root->head.next))
@@ -2559,7 +2532,7 @@ static void vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping)
                 */
                if (test_and_set_bit(AS_MM_ALL_LOCKS, &mapping->flags))
                        BUG();
-               spin_lock_nest_lock(&mapping->i_mmap_lock, &mm->mmap_sem);
+               mutex_lock_nest_lock(&mapping->i_mmap_mutex, &mm->mmap_sem);
        }
 }
 
@@ -2586,7 +2559,7 @@ static void vm_lock_mapping(struct mm_struct *mm, struct address_space *mapping)
  * vma in this mm is backed by the same anon_vma or address_space.
  *
  * We can take all the locks in random order because the VM code
- * taking i_mmap_lock or anon_vma->lock outside the mmap_sem never
+ * taking i_mmap_mutex or anon_vma->mutex outside the mmap_sem never
  * takes more than one of them in a row. Secondly we're protected
  * against a concurrent mm_take_all_locks() by the mm_all_locks_mutex.
  *
@@ -2642,7 +2615,7 @@ static void vm_unlock_anon_vma(struct anon_vma *anon_vma)
                 *
                 * No need of atomic instructions here, head.next
                 * can't change from under us until we release the
-                * anon_vma->root->lock.
+                * anon_vma->root->mutex.
                 */
                if (!__test_and_clear_bit(0, (unsigned long *)
                                          &anon_vma->root->head.next))
@@ -2658,7 +2631,7 @@ static void vm_unlock_mapping(struct address_space *mapping)
                 * AS_MM_ALL_LOCKS can't change to 0 from under us
                 * because we hold the mm_all_locks_mutex.
                 */
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
                if (!test_and_clear_bit(AS_MM_ALL_LOCKS,
                                        &mapping->flags))
                        BUG();
index a7c1f9f9b94157033e232ef2618ebb67e0eef99d..506fa44403df5cc3215cb69ec2d1098a96bb7919 100644 (file)
@@ -93,8 +93,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
                 * and we propagate stale pages into the dst afterward.
                 */
                mapping = vma->vm_file->f_mapping;
-               spin_lock(&mapping->i_mmap_lock);
-               new_vma->vm_truncate_count = 0;
+               mutex_lock(&mapping->i_mmap_mutex);
        }
 
        /*
@@ -123,7 +122,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
        pte_unmap(new_pte - 1);
        pte_unmap_unlock(old_pte - 1, old_ptl);
        if (mapping)
-               spin_unlock(&mapping->i_mmap_lock);
+               mutex_unlock(&mapping->i_mmap_mutex);
        mmu_notifier_invalidate_range_end(vma->vm_mm, old_start, old_end);
 }
 
index 9109049f0bbce176071d1776da87e12087485a12..6e93dc7f25863628b576539648dfe0c7ba8d3f10 100644 (file)
@@ -307,30 +307,7 @@ void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
 void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
                                   unsigned long align, unsigned long goal)
 {
-#ifdef MAX_DMA32_PFN
-       unsigned long end_pfn;
-
-       if (WARN_ON_ONCE(slab_is_available()))
-               return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
-
-       /* update goal according ...MAX_DMA32_PFN */
-       end_pfn = pgdat->node_start_pfn + pgdat->node_spanned_pages;
-
-       if (end_pfn > MAX_DMA32_PFN + (128 >> (20 - PAGE_SHIFT)) &&
-           (goal >> PAGE_SHIFT) < MAX_DMA32_PFN) {
-               void *ptr;
-               unsigned long new_goal;
-
-               new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
-               ptr =  __alloc_memory_core_early(pgdat->node_id, size, align,
-                                                new_goal, -1ULL);
-               if (ptr)
-                       return ptr;
-       }
-#endif
-
        return __alloc_bootmem_node(pgdat, size, align, goal);
-
 }
 
 #ifdef CONFIG_SPARSEMEM
index c4c542c736a962774f0770eef0d50c419b19a2cb..1fd0c51b10a63db69181fc6ba2f42127aaad6ef7 100644 (file)
@@ -680,9 +680,9 @@ static void protect_vma(struct vm_area_struct *vma, unsigned long flags)
  */
 static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
 {
-       struct vm_area_struct *pvma, **pp, *next;
+       struct vm_area_struct *pvma, *prev;
        struct address_space *mapping;
-       struct rb_node **p, *parent;
+       struct rb_node **p, *parent, *rb_prev;
 
        kenter(",%p", vma);
 
@@ -703,7 +703,7 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
        }
 
        /* add the VMA to the tree */
-       parent = NULL;
+       parent = rb_prev = NULL;
        p = &mm->mm_rb.rb_node;
        while (*p) {
                parent = *p;
@@ -713,17 +713,20 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
                 * (the latter is necessary as we may get identical VMAs) */
                if (vma->vm_start < pvma->vm_start)
                        p = &(*p)->rb_left;
-               else if (vma->vm_start > pvma->vm_start)
+               else if (vma->vm_start > pvma->vm_start) {
+                       rb_prev = parent;
                        p = &(*p)->rb_right;
-               else if (vma->vm_end < pvma->vm_end)
+               else if (vma->vm_end < pvma->vm_end)
                        p = &(*p)->rb_left;
-               else if (vma->vm_end > pvma->vm_end)
+               else if (vma->vm_end > pvma->vm_end) {
+                       rb_prev = parent;
                        p = &(*p)->rb_right;
-               else if (vma < pvma)
+               else if (vma < pvma)
                        p = &(*p)->rb_left;
-               else if (vma > pvma)
+               else if (vma > pvma) {
+                       rb_prev = parent;
                        p = &(*p)->rb_right;
-               else
+               else
                        BUG();
        }
 
@@ -731,20 +734,11 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
        rb_insert_color(&vma->vm_rb, &mm->mm_rb);
 
        /* add VMA to the VMA list also */
-       for (pp = &mm->mmap; (pvma = *pp); pp = &(*pp)->vm_next) {
-               if (pvma->vm_start > vma->vm_start)
-                       break;
-               if (pvma->vm_start < vma->vm_start)
-                       continue;
-               if (pvma->vm_end < vma->vm_end)
-                       break;
-       }
+       prev = NULL;
+       if (rb_prev)
+               prev = rb_entry(rb_prev, struct vm_area_struct, vm_rb);
 
-       next = *pp;
-       *pp = vma;
-       vma->vm_next = next;
-       if (next)
-               next->vm_prev = vma;
+       __vma_link_list(mm, vma, prev, parent);
 }
 
 /*
@@ -752,7 +746,6 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
  */
 static void delete_vma_from_mm(struct vm_area_struct *vma)
 {
-       struct vm_area_struct **pp;
        struct address_space *mapping;
        struct mm_struct *mm = vma->vm_mm;
 
@@ -775,12 +768,14 @@ static void delete_vma_from_mm(struct vm_area_struct *vma)
 
        /* remove from the MM's tree and list */
        rb_erase(&vma->vm_rb, &mm->mm_rb);
-       for (pp = &mm->mmap; *pp; pp = &(*pp)->vm_next) {
-               if (*pp == vma) {
-                       *pp = vma->vm_next;
-                       break;
-               }
-       }
+
+       if (vma->vm_prev)
+               vma->vm_prev->vm_next = vma->vm_next;
+       else
+               mm->mmap = vma->vm_next;
+
+       if (vma->vm_next)
+               vma->vm_next->vm_prev = vma->vm_prev;
 
        vma->vm_mm = NULL;
 }
@@ -809,17 +804,15 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma)
 struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
 {
        struct vm_area_struct *vma;
-       struct rb_node *n = mm->mm_rb.rb_node;
 
        /* check the cache first */
        vma = mm->mmap_cache;
        if (vma && vma->vm_start <= addr && vma->vm_end > addr)
                return vma;
 
-       /* trawl the tree (there may be multiple mappings in which addr
+       /* trawl the list (there may be multiple mappings in which addr
         * resides) */
-       for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) {
-               vma = rb_entry(n, struct vm_area_struct, vm_rb);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
                if (vma->vm_start > addr)
                        return NULL;
                if (vma->vm_end > addr) {
@@ -859,7 +852,6 @@ static struct vm_area_struct *find_vma_exact(struct mm_struct *mm,
                                             unsigned long len)
 {
        struct vm_area_struct *vma;
-       struct rb_node *n = mm->mm_rb.rb_node;
        unsigned long end = addr + len;
 
        /* check the cache first */
@@ -867,10 +859,9 @@ static struct vm_area_struct *find_vma_exact(struct mm_struct *mm,
        if (vma && vma->vm_start == addr && vma->vm_end == end)
                return vma;
 
-       /* trawl the tree (there may be multiple mappings in which addr
+       /* trawl the list (there may be multiple mappings in which addr
         * resides) */
-       for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) {
-               vma = rb_entry(n, struct vm_area_struct, vm_rb);
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
                if (vma->vm_start < addr)
                        continue;
                if (vma->vm_start > addr)
@@ -1133,7 +1124,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
                           unsigned long capabilities)
 {
        struct page *pages;
-       unsigned long total, point, n, rlen;
+       unsigned long total, point, n;
        void *base;
        int ret, order;
 
@@ -1157,13 +1148,12 @@ static int do_mmap_private(struct vm_area_struct *vma,
                 * make a private copy of the data and map that instead */
        }
 
-       rlen = PAGE_ALIGN(len);
 
        /* allocate some memory to hold the mapping
         * - note that this may not return a page-aligned address if the object
         *   we're allocating is smaller than a page
         */
-       order = get_order(rlen);
+       order = get_order(len);
        kdebug("alloc order %d for %lx", order, len);
 
        pages = alloc_pages(GFP_KERNEL, order);
@@ -1173,7 +1163,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
        total = 1 << order;
        atomic_long_add(total, &mmap_pages_allocated);
 
-       point = rlen >> PAGE_SHIFT;
+       point = len >> PAGE_SHIFT;
 
        /* we allocated a power-of-2 sized page set, so we may want to trim off
         * the excess */
@@ -1195,7 +1185,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
        base = page_address(pages);
        region->vm_flags = vma->vm_flags |= VM_MAPPED_COPY;
        region->vm_start = (unsigned long) base;
-       region->vm_end   = region->vm_start + rlen;
+       region->vm_end   = region->vm_start + len;
        region->vm_top   = region->vm_start + (total << PAGE_SHIFT);
 
        vma->vm_start = region->vm_start;
@@ -1211,22 +1201,22 @@ static int do_mmap_private(struct vm_area_struct *vma,
 
                old_fs = get_fs();
                set_fs(KERNEL_DS);
-               ret = vma->vm_file->f_op->read(vma->vm_file, base, rlen, &fpos);
+               ret = vma->vm_file->f_op->read(vma->vm_file, base, len, &fpos);
                set_fs(old_fs);
 
                if (ret < 0)
                        goto error_free;
 
                /* clear the last little bit */
-               if (ret < rlen)
-                       memset(base + ret, 0, rlen - ret);
+               if (ret < len)
+                       memset(base + ret, 0, len - ret);
 
        }
 
        return 0;
 
 error_free:
-       free_page_series(region->vm_start, region->vm_end);
+       free_page_series(region->vm_start, region->vm_top);
        region->vm_start = vma->vm_start = 0;
        region->vm_end   = vma->vm_end = 0;
        region->vm_top   = 0;
@@ -1235,7 +1225,7 @@ error_free:
 enomem:
        printk("Allocation of length %lu from process %d (%s) failed\n",
               len, current->pid, current->comm);
-       show_free_areas();
+       show_free_areas(0);
        return -ENOMEM;
 }
 
@@ -1268,6 +1258,7 @@ unsigned long do_mmap_pgoff(struct file *file,
 
        /* we ignore the address hint */
        addr = 0;
+       len = PAGE_ALIGN(len);
 
        /* we've determined that we can make the mapping, now translate what we
         * now know into VMA flags */
@@ -1385,15 +1376,15 @@ unsigned long do_mmap_pgoff(struct file *file,
                if (capabilities & BDI_CAP_MAP_DIRECT) {
                        addr = file->f_op->get_unmapped_area(file, addr, len,
                                                             pgoff, flags);
-                       if (IS_ERR((void *) addr)) {
+                       if (IS_ERR_VALUE(addr)) {
                                ret = addr;
-                               if (ret != (unsigned long) -ENOSYS)
+                               if (ret != -ENOSYS)
                                        goto error_just_free;
 
                                /* the driver refused to tell us where to site
                                 * the mapping so we'll have to attempt to copy
                                 * it */
-                               ret = (unsigned long) -ENODEV;
+                               ret = -ENODEV;
                                if (!(capabilities & BDI_CAP_MAP_COPY))
                                        goto error_just_free;
 
@@ -1468,14 +1459,14 @@ error_getting_vma:
        printk(KERN_WARNING "Allocation of vma for %lu byte allocation"
               " from process %d failed\n",
               len, current->pid);
-       show_free_areas();
+       show_free_areas(0);
        return -ENOMEM;
 
 error_getting_region:
        printk(KERN_WARNING "Allocation of vm region for %lu byte allocation"
               " from process %d failed\n",
               len, current->pid);
-       show_free_areas();
+       show_free_areas(0);
        return -ENOMEM;
 }
 EXPORT_SYMBOL(do_mmap_pgoff);
@@ -1644,15 +1635,17 @@ static int shrink_vma(struct mm_struct *mm,
 int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
 {
        struct vm_area_struct *vma;
-       struct rb_node *rb;
-       unsigned long end = start + len;
+       unsigned long end;
        int ret;
 
        kenter(",%lx,%zx", start, len);
 
+       len = PAGE_ALIGN(len);
        if (len == 0)
                return -EINVAL;
 
+       end = start + len;
+
        /* find the first potentially overlapping VMA */
        vma = find_vma(mm, start);
        if (!vma) {
@@ -1677,9 +1670,8 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
                        }
                        if (end == vma->vm_end)
                                goto erase_whole_vma;
-                       rb = rb_next(&vma->vm_rb);
-                       vma = rb_entry(rb, struct vm_area_struct, vm_rb);
-               } while (rb);
+                       vma = vma->vm_next;
+               } while (vma);
                kleave(" = -EINVAL [split file]");
                return -EINVAL;
        } else {
@@ -1773,6 +1765,8 @@ unsigned long do_mremap(unsigned long addr,
        struct vm_area_struct *vma;
 
        /* insanity checks first */
+       old_len = PAGE_ALIGN(old_len);
+       new_len = PAGE_ALIGN(new_len);
        if (old_len == 0 || new_len == 0)
                return (unsigned long) -EINVAL;
 
index f52e85c80e8d554fcae1a7ad40e0617c0bb1318f..e4b0991ca3516b3fc3590f40da1ede9f8a4ba637 100644 (file)
@@ -38,6 +38,33 @@ int sysctl_oom_kill_allocating_task;
 int sysctl_oom_dump_tasks = 1;
 static DEFINE_SPINLOCK(zone_scan_lock);
 
+/**
+ * test_set_oom_score_adj() - set current's oom_score_adj and return old value
+ * @new_val: new oom_score_adj value
+ *
+ * Sets the oom_score_adj value for current to @new_val with proper
+ * synchronization and returns the old value.  Usually used to temporarily
+ * set a value, save the old value in the caller, and then reinstate it later.
+ */
+int test_set_oom_score_adj(int new_val)
+{
+       struct sighand_struct *sighand = current->sighand;
+       int old_val;
+
+       spin_lock_irq(&sighand->siglock);
+       old_val = current->signal->oom_score_adj;
+       if (new_val != old_val) {
+               if (new_val == OOM_SCORE_ADJ_MIN)
+                       atomic_inc(&current->mm->oom_disable_count);
+               else if (old_val == OOM_SCORE_ADJ_MIN)
+                       atomic_dec(&current->mm->oom_disable_count);
+               current->signal->oom_score_adj = new_val;
+       }
+       spin_unlock_irq(&sighand->siglock);
+
+       return old_val;
+}
+
 #ifdef CONFIG_NUMA
 /**
  * has_intersects_mems_allowed() - check task eligiblity for kill
@@ -154,15 +181,6 @@ unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem,
                return 0;
        }
 
-       /*
-        * When the PF_OOM_ORIGIN bit is set, it indicates the task should have
-        * priority for oom killing.
-        */
-       if (p->flags & PF_OOM_ORIGIN) {
-               task_unlock(p);
-               return 1000;
-       }
-
        /*
         * The memory controller may have a limit of 0 bytes, so avoid a divide
         * by zero, if necessary.
index 9d5498e2d0f5a73c527c32b4ffe14cbfa897a7be..2a00f17c3bf453efa0460d1a9b92171b4f92e2b7 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/pagevec.h>
 #include <linux/blkdev.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #include <linux/oom.h>
 #include <linux/notifier.h>
 #include <linux/topology.h>
@@ -39,6 +40,7 @@
 #include <linux/memory_hotplug.h>
 #include <linux/nodemask.h>
 #include <linux/vmalloc.h>
+#include <linux/vmstat.h>
 #include <linux/mempolicy.h>
 #include <linux/stop_machine.h>
 #include <linux/sort.h>
@@ -1735,6 +1737,45 @@ static inline bool should_suppress_show_mem(void)
        return ret;
 }
 
+static DEFINE_RATELIMIT_STATE(nopage_rs,
+               DEFAULT_RATELIMIT_INTERVAL,
+               DEFAULT_RATELIMIT_BURST);
+
+void warn_alloc_failed(gfp_t gfp_mask, int order, const char *fmt, ...)
+{
+       va_list args;
+       unsigned int filter = SHOW_MEM_FILTER_NODES;
+
+       if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs))
+               return;
+
+       /*
+        * This documents exceptions given to allocations in certain
+        * contexts that are allowed to allocate outside current's set
+        * of allowed nodes.
+        */
+       if (!(gfp_mask & __GFP_NOMEMALLOC))
+               if (test_thread_flag(TIF_MEMDIE) ||
+                   (current->flags & (PF_MEMALLOC | PF_EXITING)))
+                       filter &= ~SHOW_MEM_FILTER_NODES;
+       if (in_interrupt() || !(gfp_mask & __GFP_WAIT))
+               filter &= ~SHOW_MEM_FILTER_NODES;
+
+       if (fmt) {
+               printk(KERN_WARNING);
+               va_start(args, fmt);
+               vprintk(fmt, args);
+               va_end(args);
+       }
+
+       pr_warning("%s: page allocation failure: order:%d, mode:0x%x\n",
+                  current->comm, order, gfp_mask);
+
+       dump_stack();
+       if (!should_suppress_show_mem())
+               show_mem(filter);
+}
+
 static inline int
 should_alloc_retry(gfp_t gfp_mask, unsigned int order,
                                unsigned long pages_reclaimed)
@@ -2065,6 +2106,7 @@ restart:
                first_zones_zonelist(zonelist, high_zoneidx, NULL,
                                        &preferred_zone);
 
+rebalance:
        /* This is the last chance, in general, before the goto nopage. */
        page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist,
                        high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS,
@@ -2072,7 +2114,6 @@ restart:
        if (page)
                goto got_pg;
 
-rebalance:
        /* Allocate without watermarks if the context allows */
        if (alloc_flags & ALLOC_NO_WATERMARKS) {
                page = __alloc_pages_high_priority(gfp_mask, order,
@@ -2106,7 +2147,7 @@ rebalance:
                                        sync_migration);
        if (page)
                goto got_pg;
-       sync_migration = !(gfp_mask & __GFP_NO_KSWAPD);
+       sync_migration = true;
 
        /* Try direct reclaim and then allocating */
        page = __alloc_pages_direct_reclaim(gfp_mask, order,
@@ -2177,27 +2218,7 @@ rebalance:
        }
 
 nopage:
-       if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) {
-               unsigned int filter = SHOW_MEM_FILTER_NODES;
-
-               /*
-                * This documents exceptions given to allocations in certain
-                * contexts that are allowed to allocate outside current's set
-                * of allowed nodes.
-                */
-               if (!(gfp_mask & __GFP_NOMEMALLOC))
-                       if (test_thread_flag(TIF_MEMDIE) ||
-                           (current->flags & (PF_MEMALLOC | PF_EXITING)))
-                               filter &= ~SHOW_MEM_FILTER_NODES;
-               if (in_interrupt() || !wait)
-                       filter &= ~SHOW_MEM_FILTER_NODES;
-
-               pr_warning("%s: page allocation failure. order:%d, mode:0x%x\n",
-                       current->comm, order, gfp_mask);
-               dump_stack();
-               if (!should_suppress_show_mem())
-                       show_mem(filter);
-       }
+       warn_alloc_failed(gfp_mask, order, NULL);
        return page;
 got_pg:
        if (kmemcheck_enabled)
@@ -2226,6 +2247,10 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
 
        if (should_fail_alloc_page(gfp_mask, order))
                return NULL;
+#ifndef CONFIG_ZONE_DMA
+       if (WARN_ON_ONCE(gfp_mask & __GFP_DMA))
+               return NULL;
+#endif
 
        /*
         * Check the zones suitable for the gfp_mask contain at least one
@@ -2473,10 +2498,10 @@ void si_meminfo_node(struct sysinfo *val, int nid)
 #endif
 
 /*
- * Determine whether the zone's node should be displayed or not, depending on
- * whether SHOW_MEM_FILTER_NODES was passed to __show_free_areas().
+ * Determine whether the node should be displayed or not, depending on whether
+ * SHOW_MEM_FILTER_NODES was passed to show_free_areas().
  */
-static bool skip_free_areas_zone(unsigned int flags, const struct zone *zone)
+bool skip_free_areas_node(unsigned int flags, int nid)
 {
        bool ret = false;
 
@@ -2484,8 +2509,7 @@ static bool skip_free_areas_zone(unsigned int flags, const struct zone *zone)
                goto out;
 
        get_mems_allowed();
-       ret = !node_isset(zone->zone_pgdat->node_id,
-                               cpuset_current_mems_allowed);
+       ret = !node_isset(nid, cpuset_current_mems_allowed);
        put_mems_allowed();
 out:
        return ret;
@@ -2500,13 +2524,13 @@ out:
  * Suppresses nodes that are not allowed by current's cpuset if
  * SHOW_MEM_FILTER_NODES is passed.
  */
-void __show_free_areas(unsigned int filter)
+void show_free_areas(unsigned int filter)
 {
        int cpu;
        struct zone *zone;
 
        for_each_populated_zone(zone) {
-               if (skip_free_areas_zone(filter, zone))
+               if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
                printk("%s per-cpu:\n", zone->name);
@@ -2549,7 +2573,7 @@ void __show_free_areas(unsigned int filter)
        for_each_populated_zone(zone) {
                int i;
 
-               if (skip_free_areas_zone(filter, zone))
+               if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
                printk("%s"
@@ -2618,7 +2642,7 @@ void __show_free_areas(unsigned int filter)
        for_each_populated_zone(zone) {
                unsigned long nr[MAX_ORDER], flags, order, total = 0;
 
-               if (skip_free_areas_zone(filter, zone))
+               if (skip_free_areas_node(filter, zone_to_nid(zone)))
                        continue;
                show_node(zone);
                printk("%s: ", zone->name);
@@ -2639,11 +2663,6 @@ void __show_free_areas(unsigned int filter)
        show_swap_cache_info();
 }
 
-void show_free_areas(void)
-{
-       __show_free_areas(0);
-}
-
 static void zoneref_set_zone(struct zone *zone, struct zoneref *zoneref)
 {
        zoneref->zone = zone;
@@ -3313,6 +3332,20 @@ static inline unsigned long wait_table_bits(unsigned long size)
 
 #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
 
+/*
+ * Check if a pageblock contains reserved pages
+ */
+static int pageblock_is_reserved(unsigned long start_pfn, unsigned long end_pfn)
+{
+       unsigned long pfn;
+
+       for (pfn = start_pfn; pfn < end_pfn; pfn++) {
+               if (!pfn_valid_within(pfn) || PageReserved(pfn_to_page(pfn)))
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * Mark a number of pageblocks as MIGRATE_RESERVE. The number
  * of blocks reserved is based on min_wmark_pages(zone). The memory within
@@ -3322,7 +3355,7 @@ static inline unsigned long wait_table_bits(unsigned long size)
  */
 static void setup_zone_migrate_reserve(struct zone *zone)
 {
-       unsigned long start_pfn, pfn, end_pfn;
+       unsigned long start_pfn, pfn, end_pfn, block_end_pfn;
        struct page *page;
        unsigned long block_migratetype;
        int reserve;
@@ -3352,7 +3385,8 @@ static void setup_zone_migrate_reserve(struct zone *zone)
                        continue;
 
                /* Blocks with reserved pages will never free, skip them. */
-               if (PageReserved(page))
+               block_end_pfn = min(pfn + pageblock_nr_pages, end_pfn);
+               if (pageblock_is_reserved(pfn, block_end_pfn))
                        continue;
 
                block_migratetype = get_pageblock_migratetype(page);
@@ -5100,7 +5134,7 @@ void setup_per_zone_wmarks(void)
  *    1TB     101        10GB
  *   10TB     320        32GB
  */
-void calculate_zone_inactive_ratio(struct zone *zone)
+static void __meminit calculate_zone_inactive_ratio(struct zone *zone)
 {
        unsigned int gb, ratio;
 
@@ -5114,7 +5148,7 @@ void calculate_zone_inactive_ratio(struct zone *zone)
        zone->inactive_ratio = ratio;
 }
 
-static void __init setup_per_zone_inactive_ratio(void)
+static void __meminit setup_per_zone_inactive_ratio(void)
 {
        struct zone *zone;
 
@@ -5146,7 +5180,7 @@ static void __init setup_per_zone_inactive_ratio(void)
  * 8192MB:     11584k
  * 16384MB:    16384k
  */
-static int __init init_per_zone_wmark_min(void)
+int __meminit init_per_zone_wmark_min(void)
 {
        unsigned long lowmem_kbytes;
 
@@ -5158,6 +5192,7 @@ static int __init init_per_zone_wmark_min(void)
        if (min_free_kbytes > 65536)
                min_free_kbytes = 65536;
        setup_per_zone_wmarks();
+       refresh_zone_stat_thresholds();
        setup_per_zone_lowmem_reserve();
        setup_per_zone_inactive_ratio();
        return 0;
@@ -5508,10 +5543,8 @@ int set_migratetype_isolate(struct page *page)
        struct memory_isolate_notify arg;
        int notifier_ret;
        int ret = -EBUSY;
-       int zone_idx;
 
        zone = page_zone(page);
-       zone_idx = zone_idx(zone);
 
        spin_lock_irqsave(&zone->lock, flags);
 
index 2c0cc489e2880cb319a92b905a5ee7b292039b7f..867f9dd82dcde9d5c11f49bde159c3c6a0276c4e 100644 (file)
@@ -180,7 +180,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
                if (page)
                        continue;
 
-               page = page_cache_alloc_cold(mapping);
+               page = page_cache_alloc_readahead(mapping);
                if (!page)
                        break;
                page->index = page_offset;
index 522e4a93cadda8d33bcc25025c224dc7acacc9d6..3a39b518a653135f7c383e3fcbfca7e20d5f6793 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -24,8 +24,8 @@
  *   inode->i_alloc_sem (vmtruncate_range)
  *   mm->mmap_sem
  *     page->flags PG_locked (lock_page)
- *       mapping->i_mmap_lock
- *         anon_vma->lock
+ *       mapping->i_mmap_mutex
+ *         anon_vma->mutex
  *           mm->page_table_lock or pte_lock
  *             zone->lru_lock (in mark_page_accessed, isolate_lru_page)
  *             swap_lock (in swap_duplicate, swap_info_get)
@@ -40,7 +40,7 @@
  *
  * (code doesn't rely on that order so it could be switched around)
  * ->tasklist_lock
- *   anon_vma->lock      (memory_failure, collect_procs_anon)
+ *   anon_vma->mutex      (memory_failure, collect_procs_anon)
  *     pte map lock
  */
 
@@ -86,6 +86,29 @@ static inline struct anon_vma *anon_vma_alloc(void)
 static inline void anon_vma_free(struct anon_vma *anon_vma)
 {
        VM_BUG_ON(atomic_read(&anon_vma->refcount));
+
+       /*
+        * Synchronize against page_lock_anon_vma() such that
+        * we can safely hold the lock without the anon_vma getting
+        * freed.
+        *
+        * Relies on the full mb implied by the atomic_dec_and_test() from
+        * put_anon_vma() against the acquire barrier implied by
+        * mutex_trylock() from page_lock_anon_vma(). This orders:
+        *
+        * page_lock_anon_vma()         VS      put_anon_vma()
+        *   mutex_trylock()                      atomic_dec_and_test()
+        *   LOCK                                 MB
+        *   atomic_read()                        mutex_is_locked()
+        *
+        * LOCK should suffice since the actual taking of the lock must
+        * happen _before_ what follows.
+        */
+       if (mutex_is_locked(&anon_vma->root->mutex)) {
+               anon_vma_lock(anon_vma);
+               anon_vma_unlock(anon_vma);
+       }
+
        kmem_cache_free(anon_vma_cachep, anon_vma);
 }
 
@@ -307,7 +330,7 @@ static void anon_vma_ctor(void *data)
 {
        struct anon_vma *anon_vma = data;
 
-       spin_lock_init(&anon_vma->lock);
+       mutex_init(&anon_vma->mutex);
        atomic_set(&anon_vma->refcount, 0);
        INIT_LIST_HEAD(&anon_vma->head);
 }
@@ -320,12 +343,26 @@ void __init anon_vma_init(void)
 }
 
 /*
- * Getting a lock on a stable anon_vma from a page off the LRU is
- * tricky: page_lock_anon_vma rely on RCU to guard against the races.
+ * Getting a lock on a stable anon_vma from a page off the LRU is tricky!
+ *
+ * Since there is no serialization what so ever against page_remove_rmap()
+ * the best this function can do is return a locked anon_vma that might
+ * have been relevant to this page.
+ *
+ * The page might have been remapped to a different anon_vma or the anon_vma
+ * returned may already be freed (and even reused).
+ *
+ * All users of this function must be very careful when walking the anon_vma
+ * chain and verify that the page in question is indeed mapped in it
+ * [ something equivalent to page_mapped_in_vma() ].
+ *
+ * Since anon_vma's slab is DESTROY_BY_RCU and we know from page_remove_rmap()
+ * that the anon_vma pointer from page->mapping is valid if there is a
+ * mapcount, we can dereference the anon_vma after observing those.
  */
-struct anon_vma *__page_lock_anon_vma(struct page *page)
+struct anon_vma *page_get_anon_vma(struct page *page)
 {
-       struct anon_vma *anon_vma, *root_anon_vma;
+       struct anon_vma *anon_vma = NULL;
        unsigned long anon_mapping;
 
        rcu_read_lock();
@@ -336,32 +373,97 @@ struct anon_vma *__page_lock_anon_vma(struct page *page)
                goto out;
 
        anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON);
-       root_anon_vma = ACCESS_ONCE(anon_vma->root);
-       spin_lock(&root_anon_vma->lock);
+       if (!atomic_inc_not_zero(&anon_vma->refcount)) {
+               anon_vma = NULL;
+               goto out;
+       }
 
        /*
         * If this page is still mapped, then its anon_vma cannot have been
-        * freed.  But if it has been unmapped, we have no security against
-        * the anon_vma structure being freed and reused (for another anon_vma:
-        * SLAB_DESTROY_BY_RCU guarantees that - so the spin_lock above cannot
-        * corrupt): with anon_vma_prepare() or anon_vma_fork() redirecting
-        * anon_vma->root before page_unlock_anon_vma() is called to unlock.
+        * freed.  But if it has been unmapped, we have no security against the
+        * anon_vma structure being freed and reused (for another anon_vma:
+        * SLAB_DESTROY_BY_RCU guarantees that - so the atomic_inc_not_zero()
+        * above cannot corrupt).
         */
-       if (page_mapped(page))
-               return anon_vma;
+       if (!page_mapped(page)) {
+               put_anon_vma(anon_vma);
+               anon_vma = NULL;
+       }
+out:
+       rcu_read_unlock();
+
+       return anon_vma;
+}
+
+/*
+ * Similar to page_get_anon_vma() except it locks the anon_vma.
+ *
+ * Its a little more complex as it tries to keep the fast path to a single
+ * atomic op -- the trylock. If we fail the trylock, we fall back to getting a
+ * reference like with page_get_anon_vma() and then block on the mutex.
+ */
+struct anon_vma *page_lock_anon_vma(struct page *page)
+{
+       struct anon_vma *anon_vma = NULL;
+       unsigned long anon_mapping;
+
+       rcu_read_lock();
+       anon_mapping = (unsigned long) ACCESS_ONCE(page->mapping);
+       if ((anon_mapping & PAGE_MAPPING_FLAGS) != PAGE_MAPPING_ANON)
+               goto out;
+       if (!page_mapped(page))
+               goto out;
+
+       anon_vma = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON);
+       if (mutex_trylock(&anon_vma->root->mutex)) {
+               /*
+                * If we observe a !0 refcount, then holding the lock ensures
+                * the anon_vma will not go away, see __put_anon_vma().
+                */
+               if (!atomic_read(&anon_vma->refcount)) {
+                       anon_vma_unlock(anon_vma);
+                       anon_vma = NULL;
+               }
+               goto out;
+       }
+
+       /* trylock failed, we got to sleep */
+       if (!atomic_inc_not_zero(&anon_vma->refcount)) {
+               anon_vma = NULL;
+               goto out;
+       }
+
+       if (!page_mapped(page)) {
+               put_anon_vma(anon_vma);
+               anon_vma = NULL;
+               goto out;
+       }
+
+       /* we pinned the anon_vma, its safe to sleep */
+       rcu_read_unlock();
+       anon_vma_lock(anon_vma);
+
+       if (atomic_dec_and_test(&anon_vma->refcount)) {
+               /*
+                * Oops, we held the last refcount, release the lock
+                * and bail -- can't simply use put_anon_vma() because
+                * we'll deadlock on the anon_vma_lock() recursion.
+                */
+               anon_vma_unlock(anon_vma);
+               __put_anon_vma(anon_vma);
+               anon_vma = NULL;
+       }
+
+       return anon_vma;
 
-       spin_unlock(&root_anon_vma->lock);
 out:
        rcu_read_unlock();
-       return NULL;
+       return anon_vma;
 }
 
 void page_unlock_anon_vma(struct anon_vma *anon_vma)
-       __releases(&anon_vma->root->lock)
-       __releases(RCU)
 {
        anon_vma_unlock(anon_vma);
-       rcu_read_unlock();
 }
 
 /*
@@ -646,14 +748,14 @@ static int page_referenced_file(struct page *page,
         * The page lock not only makes sure that page->mapping cannot
         * suddenly be NULLified by truncation, it makes sure that the
         * structure at mapping cannot be freed and reused yet,
-        * so we can safely take mapping->i_mmap_lock.
+        * so we can safely take mapping->i_mmap_mutex.
         */
        BUG_ON(!PageLocked(page));
 
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
 
        /*
-        * i_mmap_lock does not stabilize mapcount at all, but mapcount
+        * i_mmap_mutex does not stabilize mapcount at all, but mapcount
         * is more likely to be accurate if we note it after spinning.
         */
        mapcount = page_mapcount(page);
@@ -675,7 +777,7 @@ static int page_referenced_file(struct page *page,
                        break;
        }
 
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        return referenced;
 }
 
@@ -762,7 +864,7 @@ static int page_mkclean_file(struct address_space *mapping, struct page *page)
 
        BUG_ON(PageAnon(page));
 
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                if (vma->vm_flags & VM_SHARED) {
                        unsigned long address = vma_address(page, vma);
@@ -771,7 +873,7 @@ static int page_mkclean_file(struct address_space *mapping, struct page *page)
                        ret += page_mkclean_one(page, vma, address);
                }
        }
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        return ret;
 }
 
@@ -1119,7 +1221,7 @@ out_mlock:
        /*
         * We need mmap_sem locking, Otherwise VM_LOCKED check makes
         * unstable result and race. Plus, We can't wait here because
-        * we now hold anon_vma->lock or mapping->i_mmap_lock.
+        * we now hold anon_vma->mutex or mapping->i_mmap_mutex.
         * if trylock failed, the page remain in evictable lru and later
         * vmscan could retry to move the page to unevictable lru if the
         * page is actually mlocked.
@@ -1345,7 +1447,7 @@ static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
        unsigned long max_nl_size = 0;
        unsigned int mapcount;
 
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                unsigned long address = vma_address(page, vma);
                if (address == -EFAULT)
@@ -1391,7 +1493,7 @@ static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
        mapcount = page_mapcount(page);
        if (!mapcount)
                goto out;
-       cond_resched_lock(&mapping->i_mmap_lock);
+       cond_resched();
 
        max_nl_size = (max_nl_size + CLUSTER_SIZE - 1) & CLUSTER_MASK;
        if (max_nl_cursor == 0)
@@ -1413,7 +1515,7 @@ static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
                        }
                        vma->vm_private_data = (void *) max_nl_cursor;
                }
-               cond_resched_lock(&mapping->i_mmap_lock);
+               cond_resched();
                max_nl_cursor += CLUSTER_SIZE;
        } while (max_nl_cursor <= max_nl_size);
 
@@ -1425,7 +1527,7 @@ static int try_to_unmap_file(struct page *page, enum ttu_flags flags)
        list_for_each_entry(vma, &mapping->i_mmap_nonlinear, shared.vm_set.list)
                vma->vm_private_data = NULL;
 out:
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        return ret;
 }
 
@@ -1544,7 +1646,7 @@ static int rmap_walk_file(struct page *page, int (*rmap_one)(struct page *,
 
        if (!mapping)
                return ret;
-       spin_lock(&mapping->i_mmap_lock);
+       mutex_lock(&mapping->i_mmap_mutex);
        vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
                unsigned long address = vma_address(page, vma);
                if (address == -EFAULT)
@@ -1558,7 +1660,7 @@ static int rmap_walk_file(struct page *page, int (*rmap_one)(struct page *,
         * never contain migration ptes.  Decide what to do about this
         * limitation to linear when we need rmap_walk() on nonlinear.
         */
-       spin_unlock(&mapping->i_mmap_lock);
+       mutex_unlock(&mapping->i_mmap_mutex);
        return ret;
 }
 
index ba4ad28b7db6b81c141915a5d3eb4241fdbfd1a7..69edb45a9f2830d0919a313e977d35f6a94efdd7 100644 (file)
@@ -99,6 +99,13 @@ static struct vfsmount *shm_mnt;
 /* Pretend that each entry is of this size in directory's i_size */
 #define BOGO_DIRENT_SIZE 20
 
+struct shmem_xattr {
+       struct list_head list;  /* anchored by shmem_inode_info->xattr_list */
+       char *name;             /* xattr name */
+       size_t size;
+       char value[0];
+};
+
 /* Flag allocation requirements to shmem_getpage and shmem_swp_alloc */
 enum sgp_type {
        SGP_READ,       /* don't exceed i_size, don't allocate page */
@@ -822,6 +829,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
 static void shmem_evict_inode(struct inode *inode)
 {
        struct shmem_inode_info *info = SHMEM_I(inode);
+       struct shmem_xattr *xattr, *nxattr;
 
        if (inode->i_mapping->a_ops == &shmem_aops) {
                truncate_inode_pages(inode->i_mapping, 0);
@@ -834,6 +842,11 @@ static void shmem_evict_inode(struct inode *inode)
                        mutex_unlock(&shmem_swaplist_mutex);
                }
        }
+
+       list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
+               kfree(xattr->name);
+               kfree(xattr);
+       }
        BUG_ON(inode->i_blocks);
        shmem_free_inode(inode->i_sb);
        end_writeback(inode);
@@ -1615,6 +1628,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
                spin_lock_init(&info->lock);
                info->flags = flags & VM_NORESERVE;
                INIT_LIST_HEAD(&info->swaplist);
+               INIT_LIST_HEAD(&info->xattr_list);
                cache_no_acl(inode);
 
                switch (mode & S_IFMT) {
@@ -2014,9 +2028,9 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
 
        info = SHMEM_I(inode);
        inode->i_size = len-1;
-       if (len <= (char *)inode - (char *)info) {
+       if (len <= SHMEM_SYMLINK_INLINE_LEN) {
                /* do it inline */
-               memcpy(info, symname, len);
+               memcpy(info->inline_symlink, symname, len);
                inode->i_op = &shmem_symlink_inline_operations;
        } else {
                error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
@@ -2042,7 +2056,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
 
 static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
 {
-       nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode));
+       nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink);
        return NULL;
 }
 
@@ -2066,63 +2080,253 @@ static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *co
        }
 }
 
-static const struct inode_operations shmem_symlink_inline_operations = {
-       .readlink       = generic_readlink,
-       .follow_link    = shmem_follow_link_inline,
-};
-
-static const struct inode_operations shmem_symlink_inode_operations = {
-       .readlink       = generic_readlink,
-       .follow_link    = shmem_follow_link,
-       .put_link       = shmem_put_link,
-};
-
-#ifdef CONFIG_TMPFS_POSIX_ACL
+#ifdef CONFIG_TMPFS_XATTR
 /*
- * Superblocks without xattr inode operations will get security.* xattr
- * support from the VFS "for free". As soon as we have any other xattrs
+ * Superblocks without xattr inode operations may get some security.* xattr
+ * support from the LSM "for free". As soon as we have any other xattrs
  * like ACLs, we also need to implement the security.* handlers at
  * filesystem level, though.
  */
 
-static size_t shmem_xattr_security_list(struct dentry *dentry, char *list,
-                                       size_t list_len, const char *name,
-                                       size_t name_len, int handler_flags)
+static int shmem_xattr_get(struct dentry *dentry, const char *name,
+                          void *buffer, size_t size)
 {
-       return security_inode_listsecurity(dentry->d_inode, list, list_len);
-}
+       struct shmem_inode_info *info;
+       struct shmem_xattr *xattr;
+       int ret = -ENODATA;
 
-static int shmem_xattr_security_get(struct dentry *dentry, const char *name,
-               void *buffer, size_t size, int handler_flags)
-{
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-       return xattr_getsecurity(dentry->d_inode, name, buffer, size);
+       info = SHMEM_I(dentry->d_inode);
+
+       spin_lock(&info->lock);
+       list_for_each_entry(xattr, &info->xattr_list, list) {
+               if (strcmp(name, xattr->name))
+                       continue;
+
+               ret = xattr->size;
+               if (buffer) {
+                       if (size < xattr->size)
+                               ret = -ERANGE;
+                       else
+                               memcpy(buffer, xattr->value, xattr->size);
+               }
+               break;
+       }
+       spin_unlock(&info->lock);
+       return ret;
 }
 
-static int shmem_xattr_security_set(struct dentry *dentry, const char *name,
-               const void *value, size_t size, int flags, int handler_flags)
+static int shmem_xattr_set(struct dentry *dentry, const char *name,
+                          const void *value, size_t size, int flags)
 {
-       if (strcmp(name, "") == 0)
-               return -EINVAL;
-       return security_inode_setsecurity(dentry->d_inode, name, value,
-                                         size, flags);
+       struct inode *inode = dentry->d_inode;
+       struct shmem_inode_info *info = SHMEM_I(inode);
+       struct shmem_xattr *xattr;
+       struct shmem_xattr *new_xattr = NULL;
+       size_t len;
+       int err = 0;
+
+       /* value == NULL means remove */
+       if (value) {
+               /* wrap around? */
+               len = sizeof(*new_xattr) + size;
+               if (len <= sizeof(*new_xattr))
+                       return -ENOMEM;
+
+               new_xattr = kmalloc(len, GFP_KERNEL);
+               if (!new_xattr)
+                       return -ENOMEM;
+
+               new_xattr->name = kstrdup(name, GFP_KERNEL);
+               if (!new_xattr->name) {
+                       kfree(new_xattr);
+                       return -ENOMEM;
+               }
+
+               new_xattr->size = size;
+               memcpy(new_xattr->value, value, size);
+       }
+
+       spin_lock(&info->lock);
+       list_for_each_entry(xattr, &info->xattr_list, list) {
+               if (!strcmp(name, xattr->name)) {
+                       if (flags & XATTR_CREATE) {
+                               xattr = new_xattr;
+                               err = -EEXIST;
+                       } else if (new_xattr) {
+                               list_replace(&xattr->list, &new_xattr->list);
+                       } else {
+                               list_del(&xattr->list);
+                       }
+                       goto out;
+               }
+       }
+       if (flags & XATTR_REPLACE) {
+               xattr = new_xattr;
+               err = -ENODATA;
+       } else {
+               list_add(&new_xattr->list, &info->xattr_list);
+               xattr = NULL;
+       }
+out:
+       spin_unlock(&info->lock);
+       if (xattr)
+               kfree(xattr->name);
+       kfree(xattr);
+       return err;
 }
 
-static const struct xattr_handler shmem_xattr_security_handler = {
-       .prefix = XATTR_SECURITY_PREFIX,
-       .list   = shmem_xattr_security_list,
-       .get    = shmem_xattr_security_get,
-       .set    = shmem_xattr_security_set,
-};
 
 static const struct xattr_handler *shmem_xattr_handlers[] = {
+#ifdef CONFIG_TMPFS_POSIX_ACL
        &generic_acl_access_handler,
        &generic_acl_default_handler,
-       &shmem_xattr_security_handler,
+#endif
        NULL
 };
+
+static int shmem_xattr_validate(const char *name)
+{
+       struct { const char *prefix; size_t len; } arr[] = {
+               { XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
+               { XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
+       };
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(arr); i++) {
+               size_t preflen = arr[i].len;
+               if (strncmp(name, arr[i].prefix, preflen) == 0) {
+                       if (!name[preflen])
+                               return -EINVAL;
+                       return 0;
+               }
+       }
+       return -EOPNOTSUPP;
+}
+
+static ssize_t shmem_getxattr(struct dentry *dentry, const char *name,
+                             void *buffer, size_t size)
+{
+       int err;
+
+       /*
+        * If this is a request for a synthetic attribute in the system.*
+        * namespace use the generic infrastructure to resolve a handler
+        * for it via sb->s_xattr.
+        */
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_getxattr(dentry, name, buffer, size);
+
+       err = shmem_xattr_validate(name);
+       if (err)
+               return err;
+
+       return shmem_xattr_get(dentry, name, buffer, size);
+}
+
+static int shmem_setxattr(struct dentry *dentry, const char *name,
+                         const void *value, size_t size, int flags)
+{
+       int err;
+
+       /*
+        * If this is a request for a synthetic attribute in the system.*
+        * namespace use the generic infrastructure to resolve a handler
+        * for it via sb->s_xattr.
+        */
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_setxattr(dentry, name, value, size, flags);
+
+       err = shmem_xattr_validate(name);
+       if (err)
+               return err;
+
+       if (size == 0)
+               value = "";  /* empty EA, do not remove */
+
+       return shmem_xattr_set(dentry, name, value, size, flags);
+
+}
+
+static int shmem_removexattr(struct dentry *dentry, const char *name)
+{
+       int err;
+
+       /*
+        * If this is a request for a synthetic attribute in the system.*
+        * namespace use the generic infrastructure to resolve a handler
+        * for it via sb->s_xattr.
+        */
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_removexattr(dentry, name);
+
+       err = shmem_xattr_validate(name);
+       if (err)
+               return err;
+
+       return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
+}
+
+static bool xattr_is_trusted(const char *name)
+{
+       return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
+}
+
+static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+       bool trusted = capable(CAP_SYS_ADMIN);
+       struct shmem_xattr *xattr;
+       struct shmem_inode_info *info;
+       size_t used = 0;
+
+       info = SHMEM_I(dentry->d_inode);
+
+       spin_lock(&info->lock);
+       list_for_each_entry(xattr, &info->xattr_list, list) {
+               size_t len;
+
+               /* skip "trusted." attributes for unprivileged callers */
+               if (!trusted && xattr_is_trusted(xattr->name))
+                       continue;
+
+               len = strlen(xattr->name) + 1;
+               used += len;
+               if (buffer) {
+                       if (size < used) {
+                               used = -ERANGE;
+                               break;
+                       }
+                       memcpy(buffer, xattr->name, len);
+                       buffer += len;
+               }
+       }
+       spin_unlock(&info->lock);
+
+       return used;
+}
+#endif /* CONFIG_TMPFS_XATTR */
+
+static const struct inode_operations shmem_symlink_inline_operations = {
+       .readlink       = generic_readlink,
+       .follow_link    = shmem_follow_link_inline,
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
+#endif
+};
+
+static const struct inode_operations shmem_symlink_inode_operations = {
+       .readlink       = generic_readlink,
+       .follow_link    = shmem_follow_link,
+       .put_link       = shmem_put_link,
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
 #endif
+};
 
 static struct dentry *shmem_get_parent(struct dentry *child)
 {
@@ -2402,8 +2606,10 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_magic = TMPFS_MAGIC;
        sb->s_op = &shmem_ops;
        sb->s_time_gran = 1;
-#ifdef CONFIG_TMPFS_POSIX_ACL
+#ifdef CONFIG_TMPFS_XATTR
        sb->s_xattr = shmem_xattr_handlers;
+#endif
+#ifdef CONFIG_TMPFS_POSIX_ACL
        sb->s_flags |= MS_POSIXACL;
 #endif
 
@@ -2501,11 +2707,13 @@ static const struct file_operations shmem_file_operations = {
 static const struct inode_operations shmem_inode_operations = {
        .setattr        = shmem_notify_change,
        .truncate_range = shmem_truncate_range,
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
+#endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
        .check_acl      = generic_check_acl,
 #endif
 
@@ -2523,23 +2731,27 @@ static const struct inode_operations shmem_dir_inode_operations = {
        .mknod          = shmem_mknod,
        .rename         = shmem_rename,
 #endif
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
+#endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
        .setattr        = shmem_notify_change,
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
        .check_acl      = generic_check_acl,
 #endif
 };
 
 static const struct inode_operations shmem_special_inode_operations = {
+#ifdef CONFIG_TMPFS_XATTR
+       .setxattr       = shmem_setxattr,
+       .getxattr       = shmem_getxattr,
+       .listxattr      = shmem_listxattr,
+       .removexattr    = shmem_removexattr,
+#endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
        .setattr        = shmem_notify_change,
-       .setxattr       = generic_setxattr,
-       .getxattr       = generic_getxattr,
-       .listxattr      = generic_listxattr,
-       .removexattr    = generic_removexattr,
        .check_acl      = generic_check_acl,
 #endif
 };
index 4ea7f1a22a9468f332f529c60e7be0b85a97616f..7be0223531b090dbd9f716104714bc4d9ca9c7b5 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1831,7 +1831,6 @@ load_freelist:
        page->inuse = page->objects;
        page->freelist = NULL;
 
-unlock_out:
        slab_unlock(page);
        c->tid = next_tid(c->tid);
        local_irq_restore(flags);
@@ -1884,7 +1883,8 @@ debug:
        deactivate_slab(s, c);
        c->page = NULL;
        c->node = NUMA_NO_NODE;
-       goto unlock_out;
+       local_irq_restore(flags);
+       return object;
 }
 
 /*
index 5602f1a1b1e724ba547bdee3ef21d773fd24ee04..3a442f18b0b3dab5acfd99b5fc4e85389b9b5439 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -272,14 +272,10 @@ static void update_page_reclaim_stat(struct zone *zone, struct page *page,
                memcg_reclaim_stat->recent_rotated[file]++;
 }
 
-/*
- * FIXME: speed this up?
- */
-void activate_page(struct page *page)
+static void __activate_page(struct page *page, void *arg)
 {
        struct zone *zone = page_zone(page);
 
-       spin_lock_irq(&zone->lru_lock);
        if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
                int file = page_is_file_cache(page);
                int lru = page_lru_base_type(page);
@@ -292,8 +288,45 @@ void activate_page(struct page *page)
 
                update_page_reclaim_stat(zone, page, file, 1);
        }
+}
+
+#ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct pagevec, activate_page_pvecs);
+
+static void activate_page_drain(int cpu)
+{
+       struct pagevec *pvec = &per_cpu(activate_page_pvecs, cpu);
+
+       if (pagevec_count(pvec))
+               pagevec_lru_move_fn(pvec, __activate_page, NULL);
+}
+
+void activate_page(struct page *page)
+{
+       if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
+               struct pagevec *pvec = &get_cpu_var(activate_page_pvecs);
+
+               page_cache_get(page);
+               if (!pagevec_add(pvec, page))
+                       pagevec_lru_move_fn(pvec, __activate_page, NULL);
+               put_cpu_var(activate_page_pvecs);
+       }
+}
+
+#else
+static inline void activate_page_drain(int cpu)
+{
+}
+
+void activate_page(struct page *page)
+{
+       struct zone *zone = page_zone(page);
+
+       spin_lock_irq(&zone->lru_lock);
+       __activate_page(page, NULL);
        spin_unlock_irq(&zone->lru_lock);
 }
+#endif
 
 /*
  * Mark a page as having seen activity.
@@ -464,6 +497,8 @@ static void drain_cpu_pagevecs(int cpu)
        pvec = &per_cpu(lru_deactivate_pvecs, cpu);
        if (pagevec_count(pvec))
                pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL);
+
+       activate_page_drain(cpu);
 }
 
 /**
@@ -476,6 +511,13 @@ static void drain_cpu_pagevecs(int cpu)
  */
 void deactivate_page(struct page *page)
 {
+       /*
+        * In a workload with many unevictable page such as mprotect, unevictable
+        * page deactivation for accelerating reclaim is pointless.
+        */
+       if (PageUnevictable(page))
+               return;
+
        if (likely(get_page_unless_zero(page))) {
                struct pagevec *pvec = &get_cpu_var(lru_deactivate_pvecs);
 
index 8c6b3ce38f09aa0e4f824ce3f70e6e9254a87724..d537d29e9b7bb5d9364b531e17f972618a5cad4b 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/syscalls.h>
 #include <linux/memcontrol.h>
 #include <linux/poll.h>
+#include <linux/oom.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -1555,6 +1556,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        struct address_space *mapping;
        struct inode *inode;
        char *pathname;
+       int oom_score_adj;
        int i, type, prev;
        int err;
 
@@ -1613,9 +1615,9 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        p->flags &= ~SWP_WRITEOK;
        spin_unlock(&swap_lock);
 
-       current->flags |= PF_OOM_ORIGIN;
+       oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX);
        err = try_to_unuse(type);
-       current->flags &= ~PF_OOM_ORIGIN;
+       test_set_oom_score_adj(oom_score_adj);
 
        if (err) {
                /*
index e7b103a6fd21c50857eda25cb5750e6d319e6498..88ea1bd661c0f5164e37a8415050808fa815808f 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -6,6 +6,8 @@
 #include <linux/sched.h>
 #include <asm/uaccess.h>
 
+#include "internal.h"
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/kmem.h>
 
@@ -215,6 +217,28 @@ char *strndup_user(const char __user *s, long n)
 }
 EXPORT_SYMBOL(strndup_user);
 
+void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
+               struct vm_area_struct *prev, struct rb_node *rb_parent)
+{
+       struct vm_area_struct *next;
+
+       vma->vm_prev = prev;
+       if (prev) {
+               next = prev->vm_next;
+               prev->vm_next = vma;
+       } else {
+               mm->mmap = vma;
+               if (rb_parent)
+                       next = rb_entry(rb_parent,
+                                       struct vm_area_struct, vm_rb);
+               else
+                       next = NULL;
+       }
+       vma->vm_next = next;
+       if (next)
+               next->vm_prev = vma;
+}
+
 #if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT)
 void arch_pick_mmap_layout(struct mm_struct *mm)
 {
index 5d6030235d7a8e4462498e6d9154ca97029069ed..b5ccf3158d82440525eecceb66e0f291e7cd2795 100644 (file)
@@ -375,7 +375,7 @@ nocache:
        /* find starting point for our search */
        if (free_vmap_cache) {
                first = rb_entry(free_vmap_cache, struct vmap_area, rb_node);
-               addr = ALIGN(first->va_end + PAGE_SIZE, align);
+               addr = ALIGN(first->va_end, align);
                if (addr < vstart)
                        goto nocache;
                if (addr + size - 1 < addr)
@@ -406,10 +406,10 @@ nocache:
        }
 
        /* from the starting point, walk areas until a suitable hole is found */
-       while (addr + size >= first->va_start && addr + size <= vend) {
+       while (addr + size > first->va_start && addr + size <= vend) {
                if (addr + cached_hole_size < first->va_start)
                        cached_hole_size = first->va_start - addr;
-               addr = ALIGN(first->va_end + PAGE_SIZE, align);
+               addr = ALIGN(first->va_end, align);
                if (addr + size - 1 < addr)
                        goto overflow;
 
@@ -1534,6 +1534,7 @@ static void *__vmalloc_node(unsigned long size, unsigned long align,
 static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
                                 pgprot_t prot, int node, void *caller)
 {
+       const int order = 0;
        struct page **pages;
        unsigned int nr_pages, array_size, i;
        gfp_t nested_gfp = (gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO;
@@ -1560,11 +1561,12 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
 
        for (i = 0; i < area->nr_pages; i++) {
                struct page *page;
+               gfp_t tmp_mask = gfp_mask | __GFP_NOWARN;
 
                if (node < 0)
-                       page = alloc_page(gfp_mask);
+                       page = alloc_page(tmp_mask);
                else
-                       page = alloc_pages_node(node, gfp_mask, 0);
+                       page = alloc_pages_node(node, tmp_mask, order);
 
                if (unlikely(!page)) {
                        /* Successfully allocated i pages, free them in __vunmap() */
@@ -1579,6 +1581,9 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
        return area->addr;
 
 fail:
+       warn_alloc_failed(gfp_mask, order, "vmalloc: allocation failure, "
+                         "allocated %ld of %ld bytes\n",
+                         (area->nr_pages*PAGE_SIZE), area->size);
        vfree(area->addr);
        return NULL;
 }
index c9177202c8ce2ce2f9bfe9045f2a40a8105de8e8..7e0116150dc73a02b762cb8939c5db34688aa194 100644 (file)
@@ -202,6 +202,14 @@ void unregister_shrinker(struct shrinker *shrinker)
 }
 EXPORT_SYMBOL(unregister_shrinker);
 
+static inline int do_shrinker_shrink(struct shrinker *shrinker,
+                                    struct shrink_control *sc,
+                                    unsigned long nr_to_scan)
+{
+       sc->nr_to_scan = nr_to_scan;
+       return (*shrinker->shrink)(shrinker, sc);
+}
+
 #define SHRINK_BATCH 128
 /*
  * Call the shrink functions to age shrinkable caches
@@ -222,25 +230,29 @@ EXPORT_SYMBOL(unregister_shrinker);
  *
  * Returns the number of slab objects which we shrunk.
  */
-unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
-                       unsigned long lru_pages)
+unsigned long shrink_slab(struct shrink_control *shrink,
+                         unsigned long nr_pages_scanned,
+                         unsigned long lru_pages)
 {
        struct shrinker *shrinker;
        unsigned long ret = 0;
 
-       if (scanned == 0)
-               scanned = SWAP_CLUSTER_MAX;
+       if (nr_pages_scanned == 0)
+               nr_pages_scanned = SWAP_CLUSTER_MAX;
 
-       if (!down_read_trylock(&shrinker_rwsem))
-               return 1;       /* Assume we'll be able to shrink next time */
+       if (!down_read_trylock(&shrinker_rwsem)) {
+               /* Assume we'll be able to shrink next time */
+               ret = 1;
+               goto out;
+       }
 
        list_for_each_entry(shrinker, &shrinker_list, list) {
                unsigned long long delta;
                unsigned long total_scan;
                unsigned long max_pass;
 
-               max_pass = (*shrinker->shrink)(shrinker, 0, gfp_mask);
-               delta = (4 * scanned) / shrinker->seeks;
+               max_pass = do_shrinker_shrink(shrinker, shrink, 0);
+               delta = (4 * nr_pages_scanned) / shrinker->seeks;
                delta *= max_pass;
                do_div(delta, lru_pages + 1);
                shrinker->nr += delta;
@@ -267,9 +279,9 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
                        int shrink_ret;
                        int nr_before;
 
-                       nr_before = (*shrinker->shrink)(shrinker, 0, gfp_mask);
-                       shrink_ret = (*shrinker->shrink)(shrinker, this_scan,
-                                                               gfp_mask);
+                       nr_before = do_shrinker_shrink(shrinker, shrink, 0);
+                       shrink_ret = do_shrinker_shrink(shrinker, shrink,
+                                                       this_scan);
                        if (shrink_ret == -1)
                                break;
                        if (shrink_ret < nr_before)
@@ -283,6 +295,8 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
                shrinker->nr += total_scan;
        }
        up_read(&shrinker_rwsem);
+out:
+       cond_resched();
        return ret;
 }
 
@@ -1202,13 +1216,16 @@ int isolate_lru_page(struct page *page)
 {
        int ret = -EBUSY;
 
+       VM_BUG_ON(!page_count(page));
+
        if (PageLRU(page)) {
                struct zone *zone = page_zone(page);
 
                spin_lock_irq(&zone->lru_lock);
-               if (PageLRU(page) && get_page_unless_zero(page)) {
+               if (PageLRU(page)) {
                        int lru = page_lru(page);
                        ret = 0;
+                       get_page(page);
                        ClearPageLRU(page);
 
                        del_page_from_lru_list(zone, page, lru);
@@ -2027,7 +2044,8 @@ static bool all_unreclaimable(struct zonelist *zonelist,
  *             else, the number of pages reclaimed
  */
 static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
-                                       struct scan_control *sc)
+                                       struct scan_control *sc,
+                                       struct shrink_control *shrink)
 {
        int priority;
        unsigned long total_scanned = 0;
@@ -2061,7 +2079,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                                lru_pages += zone_reclaimable_pages(zone);
                        }
 
-                       shrink_slab(sc->nr_scanned, sc->gfp_mask, lru_pages);
+                       shrink_slab(shrink, sc->nr_scanned, lru_pages);
                        if (reclaim_state) {
                                sc->nr_reclaimed += reclaim_state->reclaimed_slab;
                                reclaim_state->reclaimed_slab = 0;
@@ -2133,12 +2151,15 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
                .mem_cgroup = NULL,
                .nodemask = nodemask,
        };
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
+       };
 
        trace_mm_vmscan_direct_reclaim_begin(order,
                                sc.may_writepage,
                                gfp_mask);
 
-       nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
+       nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
 
        trace_mm_vmscan_direct_reclaim_end(nr_reclaimed);
 
@@ -2198,17 +2219,20 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
                .order = 0,
                .mem_cgroup = mem_cont,
                .nodemask = NULL, /* we don't care the placement */
+               .gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
+                               (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK),
+       };
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
        };
 
-       sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
-                       (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
        zonelist = NODE_DATA(numa_node_id())->node_zonelists;
 
        trace_mm_vmscan_memcg_reclaim_begin(0,
                                            sc.may_writepage,
                                            sc.gfp_mask);
 
-       nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
+       nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
 
        trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
 
@@ -2287,7 +2311,7 @@ static bool sleeping_prematurely(pg_data_t *pgdat, int order, long remaining,
         * must be balanced
         */
        if (order)
-               return pgdat_balanced(pgdat, balanced, classzone_idx);
+               return !pgdat_balanced(pgdat, balanced, classzone_idx);
        else
                return !all_zones_ok;
 }
@@ -2336,6 +2360,9 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
                .order = order,
                .mem_cgroup = NULL,
        };
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
+       };
 loop_again:
        total_scanned = 0;
        sc.nr_reclaimed = 0;
@@ -2435,8 +2462,7 @@ loop_again:
                                        end_zone, 0))
                                shrink_zone(priority, zone, &sc);
                        reclaim_state->reclaimed_slab = 0;
-                       nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL,
-                                               lru_pages);
+                       nr_slab = shrink_slab(&shrink, sc.nr_scanned, lru_pages);
                        sc.nr_reclaimed += reclaim_state->reclaimed_slab;
                        total_scanned += sc.nr_scanned;
 
@@ -2788,7 +2814,10 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
                .swappiness = vm_swappiness,
                .order = 0,
        };
-       struct zonelist * zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
+       };
+       struct zonelist *zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
        struct task_struct *p = current;
        unsigned long nr_reclaimed;
 
@@ -2797,7 +2826,7 @@ unsigned long shrink_all_memory(unsigned long nr_to_reclaim)
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
 
-       nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
+       nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
 
        p->reclaim_state = NULL;
        lockdep_clear_current_reclaim_state();
@@ -2972,6 +3001,9 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
                .swappiness = vm_swappiness,
                .order = order,
        };
+       struct shrink_control shrink = {
+               .gfp_mask = sc.gfp_mask,
+       };
        unsigned long nr_slab_pages0, nr_slab_pages1;
 
        cond_resched();
@@ -3013,7 +3045,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
                        unsigned long lru_pages = zone_reclaimable_pages(zone);
 
                        /* No reclaimable slab or very low memory pressure */
-                       if (!shrink_slab(sc.nr_scanned, gfp_mask, lru_pages))
+                       if (!shrink_slab(&shrink, sc.nr_scanned, lru_pages))
                                break;
 
                        /* Freed enough memory */
index 897ea9e88238d1a9ffd99c4f35124988bbc85ef0..20c18b7694b284f236149612335d017a2419f063 100644 (file)
@@ -157,7 +157,7 @@ int calculate_normal_threshold(struct zone *zone)
 /*
  * Refresh the thresholds for each zone.
  */
-static void refresh_zone_stat_thresholds(void)
+void refresh_zone_stat_thresholds(void)
 {
        struct zone *zone;
        int cpu;
@@ -659,6 +659,138 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
 }
 #endif
 
+#if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS)
+#ifdef CONFIG_ZONE_DMA
+#define TEXT_FOR_DMA(xx) xx "_dma",
+#else
+#define TEXT_FOR_DMA(xx)
+#endif
+
+#ifdef CONFIG_ZONE_DMA32
+#define TEXT_FOR_DMA32(xx) xx "_dma32",
+#else
+#define TEXT_FOR_DMA32(xx)
+#endif
+
+#ifdef CONFIG_HIGHMEM
+#define TEXT_FOR_HIGHMEM(xx) xx "_high",
+#else
+#define TEXT_FOR_HIGHMEM(xx)
+#endif
+
+#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
+                                       TEXT_FOR_HIGHMEM(xx) xx "_movable",
+
+const char * const vmstat_text[] = {
+       /* Zoned VM counters */
+       "nr_free_pages",
+       "nr_inactive_anon",
+       "nr_active_anon",
+       "nr_inactive_file",
+       "nr_active_file",
+       "nr_unevictable",
+       "nr_mlock",
+       "nr_anon_pages",
+       "nr_mapped",
+       "nr_file_pages",
+       "nr_dirty",
+       "nr_writeback",
+       "nr_slab_reclaimable",
+       "nr_slab_unreclaimable",
+       "nr_page_table_pages",
+       "nr_kernel_stack",
+       "nr_unstable",
+       "nr_bounce",
+       "nr_vmscan_write",
+       "nr_writeback_temp",
+       "nr_isolated_anon",
+       "nr_isolated_file",
+       "nr_shmem",
+       "nr_dirtied",
+       "nr_written",
+
+#ifdef CONFIG_NUMA
+       "numa_hit",
+       "numa_miss",
+       "numa_foreign",
+       "numa_interleave",
+       "numa_local",
+       "numa_other",
+#endif
+       "nr_anon_transparent_hugepages",
+       "nr_dirty_threshold",
+       "nr_dirty_background_threshold",
+
+#ifdef CONFIG_VM_EVENT_COUNTERS
+       "pgpgin",
+       "pgpgout",
+       "pswpin",
+       "pswpout",
+
+       TEXTS_FOR_ZONES("pgalloc")
+
+       "pgfree",
+       "pgactivate",
+       "pgdeactivate",
+
+       "pgfault",
+       "pgmajfault",
+
+       TEXTS_FOR_ZONES("pgrefill")
+       TEXTS_FOR_ZONES("pgsteal")
+       TEXTS_FOR_ZONES("pgscan_kswapd")
+       TEXTS_FOR_ZONES("pgscan_direct")
+
+#ifdef CONFIG_NUMA
+       "zone_reclaim_failed",
+#endif
+       "pginodesteal",
+       "slabs_scanned",
+       "kswapd_steal",
+       "kswapd_inodesteal",
+       "kswapd_low_wmark_hit_quickly",
+       "kswapd_high_wmark_hit_quickly",
+       "kswapd_skip_congestion_wait",
+       "pageoutrun",
+       "allocstall",
+
+       "pgrotated",
+
+#ifdef CONFIG_COMPACTION
+       "compact_blocks_moved",
+       "compact_pages_moved",
+       "compact_pagemigrate_failed",
+       "compact_stall",
+       "compact_fail",
+       "compact_success",
+#endif
+
+#ifdef CONFIG_HUGETLB_PAGE
+       "htlb_buddy_alloc_success",
+       "htlb_buddy_alloc_fail",
+#endif
+       "unevictable_pgs_culled",
+       "unevictable_pgs_scanned",
+       "unevictable_pgs_rescued",
+       "unevictable_pgs_mlocked",
+       "unevictable_pgs_munlocked",
+       "unevictable_pgs_cleared",
+       "unevictable_pgs_stranded",
+       "unevictable_pgs_mlockfreed",
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       "thp_fault_alloc",
+       "thp_fault_fallback",
+       "thp_collapse_alloc",
+       "thp_collapse_alloc_failed",
+       "thp_split",
+#endif
+
+#endif /* CONFIG_VM_EVENTS_COUNTERS */
+};
+#endif /* CONFIG_PROC_FS || CONFIG_SYSFS */
+
+
 #ifdef CONFIG_PROC_FS
 static void frag_show_print(struct seq_file *m, pg_data_t *pgdat,
                                                struct zone *zone)
@@ -831,135 +963,6 @@ static const struct file_operations pagetypeinfo_file_ops = {
        .release        = seq_release,
 };
 
-#ifdef CONFIG_ZONE_DMA
-#define TEXT_FOR_DMA(xx) xx "_dma",
-#else
-#define TEXT_FOR_DMA(xx)
-#endif
-
-#ifdef CONFIG_ZONE_DMA32
-#define TEXT_FOR_DMA32(xx) xx "_dma32",
-#else
-#define TEXT_FOR_DMA32(xx)
-#endif
-
-#ifdef CONFIG_HIGHMEM
-#define TEXT_FOR_HIGHMEM(xx) xx "_high",
-#else
-#define TEXT_FOR_HIGHMEM(xx)
-#endif
-
-#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
-                                       TEXT_FOR_HIGHMEM(xx) xx "_movable",
-
-static const char * const vmstat_text[] = {
-       /* Zoned VM counters */
-       "nr_free_pages",
-       "nr_inactive_anon",
-       "nr_active_anon",
-       "nr_inactive_file",
-       "nr_active_file",
-       "nr_unevictable",
-       "nr_mlock",
-       "nr_anon_pages",
-       "nr_mapped",
-       "nr_file_pages",
-       "nr_dirty",
-       "nr_writeback",
-       "nr_slab_reclaimable",
-       "nr_slab_unreclaimable",
-       "nr_page_table_pages",
-       "nr_kernel_stack",
-       "nr_unstable",
-       "nr_bounce",
-       "nr_vmscan_write",
-       "nr_writeback_temp",
-       "nr_isolated_anon",
-       "nr_isolated_file",
-       "nr_shmem",
-       "nr_dirtied",
-       "nr_written",
-
-#ifdef CONFIG_NUMA
-       "numa_hit",
-       "numa_miss",
-       "numa_foreign",
-       "numa_interleave",
-       "numa_local",
-       "numa_other",
-#endif
-       "nr_anon_transparent_hugepages",
-       "nr_dirty_threshold",
-       "nr_dirty_background_threshold",
-
-#ifdef CONFIG_VM_EVENT_COUNTERS
-       "pgpgin",
-       "pgpgout",
-       "pswpin",
-       "pswpout",
-
-       TEXTS_FOR_ZONES("pgalloc")
-
-       "pgfree",
-       "pgactivate",
-       "pgdeactivate",
-
-       "pgfault",
-       "pgmajfault",
-
-       TEXTS_FOR_ZONES("pgrefill")
-       TEXTS_FOR_ZONES("pgsteal")
-       TEXTS_FOR_ZONES("pgscan_kswapd")
-       TEXTS_FOR_ZONES("pgscan_direct")
-
-#ifdef CONFIG_NUMA
-       "zone_reclaim_failed",
-#endif
-       "pginodesteal",
-       "slabs_scanned",
-       "kswapd_steal",
-       "kswapd_inodesteal",
-       "kswapd_low_wmark_hit_quickly",
-       "kswapd_high_wmark_hit_quickly",
-       "kswapd_skip_congestion_wait",
-       "pageoutrun",
-       "allocstall",
-
-       "pgrotated",
-
-#ifdef CONFIG_COMPACTION
-       "compact_blocks_moved",
-       "compact_pages_moved",
-       "compact_pagemigrate_failed",
-       "compact_stall",
-       "compact_fail",
-       "compact_success",
-#endif
-
-#ifdef CONFIG_HUGETLB_PAGE
-       "htlb_buddy_alloc_success",
-       "htlb_buddy_alloc_fail",
-#endif
-       "unevictable_pgs_culled",
-       "unevictable_pgs_scanned",
-       "unevictable_pgs_rescued",
-       "unevictable_pgs_mlocked",
-       "unevictable_pgs_munlocked",
-       "unevictable_pgs_cleared",
-       "unevictable_pgs_stranded",
-       "unevictable_pgs_mlockfreed",
-
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       "thp_fault_alloc",
-       "thp_fault_fallback",
-       "thp_collapse_alloc",
-       "thp_collapse_alloc_failed",
-       "thp_split",
-#endif
-
-#endif /* CONFIG_VM_EVENTS_COUNTERS */
-};
-
 static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
                                                        struct zone *zone)
 {
@@ -1198,7 +1201,6 @@ static int __init setup_vmstat(void)
 #ifdef CONFIG_SMP
        int cpu;
 
-       refresh_zone_stat_thresholds();
        register_cpu_notifier(&vmstat_notifier);
 
        for_each_online_cpu(cpu)
index 21cde8fd5795310a823367783cc3f4cd9eb92d0c..db6baf7cf6e97779bdf5405aa55cfe282107a5fe 100644 (file)
@@ -147,7 +147,6 @@ struct datalink_proto *register_snap_client(const unsigned char *desc,
 out:
        spin_unlock_bh(&snap_lock);
 
-       synchronize_net();
        return proto;
 }
 
index c3408def8a19992014f94fa193115c8054585065..9da07e30d1a250aabd453bbe90e1aa6bd18c8521 100644 (file)
@@ -118,11 +118,6 @@ extern void vlan_netlink_fini(void);
 
 extern struct rtnl_link_ops vlan_link_ops;
 
-static inline int is_vlan_dev(struct net_device *dev)
-{
-       return dev->priv_flags & IFF_802_1Q_VLAN;
-}
-
 extern int vlan_net_id;
 
 struct proc_dir_entry;
index 7ed75c7bd5d1384943e7425dd9c81f44983fec8e..d9ea09b11cf8140529b0649b34a5252a551e81b5 100644 (file)
@@ -3,8 +3,8 @@
 #
 
 menuconfig NET_9P
-       depends on NET && EXPERIMENTAL
-       tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
+       depends on NET
+       tristate "Plan 9 Resource Sharing Support (9P2000)"
        help
          If you say Y here, you will get experimental support for
          Plan 9 resource sharing via the 9P2000 protocol.
@@ -16,8 +16,8 @@ menuconfig NET_9P
 if NET_9P
 
 config NET_9P_VIRTIO
-       depends on EXPERIMENTAL && VIRTIO
-       tristate "9P Virtio Transport (Experimental)"
+       depends on VIRTIO
+       tristate "9P Virtio Transport"
        help
          This builds support for a transports between
          guest partitions and a host partition.
index ceab943dfc496cd10467f78c948d28ebf1d29a93..9e3b0e640da179a122f6f846bd8cff31920db159 100644 (file)
@@ -92,9 +92,6 @@ static int get_protocol_version(const substring_t *name)
        return version;
 }
 
-static struct p9_req_t *
-p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
-
 /**
  * parse_options - parse mount options into client structure
  * @opts: options string passed from mount
@@ -307,12 +304,13 @@ static int p9_tag_init(struct p9_client *c)
        c->tagpool = p9_idpool_create();
        if (IS_ERR(c->tagpool)) {
                err = PTR_ERR(c->tagpool);
-               c->tagpool = NULL;
                goto error;
        }
-
-       p9_idpool_get(c->tagpool); /* reserve tag 0 */
-
+       err = p9_idpool_get(c->tagpool); /* reserve tag 0 */
+       if (err < 0) {
+               p9_idpool_destroy(c->tagpool);
+               goto error;
+       }
        c->max_tag = 0;
 error:
        return err;
@@ -518,12 +516,15 @@ out_err:
        return err;
 }
 
+static struct p9_req_t *
+p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
+
 /**
  * p9_client_flush - flush (cancel) a request
  * @c: client state
  * @oldreq: request to cancel
  *
- * This sents a flush for a particular requests and links
+ * This sents a flush for a particular request and links
  * the flush request to the original request.  The current
  * code only supports a single flush request although the protocol
  * allows for multiple flush requests to be sent for a single request.
@@ -789,11 +790,13 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
        spin_lock_init(&clnt->lock);
        INIT_LIST_HEAD(&clnt->fidlist);
 
-       p9_tag_init(clnt);
+       err = p9_tag_init(clnt);
+       if (err < 0)
+               goto free_client;
 
        err = parse_opts(options, clnt);
        if (err < 0)
-               goto free_client;
+               goto destroy_tagpool;
 
        if (!clnt->trans_mod)
                clnt->trans_mod = v9fs_get_default_trans();
@@ -802,13 +805,12 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
                err = -EPROTONOSUPPORT;
                P9_DPRINTK(P9_DEBUG_ERROR,
                                "No transport defined or default transport\n");
-               goto free_client;
+               goto destroy_tagpool;
        }
 
        clnt->fidpool = p9_idpool_create();
        if (IS_ERR(clnt->fidpool)) {
                err = PTR_ERR(clnt->fidpool);
-               clnt->fidpool = NULL;
                goto put_trans;
        }
 
@@ -834,6 +836,8 @@ destroy_fidpool:
        p9_idpool_destroy(clnt->fidpool);
 put_trans:
        v9fs_put_trans(clnt->trans_mod);
+destroy_tagpool:
+       p9_idpool_destroy(clnt->tagpool);
 free_client:
        kfree(clnt);
        return ERR_PTR(err);
@@ -1298,7 +1302,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
        if (count < rsize)
                rsize = count;
 
-       /* Don't bother zerocopy form small IO (< 1024) */
+       /* Don't bother zerocopy for small IO (< 1024) */
        if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) ==
                        P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) {
                req = p9_client_rpc(clnt, P9_TREAD, "dqE", fid->fid, offset,
index cf8a4128cd5c03560bfb93971779965176bea7dd..72c39827505125b618b7a007b6a1dc23d98b4f4f 100644 (file)
@@ -139,7 +139,7 @@ void v9fs_put_trans(struct p9_trans_module *m)
 }
 
 /**
- * v9fs_init - Initialize module
+ * init_p9 - Initialize module
  *
  */
 static int __init init_p9(void)
@@ -154,7 +154,7 @@ static int __init init_p9(void)
 }
 
 /**
- * v9fs_init - shutdown module
+ * exit_p9 - shutdown module
  *
  */
 
index 4a9084395d358320840a3fdf7398da8b0d85b09b..fdfdb5747f63b6492fc23eafa000dcd7d93c9c5b 100644 (file)
@@ -916,8 +916,8 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
        sin_server.sin_family = AF_INET;
        sin_server.sin_addr.s_addr = in_aton(addr);
        sin_server.sin_port = htons(opts.port);
-       err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
-
+       err = __sock_create(read_pnet(&current->nsproxy->net_ns), PF_INET,
+                           SOCK_STREAM, IPPROTO_TCP, &csocket, 1);
        if (err) {
                P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
                return err;
@@ -954,7 +954,8 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
 
        sun_server.sun_family = PF_UNIX;
        strcpy(sun_server.sun_path, addr);
-       err = sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
+       err = __sock_create(read_pnet(&current->nsproxy->net_ns), PF_UNIX,
+                           SOCK_STREAM, 0, &csocket, 1);
        if (err < 0) {
                P9_EPRINTK(KERN_ERR, "p9_trans_unix: problem creating socket\n");
                return err;
index da6af81e59d9fa504345c306e6636acd1f91b093..9c1c9348ac35d3410ccb255266f9367bbf5d2549 100644 (file)
@@ -93,7 +93,7 @@ int p9_idpool_get(struct p9_idpool *p)
 
 retry:
        if (idr_pre_get(&p->pool, GFP_NOFS) == 0)
-               return 0;
+               return -1;
 
        spin_lock_irqsave(&p->lock, flags);
 
index f85da0779e5ee162015ae88aa00e48e2114aa5e3..be3afdefec5832bb8e3861f883eff27e07bfcad0 100644 (file)
@@ -191,7 +191,7 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
 {
        struct sock *sk = sk_atm(vcc);
 
-       seq_printf(seq, "%p ", vcc);
+       seq_printf(seq, "%pK ", vcc);
        if (!vcc->dev)
                seq_printf(seq, "Unassigned    ");
        else
@@ -218,7 +218,7 @@ static void svc_info(struct seq_file *seq, struct atm_vcc *vcc)
 {
        if (!vcc->dev)
                seq_printf(seq, sizeof(void *) == 4 ?
-                          "N/A@%p%10s" : "N/A@%p%2s", vcc, "");
+                          "N/A@%pK%10s" : "N/A@%pK%2s", vcc, "");
        else
                seq_printf(seq, "%3d %3d %5d         ",
                           vcc->dev->number, vcc->vpi, vcc->vci);
index e1f5ec75e91cd8c93fb22f3092dbdd30f5855c85..3fa123185e891b93cd98b3ac23bdec3518b6f066 100644 (file)
@@ -117,6 +117,10 @@ static struct dst_ops fake_dst_ops = {
  * ipt_REJECT needs it.  Future netfilter modules might
  * require us to fill additional fields.
  */
+static const u32 br_dst_default_metrics[RTAX_MAX] = {
+       [RTAX_MTU - 1] = 1500,
+};
+
 void br_netfilter_rtable_init(struct net_bridge *br)
 {
        struct rtable *rt = &br->fake_rtable;
@@ -124,7 +128,7 @@ void br_netfilter_rtable_init(struct net_bridge *br)
        atomic_set(&rt->dst.__refcnt, 1);
        rt->dst.dev = br->dev;
        rt->dst.path = &rt->dst;
-       dst_metric_set(&rt->dst, RTAX_MTU, 1500);
+       dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
        rt->dst.flags   = DST_NOXFRM;
        rt->dst.ops = &fake_dst_ops;
 }
index cced806098a94ab81f76347c5bdc0ab0c23e28e3..184a6572b67e6be824ba1ef30b122d065269a262 100644 (file)
@@ -165,9 +165,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
        struct bcm_sock *bo = bcm_sk(sk);
        struct bcm_op *op;
 
-       seq_printf(m, ">>> socket %p", sk->sk_socket);
-       seq_printf(m, " / sk %p", sk);
-       seq_printf(m, " / bo %p", bo);
+       seq_printf(m, ">>> socket %pK", sk->sk_socket);
+       seq_printf(m, " / sk %pK", sk);
+       seq_printf(m, " / bo %pK", bo);
        seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs);
        seq_printf(m, " / bound %s", bcm_proc_getifname(ifname, bo->ifindex));
        seq_printf(m, " <<<\n");
index e15a82ccc05f69789e162c5caa51d4bb2cc082a5..78b55f49de7cba5bbdf0fb872b4b3c0464190f04 100644 (file)
@@ -76,7 +76,8 @@ const char *ceph_pr_addr(const struct sockaddr_storage *ss)
                break;
 
        default:
-               sprintf(s, "(unknown sockaddr family %d)", (int)ss->ss_family);
+               snprintf(s, MAX_ADDR_STR_LEN, "(unknown sockaddr family %d)",
+                        (int)ss->ss_family);
        }
 
        return s;
@@ -598,7 +599,7 @@ static void prepare_write_keepalive(struct ceph_connection *con)
  * Connection negotiation.
  */
 
-static void prepare_connect_authorizer(struct ceph_connection *con)
+static int prepare_connect_authorizer(struct ceph_connection *con)
 {
        void *auth_buf;
        int auth_len = 0;
@@ -612,13 +613,20 @@ static void prepare_connect_authorizer(struct ceph_connection *con)
                                         con->auth_retry);
        mutex_lock(&con->mutex);
 
+       if (test_bit(CLOSED, &con->state) ||
+           test_bit(OPENING, &con->state))
+               return -EAGAIN;
+
        con->out_connect.authorizer_protocol = cpu_to_le32(auth_protocol);
        con->out_connect.authorizer_len = cpu_to_le32(auth_len);
 
-       con->out_kvec[con->out_kvec_left].iov_base = auth_buf;
-       con->out_kvec[con->out_kvec_left].iov_len = auth_len;
-       con->out_kvec_left++;
-       con->out_kvec_bytes += auth_len;
+       if (auth_len) {
+               con->out_kvec[con->out_kvec_left].iov_base = auth_buf;
+               con->out_kvec[con->out_kvec_left].iov_len = auth_len;
+               con->out_kvec_left++;
+               con->out_kvec_bytes += auth_len;
+       }
+       return 0;
 }
 
 /*
@@ -640,9 +648,9 @@ static void prepare_write_banner(struct ceph_messenger *msgr,
        set_bit(WRITE_PENDING, &con->state);
 }
 
-static void prepare_write_connect(struct ceph_messenger *msgr,
-                                 struct ceph_connection *con,
-                                 int after_banner)
+static int prepare_write_connect(struct ceph_messenger *msgr,
+                                struct ceph_connection *con,
+                                int after_banner)
 {
        unsigned global_seq = get_global_seq(con->msgr, 0);
        int proto;
@@ -683,7 +691,7 @@ static void prepare_write_connect(struct ceph_messenger *msgr,
        con->out_more = 0;
        set_bit(WRITE_PENDING, &con->state);
 
-       prepare_connect_authorizer(con);
+       return prepare_connect_authorizer(con);
 }
 
 
@@ -1065,8 +1073,10 @@ static void addr_set_port(struct sockaddr_storage *ss, int p)
        switch (ss->ss_family) {
        case AF_INET:
                ((struct sockaddr_in *)ss)->sin_port = htons(p);
+               break;
        case AF_INET6:
                ((struct sockaddr_in6 *)ss)->sin6_port = htons(p);
+               break;
        }
 }
 
@@ -1216,6 +1226,7 @@ static int process_connect(struct ceph_connection *con)
        u64 sup_feat = con->msgr->supported_features;
        u64 req_feat = con->msgr->required_features;
        u64 server_feat = le64_to_cpu(con->in_reply.features);
+       int ret;
 
        dout("process_connect on %p tag %d\n", con, (int)con->in_tag);
 
@@ -1250,7 +1261,9 @@ static int process_connect(struct ceph_connection *con)
                        return -1;
                }
                con->auth_retry = 1;
-               prepare_write_connect(con->msgr, con, 0);
+               ret = prepare_write_connect(con->msgr, con, 0);
+               if (ret < 0)
+                       return ret;
                prepare_read_connect(con);
                break;
 
@@ -1277,6 +1290,9 @@ static int process_connect(struct ceph_connection *con)
                if (con->ops->peer_reset)
                        con->ops->peer_reset(con);
                mutex_lock(&con->mutex);
+               if (test_bit(CLOSED, &con->state) ||
+                   test_bit(OPENING, &con->state))
+                       return -EAGAIN;
                break;
 
        case CEPH_MSGR_TAG_RETRY_SESSION:
@@ -1341,7 +1357,9 @@ static int process_connect(struct ceph_connection *con)
                 * to WAIT.  This shouldn't happen if we are the
                 * client.
                 */
-               pr_err("process_connect peer connecting WAIT\n");
+               pr_err("process_connect got WAIT as client\n");
+               con->error_msg = "protocol error, got WAIT as client";
+               return -1;
 
        default:
                pr_err("connect protocol error, will retry\n");
@@ -1810,6 +1828,17 @@ static int try_read(struct ceph_connection *con)
 more:
        dout("try_read tag %d in_base_pos %d\n", (int)con->in_tag,
             con->in_base_pos);
+
+       /*
+        * process_connect and process_message drop and re-take
+        * con->mutex.  make sure we handle a racing close or reopen.
+        */
+       if (test_bit(CLOSED, &con->state) ||
+           test_bit(OPENING, &con->state)) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
        if (test_bit(CONNECTING, &con->state)) {
                if (!test_bit(NEGOTIATING, &con->state)) {
                        dout("try_read connecting\n");
@@ -1938,8 +1967,10 @@ static void con_work(struct work_struct *work)
 {
        struct ceph_connection *con = container_of(work, struct ceph_connection,
                                                   work.work);
+       int ret;
 
        mutex_lock(&con->mutex);
+restart:
        if (test_and_clear_bit(BACKOFF, &con->state)) {
                dout("con_work %p backing off\n", con);
                if (queue_delayed_work(ceph_msgr_wq, &con->work,
@@ -1969,18 +2000,31 @@ static void con_work(struct work_struct *work)
                con_close_socket(con);
        }
 
-       if (test_and_clear_bit(SOCK_CLOSED, &con->state) ||
-           try_read(con) < 0 ||
-           try_write(con) < 0) {
-               mutex_unlock(&con->mutex);
-               ceph_fault(con);     /* error/fault path */
-               goto done_unlocked;
-       }
+       if (test_and_clear_bit(SOCK_CLOSED, &con->state))
+               goto fault;
+
+       ret = try_read(con);
+       if (ret == -EAGAIN)
+               goto restart;
+       if (ret < 0)
+               goto fault;
+
+       ret = try_write(con);
+       if (ret == -EAGAIN)
+               goto restart;
+       if (ret < 0)
+               goto fault;
 
 done:
        mutex_unlock(&con->mutex);
 done_unlocked:
        con->ops->put(con);
+       return;
+
+fault:
+       mutex_unlock(&con->mutex);
+       ceph_fault(con);     /* error/fault path */
+       goto done_unlocked;
 }
 
 
index 6b5dda1cb5df1a7adf6b93a49201b34d81eb8dcb..6ea2b892f44b8ab498cdec7344fc07c73b9a6819 100644 (file)
@@ -124,7 +124,7 @@ static void calc_layout(struct ceph_osd_client *osdc,
        ceph_calc_raw_layout(osdc, layout, vino.snap, off,
                             plen, &bno, req, op);
 
-       sprintf(req->r_oid, "%llx.%08llx", vino.ino, bno);
+       snprintf(req->r_oid, sizeof(req->r_oid), "%llx.%08llx", vino.ino, bno);
        req->r_oid_len = strlen(req->r_oid);
 }
 
@@ -1421,6 +1421,15 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
 done:
        downgrade_write(&osdc->map_sem);
        ceph_monc_got_osdmap(&osdc->client->monc, osdc->osdmap->epoch);
+
+       /*
+        * subscribe to subsequent osdmap updates if full to ensure
+        * we find out when we are no longer full and stop returning
+        * ENOSPC.
+        */
+       if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL))
+               ceph_monc_request_next_osdmap(&osdc->client->monc);
+
        send_queued(osdc);
        up_read(&osdc->map_sem);
        wake_up_all(&osdc->client->auth_wq);
@@ -1677,8 +1686,14 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
         */
        if (req->r_sent == 0) {
                rc = __map_request(osdc, req);
-               if (rc < 0)
+               if (rc < 0) {
+                       if (nofail) {
+                               dout("osdc_start_request failed map, "
+                                    " will retry %lld\n", req->r_tid);
+                               rc = 0;
+                       }
                        goto out_unlock;
+               }
                if (req->r_osd == NULL) {
                        dout("send_request %p no up osds in pg\n", req);
                        ceph_monc_request_next_osdmap(&osdc->client->monc);
index 71603ac3dff54486cf1cdacaea142a3ecfc5f6fc..e97c3588c3ec00e719f7cb400784c36b5cb2fad6 100644 (file)
@@ -765,7 +765,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
        }
 
        map->epoch++;
-       map->modified = map->modified;
+       map->modified = modified;
        if (newcrush) {
                if (map->crush)
                        crush_destroy(map->crush);
@@ -830,15 +830,20 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                map->osd_addr[osd] = addr;
        }
 
-       /* new_down */
+       /* new_state */
        ceph_decode_32_safe(p, end, len, bad);
        while (len--) {
                u32 osd;
+               u8 xorstate;
                ceph_decode_32_safe(p, end, osd, bad);
+               xorstate = **(u8 **)p;
                (*p)++;  /* clean flag */
-               pr_info("osd%d down\n", osd);
+               if (xorstate == 0)
+                       xorstate = CEPH_OSD_UP;
+               if (xorstate & CEPH_OSD_UP)
+                       pr_info("osd%d down\n", osd);
                if (osd < map->max_osd)
-                       map->osd_state[osd] &= ~CEPH_OSD_UP;
+                       map->osd_state[osd] ^= xorstate;
        }
 
        /* new_weight */
index bcb05cb799c11ff4373ca112b3c3b62a46d55ad2..c7e305d13b71b9371aa8973354c2b4cbe09889f6 100644 (file)
@@ -1308,6 +1308,13 @@ void dev_disable_lro(struct net_device *dev)
 {
        u32 flags;
 
+       /*
+        * If we're trying to disable lro on a vlan device
+        * use the underlying physical device instead
+        */
+       if (is_vlan_dev(dev))
+               dev = vlan_dev_real_dev(dev);
+
        if (dev->ethtool_ops && dev->ethtool_ops->get_flags)
                flags = dev->ethtool_ops->get_flags(dev);
        else
@@ -5954,7 +5961,10 @@ EXPORT_SYMBOL(free_netdev);
 void synchronize_net(void)
 {
        might_sleep();
-       synchronize_rcu();
+       if (rtnl_is_locked())
+               synchronize_rcu_expedited();
+       else
+               synchronize_rcu();
 }
 EXPORT_SYMBOL(synchronize_net);
 
index 81a4fa1c95ed32a266ef503b796ee998f4599a1d..9ccca038444f11fda683bbed8bf56ad0d5e1b65e 100644 (file)
@@ -315,7 +315,7 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)
 {
        unsigned long prev, new;
 
-       new = (unsigned long) dst_default_metrics;
+       new = ((unsigned long) dst_default_metrics) | DST_METRICS_READ_ONLY;
        prev = cmpxchg(&dst->_metrics, old, new);
        if (prev == old)
                kfree(__DST_METRICS_PTR(old));
index 3911586e12e4b09d2fa5ab0d02110d5db877f479..008dc70b064b3043cbf17fd4a63605db51d0fa94 100644 (file)
@@ -602,6 +602,7 @@ static int dump_rules(struct sk_buff *skb, struct netlink_callback *cb,
 skip:
                idx++;
        }
+       rcu_read_unlock();
        cb->args[1] = idx;
        rules_ops_put(ops);
 
index 0eb8c4466eaa001bad837087e72df34685778c9a..0e3622f1dcb1eac6b3eea810e32806edf669d497 100644 (file)
@@ -350,7 +350,9 @@ load_b:
                        continue;
                }
                default:
-                       WARN_ON(1);
+                       WARN_RATELIMIT(1, "Unknown code:%u jt:%u tf:%u k:%u\n",
+                                      fentry->code, fentry->jt,
+                                      fentry->jf, fentry->k);
                        return 0;
                }
        }
index 2e2dce6583e14f10c786ecf81b4042cacf3593ae..6c6b86d0da155c057488cc66fcea108bebf7f391 100644 (file)
@@ -8,6 +8,8 @@
 #include <linux/idr.h>
 #include <linux/rculist.h>
 #include <linux/nsproxy.h>
+#include <linux/proc_fs.h>
+#include <linux/file.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 
@@ -302,6 +304,28 @@ void __put_net(struct net *net)
 }
 EXPORT_SYMBOL_GPL(__put_net);
 
+struct net *get_net_ns_by_fd(int fd)
+{
+       struct proc_inode *ei;
+       struct file *file;
+       struct net *net;
+
+       net = ERR_PTR(-EINVAL);
+       file = proc_ns_fget(fd);
+       if (!file)
+               goto out;
+
+       ei = PROC_I(file->f_dentry->d_inode);
+       if (ei->ns_ops != &netns_operations)
+               goto out;
+
+       net = get_net(ei->ns);
+out:
+       if (file)
+               fput(file);
+       return net;
+}
+
 #else
 struct net *copy_net_ns(unsigned long flags, struct net *old_net)
 {
@@ -309,6 +333,11 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
                return ERR_PTR(-EINVAL);
        return old_net;
 }
+
+struct net *get_net_ns_by_fd(int fd)
+{
+       return ERR_PTR(-EINVAL);
+}
 #endif
 
 struct net *get_net_ns_by_pid(pid_t pid)
@@ -561,3 +590,39 @@ void unregister_pernet_device(struct pernet_operations *ops)
        mutex_unlock(&net_mutex);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_device);
+
+#ifdef CONFIG_NET_NS
+static void *netns_get(struct task_struct *task)
+{
+       struct net *net = NULL;
+       struct nsproxy *nsproxy;
+
+       rcu_read_lock();
+       nsproxy = task_nsproxy(task);
+       if (nsproxy)
+               net = get_net(nsproxy->net_ns);
+       rcu_read_unlock();
+
+       return net;
+}
+
+static void netns_put(void *ns)
+{
+       put_net(ns);
+}
+
+static int netns_install(struct nsproxy *nsproxy, void *ns)
+{
+       put_net(nsproxy->net_ns);
+       nsproxy->net_ns = get_net(ns);
+       return 0;
+}
+
+const struct proc_ns_operations netns_operations = {
+       .name           = "net",
+       .type           = CLONE_NEWNET,
+       .get            = netns_get,
+       .put            = netns_put,
+       .install        = netns_install,
+};
+#endif
index d1644e317e70cd2634e92fb5a61153ec18c74882..abd936d8a71658ecb108cadcfd1af67f5c8b982a 100644 (file)
@@ -850,6 +850,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        struct nlattr *attr, *af_spec;
        struct rtnl_af_ops *af_ops;
 
+       ASSERT_RTNL();
        nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
        if (nlh == NULL)
                return -EMSGSIZE;
@@ -1045,6 +1046,7 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_LINKMODE]         = { .type = NLA_U8 },
        [IFLA_LINKINFO]         = { .type = NLA_NESTED },
        [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
+       [IFLA_NET_NS_FD]        = { .type = NLA_U32 },
        [IFLA_IFALIAS]          = { .type = NLA_STRING, .len = IFALIASZ-1 },
        [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED },
        [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
@@ -1093,6 +1095,8 @@ struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
         */
        if (tb[IFLA_NET_NS_PID])
                net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID]));
+       else if (tb[IFLA_NET_NS_FD])
+               net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD]));
        else
                net = get_net(src_net);
        return net;
@@ -1223,7 +1227,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
        int send_addr_notify = 0;
        int err;
 
-       if (tb[IFLA_NET_NS_PID]) {
+       if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) {
                struct net *net = rtnl_link_get_net(dev_net(dev), tb);
                if (IS_ERR(net)) {
                        err = PTR_ERR(net);
@@ -1876,6 +1880,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        int min_len;
        int family;
        int type;
+       int err;
 
        type = nlh->nlmsg_type;
        if (type > RTM_MAX)
@@ -1902,8 +1907,11 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                if (dumpit == NULL)
                        return -EOPNOTSUPP;
 
+               __rtnl_unlock();
                rtnl = net->rtnl;
-               return netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
+               err = netlink_dump_start(rtnl, skb, nlh, dumpit, NULL);
+               rtnl_lock();
+               return err;
        }
 
        memset(rta_buf, 0, (rtattr_max * sizeof(struct rtattr *)));
@@ -1975,7 +1983,7 @@ static int __net_init rtnetlink_net_init(struct net *net)
 {
        struct sock *sk;
        sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
-                                  rtnetlink_rcv, NULL, THIS_MODULE);
+                                  rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
        if (!sk)
                return -ENOMEM;
        net->rtnl = sk;
index 672e476c8c8a824a98c99fee9c3cabe765411c72..f1d27f6c9351d2a2bdc15d22fbb35ea270022f22 100644 (file)
@@ -1155,20 +1155,18 @@ static void igmp_group_dropped(struct ip_mc_list *im)
 
        if (!in_dev->dead) {
                if (IGMP_V1_SEEN(in_dev))
-                       goto done;
+                       return;
                if (IGMP_V2_SEEN(in_dev)) {
                        if (reporter)
                                igmp_send_report(in_dev, im, IGMP_HOST_LEAVE_MESSAGE);
-                       goto done;
+                       return;
                }
                /* IGMPv3 */
                igmpv3_add_delrec(in_dev, im);
 
                igmp_ifc_event(in_dev);
        }
-done:
 #endif
-       ip_mc_clear_src(im);
 }
 
 static void igmp_group_added(struct ip_mc_list *im)
@@ -1305,6 +1303,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
                                *ip = i->next_rcu;
                                in_dev->mc_count--;
                                igmp_group_dropped(i);
+                               ip_mc_clear_src(i);
 
                                if (!in_dev->dead)
                                        ip_rt_multicast_event(in_dev);
@@ -1414,7 +1413,8 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
                in_dev->mc_list = i->next_rcu;
                in_dev->mc_count--;
 
-               igmp_group_dropped(i);
+               /* We've dropped the groups in ip_mc_down already */
+               ip_mc_clear_src(i);
                ip_ma_put(i);
        }
 }
index 1f3bb11490c960fff3f4d332c00bd1aeb98d9054..9aaa67165f42453ed0af947cebb53cc49163ab4a 100644 (file)
@@ -137,9 +137,6 @@ static void ping_v4_unhash(struct sock *sk)
        struct inet_sock *isk = inet_sk(sk);
        pr_debug("ping_v4_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
        if (sk_hashed(sk)) {
-               struct hlist_nulls_head *hslot;
-
-               hslot = ping_hashslot(&ping_table, sock_net(sk), isk->inet_num);
                write_lock_bh(&ping_table.lock);
                hlist_nulls_del(&sk->sk_nulls_node);
                sock_put(sk);
index 11e1780455f2aea349a8c163eecbb7f6bb43d1a6..c9893d43242e52c83580f4676f20793fd5bdf48b 100644 (file)
@@ -979,7 +979,7 @@ static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
              srcp  = inet->inet_num;
 
        seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
-               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
+               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n",
                i, src, srcp, dest, destp, sp->sk_state,
                sk_wmem_alloc_get(sp),
                sk_rmem_alloc_get(sp),
index 3c8d9b6f1ea4f05af6d8227672119e258ec7d8f5..a7d6671e33b8a6e46aba0b352ad083736d1b421b 100644 (file)
@@ -2371,7 +2371,7 @@ static void get_openreq4(struct sock *sk, struct request_sock *req,
        int ttd = req->expires - jiffies;
 
        seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p%n",
+               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %pK%n",
                i,
                ireq->loc_addr,
                ntohs(inet_sk(sk)->inet_sport),
@@ -2426,7 +2426,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
                rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
 
        seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
-                       "%08X %5d %8d %lu %d %p %lu %lu %u %u %d%n",
+                       "%08X %5d %8d %lu %d %pK %lu %lu %u %u %d%n",
                i, src, srcp, dest, destp, sk->sk_state,
                tp->write_seq - tp->snd_una,
                rx_queue,
@@ -2461,7 +2461,7 @@ static void get_timewait4_sock(struct inet_timewait_sock *tw,
        srcp  = ntohs(tw->tw_sport);
 
        seq_printf(f, "%4d: %08X:%04X %08X:%04X"
-               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p%n",
+               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK%n",
                i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
                3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
                atomic_read(&tw->tw_refcnt), tw, len);
index 599374f65c7646473c1fa6781a9cf92ce6d90153..abca870d8ff69fe76a19bef7d9338d4f80fabaf0 100644 (file)
@@ -2090,7 +2090,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
        __u16 srcp        = ntohs(inet->inet_sport);
 
        seq_printf(f, "%5d: %08X:%04X %08X:%04X"
-               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n",
+               " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d%n",
                bucket, src, srcp, dest, destp, sp->sk_state,
                sk_wmem_alloc_get(sp),
                sk_rmem_alloc_get(sp),
index ae64984f81aa857ee1b361a9786a7524b989d3ef..cc7313b8f7eaee42ec5385f9fa9999f1227f01db 100644 (file)
@@ -1240,7 +1240,7 @@ static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
        srcp  = inet_sk(sp)->inet_num;
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
index 868366470b4af1702b81dcfa03db815b33378d00..d1fd28711ba50e1ad8ac90a0c32df360ec911d70 100644 (file)
@@ -2036,7 +2036,7 @@ static void get_openreq6(struct seq_file *seq,
 
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3],
@@ -2087,7 +2087,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
 
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %lu %lu %u %u %d\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %lu %lu %u %u %d\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
@@ -2129,7 +2129,7 @@ static void get_timewait6_sock(struct seq_file *seq,
 
        seq_printf(seq,
                   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n",
                   i,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
index fc0c42a88e549edb441c62a1d13a32d0499154d6..41f8c9c08dbaf86051a16c5488b6c961f65278fc 100644 (file)
@@ -1391,7 +1391,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
        srcp  = ntohs(inet->inet_sport);
        seq_printf(seq,
                   "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
+                  "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d\n",
                   bucket,
                   src->s6_addr32[0], src->s6_addr32[1],
                   src->s6_addr32[2], src->s6_addr32[3], srcp,
index a6770a04e3bd33fbc05c8ce157ea05520401ae99..4fe1db12d2a3761d550c17d58531a7e8de6825bb 100644 (file)
@@ -241,7 +241,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb)
        __be32 spi;
 
        spi = xfrm6_tunnel_spi_lookup(net, (const xfrm_address_t *)&iph->saddr);
-       return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0;
+       return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi);
 }
 
 static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
index d62401c2568434e7f36aac8d5a5613a30ff26281..8f92cf8116ea6b0604961c8438b15acf21fcf6f1 100644 (file)
@@ -3656,7 +3656,7 @@ static int pfkey_seq_show(struct seq_file *f, void *v)
        if (v == SEQ_START_TOKEN)
                seq_printf(f ,"sk       RefCnt Rmem   Wmem   User   Inode\n");
        else
-               seq_printf(f ,"%p %-6d %-6u %-6u %-6u %-6lu\n",
+               seq_printf(f, "%pK %-6d %-6u %-6u %-6u %-6lu\n",
                               s,
                               atomic_read(&s->sk_refcnt),
                               sk_rmem_alloc_get(s),
index 7dfbe71dc637334d410eea7e4eef04a6b114b7d8..49d4f869e0bc74cfcd397558b2283440da761c1d 100644 (file)
@@ -384,11 +384,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        int i;
        enum nl80211_channel_type orig_ct;
 
+       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
        if (local->scan_sdata == sdata)
                ieee80211_scan_cancel(local);
 
-       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
-
        /*
         * Stop TX on this interface first.
         */
index 0d7b08db8e564e07e953b1a501bc97a0e41a6db6..866f269183cf9a1532f317e3b9f52bc437a98213 100644 (file)
@@ -752,11 +752,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
        hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
 
-       /* mac80211 doesn't support more than 1 channel */
-       for (i = 0; i < hw->wiphy->n_iface_combinations; i++)
-               if (hw->wiphy->iface_combinations[i].num_different_channels > 1)
+       /*
+        * mac80211 doesn't support more than 1 channel, and also not more
+        * than one IBSS interface
+        */
+       for (i = 0; i < hw->wiphy->n_iface_combinations; i++) {
+               const struct ieee80211_iface_combination *c;
+               int j;
+
+               c = &hw->wiphy->iface_combinations[i];
+
+               if (c->num_different_channels > 1)
                        return -EINVAL;
 
+               for (j = 0; j < c->n_limits; j++)
+                       if ((c->limits[j].types & BIT(NL80211_IFTYPE_ADHOC)) &&
+                           c->limits[j].max > 1)
+                               return -EINVAL;
+       }
+
 #ifndef CONFIG_MAC80211_MESH
        /* mesh depends on Kconfig, but drivers should set it if they want */
        local->hw.wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MESH_POINT);
@@ -1076,6 +1090,8 @@ static void __exit ieee80211_exit(void)
                ieee80211s_stop();
 
        ieee80211_iface_exit();
+
+       rcu_barrier();
 }
 
 
index e7c5fddb480400a8d61c08b577d093ff32b3b22b..249e733362e7b9bf4d48714800ba7da48273832d 100644 (file)
@@ -120,6 +120,7 @@ struct mesh_path {
  *     buckets
  * @mean_chain_len: maximum average length for the hash buckets' list, if it is
  *     reached, the table will grow
+ * rcu_head: RCU head to free the table
  */
 struct mesh_table {
        /* Number of buckets will be 2^N */
@@ -132,6 +133,8 @@ struct mesh_table {
        int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
        int size_order;
        int mean_chain_len;
+
+       struct rcu_head rcu_head;
 };
 
 /* Recent multicast cache */
@@ -286,10 +289,6 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
        return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP;
 }
 
-#define for_each_mesh_entry(x, p, node, i) \
-       for (i = 0; i <= x->hash_mask; i++) \
-               hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list)
-
 void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
 
 void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
index 83ce48e3191344384939ce669a71b5e266f336bf..0d2faacc3e870c0feee42ad2d854cb1110f32ecc 100644 (file)
@@ -36,8 +36,8 @@ struct mpath_node {
        struct mesh_path *mpath;
 };
 
-static struct mesh_table *mesh_paths;
-static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
+static struct mesh_table __rcu *mesh_paths;
+static struct mesh_table __rcu *mpp_paths; /* Store paths for MPP&MAP */
 
 int mesh_paths_generation;
 
@@ -48,17 +48,40 @@ int mesh_paths_generation;
 static DEFINE_RWLOCK(pathtbl_resize_lock);
 
 
+static inline struct mesh_table *resize_dereference_mesh_paths(void)
+{
+       return rcu_dereference_protected(mesh_paths,
+               lockdep_is_held(&pathtbl_resize_lock));
+}
+
+static inline struct mesh_table *resize_dereference_mpp_paths(void)
+{
+       return rcu_dereference_protected(mpp_paths,
+               lockdep_is_held(&pathtbl_resize_lock));
+}
+
+/*
+ * CAREFUL -- "tbl" must not be an expression,
+ * in particular not an rcu_dereference(), since
+ * it's used twice. So it is illegal to do
+ *     for_each_mesh_entry(rcu_dereference(...), ...)
+ */
+#define for_each_mesh_entry(tbl, p, node, i) \
+       for (i = 0; i <= tbl->hash_mask; i++) \
+               hlist_for_each_entry_rcu(node, p, &tbl->hash_buckets[i], list)
+
+
 static struct mesh_table *mesh_table_alloc(int size_order)
 {
        int i;
        struct mesh_table *newtbl;
 
-       newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
+       newtbl = kmalloc(sizeof(struct mesh_table), GFP_ATOMIC);
        if (!newtbl)
                return NULL;
 
        newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
-                       (1 << size_order), GFP_KERNEL);
+                       (1 << size_order), GFP_ATOMIC);
 
        if (!newtbl->hash_buckets) {
                kfree(newtbl);
@@ -66,7 +89,7 @@ static struct mesh_table *mesh_table_alloc(int size_order)
        }
 
        newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
-                       (1 << size_order), GFP_KERNEL);
+                       (1 << size_order), GFP_ATOMIC);
        if (!newtbl->hashwlock) {
                kfree(newtbl->hash_buckets);
                kfree(newtbl);
@@ -258,12 +281,13 @@ struct mesh_path *mpp_path_lookup(u8 *dst, struct ieee80211_sub_if_data *sdata)
  */
 struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data *sdata)
 {
+       struct mesh_table *tbl = rcu_dereference(mesh_paths);
        struct mpath_node *node;
        struct hlist_node *p;
        int i;
        int j = 0;
 
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       for_each_mesh_entry(tbl, p, node, i) {
                if (sdata && node->mpath->sdata != sdata)
                        continue;
                if (j++ == idx) {
@@ -293,6 +317,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct ieee80211_local *local = sdata->local;
+       struct mesh_table *tbl;
        struct mesh_path *mpath, *new_mpath;
        struct mpath_node *node, *new_node;
        struct hlist_head *bucket;
@@ -332,10 +357,12 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        spin_lock_init(&new_mpath->state_lock);
        init_timer(&new_mpath->timer);
 
-       hash_idx = mesh_table_hash(dst, sdata, mesh_paths);
-       bucket = &mesh_paths->hash_buckets[hash_idx];
+       tbl = resize_dereference_mesh_paths();
+
+       hash_idx = mesh_table_hash(dst, sdata, tbl);
+       bucket = &tbl->hash_buckets[hash_idx];
 
-       spin_lock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_lock_bh(&tbl->hashwlock[hash_idx]);
 
        err = -EEXIST;
        hlist_for_each_entry(node, n, bucket, list) {
@@ -345,13 +372,13 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        }
 
        hlist_add_head_rcu(&new_node->list, bucket);
-       if (atomic_inc_return(&mesh_paths->entries) >=
-               mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1))
+       if (atomic_inc_return(&tbl->entries) >=
+           tbl->mean_chain_len * (tbl->hash_mask + 1))
                grow = 1;
 
        mesh_paths_generation++;
 
-       spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        if (grow) {
                set_bit(MESH_WORK_GROW_MPATH_TABLE,  &ifmsh->wrkq_flags);
@@ -360,7 +387,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
        return 0;
 
 err_exists:
-       spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        kfree(new_node);
 err_node_alloc:
@@ -370,58 +397,59 @@ err_path_alloc:
        return err;
 }
 
+static void mesh_table_free_rcu(struct rcu_head *rcu)
+{
+       struct mesh_table *tbl = container_of(rcu, struct mesh_table, rcu_head);
+
+       mesh_table_free(tbl, false);
+}
+
 void mesh_mpath_table_grow(void)
 {
        struct mesh_table *oldtbl, *newtbl;
 
-       rcu_read_lock();
-       newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1);
-       if (!newtbl)
-               return;
        write_lock_bh(&pathtbl_resize_lock);
-       oldtbl = mesh_paths;
-       if (mesh_table_grow(mesh_paths, newtbl) < 0) {
-               rcu_read_unlock();
+       oldtbl = resize_dereference_mesh_paths();
+       newtbl = mesh_table_alloc(oldtbl->size_order + 1);
+       if (!newtbl)
+               goto out;
+       if (mesh_table_grow(oldtbl, newtbl) < 0) {
                __mesh_table_free(newtbl);
-               write_unlock_bh(&pathtbl_resize_lock);
-               return;
+               goto out;
        }
-       rcu_read_unlock();
        rcu_assign_pointer(mesh_paths, newtbl);
-       write_unlock_bh(&pathtbl_resize_lock);
 
-       synchronize_rcu();
-       mesh_table_free(oldtbl, false);
+       call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
+
+ out:
+       write_unlock_bh(&pathtbl_resize_lock);
 }
 
 void mesh_mpp_table_grow(void)
 {
        struct mesh_table *oldtbl, *newtbl;
 
-       rcu_read_lock();
-       newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1);
-       if (!newtbl)
-               return;
        write_lock_bh(&pathtbl_resize_lock);
-       oldtbl = mpp_paths;
-       if (mesh_table_grow(mpp_paths, newtbl) < 0) {
-               rcu_read_unlock();
+       oldtbl = resize_dereference_mpp_paths();
+       newtbl = mesh_table_alloc(oldtbl->size_order + 1);
+       if (!newtbl)
+               goto out;
+       if (mesh_table_grow(oldtbl, newtbl) < 0) {
                __mesh_table_free(newtbl);
-               write_unlock_bh(&pathtbl_resize_lock);
-               return;
+               goto out;
        }
-       rcu_read_unlock();
        rcu_assign_pointer(mpp_paths, newtbl);
-       write_unlock_bh(&pathtbl_resize_lock);
+       call_rcu(&oldtbl->rcu_head, mesh_table_free_rcu);
 
-       synchronize_rcu();
-       mesh_table_free(oldtbl, false);
+ out:
+       write_unlock_bh(&pathtbl_resize_lock);
 }
 
 int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct ieee80211_local *local = sdata->local;
+       struct mesh_table *tbl;
        struct mesh_path *mpath, *new_mpath;
        struct mpath_node *node, *new_node;
        struct hlist_head *bucket;
@@ -456,10 +484,12 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        new_mpath->exp_time = jiffies;
        spin_lock_init(&new_mpath->state_lock);
 
-       hash_idx = mesh_table_hash(dst, sdata, mpp_paths);
-       bucket = &mpp_paths->hash_buckets[hash_idx];
+       tbl = resize_dereference_mpp_paths();
 
-       spin_lock_bh(&mpp_paths->hashwlock[hash_idx]);
+       hash_idx = mesh_table_hash(dst, sdata, tbl);
+       bucket = &tbl->hash_buckets[hash_idx];
+
+       spin_lock_bh(&tbl->hashwlock[hash_idx]);
 
        err = -EEXIST;
        hlist_for_each_entry(node, n, bucket, list) {
@@ -469,11 +499,11 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        }
 
        hlist_add_head_rcu(&new_node->list, bucket);
-       if (atomic_inc_return(&mpp_paths->entries) >=
-               mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1))
+       if (atomic_inc_return(&tbl->entries) >=
+           tbl->mean_chain_len * (tbl->hash_mask + 1))
                grow = 1;
 
-       spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        if (grow) {
                set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
@@ -482,7 +512,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
        return 0;
 
 err_exists:
-       spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        kfree(new_node);
 err_node_alloc:
@@ -502,6 +532,7 @@ err_path_alloc:
  */
 void mesh_plink_broken(struct sta_info *sta)
 {
+       struct mesh_table *tbl;
        static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
        struct mesh_path *mpath;
        struct mpath_node *node;
@@ -510,10 +541,11 @@ void mesh_plink_broken(struct sta_info *sta)
        int i;
 
        rcu_read_lock();
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       tbl = rcu_dereference(mesh_paths);
+       for_each_mesh_entry(tbl, p, node, i) {
                mpath = node->mpath;
                spin_lock_bh(&mpath->state_lock);
-               if (mpath->next_hop == sta &&
+               if (rcu_dereference(mpath->next_hop) == sta &&
                    mpath->flags & MESH_PATH_ACTIVE &&
                    !(mpath->flags & MESH_PATH_FIXED)) {
                        mpath->flags &= ~MESH_PATH_ACTIVE;
@@ -542,30 +574,38 @@ void mesh_plink_broken(struct sta_info *sta)
  */
 void mesh_path_flush_by_nexthop(struct sta_info *sta)
 {
+       struct mesh_table *tbl;
        struct mesh_path *mpath;
        struct mpath_node *node;
        struct hlist_node *p;
        int i;
 
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       rcu_read_lock();
+       tbl = rcu_dereference(mesh_paths);
+       for_each_mesh_entry(tbl, p, node, i) {
                mpath = node->mpath;
-               if (mpath->next_hop == sta)
+               if (rcu_dereference(mpath->next_hop) == sta)
                        mesh_path_del(mpath->dst, mpath->sdata);
        }
+       rcu_read_unlock();
 }
 
 void mesh_path_flush(struct ieee80211_sub_if_data *sdata)
 {
+       struct mesh_table *tbl;
        struct mesh_path *mpath;
        struct mpath_node *node;
        struct hlist_node *p;
        int i;
 
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       rcu_read_lock();
+       tbl = rcu_dereference(mesh_paths);
+       for_each_mesh_entry(tbl, p, node, i) {
                mpath = node->mpath;
                if (mpath->sdata == sdata)
                        mesh_path_del(mpath->dst, mpath->sdata);
        }
+       rcu_read_unlock();
 }
 
 static void mesh_path_node_reclaim(struct rcu_head *rp)
@@ -589,6 +629,7 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
  */
 int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
 {
+       struct mesh_table *tbl;
        struct mesh_path *mpath;
        struct mpath_node *node;
        struct hlist_head *bucket;
@@ -597,19 +638,20 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
        int err = 0;
 
        read_lock_bh(&pathtbl_resize_lock);
-       hash_idx = mesh_table_hash(addr, sdata, mesh_paths);
-       bucket = &mesh_paths->hash_buckets[hash_idx];
+       tbl = resize_dereference_mesh_paths();
+       hash_idx = mesh_table_hash(addr, sdata, tbl);
+       bucket = &tbl->hash_buckets[hash_idx];
 
-       spin_lock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_lock_bh(&tbl->hashwlock[hash_idx]);
        hlist_for_each_entry(node, n, bucket, list) {
                mpath = node->mpath;
                if (mpath->sdata == sdata &&
-                               memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
+                   memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
                        spin_lock_bh(&mpath->state_lock);
                        mpath->flags |= MESH_PATH_RESOLVING;
                        hlist_del_rcu(&node->list);
                        call_rcu(&node->rcu, mesh_path_node_reclaim);
-                       atomic_dec(&mesh_paths->entries);
+                       atomic_dec(&tbl->entries);
                        spin_unlock_bh(&mpath->state_lock);
                        goto enddel;
                }
@@ -618,7 +660,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
        err = -ENXIO;
 enddel:
        mesh_paths_generation++;
-       spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
+       spin_unlock_bh(&tbl->hashwlock[hash_idx]);
        read_unlock_bh(&pathtbl_resize_lock);
        return err;
 }
@@ -719,8 +761,10 @@ static void mesh_path_node_free(struct hlist_node *p, bool free_leafs)
        struct mpath_node *node = hlist_entry(p, struct mpath_node, list);
        mpath = node->mpath;
        hlist_del_rcu(p);
-       if (free_leafs)
+       if (free_leafs) {
+               del_timer_sync(&mpath->timer);
                kfree(mpath);
+       }
        kfree(node);
 }
 
@@ -745,52 +789,60 @@ static int mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
 
 int mesh_pathtbl_init(void)
 {
-       mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
-       if (!mesh_paths)
+       struct mesh_table *tbl_path, *tbl_mpp;
+
+       tbl_path = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
+       if (!tbl_path)
                return -ENOMEM;
-       mesh_paths->free_node = &mesh_path_node_free;
-       mesh_paths->copy_node = &mesh_path_node_copy;
-       mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
+       tbl_path->free_node = &mesh_path_node_free;
+       tbl_path->copy_node = &mesh_path_node_copy;
+       tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
 
-       mpp_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
-       if (!mpp_paths) {
-               mesh_table_free(mesh_paths, true);
+       tbl_mpp = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
+       if (!tbl_mpp) {
+               mesh_table_free(tbl_path, true);
                return -ENOMEM;
        }
-       mpp_paths->free_node = &mesh_path_node_free;
-       mpp_paths->copy_node = &mesh_path_node_copy;
-       mpp_paths->mean_chain_len = MEAN_CHAIN_LEN;
+       tbl_mpp->free_node = &mesh_path_node_free;
+       tbl_mpp->copy_node = &mesh_path_node_copy;
+       tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
+
+       /* Need no locking since this is during init */
+       RCU_INIT_POINTER(mesh_paths, tbl_path);
+       RCU_INIT_POINTER(mpp_paths, tbl_mpp);
 
        return 0;
 }
 
 void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
 {
+       struct mesh_table *tbl;
        struct mesh_path *mpath;
        struct mpath_node *node;
        struct hlist_node *p;
        int i;
 
-       read_lock_bh(&pathtbl_resize_lock);
-       for_each_mesh_entry(mesh_paths, p, node, i) {
+       rcu_read_lock();
+       tbl = rcu_dereference(mesh_paths);
+       for_each_mesh_entry(tbl, p, node, i) {
                if (node->mpath->sdata != sdata)
                        continue;
                mpath = node->mpath;
                spin_lock_bh(&mpath->state_lock);
                if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
                    (!(mpath->flags & MESH_PATH_FIXED)) &&
-                       time_after(jiffies,
-                        mpath->exp_time + MESH_PATH_EXPIRE)) {
+                    time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) {
                        spin_unlock_bh(&mpath->state_lock);
                        mesh_path_del(mpath->dst, mpath->sdata);
                } else
                        spin_unlock_bh(&mpath->state_lock);
        }
-       read_unlock_bh(&pathtbl_resize_lock);
+       rcu_read_unlock();
 }
 
 void mesh_pathtbl_unregister(void)
 {
-       mesh_table_free(mesh_paths, true);
-       mesh_table_free(mpp_paths, true);
+       /* no need for locking during exit path */
+       mesh_table_free(rcu_dereference_raw(mesh_paths), true);
+       mesh_table_free(rcu_dereference_raw(mpp_paths), true);
 }
index d20046b5d8f4953bb4ae4007e927ccee1505985a..27af6723cb5e5496efc606010bf04541806da43e 100644 (file)
@@ -719,6 +719,11 @@ void ieee80211_scan_work(struct work_struct *work)
         * without scheduling a new work
         */
        do {
+               if (!ieee80211_sdata_running(sdata)) {
+                       aborted = true;
+                       goto out_complete;
+               }
+
                switch (local->next_scan_state) {
                case SCAN_DECISION:
                        /* if no more bands/channels left, complete scan */
index 5fe4f3b04ed37e8d0cc46d456804aef6044c3150..6ef64adf7362a421240c28e5196407ce5729f1dd 100644 (file)
@@ -1985,7 +1985,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
                struct sock *s = v;
                struct netlink_sock *nlk = nlk_sk(s);
 
-               seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %-8d %-8d %-8lu\n",
+               seq_printf(seq, "%pK %-3d %-6d %08x %-8d %-8d %pK %-8d %-8d %-8lu\n",
                           s,
                           s->sk_protocol,
                           nlk->pid,
index 549527bca87a9a6b9bc323e19834aae5cf03d647..925f715686a5d0e57c657ee6af40b5792c085a6d 100644 (file)
@@ -2706,7 +2706,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
                const struct packet_sock *po = pkt_sk(s);
 
                seq_printf(seq,
-                          "%p %-6d %-4d %04x   %-5d %1d %-6u %-6u %-6lu\n",
+                          "%pK %-6d %-4d %04x   %-5d %1d %-6u %-6u %-6lu\n",
                           s,
                           atomic_read(&s->sk_refcnt),
                           s->sk_type,
index 8c5bfcef92cb1707d25fa209e9a461f2654b6939..ab07711cf2f40e161cd0602678ce3b4555ab68b3 100644 (file)
@@ -607,7 +607,7 @@ static int pn_sock_seq_show(struct seq_file *seq, void *v)
                struct pn_sock *pn = pn_sk(sk);
 
                seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
-                       "%d %p %d%n",
+                       "%d %pK %d%n",
                        sk->sk_protocol, pn->sobject, pn->dobject,
                        pn->resource, sk->sk_state,
                        sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
index 48464ca13b242c45a8825ed57e326affc5026455..78efe895b6636c4a57af6d72f156501e2c778992 100644 (file)
@@ -33,3 +33,12 @@ config RFKILL_REGULATOR
 
           To compile this driver as a module, choose M here: the module will
           be called rfkill-regulator.
+
+config RFKILL_GPIO
+       tristate "GPIO RFKILL driver"
+       depends on RFKILL && GPIOLIB && HAVE_CLK
+       default n
+       help
+         If you say yes here you get support of a generic gpio RFKILL
+         driver. The platform should fill in the appropriate fields in the
+         rfkill_gpio_platform_data structure and pass that to the driver.
index d9a5a58ffd8c8102553f18abdd7729d6d7e4c43c..311768783f4a116843349687c99a3cf65f6c6314 100644 (file)
@@ -6,3 +6,4 @@ rfkill-y                        += core.o
 rfkill-$(CONFIG_RFKILL_INPUT)  += input.o
 obj-$(CONFIG_RFKILL)           += rfkill.o
 obj-$(CONFIG_RFKILL_REGULATOR) += rfkill-regulator.o
+obj-$(CONFIG_RFKILL_GPIO)      += rfkill-gpio.o
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
new file mode 100644 (file)
index 0000000..256c5dd
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rfkill.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <linux/rfkill-gpio.h>
+
+enum rfkill_gpio_clk_state {
+       UNSPECIFIED = 0,
+       PWR_ENABLED,
+       PWR_DISABLED
+};
+
+#define PWR_CLK_SET(_RF, _EN) \
+       ((_RF)->pwr_clk_enabled = (!(_EN) ? PWR_ENABLED : PWR_DISABLED))
+#define PWR_CLK_ENABLED(_RF) ((_RF)->pwr_clk_enabled == PWR_ENABLED)
+#define PWR_CLK_DISABLED(_RF) ((_RF)->pwr_clk_enabled != PWR_ENABLED)
+
+struct rfkill_gpio_data {
+       struct rfkill_gpio_platform_data        *pdata;
+       struct rfkill                           *rfkill_dev;
+       char                                    *reset_name;
+       char                                    *shutdown_name;
+       enum rfkill_gpio_clk_state              pwr_clk_enabled;
+       struct clk                              *pwr_clk;
+};
+
+static int rfkill_gpio_set_power(void *data, bool blocked)
+{
+       struct rfkill_gpio_data *rfkill = data;
+
+       if (blocked) {
+               if (gpio_is_valid(rfkill->pdata->shutdown_gpio))
+                       gpio_direction_output(rfkill->pdata->shutdown_gpio, 0);
+               if (gpio_is_valid(rfkill->pdata->reset_gpio))
+                       gpio_direction_output(rfkill->pdata->reset_gpio, 0);
+               if (rfkill->pwr_clk && PWR_CLK_ENABLED(rfkill))
+                       clk_disable(rfkill->pwr_clk);
+       } else {
+               if (rfkill->pwr_clk && PWR_CLK_DISABLED(rfkill))
+                       clk_enable(rfkill->pwr_clk);
+               if (gpio_is_valid(rfkill->pdata->reset_gpio))
+                       gpio_direction_output(rfkill->pdata->reset_gpio, 1);
+               if (gpio_is_valid(rfkill->pdata->shutdown_gpio))
+                       gpio_direction_output(rfkill->pdata->shutdown_gpio, 1);
+       }
+
+       if (rfkill->pwr_clk)
+               PWR_CLK_SET(rfkill, blocked);
+
+       return 0;
+}
+
+static const struct rfkill_ops rfkill_gpio_ops = {
+       .set_block = rfkill_gpio_set_power,
+};
+
+static int rfkill_gpio_probe(struct platform_device *pdev)
+{
+       struct rfkill_gpio_data *rfkill;
+       struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
+       int ret = 0;
+       int len = 0;
+
+       if (!pdata) {
+               pr_warn("%s: No platform data specified\n", __func__);
+               return -EINVAL;
+       }
+
+       /* make sure at-least one of the GPIO is defined and that
+        * a name is specified for this instance */
+       if (!pdata->name || (!gpio_is_valid(pdata->reset_gpio) &&
+               !gpio_is_valid(pdata->shutdown_gpio))) {
+               pr_warn("%s: invalid platform data\n", __func__);
+               return -EINVAL;
+       }
+
+       rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL);
+       if (!rfkill)
+               return -ENOMEM;
+
+       rfkill->pdata = pdata;
+
+       len = strlen(pdata->name);
+       rfkill->reset_name = kzalloc(len + 7, GFP_KERNEL);
+       if (!rfkill->reset_name) {
+               ret = -ENOMEM;
+               goto fail_alloc;
+       }
+
+       rfkill->shutdown_name = kzalloc(len + 10, GFP_KERNEL);
+       if (!rfkill->shutdown_name) {
+               ret = -ENOMEM;
+               goto fail_reset_name;
+       }
+
+       snprintf(rfkill->reset_name, len + 6 , "%s_reset", pdata->name);
+       snprintf(rfkill->shutdown_name, len + 9, "%s_shutdown", pdata->name);
+
+       if (pdata->power_clk_name) {
+               rfkill->pwr_clk = clk_get(&pdev->dev, pdata->power_clk_name);
+               if (IS_ERR(rfkill->pwr_clk)) {
+                       pr_warn("%s: can't find pwr_clk.\n", __func__);
+                       goto fail_shutdown_name;
+               }
+       }
+
+       if (gpio_is_valid(pdata->reset_gpio)) {
+               ret = gpio_request(pdata->reset_gpio, rfkill->reset_name);
+               if (ret) {
+                       pr_warn("%s: failed to get reset gpio.\n", __func__);
+                       goto fail_clock;
+               }
+       }
+
+       if (gpio_is_valid(pdata->shutdown_gpio)) {
+               ret = gpio_request(pdata->shutdown_gpio, rfkill->shutdown_name);
+               if (ret) {
+                       pr_warn("%s: failed to get shutdown gpio.\n", __func__);
+                       goto fail_reset;
+               }
+       }
+
+       rfkill->rfkill_dev = rfkill_alloc(pdata->name, &pdev->dev, pdata->type,
+                               &rfkill_gpio_ops, rfkill);
+       if (!rfkill->rfkill_dev)
+               goto fail_shutdown;
+
+       ret = rfkill_register(rfkill->rfkill_dev);
+       if (ret < 0)
+               goto fail_rfkill;
+
+       platform_set_drvdata(pdev, rfkill);
+
+       dev_info(&pdev->dev, "%s device registered.\n", pdata->name);
+
+       return 0;
+
+fail_rfkill:
+       rfkill_destroy(rfkill->rfkill_dev);
+fail_shutdown:
+       if (gpio_is_valid(pdata->shutdown_gpio))
+               gpio_free(pdata->shutdown_gpio);
+fail_reset:
+       if (gpio_is_valid(pdata->reset_gpio))
+               gpio_free(pdata->reset_gpio);
+fail_clock:
+       if (rfkill->pwr_clk)
+               clk_put(rfkill->pwr_clk);
+fail_shutdown_name:
+       kfree(rfkill->shutdown_name);
+fail_reset_name:
+       kfree(rfkill->reset_name);
+fail_alloc:
+       kfree(rfkill);
+
+       return ret;
+}
+
+static int rfkill_gpio_remove(struct platform_device *pdev)
+{
+       struct rfkill_gpio_data *rfkill = platform_get_drvdata(pdev);
+
+       rfkill_unregister(rfkill->rfkill_dev);
+       rfkill_destroy(rfkill->rfkill_dev);
+       if (gpio_is_valid(rfkill->pdata->shutdown_gpio))
+               gpio_free(rfkill->pdata->shutdown_gpio);
+       if (gpio_is_valid(rfkill->pdata->reset_gpio))
+               gpio_free(rfkill->pdata->reset_gpio);
+       if (rfkill->pwr_clk && PWR_CLK_ENABLED(rfkill))
+               clk_disable(rfkill->pwr_clk);
+       if (rfkill->pwr_clk)
+               clk_put(rfkill->pwr_clk);
+       kfree(rfkill->shutdown_name);
+       kfree(rfkill->reset_name);
+       kfree(rfkill);
+
+       return 0;
+}
+
+static struct platform_driver rfkill_gpio_driver = {
+       .probe = rfkill_gpio_probe,
+       .remove = __devexit_p(rfkill_gpio_remove),
+       .driver = {
+                  .name = "rfkill_gpio",
+                  .owner = THIS_MODULE,
+       },
+};
+
+static int __init rfkill_gpio_init(void)
+{
+       return platform_driver_register(&rfkill_gpio_driver);
+}
+
+static void __exit rfkill_gpio_exit(void)
+{
+       platform_driver_unregister(&rfkill_gpio_driver);
+}
+
+module_init(rfkill_gpio_init);
+module_exit(rfkill_gpio_exit);
+
+MODULE_DESCRIPTION("gpio rfkill");
+MODULE_AUTHOR("NVIDIA");
+MODULE_LICENSE("GPL");
index 7ef87f9eb675d3b29ef207703c917d7912f6b130..b6ea6afa55b0197a7d7975ea5ec24aa500a92868 100644 (file)
@@ -361,7 +361,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct sfq_sched_data *q = qdisc_priv(sch);
        unsigned int hash;
-       sfq_index x;
+       sfq_index x, qlen;
        struct sfq_slot *slot;
        int uninitialized_var(ret);
 
@@ -405,20 +405,12 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        if (++sch->q.qlen <= q->limit)
                return NET_XMIT_SUCCESS;
 
+       qlen = slot->qlen;
        sfq_drop(sch);
-       return NET_XMIT_CN;
-}
-
-static struct sk_buff *
-sfq_peek(struct Qdisc *sch)
-{
-       struct sfq_sched_data *q = qdisc_priv(sch);
-
-       /* No active slots */
-       if (q->tail == NULL)
-               return NULL;
-
-       return q->slots[q->tail->next].skblist_next;
+       /* Return Congestion Notification only if we dropped a packet
+        * from this flow.
+        */
+       return (qlen != slot->qlen) ? NET_XMIT_CN : NET_XMIT_SUCCESS;
 }
 
 static struct sk_buff *
@@ -702,7 +694,7 @@ static struct Qdisc_ops sfq_qdisc_ops __read_mostly = {
        .priv_size      =       sizeof(struct sfq_sched_data),
        .enqueue        =       sfq_enqueue,
        .dequeue        =       sfq_dequeue,
-       .peek           =       sfq_peek,
+       .peek           =       qdisc_peek_dequeued,
        .drop           =       sfq_drop,
        .init           =       sfq_init,
        .reset          =       sfq_reset,
index 1a21c571aa034fc90db2a38d4606681af03f0669..525f97c467e97e3e04a3d279431fc0bf08ff0d2f 100644 (file)
@@ -64,6 +64,7 @@
 /* Forward declarations for internal functions. */
 static void sctp_assoc_bh_rcv(struct work_struct *work);
 static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc);
+static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc);
 
 /* Keep track of the new idr low so that we don't re-use association id
  * numbers too fast.  It is protected by they idr spin lock is in the
@@ -446,6 +447,9 @@ void sctp_association_free(struct sctp_association *asoc)
        /* Free any cached ASCONF_ACK chunk. */
        sctp_assoc_free_asconf_acks(asoc);
 
+       /* Free the ASCONF queue. */
+       sctp_assoc_free_asconf_queue(asoc);
+
        /* Free any cached ASCONF chunk. */
        if (asoc->addip_last_asconf)
                sctp_chunk_free(asoc->addip_last_asconf);
@@ -1578,6 +1582,18 @@ retry:
        return error;
 }
 
+/* Free the ASCONF queue */
+static void sctp_assoc_free_asconf_queue(struct sctp_association *asoc)
+{
+       struct sctp_chunk *asconf;
+       struct sctp_chunk *tmp;
+
+       list_for_each_entry_safe(asconf, tmp, &asoc->addip_chunk_list, list) {
+               list_del_init(&asconf->list);
+               sctp_chunk_free(asconf);
+       }
+}
+
 /* Free asconf_ack cache */
 static void sctp_assoc_free_asconf_acks(struct sctp_association *asoc)
 {
index 61aacfbbaa92f55829730687fdf0026d123301d1..05a6ce2147147b4e4fbb9de92d7913d3877e4fb2 100644 (file)
@@ -212,7 +212,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
        sctp_for_each_hentry(epb, node, &head->chain) {
                ep = sctp_ep(epb);
                sk = epb->sk;
-               seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
+               seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
                           sctp_sk(sk)->type, sk->sk_state, hash,
                           epb->bind_addr.port,
                           sock_i_uid(sk), sock_i_ino(sk));
@@ -316,7 +316,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
                assoc = sctp_assoc(epb);
                sk = epb->sk;
                seq_printf(seq,
-                          "%8p %8p %-3d %-3d %-2d %-4d "
+                          "%8pK %8pK %-3d %-3d %-2d %-4d "
                           "%4d %8d %8d %7d %5lu %-5d %5d ",
                           assoc, sk, sctp_sk(sk)->type, sk->sk_state,
                           assoc->state, hash,
index 67e31276682ab5a969da50b300d2ff941d7f3553..cd6e4aa19dbfca0de4d54ea5bf6bf5e0d1a79d9f 100644 (file)
@@ -326,10 +326,12 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
  * Run memory cache shrinker.
  */
 static int
-rpcauth_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
+rpcauth_cache_shrinker(struct shrinker *shrink, struct shrink_control *sc)
 {
        LIST_HEAD(free);
        int res;
+       int nr_to_scan = sc->nr_to_scan;
+       gfp_t gfp_mask = sc->gfp_mask;
 
        if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
                return (nr_to_scan == 0) ? 0 : -1;
index b1d75beb7e20e8e3155a84be37161871023396ac..0722a25a3a33e6717b5e305d1cf0550b3abb9bb1 100644 (file)
@@ -2254,7 +2254,7 @@ static int unix_seq_show(struct seq_file *seq, void *v)
                struct unix_sock *u = unix_sk(s);
                unix_state_lock(s);
 
-               seq_printf(seq, "%p: %08X %08X %08X %04X %02X %5lu",
+               seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu",
                        s,
                        atomic_read(&s->sk_refcnt),
                        0,
index bf0fb40e3c8ba2eeac28292128e16e29fb4a7ff5..3dce1f167eba338a6a3c92d0c584636936600420 100644 (file)
@@ -245,6 +245,7 @@ struct cfg80211_event {
                        u16 status;
                } cr;
                struct {
+                       struct ieee80211_channel *channel;
                        u8 bssid[ETH_ALEN];
                        const u8 *req_ie;
                        const u8 *resp_ie;
@@ -392,7 +393,9 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 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,
+void __cfg80211_roamed(struct wireless_dev *wdev,
+                      struct ieee80211_channel *channel,
+                      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,
index 2222ce08ee91ea8d82e8c8222451c4af1bb4c5ef..ec83f413a7ed19d41b3a37a0a7e0b1d7b1ce9988 100644 (file)
@@ -3294,8 +3294,6 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
        struct 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, i;
@@ -3342,8 +3340,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
 
        request = kzalloc(sizeof(*request)
-                       + sizeof(*ssid) * n_ssids
-                       + sizeof(channel) * n_channels
+                       + sizeof(*request->ssids) * n_ssids
+                       + sizeof(*request->channels) * n_channels
                        + ie_len, GFP_KERNEL);
        if (!request)
                return -ENOMEM;
@@ -3449,8 +3447,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        struct cfg80211_sched_scan_request *request;
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
-       struct cfg80211_ssid *ssid;
-       struct ieee80211_channel *channel;
        struct nlattr *attr;
        struct wiphy *wiphy;
        int err, tmp, n_ssids = 0, n_channels, i;
@@ -3507,8 +3503,8 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                return -EINVAL;
 
        request = kzalloc(sizeof(*request)
-                       + sizeof(*ssid) * n_ssids
-                       + sizeof(channel) * n_channels
+                       + sizeof(*request->ssids) * n_ssids
+                       + sizeof(*request->channels) * n_channels
                        + ie_len, GFP_KERNEL);
        if (!request)
                return -ENOMEM;
index e17b0bee6bdc7b8e0b6d74a401ea9df3bdf7e977..b7b6ff8be553a10f7a0191ac04f09eeaff06463c 100644 (file)
@@ -250,7 +250,8 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
        if (wdev->conn->params.privacy)
                capa |= WLAN_CAPABILITY_PRIVACY;
 
-       bss = cfg80211_get_bss(wdev->wiphy, NULL, wdev->conn->params.bssid,
+       bss = cfg80211_get_bss(wdev->wiphy, wdev->conn->params.channel,
+                              wdev->conn->params.bssid,
                               wdev->conn->params.ssid,
                               wdev->conn->params.ssid_len,
                               WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY,
@@ -470,7 +471,10 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
        }
 
        if (!bss)
-               bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+               bss = cfg80211_get_bss(wdev->wiphy,
+                                      wdev->conn ? wdev->conn->params.channel :
+                                      NULL,
+                                      bssid,
                                       wdev->ssid, wdev->ssid_len,
                                       WLAN_CAPABILITY_ESS,
                                       WLAN_CAPABILITY_ESS);
@@ -538,7 +542,9 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 }
 EXPORT_SYMBOL(cfg80211_connect_result);
 
-void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
+void __cfg80211_roamed(struct wireless_dev *wdev,
+                      struct ieee80211_channel *channel,
+                      const u8 *bssid,
                       const u8 *req_ie, size_t req_ie_len,
                       const u8 *resp_ie, size_t resp_ie_len)
 {
@@ -565,7 +571,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
        cfg80211_put_bss(&wdev->current_bss->pub);
        wdev->current_bss = NULL;
 
-       bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+       bss = cfg80211_get_bss(wdev->wiphy, channel, bssid,
                               wdev->ssid, wdev->ssid_len,
                               WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
 
@@ -603,7 +609,9 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
 #endif
 }
 
-void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
+void cfg80211_roamed(struct net_device *dev,
+                    struct ieee80211_channel *channel,
+                    const u8 *bssid,
                     const u8 *req_ie, size_t req_ie_len,
                     const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp)
 {
@@ -619,6 +627,7 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
                return;
 
        ev->type = EVENT_ROAMED;
+       ev->rm.channel = channel;
        memcpy(ev->rm.bssid, bssid, ETH_ALEN);
        ev->rm.req_ie = ((u8 *)ev) + sizeof(*ev);
        ev->rm.req_ie_len = req_ie_len;
index f0536d44d43c18e11b54b8f060f8e1b5da42709d..4d7b83fbc32f0eb042e3a70e23d01d626a5add04 100644 (file)
@@ -746,7 +746,7 @@ static void cfg80211_process_wdev_events(struct wireless_dev *wdev)
                                NULL);
                        break;
                case EVENT_ROAMED:
-                       __cfg80211_roamed(wdev, ev->rm.bssid,
+                       __cfg80211_roamed(wdev, ev->rm.channel, ev->rm.bssid,
                                          ev->rm.req_ie, ev->rm.req_ie_len,
                                          ev->rm.resp_ie, ev->rm.resp_ie_len);
                        break;
index d8670810db65f664623a18f991a88a7a72a00d5b..8657f99bfb2b7d171df283d82092cba96731fcbd 100755 (executable)
@@ -210,10 +210,10 @@ our $typeTypedefs = qr{(?x:
 
 our $logFunctions = qr{(?x:
        printk|
-       pr_(debug|dbg|vdbg|devel|info|warning|err|notice|alert|crit|emerg|cont)|
-       (dev|netdev|netif)_(printk|dbg|vdbg|info|warn|err|notice|alert|crit|emerg|WARN)|
+       [a-z]+_(emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)|
        WARN|
-       panic
+       panic|
+       MODULE_[A-Z_]+
 )};
 
 our @typeList = (
@@ -1462,7 +1462,7 @@ sub process {
 #80 column limit
                if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
                    $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
-                   !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:,|\)\s*;)\s*$/ ||
+                   !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ ||
                    $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) &&
                    $length > 80)
                {
@@ -2748,6 +2748,11 @@ sub process {
                        WARN("sizeof(& should be avoided\n" . $herecurr);
                }
 
+# check for line continuations in quoted strings with odd counts of "
+               if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
+                       WARN("Avoid line continuations in quoted strings\n" . $herecurr);
+               }
+
 # check for new externs in .c files.
                if ($realfile =~ /\.c$/ && defined $stat &&
                    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
index b444e89a0095dc16d207fb23a7600a148c67834b..5e490a8ceca5582e3003890cf34a21c33447969f 100755 (executable)
@@ -12,6 +12,7 @@ $| = 1;
 my $debugging;
 
 foreach my $file (@ARGV) {
+    next if $file =~ "include/linux/version\.h";
     # Open this file.
     open( my $f, '<', $file )
       or die "Can't open $file: $!\n";
index 04dce7c15f8328c71f3ce5f6bff4ef9ef0882eac..8f79b701de876a807ae76abd89ad077d65ef3390 100644 (file)
@@ -25,11 +25,12 @@ sub alphabetically {
 sub print_depends_on {
        my ($href) = @_;
        print "\n";
-       while (my ($mod, $list) = each %$href) {
+       for my $mod (sort keys %$href) {
+               my $list = $href->{$mod};
                print "\t$mod:\n";
                foreach my $sym (sort numerically @{$list}) {
                        my ($symbol, $no) = split /\s+/, $sym;
-                       printf("\t\t%-25s\t%-25d\n", $symbol, $no);
+                       printf("\t\t%-25s\n", $symbol);
                }
                print "\n";
        }
@@ -49,8 +50,14 @@ sub usage {
 }
 
 sub collectcfiles {
-    my @file
-       = `cat .tmp_versions/*.mod | grep '.*\.ko\$' | sed s/\.ko$/.mod.c/`;
+    my @file;
+    while (<.tmp_versions/*.mod>) {
+       open my $fh, '<', $_ or die "cannot open $_: $!\n";
+       push (@file,
+             grep s/\.ko/.mod.c/,      # change the suffix
+             grep m/.+\.ko/,           # find the .ko path
+             <$fh>);                   # lines in opened file
+    }
     chomp @file;
     return @file;
 }
@@ -95,6 +102,8 @@ close($module_symvers);
 #
 # collect the usage count of each symbol.
 #
+my $modversion_warnings = 0;
+
 foreach my $thismod (@allcfiles) {
        my $module;
 
@@ -125,7 +134,8 @@ foreach my $thismod (@allcfiles) {
                }
        }
        if ($state != 2) {
-               print "WARNING:$thismod is not built with CONFIG_MODVERSION enabled\n";
+               warn "WARNING:$thismod is not built with CONFIG_MODVERSIONS enabled\n";
+               $modversion_warnings++;
        }
        close($module);
 }
@@ -159,8 +169,12 @@ printf("SECTION 2:\n\tThis section reports export-symbol-usage of in-kernel
 modules. Each module lists the modules, and the symbols from that module that
 it uses.  Each listed symbol reports the number of modules using it\n");
 
+print "\nNOTE: Got $modversion_warnings CONFIG_MODVERSIONS warnings\n\n"
+    if $modversion_warnings;
+
 print "~"x80 , "\n";
-while (my ($thismod, $list) = each %MODULE) {
+for my $thismod (sort keys %MODULE) {
+       my $list = $MODULE{$thismod};
        my %depends;
        $thismod =~ s/\.mod\.c/.ko/;
        print "\t\t\t$thismod\n";
index 368ae306aee45a42fbcee26274b491af512afbf0..faa9a4701b6f27259b9f0094aa9ee3584f237fe4 100644 (file)
@@ -77,14 +77,15 @@ localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
 # The symlink is used to repair a deficiency in arch/um
 update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
        $(Q)echo "  GEN config"
-       $(Q)xgettext --default-domain=linux              \
-           --add-comments --keyword=_ --keyword=N_      \
-           --from-code=UTF-8                            \
-           --files-from=scripts/kconfig/POTFILES.in     \
+       $(Q)xgettext --default-domain=linux                         \
+           --add-comments --keyword=_ --keyword=N_                 \
+           --from-code=UTF-8                                       \
+           --files-from=$(srctree)/scripts/kconfig/POTFILES.in     \
+           --directory=$(srctree) --directory=$(objtree)           \
            --output $(obj)/config.pot
        $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
-       $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
-       $(Q)(for i in `ls arch/*/Kconfig`;               \
+       $(Q)ln -fs Kconfig.x86 arch/um/Kconfig
+       $(Q)(for i in `ls $(srctree)/arch/*/Kconfig`;    \
            do                                           \
                echo "  GEN $$i";                        \
                $(obj)/kxgettext $$i                     \
@@ -92,7 +93,7 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
            done )
        $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
            --output $(obj)/linux.pot
-       $(Q)rm -f arch/um/Kconfig.arch
+       $(Q)rm -f $(srctree)/arch/um/Kconfig
        $(Q)rm -f $(obj)/config.pot
 
 PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
@@ -168,8 +169,11 @@ conf-objs  := conf.o  zconf.tab.o
 mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
 nconf-objs     := nconf.o zconf.tab.o nconf.gui.o
 kxgettext-objs := kxgettext.o zconf.tab.o
+qconf-cxxobjs  := qconf.o
+qconf-objs     := kconfig_load.o zconf.tab.o
+gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
 
-hostprogs-y := conf qconf gconf kxgettext
+hostprogs-y := conf
 
 ifeq ($(MAKECMDGOALS),nconfig)
        hostprogs-y += nconf
@@ -179,6 +183,10 @@ ifeq ($(MAKECMDGOALS),menuconfig)
        hostprogs-y += mconf
 endif
 
+ifeq ($(MAKECMDGOALS),update-po-config)
+       hostprogs-y += kxgettext
+endif
+
 ifeq ($(MAKECMDGOALS),xconfig)
        qconf-target := 1
 endif
@@ -188,16 +196,15 @@ endif
 
 
 ifeq ($(qconf-target),1)
-qconf-cxxobjs  := qconf.o
-qconf-objs     := kconfig_load.o zconf.tab.o
+       hostprogs-y += qconf
 endif
 
 ifeq ($(gconf-target),1)
-gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+       hostprogs-y += gconf
 endif
 
-clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck \
-                  .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
+clean-files    := lkc_defs.h qconf.moc .tmp_qtcheck .tmp_gtkcheck
+clean-files    += zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
 clean-files     += mconf qconf gconf nconf
 clean-files     += config.pot linux.pot
 
@@ -321,11 +328,12 @@ $(obj)/%.moc: $(src)/%.h
        $(KC_QT_MOC) -i $< -o $@
 
 $(obj)/lkc_defs.h: $(src)/lkc_proto.h
-       sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+       $(Q)sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
 
 # Extract gconf menu items for I18N support
 $(obj)/gconf.glade.h: $(obj)/gconf.glade
-       intltool-extract --type=gettext/glade $(obj)/gconf.glade
+       $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
+       $(obj)/gconf.glade
 
 ###
 # The following requires flex/bison/gperf
index 61c35bf2d9cb93d690a40eafb0227006bec46151..2bafd9a7c8daa0c7f80edb0294f5686995832c9f 100644 (file)
@@ -560,8 +560,6 @@ int conf_write(const char *name)
        const char *basename;
        const char *str;
        char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
-       time_t now;
-       int use_timestamp = 1;
        char *env;
 
        dirname[0] = 0;
@@ -598,19 +596,11 @@ int conf_write(const char *name)
        if (!out)
                return 1;
 
-       time(&now);
-       env = getenv("KCONFIG_NOTIMESTAMP");
-       if (env && *env)
-               use_timestamp = 0;
-
        fprintf(out, _("#\n"
                       "# Automatically generated make config: don't edit\n"
                       "# %s\n"
-                      "%s%s"
                       "#\n"),
-                    rootmenu.prompt->text,
-                    use_timestamp ? "# " : "",
-                    use_timestamp ? ctime(&now) : "");
+                    rootmenu.prompt->text);
 
        if (!conf_get_changed())
                sym_clear_all_valid();
@@ -784,7 +774,6 @@ int conf_write_autoconf(void)
        const char *str;
        const char *name;
        FILE *out, *tristate, *out_h;
-       time_t now;
        int i;
 
        sym_clear_all_valid();
@@ -811,22 +800,19 @@ int conf_write_autoconf(void)
                return 1;
        }
 
-       time(&now);
        fprintf(out, "#\n"
                     "# Automatically generated make config: don't edit\n"
                     "# %s\n"
-                    "# %s"
                     "#\n",
-                    rootmenu.prompt->text, ctime(&now));
+                    rootmenu.prompt->text);
        fprintf(tristate, "#\n"
                          "# Automatically generated - do not edit\n"
                          "\n");
        fprintf(out_h, "/*\n"
                       " * Automatically generated C config: don't edit\n"
                       " * %s\n"
-                      " * %s"
                       " */\n",
-                      rootmenu.prompt->text, ctime(&now));
+                      rootmenu.prompt->text);
 
        for_all_symbols(i, sym) {
                sym_calc_value(sym);
index 3d238db4976405fee6aa122c3582e4a717a25315..16bfae2d321742bd5bf06e0a17e3e6377b47ef71 100644 (file)
@@ -20,12 +20,8 @@ struct file {
        struct file *parent;
        const char *name;
        int lineno;
-       int flags;
 };
 
-#define FILE_BUSY              0x0001
-#define FILE_SCANNED           0x0002
-
 typedef enum tristate {
        no, mod, yes
 } tristate;
index 455896164d72ccdbe327b2b5914b9561bece6c17..a11d5f7b9eeb1f793514fb8548b646a7414ca321 100644 (file)
@@ -253,7 +253,7 @@ void init_left_tree(void)
 
        gtk_tree_view_set_model(view, model1);
        gtk_tree_view_set_headers_visible(view, TRUE);
-       gtk_tree_view_set_rules_hint(view, FALSE);
+       gtk_tree_view_set_rules_hint(view, TRUE);
 
        column = gtk_tree_view_column_new();
        gtk_tree_view_append_column(view, column);
@@ -298,7 +298,7 @@ void init_right_tree(void)
 
        gtk_tree_view_set_model(view, model2);
        gtk_tree_view_set_headers_visible(view, TRUE);
-       gtk_tree_view_set_rules_hint(view, FALSE);
+       gtk_tree_view_set_rules_hint(view, TRUE);
 
        column = gtk_tree_view_column_new();
        gtk_tree_view_append_column(view, column);
@@ -756,7 +756,6 @@ void on_load_clicked(GtkButton * button, gpointer user_data)
 void on_single_clicked(GtkButton * button, gpointer user_data)
 {
        view_mode = SINGLE_VIEW;
-       gtk_paned_set_position(GTK_PANED(hpaned), 0);
        gtk_widget_hide(tree1_w);
        current = &rootmenu;
        display_tree_part();
@@ -782,7 +781,6 @@ void on_split_clicked(GtkButton * button, gpointer user_data)
 void on_full_clicked(GtkButton * button, gpointer user_data)
 {
        view_mode = FULL_VIEW;
-       gtk_paned_set_position(GTK_PANED(hpaned), 0);
        gtk_widget_hide(tree1_w);
        if (tree2)
                gtk_tree_store_clear(tree2);
@@ -1444,6 +1442,12 @@ static void display_tree(struct menu *menu)
                 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
                    || (view_mode == FULL_VIEW)
                    || (view_mode == SPLIT_VIEW))*/
+
+               /* Change paned position if the view is not in 'split mode' */
+               if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
+                       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+               }
+
                if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
                    || (view_mode == FULL_VIEW)
                    || (view_mode == SPLIT_VIEW)) {
index 6eb039718259a38838268c7df29a2212cb265bed..d9182916f72494d3138a93a352f24a11ee3f06e7 100644 (file)
@@ -2363,11 +2363,11 @@ void zconf_initscan(const char *name)
 
        current_file = file_lookup(name);
        current_file->lineno = 1;
-       current_file->flags = FILE_BUSY;
 }
 
 void zconf_nextfile(const char *name)
 {
+       struct file *iter;
        struct file *file = file_lookup(name);
        struct buffer *buf = malloc(sizeof(*buf));
        memset(buf, 0, sizeof(*buf));
@@ -2383,18 +2383,25 @@ void zconf_nextfile(const char *name)
        buf->parent = current_buf;
        current_buf = buf;
 
-       if (file->flags & FILE_BUSY) {
-               printf("%s:%d: do not source '%s' from itself\n",
-                      zconf_curname(), zconf_lineno(), name);
-               exit(1);
-       }
-       if (file->flags & FILE_SCANNED) {
-               printf("%s:%d: file '%s' is already sourced from '%s'\n",
-                      zconf_curname(), zconf_lineno(), name,
-                      file->parent->name);
-               exit(1);
+       for (iter = current_file->parent; iter; iter = iter->parent ) {
+               if (!strcmp(current_file->name,iter->name) ) {
+                       printf("%s:%d: recursive inclusion detected. "
+                              "Inclusion path:\n  current file : '%s'\n",
+                              zconf_curname(), zconf_lineno(),
+                              zconf_curname());
+                       iter = current_file->parent;
+                       while (iter && \
+                              strcmp(iter->name,current_file->name)) {
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno-1);
+                               iter = iter->parent;
+                       }
+                       if (iter)
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno+1);
+                       exit(1);
+               }
        }
-       file->flags |= FILE_BUSY;
        file->lineno = 1;
        file->parent = current_file;
        current_file = file;
@@ -2404,8 +2411,6 @@ static void zconf_endfile(void)
 {
        struct buffer *parent;
 
-       current_file->flags |= FILE_SCANNED;
-       current_file->flags &= ~FILE_BUSY;
        current_file = current_file->parent;
 
        parent = current_buf->parent;
index db56377393d7922229562fa1ea767f3288424e25..488dd741078747132b08dc9afb33001f4a03db5a 100644 (file)
@@ -373,18 +373,18 @@ static void print_function_line(void)
        const int skip = 1;
 
        for (i = 0; i < function_keys_num; i++) {
-               wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+               (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
                mvwprintw(main_window, LINES-3, offset,
                                "%s",
                                function_keys[i].key_str);
-               wattrset(main_window, attributes[FUNCTION_TEXT]);
+               (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
                offset += strlen(function_keys[i].key_str);
                mvwprintw(main_window, LINES-3,
                                offset, "%s",
                                function_keys[i].func);
                offset += strlen(function_keys[i].func) + skip;
        }
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
 }
 
 /* help */
@@ -953,16 +953,16 @@ static void show_menu(const char *prompt, const char *instructions,
        current_instructions = instructions;
 
        clear();
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
        print_in_middle(stdscr, 1, 0, COLS,
                        menu_backtitle,
                        attributes[MAIN_HEADING]);
 
-       wattrset(main_window, attributes[MAIN_MENU_BOX]);
+       (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
        box(main_window, 0, 0);
-       wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+       (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
        mvwprintw(main_window, 0, 3, " %s ", prompt);
-       wattrset(main_window, attributes[NORMAL]);
+       (void) wattrset(main_window, attributes[NORMAL]);
 
        set_menu_items(curses_menu, curses_menu_items);
 
index 06dd2e33581de5de81863bd1b74b2fb7100af5ed..c2796b866f8f14a37453f409429b900e1f11ba44 100644 (file)
@@ -1489,8 +1489,7 @@ void ConfigMainWindow::saveConfigAs(void)
        QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
        if (s.isNull())
                return;
-       if (conf_write(QFile::encodeName(s)))
-               QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+       saveConfig();
 }
 
 void ConfigMainWindow::searchConfig(void)
@@ -1643,7 +1642,7 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
        mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
        switch (mb.exec()) {
        case QMessageBox::Yes:
-               conf_write(NULL);
+               saveConfig();
        case QMessageBox::No:
                e->accept();
                break;
index 3dbaec185cc486d183ed5ba87cfe848635e4b968..b22f884f90221650ed46ef4cf509bf6a3b33170e 100644 (file)
@@ -294,11 +294,11 @@ void zconf_initscan(const char *name)
 
        current_file = file_lookup(name);
        current_file->lineno = 1;
-       current_file->flags = FILE_BUSY;
 }
 
 void zconf_nextfile(const char *name)
 {
+       struct file *iter;
        struct file *file = file_lookup(name);
        struct buffer *buf = malloc(sizeof(*buf));
        memset(buf, 0, sizeof(*buf));
@@ -314,18 +314,25 @@ void zconf_nextfile(const char *name)
        buf->parent = current_buf;
        current_buf = buf;
 
-       if (file->flags & FILE_BUSY) {
-               printf("%s:%d: do not source '%s' from itself\n",
-                      zconf_curname(), zconf_lineno(), name);
-               exit(1);
-       }
-       if (file->flags & FILE_SCANNED) {
-               printf("%s:%d: file '%s' is already sourced from '%s'\n",
-                      zconf_curname(), zconf_lineno(), name,
-                      file->parent->name);
-               exit(1);
+       for (iter = current_file->parent; iter; iter = iter->parent ) {
+               if (!strcmp(current_file->name,iter->name) ) {
+                       printf("%s:%d: recursive inclusion detected. "
+                              "Inclusion path:\n  current file : '%s'\n",
+                              zconf_curname(), zconf_lineno(),
+                              zconf_curname());
+                       iter = current_file->parent;
+                       while (iter && \
+                              strcmp(iter->name,current_file->name)) {
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno-1);
+                               iter = iter->parent;
+                       }
+                       if (iter)
+                               printf("  included from: '%s:%d'\n",
+                                      iter->name, iter->lineno+1);
+                       exit(1);
+               }
        }
-       file->flags |= FILE_BUSY;
        file->lineno = 1;
        file->parent = current_file;
        current_file = file;
@@ -335,8 +342,6 @@ static void zconf_endfile(void)
 {
        struct buffer *parent;
 
-       current_file->flags |= FILE_SCANNED;
-       current_file->flags &= ~FILE_BUSY;
        current_file = current_file->parent;
 
        parent = current_buf->parent;
index a834b935f5363d80ab56b15a1acf3cb477f21e42..006960ebbce927adbb1761ecc1275858db00a62c 100644 (file)
@@ -26,9 +26,9 @@ RPM := $(shell if [ -x "/usr/bin/rpmbuild" ]; then echo rpmbuild; \
                   else echo rpm; fi)
 
 # Remove hyphens since they have special meaning in RPM filenames
-KERNELPATH := kernel-$(subst -,,$(KERNELRELEASE))
+KERNELPATH := kernel-$(subst -,_,$(KERNELRELEASE))
 MKSPEC     := $(srctree)/scripts/package/mkspec
-PREV       := set -e; cd ..;
+PREV       := set -e; cd -P ..;
 
 # rpm-pkg
 # ---------------------------------------------------------------------------
index e1c1d5b8ca70842e426d653fa508f9ed89601f8a..4bf17ddf7c7ff732f4ed0a9a851bfd759ad03772 100755 (executable)
@@ -22,7 +22,7 @@ if [ "`grep CONFIG_DRM=y .config | cut -f2 -d\=`" = "y" ]; then
 fi
 
 PROVIDES="$PROVIDES kernel-$KERNELRELEASE"
-__KERNELRELEASE=`echo $KERNELRELEASE | sed -e "s/-//g"`
+__KERNELRELEASE=`echo $KERNELRELEASE | sed -e "s/-/_/g"`
 
 echo "Name: kernel"
 echo "Summary: The Linux Kernel"
@@ -47,6 +47,18 @@ echo ""
 echo "%description"
 echo "The Linux Kernel, the operating system core itself"
 echo ""
+echo "%package headers"
+echo "Summary: Header files for the Linux kernel for use by glibc"
+echo "Group: Development/System"
+echo "Obsoletes: kernel-headers"
+echo "Provides: kernel-headers = %{version}"
+echo "%description headers"
+echo "Kernel-headers includes the C header files that specify the interface"
+echo "between the Linux kernel and userspace libraries and programs.  The"
+echo "header files define structures and constants that are needed for"
+echo "building most standard programs and are also needed for rebuilding the"
+echo "glibc package."
+echo ""
 
 if ! $PREBUILT; then
 echo "%prep"
@@ -83,6 +95,7 @@ echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
 echo "%endif"
 echo "%endif"
 
+echo 'make %{?_smp_mflags} INSTALL_HDR_PATH=$RPM_BUILD_ROOT/usr headers_install'
 echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE"
 
 echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$KERNELRELEASE"
@@ -105,3 +118,7 @@ echo "/lib/modules/$KERNELRELEASE"
 echo "/lib/firmware"
 echo "/boot/*"
 echo ""
+echo "%files headers"
+echo '%defattr (-, root, root)'
+echo "/usr/include"
+echo ""
index 46a59cae3a0a6d52840483ab10212ef93fb6f3c3..20fb25c2338299f33a8954d6b046ce17f7b466fe 100755 (executable)
@@ -250,7 +250,7 @@ while :                             # incrementing SUBLEVEL (s in v.p.s)
 do
     CURRENTFULLVERSION="$VERSION.$PATCHLEVEL.$SUBLEVEL"
     EXTRAVER=
-    if [ $STOPFULLVERSION = $CURRENTFULLVERSION ]; then
+    if [ x$STOPFULLVERSION = x$CURRENTFULLVERSION ]; then
         echo "Stopping at $CURRENTFULLVERSION base as requested."
         break
     fi