]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
Merge branch 'for-rmk' of git://github.com/at91linux/linux-2.6-at91 into devel-stable
authorRussell King <rmk+kernel@arm.linux.org.uk>
Wed, 25 May 2011 23:41:21 +0000 (00:41 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Wed, 25 May 2011 23:41:21 +0000 (00:41 +0100)
536 files changed:
.gitignore
Documentation/DocBook/Makefile
Documentation/filesystems/ubifs.txt
Documentation/i2c/busses/i2c-i801
Documentation/i2c/writing-clients
Documentation/input/elantech.txt
Documentation/input/rotary-encoder.txt
Documentation/kbuild/kbuild.txt
Documentation/kbuild/makefiles.txt
MAINTAINERS
Makefile
arch/alpha/kernel/vmlinux.lds.S
arch/arm/Kconfig
arch/arm/configs/at572d940hfek_defconfig [deleted file]
arch/arm/configs/at91sam9261_defconfig [moved from arch/arm/configs/at91sam9261ek_defconfig with 53% similarity]
arch/arm/configs/at91sam9263_defconfig [moved from arch/arm/configs/at91sam9263ek_defconfig with 57% similarity]
arch/arm/configs/neocore926_defconfig [deleted file]
arch/arm/configs/usb-a9263_defconfig [deleted file]
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at572d940hf.c [deleted file]
arch/arm/mach-at91/at572d940hf_devices.c [deleted file]
arch/arm/mach-at91/at91cap9.c
arch/arm/mach-at91/at91cap9_devices.c
arch/arm/mach-at91/at91rm9200.c
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9g45_devices.c
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/at91x40.c
arch/arm/mach-at91/board-1arm.c
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-at572d940hf_ek.c [deleted file]
arch/arm/mach-at91/board-cam60.c
arch/arm/mach-at91/board-cap9adk.c
arch/arm/mach-at91/board-carmeva.c
arch/arm/mach-at91/board-cpu9krea.c
arch/arm/mach-at91/board-cpuat91.c
arch/arm/mach-at91/board-csb337.c
arch/arm/mach-at91/board-csb637.c
arch/arm/mach-at91/board-eb01.c
arch/arm/mach-at91/board-eb9200.c
arch/arm/mach-at91/board-ecbat91.c
arch/arm/mach-at91/board-eco920.c
arch/arm/mach-at91/board-flexibity.c
arch/arm/mach-at91/board-foxg20.c
arch/arm/mach-at91/board-gsia18s.c
arch/arm/mach-at91/board-kafa.c
arch/arm/mach-at91/board-kb9202.c
arch/arm/mach-at91/board-neocore926.c
arch/arm/mach-at91/board-pcontrol-g20.c
arch/arm/mach-at91/board-picotux200.c
arch/arm/mach-at91/board-qil-a9260.c
arch/arm/mach-at91/board-rm9200dk.c
arch/arm/mach-at91/board-rm9200ek.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-snapper9260.c
arch/arm/mach-at91/board-stamp9g20.c
arch/arm/mach-at91/board-usb-a9260.c
arch/arm/mach-at91/board-usb-a9263.c
arch/arm/mach-at91/board-yl-9200.c
arch/arm/mach-at91/clock.c
arch/arm/mach-at91/clock.h
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/include/mach/at572d940hf.h [deleted file]
arch/arm/mach-at91/include/mach/at572d940hf_matrix.h [deleted file]
arch/arm/mach-at91/include/mach/at91cap9.h
arch/arm/mach-at91/include/mach/at91rm9200.h
arch/arm/mach-at91/include/mach/at91sam9260.h
arch/arm/mach-at91/include/mach/at91sam9261.h
arch/arm/mach-at91/include/mach/at91sam9263.h
arch/arm/mach-at91/include/mach/at91sam9g45.h
arch/arm/mach-at91/include/mach/at91sam9rl.h
arch/arm/mach-at91/include/mach/at91x40.h
arch/arm/mach-at91/include/mach/board.h
arch/arm/mach-at91/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/cpu.h
arch/arm/mach-at91/include/mach/hardware.h
arch/arm/mach-at91/include/mach/memory.h
arch/arm/mach-at91/include/mach/stamp9g20.h
arch/arm/mach-at91/include/mach/system_rev.h [new file with mode: 0644]
arch/arm/mach-at91/include/mach/timex.h
arch/arm/mach-tegra/include/mach/kbc.h
arch/arm/mach-ux500/board-mop500.c
arch/arm/plat-nomadik/include/plat/i2c.h
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/include/mach/board.h
arch/blackfin/kernel/vmlinux.lds.S
arch/cris/kernel/vmlinux.lds.S
arch/frv/kernel/vmlinux.lds.S
arch/m32r/kernel/vmlinux.lds.S
arch/m68k/Kconfig
arch/m68k/include/asm/bitops_no.h
arch/m68k/include/asm/io_no.h
arch/m68k/kernel/asm-offsets.c
arch/m68k/kernel/asm-offsets_mm.c [deleted file]
arch/m68k/kernel/asm-offsets_no.c [deleted file]
arch/m68k/kernel/entry_no.S
arch/m68k/kernel/irq.c
arch/m68k/kernel/m68k_ksyms.c
arch/m68k/kernel/m68k_ksyms_mm.c [deleted file]
arch/m68k/kernel/m68k_ksyms_no.c [deleted file]
arch/m68k/kernel/process_no.c
arch/m68k/kernel/sys_m68k.c
arch/m68k/kernel/sys_m68k_mm.c [deleted file]
arch/m68k/kernel/sys_m68k_no.c [deleted file]
arch/m68k/kernel/syscalltable.S
arch/m68k/lib/Makefile
arch/m68k/lib/Makefile_mm [deleted file]
arch/m68k/lib/Makefile_no [deleted file]
arch/m68k/lib/checksum.c [deleted file]
arch/m68k/lib/checksum_no.c
arch/m68k/lib/memcpy.c
arch/m68k/lib/memmove.c
arch/m68k/lib/memset.c
arch/m68k/lib/muldi3.c
arch/m68k/lib/muldi3_mm.c [deleted file]
arch/m68k/lib/muldi3_no.c [deleted file]
arch/m68k/lib/string.c
arch/m68k/mm/Makefile
arch/m68k/mm/Makefile_mm [deleted file]
arch/m68k/mm/Makefile_no [deleted file]
arch/m68k/mm/init_no.c
arch/m68k/mm/kmap.c
arch/m68k/mm/kmap_mm.c [deleted file]
arch/m68k/mm/kmap_no.c [deleted file]
arch/m68k/platform/68328/entry.S
arch/m68k/platform/68360/entry.S
arch/m68k/platform/coldfire/dma.c
arch/m68k/platform/coldfire/entry.S
arch/m68k/platform/coldfire/head.S
arch/mips/kernel/vmlinux.lds.S
arch/mn10300/kernel/vmlinux.lds.S
arch/parisc/kernel/vmlinux.lds.S
arch/powerpc/kernel/vmlinux.lds.S
arch/s390/Kconfig
arch/s390/appldata/appldata_base.c
arch/s390/include/asm/cmpxchg.h
arch/s390/include/asm/elf.h
arch/s390/include/asm/hugetlb.h
arch/s390/include/asm/irq.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/mmu.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/page.h
arch/s390/include/asm/percpu.h
arch/s390/include/asm/pgalloc.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/tlbflush.h
arch/s390/include/asm/unistd.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/irq.c
arch/s390/kernel/process.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/time.c
arch/s390/kernel/topology.c
arch/s390/kernel/vdso32/Makefile
arch/s390/kernel/vdso64/Makefile
arch/s390/kernel/vmlinux.lds.S
arch/s390/mm/extmem.c
arch/s390/mm/fault.c
arch/s390/mm/hugetlbpage.c
arch/s390/mm/init.c
arch/s390/mm/pageattr.c
arch/s390/mm/pgtable.c
arch/s390/mm/vmem.c
arch/s390/oprofile/hwsampler.c
arch/sh/kernel/vmlinux.lds.S
arch/sparc/kernel/vmlinux.lds.S
arch/tile/kernel/vmlinux.lds.S
arch/um/Kconfig.x86
arch/um/include/asm/common.lds.S
arch/x86/include/asm/linkage.h
arch/x86/include/asm/percpu.h
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/vmlinux.lds.S
arch/xtensa/kernel/vmlinux.lds.S
drivers/ata/pata_pcmcia.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/dtl1_cs.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/char/agp/uninorth-agp.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/cm4040_cs.c
drivers/char/pcmcia/synclink_cs.c
drivers/crypto/Kconfig
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_channel.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_grctx.h
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nouveau_perf.c
drivers/gpu/drm/nouveau/nouveau_pm.c
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nouveau_vm.h
drivers/gpu/drm/nouveau/nouveau_volt.c
drivers/gpu/drm/nouveau/nv04_crtc.c
drivers/gpu/drm/nouveau/nv04_graph.c
drivers/gpu/drm/nouveau/nv04_instmem.c
drivers/gpu/drm/nouveau/nv10_graph.c
drivers/gpu/drm/nouveau/nv20_graph.c
drivers/gpu/drm/nouveau/nv40_fifo.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/nouveau/nv40_mpeg.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_calc.c
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_grctx.c
drivers/gpu/drm/nouveau/nv50_mpeg.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_pm.c
drivers/gpu/drm/nouveau/nv50_vm.c
drivers/gpu/drm/nouveau/nv84_crypt.c
drivers/gpu/drm/nouveau/nva3_copy.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nva3_copy.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/nva3_copy.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nva3_pm.c
drivers/gpu/drm/nouveau/nvc0_copy.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_copy.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_fifo.c
drivers/gpu/drm/nouveau/nvc0_graph.c
drivers/gpu/drm/nouveau/nvc0_graph.h
drivers/gpu/drm/nouveau/nvc0_grctx.c
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/atombios.h
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/vga/vga_switcheroo.c
drivers/gpu/vga/vgaarb.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-parport-light.c
drivers/i2c/busses/i2c-parport.c
drivers/i2c/busses/i2c-parport.h
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/busses/i2c-tegra.c
drivers/ide/ide-cs.c
drivers/input/evdev.c
drivers/input/input-polldev.c
drivers/input/input.c
drivers/input/joydev.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/adp5589-keys.c [new file with mode: 0644]
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/mpr121_touchkey.c [new file with mode: 0644]
drivers/input/keyboard/omap-keypad.c
drivers/input/keyboard/qt1070.c
drivers/input/keyboard/sh_keysc.c
drivers/input/keyboard/tegra-kbc.c
drivers/input/misc/ad714x.c
drivers/input/misc/ati_remote2.c
drivers/input/misc/rotary_encoder.c
drivers/input/misc/twl4030-pwrbutton.c
drivers/input/mouse/elantech.c
drivers/input/mouse/elantech.h
drivers/input/mousedev.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/atmel_tsadcc.c
drivers/input/touchscreen/h3600_ts_input.c
drivers/input/touchscreen/max11801_ts.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2007.c
drivers/isdn/hardware/avm/avm_cs.c
drivers/isdn/hisax/avma1_cs.c
drivers/isdn/hisax/elsa_cs.c
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/teles_cs.c
drivers/mmc/host/sdricoh_cs.c
drivers/mtd/maps/pcmciamtd.c
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/debug.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/io.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/ubi-media.h
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/wl.c
drivers/net/can/softing/softing_cs.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/com20020_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/wireless/airo_cs.c
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/b43/pcmcia.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/net/wireless/orinoco/spectrum_cs.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/wl3501_cs.c
drivers/parport/parport_cs.c
drivers/pci/pci.c
drivers/pcmcia/ds.c
drivers/pcmcia/sa1100_generic.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/mxm-wmi.c [new file with mode: 0644]
drivers/s390/block/dasd_alias.c
drivers/s390/block/dasd_eckd.c
drivers/s390/char/Kconfig
drivers/s390/char/Makefile
drivers/s390/char/monwriter.c
drivers/s390/char/raw3270.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_config.c
drivers/s390/char/sclp_ocf.c [new file with mode: 0644]
drivers/s390/char/sclp_sdias.c
drivers/s390/char/sclp_tty.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_block.c [deleted file]
drivers/s390/char/tape_std.c
drivers/s390/cio/chsc.c
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/qdio_main.c
drivers/s390/crypto/ap_bus.c
drivers/scsi/pcmcia/aha152x_stub.c
drivers/scsi/pcmcia/fdomain_stub.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/qlogic_stub.c
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/spi/coldfire_qspi.c
drivers/staging/comedi/drivers/cb_das16_cs.c
drivers/staging/comedi/drivers/das08_cs.c
drivers/staging/comedi/drivers/ni_daq_700.c
drivers/staging/comedi/drivers/ni_daq_dio24.c
drivers/staging/comedi/drivers/ni_labpc_cs.c
drivers/staging/comedi/drivers/ni_mio_cs.c
drivers/staging/comedi/drivers/quatech_daqp_cs.c
drivers/staging/ft1000/ft1000-pcmcia/ft1000_cs.c
drivers/staging/wlags49_h2/wl_cs.c
drivers/telephony/ixj_pcmcia.c
drivers/tty/ipwireless/main.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/serial_cs.c
drivers/usb/host/sl811_cs.c
fs/binfmt_flat.c
fs/dlm/config.c
fs/dlm/config.h
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/lock.h
fs/dlm/lockspace.c
fs/dlm/plock.c
fs/dlm/user.c
fs/ext2/super.c
fs/ext3/namei.c
fs/jbd/commit.c
fs/jbd/journal.c
fs/jbd/transaction.c
fs/jbd2/commit.c
fs/ubifs/budget.c
fs/ubifs/commit.c
fs/ubifs/debug.c
fs/ubifs/debug.h
fs/ubifs/dir.c
fs/ubifs/file.c
fs/ubifs/find.c
fs/ubifs/gc.c
fs/ubifs/io.c
fs/ubifs/journal.c
fs/ubifs/log.c
fs/ubifs/lprops.c
fs/ubifs/lpt_commit.c
fs/ubifs/master.c
fs/ubifs/misc.h
fs/ubifs/orphan.c
fs/ubifs/recovery.c
fs/ubifs/replay.c
fs/ubifs/sb.c
fs/ubifs/super.c
fs/ubifs/tnc.c
fs/ubifs/tnc_commit.c
fs/ubifs/ubifs-media.h
fs/ubifs/ubifs.h
fs/ubifs/xattr.c
include/asm-generic/pgtable.h
include/asm-generic/vmlinux.lds.h
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_dp_helper.h
include/drm/drm_edid.h
include/drm/drm_fb_helper.h
include/linux/capability.h
include/linux/dlm_plock.h
include/linux/gpio_keys.h
include/linux/i2c/i2c-sh_mobile.h [new file with mode: 0644]
include/linux/i2c/mpr121_touchkey.h [new file with mode: 0644]
include/linux/i2c/tsc2007.h
include/linux/init_task.h
include/linux/input/ad714x.h
include/linux/input/adp5589.h [new file with mode: 0644]
include/linux/key.h
include/linux/kmod.h
include/linux/linkage.h
include/linux/lsm_audit.h
include/linux/mtd/ubi.h
include/linux/mxm-wmi.h [new file with mode: 0644]
include/linux/page-flags.h
include/linux/pci.h
include/linux/rotary_encoder.h
include/linux/spi/ads7846.h
include/mtd/ubi-user.h
include/pcmcia/ds.h
init/Kconfig
kernel/capability.c
kernel/cred.c
kernel/kmod.c
kernel/sysctl.c
kernel/workqueue.c
lib/flex_array.c
mm/percpu.c
mm/rmap.c
net/dns_resolver/dns_key.c
scripts/.gitignore
scripts/Kbuild.include
scripts/Makefile
scripts/Makefile.asm-generic [new file with mode: 0644]
scripts/Makefile.build
scripts/Makefile.headersinst
scripts/Makefile.lib
scripts/basic/.gitignore
scripts/basic/Makefile
scripts/docproc.c [moved from scripts/basic/docproc.c with 100% similarity]
scripts/gen_initramfs_list.sh
scripts/kallsyms.c
scripts/mkcompile_h
security/Kconfig
security/commoncap.c
security/keys/internal.h
security/keys/keyctl.c
security/keys/keyring.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/user_defined.c
security/lsm_audit.c
security/selinux/avc.c
security/selinux/hooks.c
security/selinux/include/security.h
security/selinux/netnode.c
security/selinux/selinuxfs.c
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c
security/smack/smack.h
security/smack/smack_lsm.c
security/tomoyo/common.c
security/tomoyo/file.c
security/tomoyo/memory.c
security/tomoyo/mount.c
security/tomoyo/util.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/vx/vxpocket.c
usr/gen_init_cpio.c

index 5d56a3fd0de6b9d4d8acc0a26495bd24c489d31f..9dacde0a4b2dcec4ce33013354b6c46738daaef7 100644 (file)
@@ -57,6 +57,7 @@ modules.builtin
 include/config
 include/linux/version.h
 include/generated
+arch/*/include/generated
 
 # stgit generated dirs
 patches-*
index 8436b018c289cbc1c858dc8722d92a5f48389b5b..3cebfa0d161182bb562f349359b5676bb660dbd2 100644 (file)
@@ -73,7 +73,7 @@ installmandocs: mandocs
 ###
 #External programs used
 KERNELDOC = $(srctree)/scripts/kernel-doc
-DOCPROC   = $(objtree)/scripts/basic/docproc
+DOCPROC   = $(objtree)/scripts/docproc
 
 XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl
 XMLTOFLAGS += --skip-validation
index d7b13b01e98054098ba8b94744173df1ed41126a..8e4fab639d9c322708c7e0ab01825697c3e4ccb7 100644 (file)
@@ -115,28 +115,8 @@ ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs
 Module Parameters for Debugging
 ===============================
 
-When UBIFS has been compiled with debugging enabled, there are 3 module
+When UBIFS has been compiled with debugging enabled, there are 2 module
 parameters that are available to control aspects of testing and debugging.
-The parameters are unsigned integers where each bit controls an option.
-The parameters are:
-
-debug_msgs     Selects which debug messages to display, as follows:
-
-               Message Type                            Flag value
-
-               General messages                        1
-               Journal messages                        2
-               Mount messages                          4
-               Commit messages                         8
-               LEB search messages                     16
-               Budgeting messages                      32
-               Garbage collection messages             64
-               Tree Node Cache (TNC) messages          128
-               LEB properties (lprops) messages        256
-               Input/output messages                   512
-               Log messages                            1024
-               Scan messages                           2048
-               Recovery messages                       4096
 
 debug_chks     Selects extra checks that UBIFS can do while running:
 
@@ -154,11 +134,9 @@ debug_tsts Selects a mode of testing, as follows:
 
                Test mode                               Flag value
 
-               Force in-the-gaps method                2
                Failure mode for recovery testing       4
 
-For example, set debug_msgs to 5 to display General messages and Mount
-messages.
+For example, set debug_chks to 3 to enable general and TNC checks.
 
 
 References
index 6df69765ccb75045615dec13c3b564c550d18021..2871fd5003492b1d3ba266e2cd65aec8ebd58406 100644 (file)
@@ -19,6 +19,7 @@ Supported adapters:
   * Intel 6 Series (PCH)
   * Intel Patsburg (PCH)
   * Intel DH89xxCC (PCH)
+  * Intel Panther Point (PCH)
    Datasheets: Publicly available at the Intel website
 
 On Intel Patsburg and later chipsets, both the normal host SMBus controller
index 5ebf5af1d71606ae3d6d31557f97ce7f3077add7..5aa53374ea2a84d264f7875d69d39fd1b0526916 100644 (file)
@@ -38,7 +38,7 @@ static struct i2c_driver foo_driver = {
                .name   = "foo",
        },
 
-       .id_table       = foo_ids,
+       .id_table       = foo_idtable,
        .probe          = foo_probe,
        .remove         = foo_remove,
        /* if device autodetection is needed: */
index 56941ae1f5dbd2b161f7871ad3959f46ae227f89..db798af5ef98a434cbb8c8828857627953c932ec 100644 (file)
@@ -34,7 +34,8 @@ Contents
 Currently the Linux Elantech touchpad driver is aware of two different
 hardware versions unimaginatively called version 1 and version 2. Version 1
 is found in "older" laptops and uses 4 bytes per packet. Version 2 seems to
-be introduced with the EeePC and uses 6 bytes per packet.
+be introduced with the EeePC and uses 6 bytes per packet, and provides
+additional features such as position of two fingers, and width of the touch.
 
 The driver tries to support both hardware versions and should be compatible
 with the Xorg Synaptics touchpad driver and its graphical configuration
@@ -94,18 +95,44 @@ Currently the Linux Elantech touchpad driver provides two extra knobs under
    can check these bits and reject any packet that appears corrupted. Using
    this knob you can bypass that check.
 
-   It is not known yet whether hardware version 2 provides the same parity
-   bits. Hence checking is disabled by default. Currently even turning it on
-   will do nothing.
-
+   Hardware version 2 does not provide the same parity bits. Only some basic
+   data consistency checking can be done. For now checking is disabled by
+   default. Currently even turning it on will do nothing.
 
 /////////////////////////////////////////////////////////////////////////////
 
+3. Differentiating hardware versions
+   =================================
+
+To detect the hardware version, read the version number as param[0].param[1].param[2]
+
+ 4 bytes version: (after the arrow is the name given in the Dell-provided driver)
+ 02.00.22 => EF013
+ 02.06.00 => EF019
+In the wild, there appear to be more versions, such as 00.01.64, 01.00.21,
+02.00.00, 02.00.04, 02.00.06.
+
+ 6 bytes:
+ 02.00.30 => EF113
+ 02.08.00 => EF023
+ 02.08.XX => EF123
+ 02.0B.00 => EF215
+ 04.01.XX => Scroll_EF051
+ 04.02.XX => EF051
+In the wild, there appear to be more versions, such as 04.03.01, 04.04.11. There
+appears to be almost no difference, except for EF113, which does not report
+pressure/width and has different data consistency checks.
+
+Probably all the versions with param[0] <= 01 can be considered as
+4 bytes/firmware 1. The versions < 02.08.00, with the exception of 02.00.30, as
+4 bytes/firmware 2. Everything >= 02.08.00 can be considered as 6 bytes.
+
+/////////////////////////////////////////////////////////////////////////////
 
-3. Hardware version 1
+4. Hardware version 1
    ==================
 
-3.1 Registers
+4.1 Registers
     ~~~~~~~~~
 
 By echoing a hexadecimal value to a register it contents can be altered.
@@ -168,7 +195,7 @@ For example:
          smart edge activation area width?
 
 
-3.2 Native relative mode 4 byte packet format
+4.2 Native relative mode 4 byte packet format
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 byte 0:
@@ -226,9 +253,13 @@ byte 3:
                        positive = down
 
 
-3.3 Native absolute mode 4 byte packet format
+4.3 Native absolute mode 4 byte packet format
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+EF013 and EF019 have a special behaviour (due to a bug in the firmware?), and
+when 1 finger is touching, the first 2 position reports must be discarded.
+This counting is reset whenever a different number of fingers is reported.
+
 byte 0:
    firmware version 1.x:
 
@@ -279,11 +310,11 @@ byte 3:
 /////////////////////////////////////////////////////////////////////////////
 
 
-4. Hardware version 2
+5. Hardware version 2
    ==================
 
 
-4.1 Registers
+5.1 Registers
     ~~~~~~~~~
 
 By echoing a hexadecimal value to a register it contents can be altered.
@@ -316,16 +347,41 @@ For example:
                                    0x7f = never i.e. tap again to release)
 
 
-4.2 Native absolute mode 6 byte packet format
+5.2 Native absolute mode 6 byte packet format
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-4.2.1 One finger touch
+5.2.1 Parity checking and packet re-synchronization
+There is no parity checking, however some consistency checks can be performed.
+
+For instance for EF113:
+        SA1= packet[0];
+        A1 = packet[1];
+        B1 = packet[2];
+        SB1= packet[3];
+        C1 = packet[4];
+        D1 = packet[5];
+        if( (((SA1 & 0x3C) != 0x3C) && ((SA1 & 0xC0) != 0x80)) || // check Byte 1
+            (((SA1 & 0x0C) != 0x0C) && ((SA1 & 0xC0) == 0x80)) || // check Byte 1 (one finger pressed)
+            (((SA1 & 0xC0) != 0x80) && (( A1 & 0xF0) != 0x00)) || // check Byte 2
+            (((SB1 & 0x3E) != 0x38) && ((SA1 & 0xC0) != 0x80)) || // check Byte 4
+            (((SB1 & 0x0E) != 0x08) && ((SA1 & 0xC0) == 0x80)) || // check Byte 4 (one finger pressed)
+            (((SA1 & 0xC0) != 0x80) && (( C1 & 0xF0) != 0x00))  ) // check Byte 5
+               // error detected
+
+For all the other ones, there are just a few constant bits:
+        if( ((packet[0] & 0x0C) != 0x04) ||
+            ((packet[3] & 0x0f) != 0x02) )
+               // error detected
+
+
+In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
+
+5.2.1 One/Three finger touch
       ~~~~~~~~~~~~~~~~
 
 byte 0:
 
    bit   7   6   5   4   3   2   1   0
-        n1  n0   .   .   .   .   R   L
+        n1  n0  w3  w2   .   .   R   L
 
          L, R = 1 when Left, Right mouse button pressed
          n1..n0 = numbers of fingers on touchpad
@@ -333,24 +389,40 @@ byte 0:
 byte 1:
 
    bit   7   6   5   4   3   2   1   0
-         .   .   .   .   .  x10 x9  x8
+        p7  p6  p5  p4  .  x10 x9  x8
 
 byte 2:
 
    bit   7   6   5   4   3   2   1   0
-        x7  x6  x5  x4  x4  x2  x1  x0
+        x7  x6  x5  x4  x3  x2  x1  x0
 
          x10..x0 = absolute x value (horizontal)
 
 byte 3:
 
    bit   7   6   5   4   3   2   1   0
-         .   .   .   .   .   .   .   .
+        n4  vf  w1  w0   .   .   .  b2
+
+        n4 = set if more than 3 fingers (only in 3 fingers mode)
+        vf = a kind of flag ? (only on EF123, 0 when finger is over one
+             of the buttons, 1 otherwise)
+        w3..w0 = width of the finger touch (not EF113)
+        b2 (on EF113 only, 0 otherwise), b2.R.L indicates one button pressed:
+               0 = none
+               1 = Left
+               2 = Right
+               3 = Middle (Left and Right)
+               4 = Forward
+               5 = Back
+               6 = Another one
+               7 = Another one
 
 byte 4:
 
    bit   7   6   5   4   3   2   1   0
-         .   .   .   .   .   .  y9  y8
+        p3  p1  p2  p0   .   .  y9  y8
+
+        p7..p0 = pressure (not EF113)
 
 byte 5:
 
@@ -363,6 +435,11 @@ byte 5:
 4.2.2 Two finger touch
       ~~~~~~~~~~~~~~~~
 
+Note that the two pairs of coordinates are not exactly the coordinates of the
+two fingers, but only the pair of the lower-left and upper-right coordinates.
+So the actual fingers might be situated on the other diagonal of the square
+defined by these two points.
+
 byte 0:
 
    bit   7   6   5   4   3   2   1   0
@@ -376,14 +453,14 @@ byte 1:
    bit   7   6   5   4   3   2   1   0
         ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
 
-         ax8..ax0 = first finger absolute x value
+        ax8..ax0 = lower-left finger absolute x value
 
 byte 2:
 
    bit   7   6   5   4   3   2   1   0
         ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0
 
-         ay8..ay0 = first finger absolute y value
+        ay8..ay0 = lower-left finger absolute y value
 
 byte 3:
 
@@ -395,11 +472,11 @@ byte 4:
    bit   7   6   5   4   3   2   1   0
         bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0
 
-         bx8..bx0 = second finger absolute x value
+         bx8..bx0 = upper-right finger absolute x value
 
 byte 5:
 
    bit   7   6   5   4   3   2   1   0
         by7 by8 by5 by4 by3 by2 by1 by0
 
-         by8..by0 = second finger absolute y value
+         by8..by0 = upper-right finger absolute y value
index 943e8f6f2b15fdcc491441d20e30854fd56f1803..92e68bce13a40ce2042326d287093c3ad41f7ad2 100644 (file)
@@ -9,6 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees
 and by triggering on falling and rising edges, the turn direction can
 be determined.
 
+Some encoders have both outputs low in stable states, whereas others also have
+a stable state with both outputs high (half-period mode).
+
 The phase diagram of these two outputs look like this:
 
                   _____       _____       _____
@@ -26,6 +29,8 @@ The phase diagram of these two outputs look like this:
                 |<-------->|
                  one step
 
+                |<-->|
+                 one step (half-period mode)
 
 For more information, please see
        http://en.wikipedia.org/wiki/Rotary_encoder
@@ -34,6 +39,13 @@ For more information, please see
 1. Events / state machine
 -------------------------
 
+In half-period mode, state a) and c) above are used to determine the
+rotational direction based on the last stable state. Events are reported in
+states b) and d) given that the new stable state is different from the last
+(i.e. the rotation was not reversed half-way).
+
+Otherwise, the following apply:
+
 a) Rising edge on channel A, channel B in low state
        This state is used to recognize a clockwise turn
 
@@ -96,6 +108,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = {
        .gpio_b         = GPIO_ROTARY_B,
        .inverted_a     = 0,
        .inverted_b     = 0,
+       .half_period    = false,
 };
 
 static struct platform_device rotary_encoder_device = {
index 7c2a89ba674c3b6cd230f95d4327710acc652c72..68e32bb6bd807df797dd52204af2b973d021e0a6 100644 (file)
@@ -201,3 +201,16 @@ KBUILD_ENABLE_EXTRA_GCC_CHECKS
 --------------------------------------------------
 If enabled over the make command line with "W=1", it turns on additional
 gcc -W... options for more extensive build-time checking.
+
+KBUILD_BUILD_TIMESTAMP
+--------------------------------------------------
+Setting this to a date string overrides the timestamp used in the
+UTS_VERSION definition (uname -v in the running kernel). The value has to
+be a string that can be passed to date -d. The default value
+is the output of the date command at one point during build.
+
+KBUILD_BUILD_USER, KBUILD_BUILD_HOST
+--------------------------------------------------
+These two variables allow to override the user@host string displayed during
+boot and in /proc/version. The default value is the output of the commands
+whoami and host, respectively.
index 5d145bb443c0a87957eb37cbb75c4ffb7543623f..47435e56c5dae3970468003034decf2698caa0e6 100644 (file)
@@ -40,11 +40,13 @@ This document describes the Linux kernel Makefiles.
           --- 6.6 Commands useful for building a boot image
           --- 6.7 Custom kbuild commands
           --- 6.8 Preprocessing linker scripts
+          --- 6.9 Generic header files
 
        === 7 Kbuild syntax for exported headers
                --- 7.1 header-y
                --- 7.2 objhdr-y
                --- 7.3 destination-y
+               --- 7.4 generic-y
 
        === 8 Kbuild Variables
        === 9 Makefile language
@@ -499,6 +501,18 @@ more details, with real examples.
        gcc >= 3.00. For gcc < 3.00, -malign-functions=4 is used.
        Note: cc-option-align uses KBUILD_CFLAGS for $(CC) options
 
+    cc-disable-warning
+       cc-disable-warning checks if gcc supports a given warning and returns
+       the commandline switch to disable it. This special function is needed,
+       because gcc 4.4 and later accept any unknown -Wno-* option and only
+       warn about it if there is another warning in the source file.
+
+       Example:
+               KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
+
+       In the above example, -Wno-unused-but-set-variable will be added to
+       KBUILD_CFLAGS only if gcc really accepts it.
+
     cc-version
        cc-version returns a numerical version of the $(CC) compiler version.
        The format is <major><minor> where both are two digits. So for example
@@ -955,6 +969,11 @@ When kbuild executes, the following steps are followed (roughly):
        used when linking modules. This is often a linker script.
        From commandline LDFLAGS_MODULE shall be used (see kbuild.txt).
 
+    KBUILD_ARFLAGS   Options for $(AR) when creating archives
+
+       $(KBUILD_ARFLAGS) set by the top level Makefile to "D" (deterministic
+       mode) if this option is supported by $(AR).
+
 --- 6.2 Add prerequisites to archprepare:
 
        The archprepare: rule is used to list prerequisites that need to be
@@ -1209,6 +1228,14 @@ When kbuild executes, the following steps are followed (roughly):
        The kbuild infrastructure for *lds file are used in several
        architecture-specific files.
 
+--- 6.9 Generic header files
+
+       The directory include/asm-generic contains the header files
+       that may be shared between individual architectures.
+       The recommended approach how to use a generic header file is
+       to list the file in the Kbuild file.
+       See "7.4 generic-y" for further info on syntax etc.
+
 === 7 Kbuild syntax for exported headers
 
 The kernel include a set of headers that is exported to userspace.
@@ -1265,6 +1292,32 @@ See subsequent chapter for the syntax of the Kbuild file.
        In the example above all exported headers in the Kbuild file
        will be located in the directory "include/linux" when exported.
 
+       --- 7.4 generic-y
+
+       If an architecture uses a verbatim copy of a header from
+       include/asm-generic then this is listed in the file
+       arch/$(ARCH)/include/asm/Kbuild like this:
+
+               Example:
+                       #arch/x86/include/asm/Kbuild
+                       generic-y += termios.h
+                       generic-y += rtc.h
+
+       During the prepare phase of the build a wrapper include
+       file is generated in the directory:
+
+               arch/$(ARCH)/include/generated/asm
+
+       When a header is exported where the architecture uses
+       the generic header a similar wrapper is generated as part
+       of the set of exported headers in the directory:
+
+               usr/include/asm
+
+       The generated wrapper will in both cases look like the following:
+
+               Example: termios.h
+                       #include <asm-generic/termios.h>
 
 === 8 Kbuild Variables
 
index 0b415248ae252b0706f16e3e5cb85e721e0b14d0..98c324b07a164913d171d4ef6d07592940b8facf 100644 (file)
@@ -2245,10 +2245,10 @@ F:      drivers/gpu/drm/
 F:     include/drm/
 
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
-M:     Chris Wilson <chris@chris-wilson.co.uk>
+M:     Keith Packard <keithp@keithp.com>
 L:     intel-gfx@lists.freedesktop.org (subscribers-only)
 L:     dri-devel@lists.freedesktop.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6.git
 S:     Supported
 F:     drivers/gpu/drm/i915
 F:     include/drm/i915*
@@ -5592,10 +5592,11 @@ M:      James Morris <jmorris@namei.org>
 M:     Eric Paris <eparis@parisplace.org>
 L:     selinux@tycho.nsa.gov (subscribers-only, general discussion)
 W:     http://selinuxproject.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
+T:     git git://git.infradead.org/users/eparis/selinux.git
 S:     Supported
 F:     include/linux/selinux*
 F:     security/selinux/
+F:     scripts/selinux/
 
 APPARMOR SECURITY MODULE
 M:     John Johansen <john.johansen@canonical.com>
index a0344a81a893b1a6e8d35346c370db7574d656ff..6b73d1eed1ea0c9aea3af6270fb504d2c836cceb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -103,7 +103,7 @@ ifeq ("$(origin O)", "command line")
 endif
 
 ifeq ("$(origin W)", "command line")
-  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := 1
+  export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W)
 endif
 
 # That's our default target when none is given on the command line
@@ -349,7 +349,8 @@ CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
 
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
-LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include -Iinclude \
+LINUXINCLUDE    := -I$(srctree)/arch/$(hdr-arch)/include \
+                   -Iarch/$(hdr-arch)/include/generated -Iinclude \
                    $(if $(KBUILD_SRC), -I$(srctree)/include) \
                    -include include/generated/autoconf.h
 
@@ -382,6 +383,7 @@ export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV
 export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE
 export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL
+export KBUILD_ARFLAGS
 
 # When compiling out-of-tree modules, put MODVERDIR in the module
 # tree rather than in the kernel tree. The kernel tree might
@@ -416,6 +418,12 @@ ifneq ($(KBUILD_SRC),)
            $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
 endif
 
+# Support for using generic headers in asm-generic
+PHONY += asm-generic
+asm-generic:
+       $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \
+                   obj=arch/$(SRCARCH)/include/generated/asm
+
 # To make sure we do not include .config for any of the *config targets
 # catch them early, and hand them over to scripts/kconfig/Makefile
 # It is allowed to specify more targets when calling make, including
@@ -559,6 +567,10 @@ ifndef CONFIG_CC_STACKPROTECTOR
 KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
 endif
 
+# This warning generated too much noise in a regular build.
+# Use make W=1 to enable this warning (see scripts/Makefile.build)
+KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
+
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS  += -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
@@ -604,7 +616,7 @@ CHECKFLAGS     += $(NOSTDINC_FLAGS)
 KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
 
 # disable pointer signed / unsigned warnings in gcc 4.0
-KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,)
+KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign)
 
 # disable invalid "can't wrap" optimizations for signed / pointers
 KBUILD_CFLAGS  += $(call cc-option,-fno-strict-overflow)
@@ -612,6 +624,9 @@ KBUILD_CFLAGS       += $(call cc-option,-fno-strict-overflow)
 # conserve stack if available
 KBUILD_CFLAGS   += $(call cc-option,-fconserve-stack)
 
+# use the deterministic mode of AR if available
+KBUILD_ARFLAGS := $(call ar-option,D)
+
 # check for 'asm goto'
 ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
        KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
@@ -797,15 +812,17 @@ ifdef CONFIG_KALLSYMS
 # o The correct .tmp_kallsyms2.o is linked into the final vmlinux.
 # o Verify that the System.map from vmlinux matches the map from
 #   .tmp_vmlinux2, just in case we did not generate kallsyms correctly.
-# o If CONFIG_KALLSYMS_EXTRA_PASS is set, do an extra pass using
+# o If 'make KALLSYMS_EXTRA_PASS=1" was used, do an extra pass using
 #   .tmp_vmlinux3 and .tmp_kallsyms3.o.  This is only meant as a
 #   temporary bypass to allow the kernel to be built while the
 #   maintainers work out what went wrong with kallsyms.
 
-ifdef CONFIG_KALLSYMS_EXTRA_PASS
-last_kallsyms := 3
-else
 last_kallsyms := 2
+
+ifdef KALLSYMS_EXTRA_PASS
+ifneq ($(KALLSYMS_EXTRA_PASS),0)
+last_kallsyms := 3
+endif
 endif
 
 kallsyms.o := .tmp_kallsyms$(last_kallsyms).o
@@ -816,7 +833,8 @@ define verify_kallsyms
          $(cmd_sysmap) .tmp_vmlinux$(last_kallsyms) .tmp_System.map
        $(Q)cmp -s System.map .tmp_System.map ||                             \
                (echo Inconsistent kallsyms data;                            \
-                echo Try setting CONFIG_KALLSYMS_EXTRA_PASS;                \
+                echo This is a bug - please report about it;                \
+                echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround;      \
                 rm .tmp_kallsyms* ; /bin/false )
 endef
 
@@ -947,7 +965,7 @@ ifneq ($(KBUILD_SRC),)
 endif
 
 # prepare2 creates a makefile if using a separate output directory
-prepare2: prepare3 outputmakefile
+prepare2: prepare3 outputmakefile asm-generic
 
 prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
                    include/config/auto.conf
@@ -1021,7 +1039,7 @@ hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
 hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
 
 PHONY += __headers
-__headers: include/linux/version.h scripts_basic FORCE
+__headers: include/linux/version.h scripts_basic asm-generic FORCE
        $(Q)$(MAKE) $(build)=scripts build_unifdef
 
 PHONY += headers_install_all
@@ -1136,7 +1154,8 @@ CLEAN_FILES +=    vmlinux System.map \
                 .tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map
 
 # Directories & files removed with 'make mrproper'
-MRPROPER_DIRS  += include/config usr/include include/generated
+MRPROPER_DIRS  += include/config usr/include include/generated          \
+                  arch/*/include/generated
 MRPROPER_FILES += .config .config.old .version .old_version             \
                   include/linux/version.h                               \
                  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
@@ -1267,7 +1286,11 @@ help:
        @echo  '  make O=dir [targets] Locate all output files in "dir", including .config'
        @echo  '  make C=1   [targets] Check all c source with $$CHECK (sparse by default)'
        @echo  '  make C=2   [targets] Force check of all c source with $$CHECK'
-       @echo  '  make W=1   [targets] Enable extra gcc checks'
+       @echo  '  make W=n   [targets] Enable extra gcc checks, n=1,2,3 where'
+       @echo  '                1: warnings which may be relevant and do not occur too often'
+       @echo  '                2: warnings which occur quite often but may still be relevant'
+       @echo  '                3: more obscure warnings, can most likely be ignored'
+       @echo  '                Multiple levels can be combined with W=12 or W=123'
        @echo  '  make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections'
        @echo  ''
        @echo  'Execute "make" or "make all" to build all targets marked with [*] '
@@ -1291,6 +1314,7 @@ $(help-board-dirs): help-%:
 # Documentation targets
 # ---------------------------------------------------------------------------
 %docs: scripts_basic FORCE
+       $(Q)$(MAKE) $(build)=scripts build_docproc
        $(Q)$(MAKE) $(build)=Documentation/DocBook $@
 
 else # KBUILD_EXTMOD
@@ -1375,7 +1399,7 @@ endif # KBUILD_EXTMOD
 clean: $(clean-dirs)
        $(call cmd,rmdirs)
        $(call cmd,rmfiles)
-       @find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
+       @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
                \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
                -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
                -o -name '*.symtypes' -o -name 'modules.order' \
index 3d890a98a08ba139f8d234755512fdb97f0fe51e..f937ad12385273ab0d97c49648fa30dad325d940 100644 (file)
@@ -39,7 +39,7 @@ SECTIONS
        __init_begin = ALIGN(PAGE_SIZE);
        INIT_TEXT_SECTION(PAGE_SIZE)
        INIT_DATA_SECTION(16)
-       PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(L1_CACHE_BYTES)
        /* Align to THREAD_SIZE rather than PAGE_SIZE here so any padding page
           needed for the THREAD_SIZE aligned init_task gets freed after init */
        . = ALIGN(THREAD_SIZE);
index f7cce8b75f49b840ca67cc88bb11d29a391ce596..f59758dd86cfc8684d431128c3e21da147792bc5 100644 (file)
@@ -294,6 +294,8 @@ config ARCH_AT91
        bool "Atmel AT91"
        select ARCH_REQUIRE_GPIOLIB
        select HAVE_CLK
+       select CLKDEV_LOOKUP
+       select ARM_PATCH_PHYS_VIRT if MMU
        help
          This enables support for systems based on the Atmel AT91RM9200,
          AT91SAM9 and AT91CAP9 processors.
diff --git a/arch/arm/configs/at572d940hfek_defconfig b/arch/arm/configs/at572d940hfek_defconfig
deleted file mode 100644 (file)
index 1b1158a..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-AT572D940HF"
-# CONFIG_LOCALVERSION_AUTO is not set
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_XACCT=y
-CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_AUDIT=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_CGROUP_SCHED=y
-CONFIG_RT_GROUP_SCHED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_RELAY=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_EXPERT=y
-CONFIG_SLAB=y
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=m
-CONFIG_KPROBES=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT572D940HF=y
-CONFIG_MACH_AT572D940HFEB=y
-CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_CMDLINE="mem=48M console=ttyS0 initrd=0x21100000,3145728 root=/dev/ram0 rw ip=172.16.1.181"
-CONFIG_KEXEC=y
-CONFIG_FPE_NWFPE=y
-CONFIG_FPE_NWFPE_XP=y
-CONFIG_NET=y
-CONFIG_PACKET=m
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_NET_PKTGEN=m
-CONFIG_NET_TCPPROBE=m
-CONFIG_CAN=m
-CONFIG_CAN_RAW=m
-CONFIG_CAN_BCM=m
-CONFIG_CAN_VCAN=m
-CONFIG_CAN_DEBUG_DEVICES=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_CONNECTOR=m
-CONFIG_MTD=m
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=1
-CONFIG_MTD_CONCAT=m
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=m
-CONFIG_MTD_BLOCK=m
-CONFIG_MTD_BLOCK_RO=m
-CONFIG_FTL=m
-CONFIG_NFTL=m
-CONFIG_NFTL_RW=y
-CONFIG_INFTL=m
-CONFIG_RFD_FTL=m
-CONFIG_SSFDC=m
-CONFIG_MTD_OOPS=m
-CONFIG_MTD_CFI=m
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_CFI_INTELEXT=m
-CONFIG_MTD_CFI_AMDSTD=m
-CONFIG_MTD_CFI_STAA=m
-CONFIG_MTD_ROM=m
-CONFIG_MTD_ABSENT=m
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=m
-CONFIG_MTD_PLATRAM=m
-CONFIG_MTD_DATAFLASH=m
-CONFIG_MTD_M25P80=m
-CONFIG_MTD_SLRAM=m
-CONFIG_MTD_PHRAM=m
-CONFIG_MTD_MTDRAM=m
-CONFIG_MTD_BLOCK2MTD=m
-CONFIG_MTD_NAND=m
-CONFIG_MTD_NAND_VERIFY_WRITE=y
-CONFIG_MTD_NAND_DISKONCHIP=m
-CONFIG_MTD_NAND_NANDSIM=m
-CONFIG_MTD_NAND_PLATFORM=m
-CONFIG_MTD_ALAUDA=m
-CONFIG_MTD_UBI=m
-CONFIG_MTD_UBI_GLUEBI=m
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=65536
-CONFIG_ATMEL_TCLIB=y
-CONFIG_ATMEL_SSC=m
-CONFIG_SENSORS_TSL2550=m
-CONFIG_DS1682=m
-CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_SCSI_TGT=m
-# CONFIG_SCSI_PROC_FS is not set
-CONFIG_BLK_DEV_SD=m
-CONFIG_BLK_DEV_SR=m
-CONFIG_CHR_DEV_SG=m
-CONFIG_CHR_DEV_SCH=m
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_SCSI_ISCSI_ATTRS=m
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_BONDING=m
-CONFIG_MACVLAN=m
-CONFIG_EQUALIZER=m
-CONFIG_TUN=m
-CONFIG_VETH=m
-CONFIG_PHYLIB=y
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
-CONFIG_BROADCOM_PHY=m
-CONFIG_ICPLUS_PHY=m
-CONFIG_MDIO_BITBANG=m
-CONFIG_NET_ETHERNET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_USB_ZD1201=m
-CONFIG_HOSTAP=m
-CONFIG_HOSTAP_FIRMWARE=y
-CONFIG_HOSTAP_FIRMWARE_NVRAM=y
-CONFIG_USB_CATC=m
-CONFIG_USB_KAWETH=m
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_RTL8150=m
-CONFIG_USB_USBNET=m
-CONFIG_USB_NET_DM9601=m
-CONFIG_USB_NET_GL620A=m
-CONFIG_USB_NET_PLUSB=m
-CONFIG_USB_NET_MCS7830=m
-CONFIG_USB_NET_RNDIS_HOST=m
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_EPSON2888=y
-CONFIG_USB_KC2190=y
-# CONFIG_USB_NET_ZAURUS is not set
-CONFIG_INPUT_MOUSEDEV=m
-CONFIG_INPUT_EVDEV=m
-CONFIG_INPUT_EVBUG=m
-CONFIG_KEYBOARD_LKKBD=m
-CONFIG_KEYBOARD_GPIO=m
-CONFIG_KEYBOARD_NEWTON=m
-CONFIG_KEYBOARD_STOWAWAY=m
-CONFIG_KEYBOARD_SUNKBD=m
-CONFIG_KEYBOARD_XTKBD=m
-CONFIG_MOUSE_PS2=m
-CONFIG_MOUSE_SERIAL=m
-CONFIG_MOUSE_APPLETOUCH=m
-CONFIG_MOUSE_VSXXXAA=m
-CONFIG_MOUSE_GPIO=m
-CONFIG_INPUT_MISC=y
-CONFIG_INPUT_UINPUT=m
-CONFIG_SERIO_SERPORT=m
-CONFIG_SERIO_RAW=m
-CONFIG_VT_HW_CONSOLE_BINDING=y
-CONFIG_SERIAL_NONSTANDARD=y
-CONFIG_N_HDLC=m
-CONFIG_SPECIALIX=m
-CONFIG_STALDRV=y
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_IPMI_HANDLER=m
-CONFIG_IPMI_DEVICE_INTERFACE=m
-CONFIG_IPMI_SI=m
-CONFIG_IPMI_WATCHDOG=m
-CONFIG_IPMI_POWEROFF=m
-CONFIG_HW_RANDOM=y
-CONFIG_R3964=m
-CONFIG_RAW_DRIVER=m
-CONFIG_TCG_TPM=m
-CONFIG_TCG_NSC=m
-CONFIG_TCG_ATMEL=m
-CONFIG_I2C=m
-CONFIG_I2C_CHARDEV=m
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-CONFIG_SPI_BITBANG=m
-CONFIG_SPI_SPIDEV=m
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-# CONFIG_SND_PCM_OSS_PLUGINS is not set
-CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_DYNAMIC_MINORS=y
-# CONFIG_SND_VERBOSE_PROCFS is not set
-CONFIG_SND_DUMMY=m
-CONFIG_SND_VIRMIDI=m
-CONFIG_SND_USB_AUDIO=m
-CONFIG_SND_USB_CAIAQ=m
-CONFIG_SND_USB_CAIAQ_INPUT=y
-CONFIG_HID=m
-CONFIG_HIDRAW=y
-CONFIG_USB_HID=m
-CONFIG_USB_HIDDEV=y
-CONFIG_USB_KBD=m
-CONFIG_USB_MOUSE=m
-CONFIG_HID_A4TECH=m
-CONFIG_HID_APPLE=m
-CONFIG_HID_BELKIN=m
-CONFIG_HID_CHERRY=m
-CONFIG_HID_CHICONY=m
-CONFIG_HID_CYPRESS=m
-CONFIG_HID_EZKEY=m
-CONFIG_HID_GYRATION=m
-CONFIG_HID_LOGITECH=m
-CONFIG_HID_MICROSOFT=m
-CONFIG_HID_MONTEREY=m
-CONFIG_HID_PANTHERLORD=m
-CONFIG_HID_PETALYNX=m
-CONFIG_HID_SAMSUNG=m
-CONFIG_HID_SONY=m
-CONFIG_HID_SUNPLUS=m
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_DYNAMIC_MINORS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=m
-CONFIG_USB_STORAGE_DATAFAB=m
-CONFIG_USB_STORAGE_FREECOM=m
-CONFIG_USB_STORAGE_ISD200=m
-CONFIG_USB_STORAGE_USBAT=m
-CONFIG_USB_STORAGE_SDDR09=m
-CONFIG_USB_STORAGE_SDDR55=m
-CONFIG_USB_STORAGE_JUMPSHOT=m
-CONFIG_USB_STORAGE_ALAUDA=m
-CONFIG_USB_STORAGE_KARMA=m
-CONFIG_USB_LIBUSUAL=y
-CONFIG_USB_SERIAL=m
-CONFIG_USB_EZUSB=y
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_PL2303=m
-CONFIG_USB_SERIAL_SPCP8X5=m
-CONFIG_USB_SERIAL_DEBUG=m
-CONFIG_USB_EMI62=m
-CONFIG_USB_EMI26=m
-CONFIG_USB_ADUTUX=m
-CONFIG_USB_TEST=m
-CONFIG_USB_GADGET=m
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=y
-CONFIG_USB_ZERO=m
-CONFIG_USB_ETH=m
-CONFIG_USB_GADGETFS=m
-CONFIG_USB_FILE_STORAGE=m
-CONFIG_USB_G_SERIAL=m
-CONFIG_USB_MIDI_GADGET=m
-CONFIG_MMC=y
-CONFIG_SDIO_UART=m
-CONFIG_MMC_AT91=m
-CONFIG_MMC_SPI=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=m
-CONFIG_LEDS_GPIO=m
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=m
-CONFIG_LEDS_TRIGGER_HEARTBEAT=m
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_INTF_DEV_UIE_EMUL=y
-CONFIG_RTC_DRV_DS1307=m
-CONFIG_RTC_DRV_DS1305=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
-CONFIG_JBD_DEBUG=y
-CONFIG_REISERFS_FS=m
-CONFIG_REISERFS_CHECK=y
-CONFIG_REISERFS_PROC_INFO=y
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-CONFIG_INOTIFY=y
-CONFIG_FUSE_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=y
-CONFIG_NTFS_FS=m
-CONFIG_NTFS_RW=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_JFFS2_FS=m
-CONFIG_JFFS2_COMPRESSION_OPTIONS=y
-CONFIG_JFFS2_LZO=y
-CONFIG_JFFS2_CMODE_FAVOURLZO=y
-CONFIG_CRAMFS=m
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_CIFS=m
-CONFIG_CIFS_WEAK_PW_HASH=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAC_PARTITION=y
-CONFIG_BSD_DISKLABEL=y
-CONFIG_MINIX_SUBPARTITION=y
-CONFIG_SOLARIS_X86_PARTITION=y
-CONFIG_UNIXWARE_DISKLABEL=y
-CONFIG_LDM_PARTITION=y
-CONFIG_LDM_DEBUG=y
-CONFIG_SGI_PARTITION=y
-CONFIG_SUN_PARTITION=y
-CONFIG_NLS_DEFAULT="cp437"
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_ASCII=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_UTF8=m
-CONFIG_DLM=m
-CONFIG_PRINTK_TIME=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_UNUSED_SYMBOLS=y
-CONFIG_DEBUG_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_GF128MUL=m
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD5=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
-CONFIG_CRC_CCITT=m
-CONFIG_CRC16=m
similarity index 53%
rename from arch/arm/configs/at91sam9261ek_defconfig
rename to arch/arm/configs/at91sam9261_defconfig
index b46025b66b64a1f92bc5639969ce50d84081bbd2..ade6b2f231164b00c1fc22ede4866e47d2aee485 100644 (file)
@@ -1,9 +1,13 @@
 CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_NAMESPACES=y
+CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -15,18 +19,27 @@ CONFIG_ARCH_AT91SAM9261=y
 CONFIG_MACH_AT91SAM9261EK=y
 CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
 # CONFIG_ARM_THUMB is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_VFP=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
 CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_LRO is not set
 # CONFIG_IPV6 is not set
+CONFIG_CFG80211=y
+CONFIG_LIB80211=y
+CONFIG_MAC80211=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
@@ -34,8 +47,12 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_GLUEBI=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_TCLIB=y
 CONFIG_ATMEL_SSC=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
@@ -45,12 +62,27 @@ CONFIG_NET_ETHERNET=y
 CONFIG_DM9000=y
 # CONFIG_NETDEV_1000 is not set
 # CONFIG_NETDEV_10000 is not set
+CONFIG_USB_ZD1201=m
+CONFIG_RTL8187=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+CONFIG_LIBERTAS_SDIO=m
+CONFIG_LIBERTAS_SPI=m
+CONFIG_RT2X00=m
+CONFIG_RT2500USB=m
+CONFIG_RT73USB=m
+CONFIG_ZD1211RW=m
+CONFIG_INPUT_POLLDEV=m
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
 CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ADS7846=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
 CONFIG_SERIAL_ATMEL=y
 CONFIG_SERIAL_ATMEL_CONSOLE=y
 CONFIG_HW_RANDOM=y
@@ -65,31 +97,62 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_AT91SAM9X_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FB_ATMEL=y
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_ATMEL_LCDC=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_AT73C213=y
+CONFIG_SND_USB_AUDIO=m
 # CONFIG_USB_HID is not set
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DEBUG=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
 CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
 CONFIG_MMC_AT91=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_AT91SAM9=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
+CONFIG_MSDOS_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_LZO=y
+CONFIG_SQUASHFS_XZ=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+CONFIG_FTRACE=y
+CONFIG_CRC_CCITT=m
similarity index 57%
rename from arch/arm/configs/at91sam9263ek_defconfig
rename to arch/arm/configs/at91sam9263_defconfig
index 8a04d6f4e065c613460ad9220bf955a00949c1d0..1cf96264cba1456ad4a7ae54daeb414479c3e684 100644 (file)
@@ -1,9 +1,13 @@
 CONFIG_EXPERIMENTAL=y
 # CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZMA=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_NAMESPACES=y
+CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -13,53 +17,81 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_ARCH_AT91=y
 CONFIG_ARCH_AT91SAM9263=y
 CONFIG_MACH_AT91SAM9263EK=y
+CONFIG_MACH_USB_A9263=y
+CONFIG_MACH_NEOCORE926=y
 CONFIG_MTD_AT91_DATAFLASH_CARD=y
 # CONFIG_ARM_THUMB is not set
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw"
-CONFIG_FPE_NWFPE=y
+CONFIG_AUTO_ZRELADDR=y
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
+CONFIG_NET_KEY=y
 CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_ROUTE_VERBOSE=y
 CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
 CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
 # CONFIG_INET_XFRM_MODE_TRANSPORT is not set
 # CONFIG_INET_XFRM_MODE_TUNNEL is not set
 # CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
 # CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
+CONFIG_NFTL=y
+CONFIG_NFTL_RW=y
 CONFIG_MTD_DATAFLASH=y
+CONFIG_MTD_BLOCK2MTD=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_GLUEBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_ATMEL_SSC=y
+CONFIG_MISC_DEVICES=y
+CONFIG_ATMEL_PWM=y
+CONFIG_ATMEL_TCLIB=y
 CONFIG_SCSI=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_MULTI_LUN=y
 CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+CONFIG_SMSC_PHY=y
+CONFIG_NET_ETHERNET=y
 CONFIG_MACB=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_USB_ZD1201=m
+CONFIG_INPUT_POLLDEV=m
 # CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
 CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 CONFIG_TOUCHSCREEN_ADS7846=y
-# CONFIG_SERIO is not set
+CONFIG_LEGACY_PTY_COUNT=4
 CONFIG_SERIAL_ATMEL=y
 CONFIG_SERIAL_ATMEL_CONSOLE=y
 CONFIG_HW_RANDOM=y
@@ -74,8 +106,25 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_AT91SAM9X_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FB_ATMEL=y
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_ATMEL_LCDC=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SEQUENCER=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_ATMEL_AC97C=y
+# CONFIG_SND_SPI is not set
+CONFIG_SND_USB_AUDIO=m
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_MON=y
@@ -83,24 +132,37 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
 CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
+CONFIG_SDIO_UART=m
 CONFIG_MMC_AT91=m
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_ATMEL_PWM=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_AT91SAM9=y
 CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
+CONFIG_FUSE_FS=m
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
 CONFIG_CRAMFS=y
 CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
 CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_CODEPAGE_850=y
 CONFIG_NLS_ISO8859_1=y
-CONFIG_DEBUG_KERNEL=y
+CONFIG_FTRACE=y
 CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
+CONFIG_XZ_DEC=y
diff --git a/arch/arm/configs/neocore926_defconfig b/arch/arm/configs/neocore926_defconfig
deleted file mode 100644 (file)
index 462dd18..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_COMPAT_BRK is not set
-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_ARCH_AT91=y
-CONFIG_ARCH_AT91SAM9263=y
-CONFIG_MACH_NEOCORE926=y
-CONFIG_MTD_AT91_DATAFLASH_CARD=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_NET_IPIP=y
-# CONFIG_INET_LRO is not set
-CONFIG_IPV6=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_NFTL=y
-CONFIG_NFTL_RW=y
-CONFIG_MTD_BLOCK2MTD=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC_SMC=y
-CONFIG_MTD_NAND_VERIFY_WRITE=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_PLATFORM=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_ATMEL_PWM=y
-CONFIG_ATMEL_TCLIB=y
-CONFIG_SCSI=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_NETDEVICES=y
-CONFIG_SMSC_PHY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_MACB=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
-# CONFIG_DEVKMEM is not set
-CONFIG_SERIAL_NONSTANDARD=y
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_SERIAL_ATMEL_PDC is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-# CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_FB=y
-CONFIG_FB_ATMEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_ATMEL_LCDC=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_LOGO=y
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_MMC=y
-CONFIG_SDIO_UART=y
-CONFIG_MMC_AT91=m
-CONFIG_EXT2_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_AUTOFS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_WBUF_VERIFY=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-# CONFIG_CRYPTO_HW is not set
diff --git a/arch/arm/configs/usb-a9263_defconfig b/arch/arm/configs/usb-a9263_defconfig
deleted file mode 100644 (file)
index ee82d09..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SLAB=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_ARCH_AT91=y
-CONFIG_ARCH_AT91SAM9263=y
-CONFIG_MACH_USB_A9263=y
-CONFIG_AT91_SLOW_CLOCK=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=64M console=ttyS0,115200"
-CONFIG_FPE_NWFPE=y
-CONFIG_PM=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_MACB=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_INPUT_EVBUG=y
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_GPIO=y
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_ETH=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_EXT2_FS=y
-CONFIG_INOTIFY=y
-CONFIG_FUSE_FS=m
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
-# CONFIG_CRYPTO_HW is not set
index b4348e62ef06e7903d07561701dd78c462ff1aaf..e5287f21badc7e87c3c2e7a2d8953d5fb270ec86 100644 (file)
@@ -82,7 +82,7 @@ SECTIONS
 #endif
        }
 
-       PERCPU(32, PAGE_SIZE)
+       PERCPU_SECTION(32)
 
 #ifndef CONFIG_XIP_KERNEL
        . = ALIGN(PAGE_SIZE);
index 2d299bf5d72fc05085dacf6ce5bcb20d9c02e1ea..22484670e7ba60948d75aeb3af23009795a2fe37 100644 (file)
@@ -3,9 +3,6 @@ if ARCH_AT91
 config HAVE_AT91_DATAFLASH_CARD
        bool
 
-config HAVE_NAND_ATMEL_BUSWIDTH_16
-       bool
-
 config HAVE_AT91_USART3
        bool
 
@@ -85,11 +82,6 @@ config ARCH_AT91CAP9
        select HAVE_FB_ATMEL
        select HAVE_NET_MACB
 
-config ARCH_AT572D940HF
-       bool "AT572D940HF"
-       select CPU_ARM926T
-       select GENERIC_CLOCKEVENTS
-
 config ARCH_AT91X40
        bool "AT91x40"
        select ARCH_USES_GETTIMEOFFSET
@@ -209,7 +201,6 @@ comment "AT91SAM9260 / AT91SAM9XE Board Type"
 config MACH_AT91SAM9260EK
        bool "Atmel AT91SAM9260-EK / AT91SAM9XE Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9260-EK or AT91SAM9XE Evaluation Kit
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933>
@@ -270,7 +261,6 @@ comment "AT91SAM9261 Board Type"
 config MACH_AT91SAM9261EK
        bool "Atmel AT91SAM9261-EK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9261-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3820>
@@ -286,7 +276,6 @@ comment "AT91SAM9G10 Board Type"
 config MACH_AT91SAM9G10EK
        bool "Atmel AT91SAM9G10-EK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G10-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4588>
@@ -302,7 +291,6 @@ comment "AT91SAM9263 Board Type"
 config MACH_AT91SAM9263EK
        bool "Atmel AT91SAM9263-EK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9263-EK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4057>
@@ -343,7 +331,6 @@ comment "AT91SAM9G20 Board Type"
 config MACH_AT91SAM9G20EK
        bool "Atmel AT91SAM9G20-EK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G20-EK Evaluation Kit
          that embeds only one SD/MMC slot.
@@ -351,7 +338,6 @@ config MACH_AT91SAM9G20EK
 config MACH_AT91SAM9G20EK_2MMC
        depends on MACH_AT91SAM9G20EK
        bool "Atmel AT91SAM9G20-EK Evaluation Kit with 2 SD/MMC Slots"
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
          with 2 SD/MMC Slots. This is the case for AT91SAM9G20-EK rev. C and
@@ -416,7 +402,6 @@ comment "AT91SAM9G45 Board Type"
 
 config MACH_AT91SAM9M10G45EK
        bool "Atmel AT91SAM9M10G45-EK Evaluation Kits"
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit.
          "ES" at the end of the name means that this board is an
@@ -433,7 +418,6 @@ comment "AT91CAP9 Board Type"
 config MACH_AT91CAP9ADK
        bool "Atmel AT91CAP9A-DK Evaluation Kit"
        select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91CAP9A-DK Evaluation Kit.
          <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4138>
@@ -442,23 +426,6 @@ endif
 
 # ----------------------------------------------------------
 
-if ARCH_AT572D940HF
-
-comment "AT572D940HF Board Type"
-
-config MACH_AT572D940HFEB
-       bool "AT572D940HF-EK"
-       depends on ARCH_AT572D940HF
-       select HAVE_AT91_DATAFLASH_CARD
-       select HAVE_NAND_ATMEL_BUSWIDTH_16
-       help
-         Select this if you are using Atmel's AT572D940HF-EK evaluation kit.
-         <http://www.atmel.com/products/diopsis/default.asp>
-
-endif
-
-# ----------------------------------------------------------
-
 if ARCH_AT91X40
 
 comment "AT91X40 Board Type"
@@ -483,13 +450,6 @@ config MTD_AT91_DATAFLASH_CARD
        help
          Enable support for the DataFlash card.
 
-config MTD_NAND_ATMEL_BUSWIDTH_16
-       bool "Enable 16-bit data bus interface to NAND flash"
-       depends on HAVE_NAND_ATMEL_BUSWIDTH_16
-       help
-         On AT91SAM926x boards both types of NAND flash can be present
-         (8 and 16 bit data bus width).
-
 # ----------------------------------------------------------
 
 comment "AT91 Feature Selections"
index a83835e0c1859b359fd15f75f45125a81525a4d8..96966231920cb5af2b18a15677ef14494b2e39dd 100644 (file)
@@ -19,7 +19,6 @@ obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devi
 obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o at91sam9_alt_reset.o
 obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91CAP9)    += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT572D940HF)  += at572d940hf.o at91sam926x_time.o at572d940hf_devices.o sam9_smc.o
 obj-$(CONFIG_ARCH_AT91X40)     += at91x40.o at91x40_time.o
 
 # AT91RM9200 board-specific support
@@ -78,9 +77,6 @@ obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
 # AT91CAP9 board-specific support
 obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
 
-# AT572D940HF board-specific support
-obj-$(CONFIG_MACH_AT572D940HFEB) += board-at572d940hf_ek.o
-
 # AT91X40 board-specific support
 obj-$(CONFIG_MACH_AT91EB01)    += board-eb01.o
 
diff --git a/arch/arm/mach-at91/at572d940hf.c b/arch/arm/mach-at91/at572d940hf.c
deleted file mode 100644 (file)
index a6b9c68..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * arch/arm/mach-at91/at572d940hf.c
- *
- * Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2008 Atmel
- *
- * Copyright (C) 2005 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#include <linux/module.h>
-
-#include <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <mach/at572d940hf.h>
-#include <mach/at91_pmc.h>
-#include <mach/at91_rstc.h>
-
-#include "generic.h"
-#include "clock.h"
-
-static struct map_desc at572d940hf_io_desc[] __initdata = {
-       {
-               .virtual        = AT91_VA_BASE_SYS,
-               .pfn            = __phys_to_pfn(AT91_BASE_SYS),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = AT91_IO_VIRT_BASE - AT572D940HF_SRAM_SIZE,
-               .pfn            = __phys_to_pfn(AT572D940HF_SRAM_BASE),
-               .length         = AT572D940HF_SRAM_SIZE,
-               .type           = MT_DEVICE,
-       },
-};
-
-/* --------------------------------------------------------------------
- *  Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioA_clk = {
-       .name           = "pioA_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_PIOA,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioB_clk = {
-       .name           = "pioB_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_PIOB,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioC_clk = {
-       .name           = "pioC_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_PIOC,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk macb_clk = {
-       .name           = "macb_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_EMAC,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
-       .name           = "usart0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_US0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
-       .name           = "usart1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_US1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
-       .name           = "usart2_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_US2,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc_clk = {
-       .name           = "mci_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_MCI,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udc_clk = {
-       .name           = "udc_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_UDP,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi0_clk = {
-       .name           = "twi0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TWI0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
-       .name           = "spi0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SPI0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
-       .name           = "spi1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SPI1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc0_clk = {
-       .name           = "ssc0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SSC0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc1_clk = {
-       .name           = "ssc1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SSC1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc2_clk = {
-       .name           = "ssc2_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SSC2,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc0_clk = {
-       .name           = "tc0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TC0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc1_clk = {
-       .name           = "tc1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TC1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc2_clk = {
-       .name           = "tc2_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TC2,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ohci_clk = {
-       .name           = "ohci_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_UHP,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc3_clk = {
-       .name           = "ssc3_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_SSC3,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi1_clk = {
-       .name           = "twi1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_TWI1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk can0_clk = {
-       .name           = "can0_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_CAN0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk can1_clk = {
-       .name           = "can1_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_CAN1,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mAgicV_clk = {
-       .name           = "mAgicV_clk",
-       .pmc_mask       = 1 << AT572D940HF_ID_MSIRQ0,
-       .type           = CLK_TYPE_PERIPHERAL,
-};
-
-
-static struct clk *periph_clocks[] __initdata = {
-       &pioA_clk,
-       &pioB_clk,
-       &pioC_clk,
-       &macb_clk,
-       &usart0_clk,
-       &usart1_clk,
-       &usart2_clk,
-       &mmc_clk,
-       &udc_clk,
-       &twi0_clk,
-       &spi0_clk,
-       &spi1_clk,
-       &ssc0_clk,
-       &ssc1_clk,
-       &ssc2_clk,
-       &tc0_clk,
-       &tc1_clk,
-       &tc2_clk,
-       &ohci_clk,
-       &ssc3_clk,
-       &twi1_clk,
-       &can0_clk,
-       &can1_clk,
-       &mAgicV_clk,
-       /* irq0 .. irq2 */
-};
-
-/*
- * The five programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
-       .name           = "pck0",
-       .pmc_mask       = AT91_PMC_PCK0,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 0,
-};
-static struct clk pck1 = {
-       .name           = "pck1",
-       .pmc_mask       = AT91_PMC_PCK1,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 1,
-};
-static struct clk pck2 = {
-       .name           = "pck2",
-       .pmc_mask       = AT91_PMC_PCK2,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 2,
-};
-static struct clk pck3 = {
-       .name           = "pck3",
-       .pmc_mask       = AT91_PMC_PCK3,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 3,
-};
-
-static struct clk mAgicV_mem_clk = {
-       .name           = "mAgicV_mem_clk",
-       .pmc_mask       = AT91_PMC_PCK4,
-       .type           = CLK_TYPE_PROGRAMMABLE,
-       .id             = 4,
-};
-
-/* HClocks */
-static struct clk hck0 = {
-       .name           = "hck0",
-       .pmc_mask       = AT91_PMC_HCK0,
-       .type           = CLK_TYPE_SYSTEM,
-       .id             = 0,
-};
-static struct clk hck1 = {
-       .name           = "hck1",
-       .pmc_mask       = AT91_PMC_HCK1,
-       .type           = CLK_TYPE_SYSTEM,
-       .id             = 1,
-};
-
-static void __init at572d940hf_register_clocks(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
-               clk_register(periph_clocks[i]);
-
-       clk_register(&pck0);
-       clk_register(&pck1);
-       clk_register(&pck2);
-       clk_register(&pck3);
-       clk_register(&mAgicV_mem_clk);
-
-       clk_register(&hck0);
-       clk_register(&hck1);
-}
-
-/* --------------------------------------------------------------------
- *  GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at572d940hf_gpio[] = {
-       {
-               .id             = AT572D940HF_ID_PIOA,
-               .offset         = AT91_PIOA,
-               .clock          = &pioA_clk,
-       }, {
-               .id             = AT572D940HF_ID_PIOB,
-               .offset         = AT91_PIOB,
-               .clock          = &pioB_clk,
-       }, {
-               .id             = AT572D940HF_ID_PIOC,
-               .offset         = AT91_PIOC,
-               .clock          = &pioC_clk,
-       }
-};
-
-static void at572d940hf_reset(void)
-{
-       at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
-}
-
-
-/* --------------------------------------------------------------------
- *  AT572D940HF processor initialization
- * -------------------------------------------------------------------- */
-
-void __init at572d940hf_initialize(unsigned long main_clock)
-{
-       /* Map peripherals */
-       iotable_init(at572d940hf_io_desc, ARRAY_SIZE(at572d940hf_io_desc));
-
-       at91_arch_reset = at572d940hf_reset;
-       at91_extern_irq = (1 << AT572D940HF_ID_IRQ0) | (1 << AT572D940HF_ID_IRQ1)
-                       | (1 << AT572D940HF_ID_IRQ2);
-
-       /* Init clock subsystem */
-       at91_clock_init(main_clock);
-
-       /* Register the processor-specific clocks */
-       at572d940hf_register_clocks();
-
-       /* Register GPIO subsystem */
-       at91_gpio_init(at572d940hf_gpio, 3);
-}
-
-/* --------------------------------------------------------------------
- *  Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at572d940hf_default_irq_priority[NR_AIC_IRQS] __initdata = {
-       7,      /* Advanced Interrupt Controller */
-       7,      /* System Peripherals */
-       0,      /* Parallel IO Controller A */
-       0,      /* Parallel IO Controller B */
-       0,      /* Parallel IO Controller C */
-       3,      /* Ethernet */
-       6,      /* USART 0 */
-       6,      /* USART 1 */
-       6,      /* USART 2 */
-       0,      /* Multimedia Card Interface */
-       4,      /* USB Device Port */
-       0,      /* Two-Wire Interface 0 */
-       6,      /* Serial Peripheral Interface 0 */
-       6,      /* Serial Peripheral Interface 1 */
-       5,      /* Serial Synchronous Controller 0 */
-       5,      /* Serial Synchronous Controller 1 */
-       5,      /* Serial Synchronous Controller 2 */
-       0,      /* Timer Counter 0 */
-       0,      /* Timer Counter 1 */
-       0,      /* Timer Counter 2 */
-       3,      /* USB Host port */
-       3,      /* Serial Synchronous Controller 3 */
-       0,      /* Two-Wire Interface 1 */
-       0,      /* CAN Controller 0 */
-       0,      /* CAN Controller 1 */
-       0,      /* mAgicV HALT line */
-       0,      /* mAgicV SIRQ0 line */
-       0,      /* mAgicV exception line */
-       0,      /* mAgicV end of DMA line */
-       0,      /* Advanced Interrupt Controller */
-       0,      /* Advanced Interrupt Controller */
-       0,      /* Advanced Interrupt Controller */
-};
-
-void __init at572d940hf_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
-       if (!priority)
-               priority = at572d940hf_default_irq_priority;
-
-       /* Initialize the AIC interrupt controller */
-       at91_aic_init(priority);
-
-       /* Enable GPIO interrupts */
-       at91_gpio_irq_setup();
-}
-
diff --git a/arch/arm/mach-at91/at572d940hf_devices.c b/arch/arm/mach-at91/at572d940hf_devices.c
deleted file mode 100644 (file)
index 0fc20a2..0000000
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * arch/arm/mach-at91/at572d940hf_devices.c
- *
- * Copyright (C) 2008 Atmel Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
- * Copyright (C) 2005 David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-
-#include <mach/board.h>
-#include <mach/gpio.h>
-#include <mach/at572d940hf.h>
-#include <mach/at572d940hf_matrix.h>
-#include <mach/at91sam9_smc.h>
-
-#include "generic.h"
-#include "sam9_smc.h"
-
-
-/* --------------------------------------------------------------------
- *  USB Host
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_data;
-
-static struct resource usbh_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_UHP_BASE,
-               .end    = AT572D940HF_UHP_BASE + SZ_1M - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_UHP,
-               .end    = AT572D940HF_ID_UHP,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_usbh_device = {
-       .name           = "at91_ohci",
-       .id             = -1,
-       .dev            = {
-                               .dma_mask               = &ohci_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &usbh_data,
-       },
-       .resource       = usbh_resources,
-       .num_resources  = ARRAY_SIZE(usbh_resources),
-};
-
-void __init at91_add_device_usbh(struct at91_usbh_data *data)
-{
-       if (!data)
-               return;
-
-       usbh_data = *data;
-       platform_device_register(&at572d940hf_usbh_device);
-
-}
-#else
-void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  USB Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_USB_GADGET_AT91
-static struct at91_udc_data udc_data;
-
-static struct resource udc_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_UDP,
-               .end    = AT572D940HF_BASE_UDP + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_UDP,
-               .end    = AT572D940HF_ID_UDP,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_udc_device = {
-       .name           = "at91_udc",
-       .id             = -1,
-       .dev            = {
-                               .platform_data          = &udc_data,
-       },
-       .resource       = udc_resources,
-       .num_resources  = ARRAY_SIZE(udc_resources),
-};
-
-void __init at91_add_device_udc(struct at91_udc_data *data)
-{
-       if (!data)
-               return;
-
-       if (data->vbus_pin) {
-               at91_set_gpio_input(data->vbus_pin, 0);
-               at91_set_deglitch(data->vbus_pin, 1);
-       }
-
-       /* Pullup pin is handled internally */
-
-       udc_data = *data;
-       platform_device_register(&at572d940hf_udc_device);
-}
-#else
-void __init at91_add_device_udc(struct at91_udc_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  Ethernet
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
-static u64 eth_dmamask = DMA_BIT_MASK(32);
-static struct at91_eth_data eth_data;
-
-static struct resource eth_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_EMAC,
-               .end    = AT572D940HF_BASE_EMAC + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_EMAC,
-               .end    = AT572D940HF_ID_EMAC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_eth_device = {
-       .name           = "macb",
-       .id             = -1,
-       .dev            = {
-                       .dma_mask               = &eth_dmamask,
-                       .coherent_dma_mask      = DMA_BIT_MASK(32),
-                       .platform_data          = &eth_data,
-       },
-       .resource       = eth_resources,
-       .num_resources  = ARRAY_SIZE(eth_resources),
-};
-
-void __init at91_add_device_eth(struct at91_eth_data *data)
-{
-       if (!data)
-               return;
-
-       if (data->phy_irq_pin) {
-               at91_set_gpio_input(data->phy_irq_pin, 0);
-               at91_set_deglitch(data->phy_irq_pin, 1);
-       }
-
-       /* Only RMII is supported */
-       data->is_rmii = 1;
-
-       /* Pins used for RMII */
-       at91_set_A_periph(AT91_PIN_PA16, 0);    /* ETXCK_EREFCK */
-       at91_set_A_periph(AT91_PIN_PA17, 0);    /* ERXDV */
-       at91_set_A_periph(AT91_PIN_PA18, 0);    /* ERX0 */
-       at91_set_A_periph(AT91_PIN_PA19, 0);    /* ERX1 */
-       at91_set_A_periph(AT91_PIN_PA20, 0);    /* ERXER */
-       at91_set_A_periph(AT91_PIN_PA23, 0);    /* ETXEN */
-       at91_set_A_periph(AT91_PIN_PA21, 0);    /* ETX0 */
-       at91_set_A_periph(AT91_PIN_PA22, 0);    /* ETX1 */
-       at91_set_A_periph(AT91_PIN_PA13, 0);    /* EMDIO */
-       at91_set_A_periph(AT91_PIN_PA14, 0);    /* EMDC */
-
-       eth_data = *data;
-       platform_device_register(&at572d940hf_eth_device);
-}
-#else
-void __init at91_add_device_eth(struct at91_eth_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  MMC / SD
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
-
-static struct resource mmc_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_MCI,
-               .end    = AT572D940HF_BASE_MCI + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_MCI,
-               .end    = AT572D940HF_ID_MCI,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_mmc_device = {
-       .name           = "at91_mci",
-       .id             = -1,
-       .dev            = {
-                               .dma_mask               = &mmc_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &mmc_data,
-       },
-       .resource       = mmc_resources,
-       .num_resources  = ARRAY_SIZE(mmc_resources),
-};
-
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-{
-       if (!data)
-               return;
-
-       /* input/irq */
-       if (data->det_pin) {
-               at91_set_gpio_input(data->det_pin, 1);
-               at91_set_deglitch(data->det_pin, 1);
-       }
-       if (data->wp_pin)
-               at91_set_gpio_input(data->wp_pin, 1);
-       if (data->vcc_pin)
-               at91_set_gpio_output(data->vcc_pin, 0);
-
-       /* CLK */
-       at91_set_A_periph(AT91_PIN_PC22, 0);
-
-       /* CMD */
-       at91_set_A_periph(AT91_PIN_PC23, 1);
-
-       /* DAT0, maybe DAT1..DAT3 */
-       at91_set_A_periph(AT91_PIN_PC24, 1);
-       if (data->wire4) {
-               at91_set_A_periph(AT91_PIN_PC25, 1);
-               at91_set_A_periph(AT91_PIN_PC26, 1);
-               at91_set_A_periph(AT91_PIN_PC27, 1);
-       }
-
-       mmc_data = *data;
-       platform_device_register(&at572d940hf_mmc_device);
-}
-#else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE      AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
-       {
-               .start  = NAND_BASE,
-               .end    = NAND_BASE + SZ_256M - 1,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device at572d940hf_nand_device = {
-       .name           = "atmel_nand",
-       .id             = -1,
-       .dev            = {
-                               .platform_data  = &nand_data,
-       },
-       .resource       = nand_resources,
-       .num_resources  = ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
-       unsigned long csa;
-
-       if (!data)
-               return;
-
-       csa = at91_sys_read(AT91_MATRIX_EBICSA);
-       at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
-
-       /* enable pin */
-       if (data->enable_pin)
-               at91_set_gpio_output(data->enable_pin, 1);
-
-       /* ready/busy pin */
-       if (data->rdy_pin)
-               at91_set_gpio_input(data->rdy_pin, 1);
-
-       /* card detect pin */
-       if (data->det_pin)
-               at91_set_gpio_input(data->det_pin, 1);
-
-       at91_set_A_periph(AT91_PIN_PB28, 0);            /* A[22] */
-       at91_set_B_periph(AT91_PIN_PA28, 0);            /* NANDOE */
-       at91_set_B_periph(AT91_PIN_PA29, 0);            /* NANDWE */
-
-       nand_data = *data;
-       platform_device_register(&at572d940hf_nand_device);
-}
-
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-
-static struct i2c_gpio_platform_data pdata = {
-       .sda_pin                = AT91_PIN_PC7,
-       .sda_is_open_drain      = 1,
-       .scl_pin                = AT91_PIN_PC8,
-       .scl_is_open_drain      = 1,
-       .udelay                 = 2,            /* ~100 kHz */
-};
-
-static struct platform_device at572d940hf_twi_device {
-       .name                   = "i2c-gpio",
-       .id                     = -1,
-       .dev.platform_data      = &pdata,
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-       at91_set_GPIO_periph(AT91_PIN_PC7, 1);          /* TWD (SDA) */
-       at91_set_multi_drive(AT91_PIN_PC7, 1);
-
-       at91_set_GPIO_periph(AT91_PIN_PA8, 1);          /* TWCK (SCL) */
-       at91_set_multi_drive(AT91_PIN_PC8, 1);
-
-       i2c_register_board_info(0, devices, nr_devices);
-       platform_device_register(&at572d940hf_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi0_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_TWI0,
-               .end    = AT572D940HF_BASE_TWI0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_TWI0,
-               .end    = AT572D940HF_ID_TWI0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_twi0_device = {
-       .name           = "at91_i2c",
-       .id             = 0,
-       .resource       = twi0_resources,
-       .num_resources  = ARRAY_SIZE(twi0_resources),
-};
-
-static struct resource twi1_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_TWI1,
-               .end    = AT572D940HF_BASE_TWI1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_TWI1,
-               .end    = AT572D940HF_ID_TWI1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_twi1_device = {
-       .name           = "at91_i2c",
-       .id             = 1,
-       .resource       = twi1_resources,
-       .num_resources  = ARRAY_SIZE(twi1_resources),
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
-       /* pins used for TWI0 interface */
-       at91_set_A_periph(AT91_PIN_PC7, 0);             /* TWD */
-       at91_set_multi_drive(AT91_PIN_PC7, 1);
-
-       at91_set_A_periph(AT91_PIN_PC8, 0);             /* TWCK */
-       at91_set_multi_drive(AT91_PIN_PC8, 1);
-
-       /* pins used for TWI1 interface */
-       at91_set_A_periph(AT91_PIN_PC20, 0);            /* TWD */
-       at91_set_multi_drive(AT91_PIN_PC20, 1);
-
-       at91_set_A_periph(AT91_PIN_PC21, 0);            /* TWCK */
-       at91_set_multi_drive(AT91_PIN_PC21, 1);
-
-       i2c_register_board_info(0, devices, nr_devices);
-       platform_device_register(&at572d940hf_twi0_device);
-       platform_device_register(&at572d940hf_twi1_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi0_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_SPI0,
-               .end    = AT572D940HF_BASE_SPI0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_SPI0,
-               .end    = AT572D940HF_ID_SPI0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_spi0_device = {
-       .name           = "atmel_spi",
-       .id             = 0,
-       .dev            = {
-                               .dma_mask               = &spi_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = spi0_resources,
-       .num_resources  = ARRAY_SIZE(spi0_resources),
-};
-
-static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PA5, AT91_PIN_PA6 };
-
-static struct resource spi1_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_SPI1,
-               .end    = AT572D940HF_BASE_SPI1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_SPI1,
-               .end    = AT572D940HF_ID_SPI1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_spi1_device = {
-       .name           = "atmel_spi",
-       .id             = 1,
-       .dev            = {
-                               .dma_mask               = &spi_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-       },
-       .resource       = spi1_resources,
-       .num_resources  = ARRAY_SIZE(spi1_resources),
-};
-
-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PC3, AT91_PIN_PC4, AT91_PIN_PC5, AT91_PIN_PC6 };
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
-       int i;
-       unsigned long cs_pin;
-       short enable_spi0 = 0;
-       short enable_spi1 = 0;
-
-       /* Choose SPI chip-selects */
-       for (i = 0; i < nr_devices; i++) {
-               if (devices[i].controller_data)
-                       cs_pin = (unsigned long) devices[i].controller_data;
-               else if (devices[i].bus_num == 0)
-                       cs_pin = spi0_standard_cs[devices[i].chip_select];
-               else
-                       cs_pin = spi1_standard_cs[devices[i].chip_select];
-
-               if (devices[i].bus_num == 0)
-                       enable_spi0 = 1;
-               else
-                       enable_spi1 = 1;
-
-               /* enable chip-select pin */
-               at91_set_gpio_output(cs_pin, 1);
-
-               /* pass chip-select pin to driver */
-               devices[i].controller_data = (void *) cs_pin;
-       }
-
-       spi_register_board_info(devices, nr_devices);
-
-       /* Configure SPI bus(es) */
-       if (enable_spi0) {
-               at91_set_A_periph(AT91_PIN_PA0, 0);     /* SPI0_MISO */
-               at91_set_A_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
-               at91_set_A_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
-
-               at91_clock_associate("spi0_clk", &at572d940hf_spi0_device.dev, "spi_clk");
-               platform_device_register(&at572d940hf_spi0_device);
-       }
-       if (enable_spi1) {
-               at91_set_A_periph(AT91_PIN_PC0, 0);     /* SPI1_MISO */
-               at91_set_A_periph(AT91_PIN_PC1, 0);     /* SPI1_MOSI */
-               at91_set_A_periph(AT91_PIN_PC2, 0);     /* SPI1_SPCK */
-
-               at91_clock_associate("spi1_clk", &at572d940hf_spi1_device.dev, "spi_clk");
-               platform_device_register(&at572d940hf_spi1_device);
-       }
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  Timer/Counter blocks
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-
-static struct resource tcb_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_TCB,
-               .end    = AT572D940HF_BASE_TCB + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_TC0,
-               .end    = AT572D940HF_ID_TC0,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = AT572D940HF_ID_TC1,
-               .end    = AT572D940HF_ID_TC1,
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = AT572D940HF_ID_TC2,
-               .end    = AT572D940HF_ID_TC2,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at572d940hf_tcb_device = {
-       .name           = "atmel_tcb",
-       .id             = 0,
-       .resource       = tcb_resources,
-       .num_resources  = ARRAY_SIZE(tcb_resources),
-};
-
-static void __init at91_add_device_tc(void)
-{
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at572d940hf_tcb_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at572d940hf_tcb_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at572d940hf_tcb_device.dev, "t2_clk");
-       platform_device_register(&at572d940hf_tcb_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- *  RTT
- * -------------------------------------------------------------------- */
-
-static struct resource rtt_resources[] = {
-       {
-               .start  = AT91_BASE_SYS + AT91_RTT,
-               .end    = AT91_BASE_SYS + AT91_RTT + SZ_16 - 1,
-               .flags  = IORESOURCE_MEM,
-       }
-};
-
-static struct platform_device at572d940hf_rtt_device = {
-       .name           = "at91_rtt",
-       .id             = 0,
-       .resource       = rtt_resources,
-       .num_resources  = ARRAY_SIZE(rtt_resources),
-};
-
-static void __init at91_add_device_rtt(void)
-{
-       platform_device_register(&at572d940hf_rtt_device);
-}
-
-
-/* --------------------------------------------------------------------
- *  Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
-static struct platform_device at572d940hf_wdt_device = {
-       .name           = "at91_wdt",
-       .id             = -1,
-       .num_resources  = 0,
-};
-
-static void __init at91_add_device_watchdog(void)
-{
-       platform_device_register(&at572d940hf_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  UART
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SERIAL_ATMEL)
-static struct resource dbgu_resources[] = {
-       [0] = {
-               .start  = AT91_VA_BASE_SYS + AT91_DBGU,
-               .end    = AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT91_ID_SYS,
-               .end    = AT91_ID_SYS,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data dbgu_data = {
-       .use_dma_tx     = 0,
-       .use_dma_rx     = 0,            /* DBGU not capable of receive DMA */
-       .regs           = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at572d940hf_dbgu_device = {
-       .name           = "atmel_usart",
-       .id             = 0,
-       .dev            = {
-                               .dma_mask               = &dbgu_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &dbgu_data,
-       },
-       .resource       = dbgu_resources,
-       .num_resources  = ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
-       at91_set_A_periph(AT91_PIN_PC31, 1);            /* DTXD */
-       at91_set_A_periph(AT91_PIN_PC30, 0);            /* DRXD */
-}
-
-static struct resource uart0_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_US0,
-               .end    = AT572D940HF_BASE_US0 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_US0,
-               .end    = AT572D940HF_ID_US0,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data uart0_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at572d940hf_uart0_device = {
-       .name           = "atmel_usart",
-       .id             = 1,
-       .dev            = {
-                               .dma_mask               = &uart0_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &uart0_data,
-       },
-       .resource       = uart0_resources,
-       .num_resources  = ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
-       at91_set_A_periph(AT91_PIN_PA8, 1);             /* TXD0 */
-       at91_set_A_periph(AT91_PIN_PA7, 0);             /* RXD0 */
-
-       if (pins & ATMEL_UART_RTS)
-               at91_set_A_periph(AT91_PIN_PA10, 0);    /* RTS0 */
-       if (pins & ATMEL_UART_CTS)
-               at91_set_A_periph(AT91_PIN_PA9, 0);     /* CTS0 */
-}
-
-static struct resource uart1_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_US1,
-               .end    = AT572D940HF_BASE_US1 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_US1,
-               .end    = AT572D940HF_ID_US1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data uart1_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at572d940hf_uart1_device = {
-       .name           = "atmel_usart",
-       .id             = 2,
-       .dev            = {
-                               .dma_mask               = &uart1_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &uart1_data,
-       },
-       .resource       = uart1_resources,
-       .num_resources  = ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
-       at91_set_A_periph(AT91_PIN_PC10, 1);            /* TXD1 */
-       at91_set_A_periph(AT91_PIN_PC9 , 0);            /* RXD1 */
-
-       if (pins & ATMEL_UART_RTS)
-               at91_set_A_periph(AT91_PIN_PC12, 0);    /* RTS1 */
-       if (pins & ATMEL_UART_CTS)
-               at91_set_A_periph(AT91_PIN_PC11, 0);    /* CTS1 */
-}
-
-static struct resource uart2_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_BASE_US2,
-               .end    = AT572D940HF_BASE_US2 + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = AT572D940HF_ID_US2,
-               .end    = AT572D940HF_ID_US2,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct atmel_uart_data uart2_data = {
-       .use_dma_tx     = 1,
-       .use_dma_rx     = 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at572d940hf_uart2_device = {
-       .name           = "atmel_usart",
-       .id             = 3,
-       .dev            = {
-                               .dma_mask               = &uart2_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &uart2_data,
-       },
-       .resource       = uart2_resources,
-       .num_resources  = ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
-       at91_set_A_periph(AT91_PIN_PC15, 1);            /* TXD2 */
-       at91_set_A_periph(AT91_PIN_PC14, 0);            /* RXD2 */
-
-       if (pins & ATMEL_UART_RTS)
-               at91_set_A_periph(AT91_PIN_PC17, 0);    /* RTS2 */
-       if (pins & ATMEL_UART_CTS)
-               at91_set_A_periph(AT91_PIN_PC16, 0);    /* CTS2 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART];  /* the UARTs to use */
-struct platform_device *atmel_default_console_device;  /* the serial console device */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
-       struct platform_device *pdev;
-
-       switch (id) {
-               case 0:         /* DBGU */
-                       pdev = &at572d940hf_dbgu_device;
-                       configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
-                       break;
-               case AT572D940HF_ID_US0:
-                       pdev = &at572d940hf_uart0_device;
-                       configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
-                       break;
-               case AT572D940HF_ID_US1:
-                       pdev = &at572d940hf_uart1_device;
-                       configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
-                       break;
-               case AT572D940HF_ID_US2:
-                       pdev = &at572d940hf_uart2_device;
-                       configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
-                       break;
-               default:
-                       return;
-       }
-       pdev->id = portnr;              /* update to mapped ID */
-
-       if (portnr < ATMEL_MAX_UART)
-               at91_uarts[portnr] = pdev;
-}
-
-void __init at91_set_serial_console(unsigned portnr)
-{
-       if (portnr < ATMEL_MAX_UART)
-               atmel_default_console_device = at91_uarts[portnr];
-}
-
-void __init at91_add_device_serial(void)
-{
-       int i;
-
-       for (i = 0; i < ATMEL_MAX_UART; i++) {
-               if (at91_uarts[i])
-                       platform_device_register(at91_uarts[i]);
-       }
-
-       if (!atmel_default_console_device)
-               printk(KERN_INFO "AT91: No default serial console defined.\n");
-}
-
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- *  mAgic
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_MAGICV
-static struct resource mAgic_resources[] = {
-       {
-               .start = AT91_MAGIC_PM_BASE,
-               .end   = AT91_MAGIC_PM_BASE + AT91_MAGIC_PM_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_DM_I_BASE,
-               .end   = AT91_MAGIC_DM_I_BASE + AT91_MAGIC_DM_I_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_DM_F_BASE,
-               .end   = AT91_MAGIC_DM_F_BASE + AT91_MAGIC_DM_F_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_DM_DB_BASE,
-               .end   = AT91_MAGIC_DM_DB_BASE + AT91_MAGIC_DM_DB_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_REGS_BASE,
-               .end   = AT91_MAGIC_REGS_BASE + AT91_MAGIC_REGS_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start = AT91_MAGIC_EXTPAGE_BASE,
-               .end   = AT91_MAGIC_EXTPAGE_BASE + AT91_MAGIC_EXTPAGE_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       {
-               .start  = AT572D940HF_ID_MSIRQ0,
-               .end    = AT572D940HF_ID_MSIRQ0,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = AT572D940HF_ID_MHALT,
-               .end    = AT572D940HF_ID_MHALT,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = AT572D940HF_ID_MEXC,
-               .end    = AT572D940HF_ID_MEXC,
-               .flags  = IORESOURCE_IRQ,
-       },
-       {
-               .start  = AT572D940HF_ID_MEDMA,
-               .end    = AT572D940HF_ID_MEDMA,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device mAgic_device = {
-       .name           = "mAgic",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(mAgic_resources),
-       .resource       = mAgic_resources,
-};
-
-void __init at91_add_device_mAgic(void)
-{
-       platform_device_register(&mAgic_device);
-}
-#else
-void __init at91_add_device_mAgic(void) {}
-#endif
-
-
-/* -------------------------------------------------------------------- */
-
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
-       at91_add_device_rtt();
-       at91_add_device_watchdog();
-       at91_add_device_tc();
-       return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
index 73376170fb914a692d04882a375d75b3a131de84..17fae4a42ab587f413025780f5228b7f0bfc7553 100644 (file)
@@ -222,6 +222,25 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq1
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
+       CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+};
+
 /*
  * The four programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -258,12 +277,29 @@ static void __init at91cap9_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
        clk_register(&pck2);
        clk_register(&pck3);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91cap9_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -303,11 +339,14 @@ static void at91cap9_poweroff(void)
  *  AT91CAP9 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91cap9_initialize(unsigned long main_clock)
+void __init at91cap9_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91cap9_io_desc, ARRAY_SIZE(at91cap9_io_desc));
+}
 
+void __init at91cap9_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91cap9_reset;
        pm_power_off = at91cap9_poweroff;
        at91_extern_irq = (1 << AT91CAP9_ID_IRQ0) | (1 << AT91CAP9_ID_IRQ1);
index 21020ceb2f3ac308064c52d5e5379c02c9d8ca73..cd850ed6f33542b5a70a7d7bfcbe0080f5d05619 100644 (file)
@@ -181,10 +181,6 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
 
        /* Pullup pin is handled internally by USB device peripheral */
 
-       /* Clocks */
-       at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
-       at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk");
-
        platform_device_register(&at91_usba_udc_device);
 }
 #else
@@ -355,7 +351,6 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
                }
 
                mmc0_data = *data;
-               at91_clock_associate("mci0_clk", &at91cap9_mmc0_device.dev, "mci_clk");
                platform_device_register(&at91cap9_mmc0_device);
        } else {                        /* MCI1 */
                /* CLK */
@@ -373,7 +368,6 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
                }
 
                mmc1_data = *data;
-               at91_clock_associate("mci1_clk", &at91cap9_mmc1_device.dev, "mci_clk");
                platform_device_register(&at91cap9_mmc1_device);
        }
 }
@@ -614,7 +608,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_B_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
                at91_set_B_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91cap9_spi0_device.dev, "spi_clk");
                platform_device_register(&at91cap9_spi0_device);
        }
        if (enable_spi1) {
@@ -622,7 +615,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB13, 0);    /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB14, 0);    /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91cap9_spi1_device.dev, "spi_clk");
                platform_device_register(&at91cap9_spi1_device);
        }
 }
@@ -659,8 +651,6 @@ static struct platform_device at91cap9_tcb_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has one clock and irq for all three TC channels */
-       at91_clock_associate("tcb_clk", &at91cap9_tcb_device.dev, "t0_clk");
        platform_device_register(&at91cap9_tcb_device);
 }
 #else
@@ -1001,12 +991,10 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91CAP9_ID_SSC0:
                pdev = &at91cap9_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "ssc");
                break;
        case AT91CAP9_ID_SSC1:
                pdev = &at91cap9_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "ssc");
                break;
        default:
                return;
@@ -1199,32 +1187,30 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91cap9_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91CAP9_ID_US0:
                        pdev = &at91cap9_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91CAP9_ID_US1:
                        pdev = &at91cap9_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91CAP9_ID_US2:
                        pdev = &at91cap9_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1232,8 +1218,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91cap9_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index 2e9ecad97f3dc76367a842eba110a046f7e20766..b228ce9e21a14b9e6c20c57e5b87d8bcc5b769bf 100644 (file)
@@ -18,6 +18,7 @@
 #include <mach/at91rm9200.h>
 #include <mach/at91_pmc.h>
 #include <mach/at91_st.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 #include "clock.h"
@@ -191,6 +192,26 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq6
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("ssc", "ssc.2", &ssc2_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
+};
+
 /*
  * The four programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -227,12 +248,29 @@ static void __init at91rm9200_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
        clk_register(&pck2);
        clk_register(&pck3);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91rm9200_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -266,15 +304,25 @@ static void at91rm9200_reset(void)
        at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
 }
 
+int rm9200_type;
+EXPORT_SYMBOL(rm9200_type);
+
+void __init at91rm9200_set_type(int type)
+{
+       rm9200_type = type;
+}
 
 /* --------------------------------------------------------------------
  *  AT91RM9200 processor initialization
  * -------------------------------------------------------------------- */
-void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks)
+void __init at91rm9200_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
+}
 
+void __init at91rm9200_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91rm9200_reset;
        at91_extern_irq = (1 << AT91RM9200_ID_IRQ0) | (1 << AT91RM9200_ID_IRQ1)
                        | (1 << AT91RM9200_ID_IRQ2) | (1 << AT91RM9200_ID_IRQ3)
@@ -288,7 +336,8 @@ void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks
        at91rm9200_register_clocks();
 
        /* Initialize GPIO subsystem */
-       at91_gpio_init(at91rm9200_gpio, banks);
+       at91_gpio_init(at91rm9200_gpio,
+               cpu_is_at91rm9200_bga() ? AT91RM9200_BGA : AT91RM9200_PQFP);
 }
 
 
index 7b539228e0efb324b258d8e247c1e14c060fb30a..a0ba475be04cd23a7aeba30d933c8eead4fb3d1f 100644 (file)
@@ -644,15 +644,7 @@ static struct platform_device at91rm9200_tcb1_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at91rm9200_tcb0_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at91rm9200_tcb0_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at91rm9200_tcb0_device.dev, "t2_clk");
        platform_device_register(&at91rm9200_tcb0_device);
-
-       at91_clock_associate("tc3_clk", &at91rm9200_tcb1_device.dev, "t0_clk");
-       at91_clock_associate("tc4_clk", &at91rm9200_tcb1_device.dev, "t1_clk");
-       at91_clock_associate("tc5_clk", &at91rm9200_tcb1_device.dev, "t2_clk");
        platform_device_register(&at91rm9200_tcb1_device);
 }
 #else
@@ -849,17 +841,14 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91RM9200_ID_SSC0:
                pdev = &at91rm9200_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "ssc");
                break;
        case AT91RM9200_ID_SSC1:
                pdev = &at91rm9200_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "ssc");
                break;
        case AT91RM9200_ID_SSC2:
                pdev = &at91rm9200_ssc2_device;
                configure_ssc2_pins(pins);
-               at91_clock_associate("ssc2_clk", &pdev->dev, "ssc");
                break;
        default:
                return;
@@ -1109,37 +1098,34 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91rm9200_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91RM9200_ID_US0:
                        pdev = &at91rm9200_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91RM9200_ID_US1:
                        pdev = &at91rm9200_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91RM9200_ID_US2:
                        pdev = &at91rm9200_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                case AT91RM9200_ID_US3:
                        pdev = &at91rm9200_uart3_device;
                        configure_usart3_pins(pins);
-                       at91_clock_associate("usart3_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1147,8 +1133,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91rm9200_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index 195208b30024cff807656304c1aef3bf833d8f83..7d606b04d313c5800359849ddff022a827655d87 100644 (file)
@@ -231,6 +231,28 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq2
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+       CLKDEV_CON_DEV_ID("t3_clk", "atmel_tcb.1", &tc3_clk),
+       CLKDEV_CON_DEV_ID("t4_clk", "atmel_tcb.1", &tc4_clk),
+       CLKDEV_CON_DEV_ID("t5_clk", "atmel_tcb.1", &tc5_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.5", &usart4_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.6", &usart5_clk),
+};
+
 /*
  * The two programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -255,10 +277,27 @@ static void __init at91sam9260_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9260_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -289,7 +328,7 @@ static void at91sam9260_poweroff(void)
  *  AT91SAM9260 processor initialization
  * -------------------------------------------------------------------- */
 
-static void __init at91sam9xe_initialize(void)
+static void __init at91sam9xe_map_io(void)
 {
        unsigned long cidr, sram_size;
 
@@ -310,18 +349,21 @@ static void __init at91sam9xe_initialize(void)
        iotable_init(at91sam9xe_sram_desc, ARRAY_SIZE(at91sam9xe_sram_desc));
 }
 
-void __init at91sam9260_initialize(unsigned long main_clock)
+void __init at91sam9260_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91sam9260_io_desc, ARRAY_SIZE(at91sam9260_io_desc));
 
        if (cpu_is_at91sam9xe())
-               at91sam9xe_initialize();
+               at91sam9xe_map_io();
        else if (cpu_is_at91sam9g20())
                iotable_init(at91sam9g20_sram_desc, ARRAY_SIZE(at91sam9g20_sram_desc));
        else
                iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc));
+}
 
+void __init at91sam9260_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9260_poweroff;
        at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
index 07eb7b07e442a69c9499b71cf49387f6ecd240e6..1fdeb9058a760a865ba0463d6fdbca89cd448bfb 100644 (file)
@@ -609,7 +609,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
                at91_set_A_periph(AT91_PIN_PA2, 0);     /* SPI1_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91sam9260_spi0_device.dev, "spi_clk");
                platform_device_register(&at91sam9260_spi0_device);
        }
        if (enable_spi1) {
@@ -617,7 +616,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB1, 0);     /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB2, 0);     /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91sam9260_spi1_device.dev, "spi_clk");
                platform_device_register(&at91sam9260_spi1_device);
        }
 }
@@ -694,15 +692,7 @@ static struct platform_device at91sam9260_tcb1_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at91sam9260_tcb0_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at91sam9260_tcb0_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at91sam9260_tcb0_device.dev, "t2_clk");
        platform_device_register(&at91sam9260_tcb0_device);
-
-       at91_clock_associate("tc3_clk", &at91sam9260_tcb1_device.dev, "t0_clk");
-       at91_clock_associate("tc4_clk", &at91sam9260_tcb1_device.dev, "t1_clk");
-       at91_clock_associate("tc5_clk", &at91sam9260_tcb1_device.dev, "t2_clk");
        platform_device_register(&at91sam9260_tcb1_device);
 }
 #else
@@ -820,7 +810,6 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9260_ID_SSC:
                pdev = &at91sam9260_ssc_device;
                configure_ssc_pins(pins);
-               at91_clock_associate("ssc_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -1139,47 +1128,42 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9260_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US0:
                        pdev = &at91sam9260_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US1:
                        pdev = &at91sam9260_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US2:
                        pdev = &at91sam9260_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US3:
                        pdev = &at91sam9260_uart3_device;
                        configure_usart3_pins(pins);
-                       at91_clock_associate("usart3_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US4:
                        pdev = &at91sam9260_uart4_device;
                        configure_usart4_pins();
-                       at91_clock_associate("usart4_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9260_ID_US5:
                        pdev = &at91sam9260_uart5_device;
                        configure_usart5_pins();
-                       at91_clock_associate("usart5_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1187,8 +1171,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9260_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index fcad88668504bde5331b764419b0676fa89edc68..c1483168c97a523569ff04676cf7f964e7282313 100644 (file)
@@ -178,6 +178,24 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq2
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+};
+
 /*
  * The four programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -228,6 +246,11 @@ static void __init at91sam9261_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
        clk_register(&pck2);
@@ -237,6 +260,18 @@ static void __init at91sam9261_register_clocks(void)
        clk_register(&hck1);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9261_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -267,7 +302,7 @@ static void at91sam9261_poweroff(void)
  *  AT91SAM9261 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9261_initialize(unsigned long main_clock)
+void __init at91sam9261_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc));
@@ -276,8 +311,10 @@ void __init at91sam9261_initialize(unsigned long main_clock)
                iotable_init(at91sam9g10_sram_desc, ARRAY_SIZE(at91sam9g10_sram_desc));
        else
                iotable_init(at91sam9261_sram_desc, ARRAY_SIZE(at91sam9261_sram_desc));
+}
 
-
+void __init at91sam9261_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9261_poweroff;
        at91_extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
index 59fc48311fb07d11760382e85e5ff386986a93f6..3eb4538fceebeb243aba31185861d3639d05c9c3 100644 (file)
@@ -426,7 +426,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
                at91_set_A_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91sam9261_spi0_device.dev, "spi_clk");
                platform_device_register(&at91sam9261_spi0_device);
        }
        if (enable_spi1) {
@@ -434,7 +433,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB31, 0);    /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB29, 0);    /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91sam9261_spi1_device.dev, "spi_clk");
                platform_device_register(&at91sam9261_spi1_device);
        }
 }
@@ -581,10 +579,6 @@ static struct platform_device at91sam9261_tcb_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at91sam9261_tcb_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at91sam9261_tcb_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at91sam9261_tcb_device.dev, "t2_clk");
        platform_device_register(&at91sam9261_tcb_device);
 }
 #else
@@ -786,17 +780,14 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9261_ID_SSC0:
                pdev = &at91sam9261_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9261_ID_SSC1:
                pdev = &at91sam9261_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9261_ID_SSC2:
                pdev = &at91sam9261_ssc2_device;
                configure_ssc2_pins(pins);
-               at91_clock_associate("ssc2_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -989,32 +980,30 @@ struct platform_device *atmel_default_console_device;     /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9261_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9261_ID_US0:
                        pdev = &at91sam9261_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9261_ID_US1:
                        pdev = &at91sam9261_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9261_ID_US2:
                        pdev = &at91sam9261_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1022,8 +1011,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9261_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index 249f900954d8b08c05078c5a7ed0cf57d53255d6..dc28477d14ffa158e0e0ae8031815ada848b9c51 100644 (file)
@@ -199,6 +199,23 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0 .. irq1
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+};
+
 /*
  * The four programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -235,12 +252,29 @@ static void __init at91sam9263_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
        clk_register(&pck2);
        clk_register(&pck3);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9263_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -279,11 +313,14 @@ static void at91sam9263_poweroff(void)
  *  AT91SAM9263 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9263_initialize(unsigned long main_clock)
+void __init at91sam9263_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc));
+}
 
+void __init at91sam9263_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9263_poweroff;
        at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
index fb5c23af1017ed13c480ae324bf90b6b7d566bf1..ffe081b77ed0f5bfafc97116919f0c381b06be98 100644 (file)
@@ -308,7 +308,6 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
                }
 
                mmc0_data = *data;
-               at91_clock_associate("mci0_clk", &at91sam9263_mmc0_device.dev, "mci_clk");
                platform_device_register(&at91sam9263_mmc0_device);
        } else {                        /* MCI1 */
                /* CLK */
@@ -339,7 +338,6 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
                }
 
                mmc1_data = *data;
-               at91_clock_associate("mci1_clk", &at91sam9263_mmc1_device.dev, "mci_clk");
                platform_device_register(&at91sam9263_mmc1_device);
        }
 }
@@ -686,7 +684,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_B_periph(AT91_PIN_PA1, 0);     /* SPI0_MOSI */
                at91_set_B_periph(AT91_PIN_PA2, 0);     /* SPI0_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91sam9263_spi0_device.dev, "spi_clk");
                platform_device_register(&at91sam9263_spi0_device);
        }
        if (enable_spi1) {
@@ -694,7 +691,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB13, 0);    /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB14, 0);    /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91sam9263_spi1_device.dev, "spi_clk");
                platform_device_register(&at91sam9263_spi1_device);
        }
 }
@@ -941,8 +937,6 @@ static struct platform_device at91sam9263_tcb_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has one clock and irq for all three TC channels */
-       at91_clock_associate("tcb_clk", &at91sam9263_tcb_device.dev, "t0_clk");
        platform_device_register(&at91sam9263_tcb_device);
 }
 #else
@@ -1171,12 +1165,10 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9263_ID_SSC0:
                pdev = &at91sam9263_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9263_ID_SSC1:
                pdev = &at91sam9263_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -1370,32 +1362,30 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9263_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9263_ID_US0:
                        pdev = &at91sam9263_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9263_ID_US1:
                        pdev = &at91sam9263_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9263_ID_US2:
                        pdev = &at91sam9263_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1403,8 +1393,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9263_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index c67b47f1c0fd805751cf226a65315337a2507942..2bb6ff9af1c7fede95a7879c3381dc0a1c424d8c 100644 (file)
@@ -184,22 +184,6 @@ static struct clk vdec_clk = {
        .type           = CLK_TYPE_PERIPHERAL,
 };
 
-/* One additional fake clock for ohci */
-static struct clk ohci_clk = {
-       .name           = "ohci_clk",
-       .pmc_mask       = 0,
-       .type           = CLK_TYPE_PERIPHERAL,
-       .parent         = &uhphs_clk,
-};
-
-/* One additional fake clock for second TC block */
-static struct clk tcb1_clk = {
-       .name           = "tcb1_clk",
-       .pmc_mask       = 0,
-       .type           = CLK_TYPE_PERIPHERAL,
-       .parent         = &tcb0_clk,
-};
-
 static struct clk *periph_clocks[] __initdata = {
        &pioA_clk,
        &pioB_clk,
@@ -228,8 +212,30 @@ static struct clk *periph_clocks[] __initdata = {
        &udphs_clk,
        &mmc1_clk,
        // irq0
-       &ohci_clk,
-       &tcb1_clk,
+};
+
+static struct clk_lookup periph_clocks_lookups[] = {
+       /* One additional fake clock for ohci */
+       CLKDEV_CON_ID("ohci_clk", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci.0", &uhphs_clk),
+       CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
+       CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
+       CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
 };
 
 /*
@@ -256,6 +262,11 @@ static void __init at91sam9g45_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        if (cpu_is_at91sam9m10() || cpu_is_at91sam9m11())
                clk_register(&vdec_clk);
 
@@ -263,6 +274,18 @@ static void __init at91sam9g45_register_clocks(void)
        clk_register(&pck1);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9g45_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -306,11 +329,14 @@ static void at91sam9g45_poweroff(void)
  *  AT91SAM9G45 processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9g45_initialize(unsigned long main_clock)
+void __init at91sam9g45_map_io(void)
 {
        /* Map peripherals */
        iotable_init(at91sam9g45_io_desc, ARRAY_SIZE(at91sam9g45_io_desc));
+}
 
+void __init at91sam9g45_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9g45_reset;
        pm_power_off = at91sam9g45_poweroff;
        at91_extern_irq = (1 << AT91SAM9G45_ID_IRQ0);
index 5e9f8a4c38df0d900c326287debd0ea8ce57f604..05674865bc214d5642885038c514b5c4b067e7a5 100644 (file)
@@ -180,7 +180,6 @@ void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data)
        }
 
        usbh_ehci_data = *data;
-       at91_clock_associate("uhphs_clk", &at91_usbh_ehci_device.dev, "ehci_clk");
        platform_device_register(&at91_usbh_ehci_device);
 }
 #else
@@ -266,10 +265,6 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
 
        /* Pullup pin is handled internally by USB device peripheral */
 
-       /* Clocks */
-       at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
-       at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk");
-
        platform_device_register(&at91_usba_udc_device);
 }
 #else
@@ -478,7 +473,6 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
                }
 
                mmc0_data = *data;
-               at91_clock_associate("mci0_clk", &at91sam9g45_mmc0_device.dev, "mci_clk");
                platform_device_register(&at91sam9g45_mmc0_device);
 
        } else {                        /* MCI1 */
@@ -504,7 +498,6 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
                }
 
                mmc1_data = *data;
-               at91_clock_associate("mci1_clk", &at91sam9g45_mmc1_device.dev, "mci_clk");
                platform_device_register(&at91sam9g45_mmc1_device);
 
        }
@@ -801,7 +794,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB1, 0);     /* SPI0_MOSI */
                at91_set_A_periph(AT91_PIN_PB2, 0);     /* SPI0_SPCK */
 
-               at91_clock_associate("spi0_clk", &at91sam9g45_spi0_device.dev, "spi_clk");
                platform_device_register(&at91sam9g45_spi0_device);
        }
        if (enable_spi1) {
@@ -809,7 +801,6 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
                at91_set_A_periph(AT91_PIN_PB15, 0);    /* SPI1_MOSI */
                at91_set_A_periph(AT91_PIN_PB16, 0);    /* SPI1_SPCK */
 
-               at91_clock_associate("spi1_clk", &at91sam9g45_spi1_device.dev, "spi_clk");
                platform_device_register(&at91sam9g45_spi1_device);
        }
 }
@@ -999,10 +990,7 @@ static struct platform_device at91sam9g45_tcb1_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has one clock and irq for all six TC channels */
-       at91_clock_associate("tcb0_clk", &at91sam9g45_tcb0_device.dev, "t0_clk");
        platform_device_register(&at91sam9g45_tcb0_device);
-       at91_clock_associate("tcb1_clk", &at91sam9g45_tcb1_device.dev, "t0_clk");
        platform_device_register(&at91sam9g45_tcb1_device);
 }
 #else
@@ -1286,12 +1274,10 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9G45_ID_SSC0:
                pdev = &at91sam9g45_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9G45_ID_SSC1:
                pdev = &at91sam9g45_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -1527,37 +1513,34 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9g45_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9G45_ID_US0:
                        pdev = &at91sam9g45_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9G45_ID_US1:
                        pdev = &at91sam9g45_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9G45_ID_US2:
                        pdev = &at91sam9g45_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9G45_ID_US3:
                        pdev = &at91sam9g45_uart3_device;
                        configure_usart3_pins(pins);
-                       at91_clock_associate("usart3_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1565,8 +1548,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9g45_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index 6a9d24e5ed8e412680c2364208c46b820959f236..1a40f16b66c849dd71a14dd238e8df60df284876 100644 (file)
@@ -190,6 +190,24 @@ static struct clk *periph_clocks[] __initdata = {
        // irq0
 };
 
+static struct clk_lookup periph_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
+       CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
+       CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
+       CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
+       CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
+       CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
+};
+
+static struct clk_lookup usart_clocks_lookups[] = {
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
+       CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
+};
+
 /*
  * The two programmable clocks.
  * You must configure pin multiplexing to bring these signals out.
@@ -214,10 +232,27 @@ static void __init at91sam9rl_register_clocks(void)
        for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
                clk_register(periph_clocks[i]);
 
+       clkdev_add_table(periph_clocks_lookups,
+                        ARRAY_SIZE(periph_clocks_lookups));
+       clkdev_add_table(usart_clocks_lookups,
+                        ARRAY_SIZE(usart_clocks_lookups));
+
        clk_register(&pck0);
        clk_register(&pck1);
 }
 
+static struct clk_lookup console_clock_lookup;
+
+void __init at91sam9rl_set_console_clock(int id)
+{
+       if (id >= ARRAY_SIZE(usart_clocks_lookups))
+               return;
+
+       console_clock_lookup.con_id = "usart";
+       console_clock_lookup.clk = usart_clocks_lookups[id].clk;
+       clkdev_add(&console_clock_lookup);
+}
+
 /* --------------------------------------------------------------------
  *  GPIO
  * -------------------------------------------------------------------- */
@@ -252,7 +287,7 @@ static void at91sam9rl_poweroff(void)
  *  AT91SAM9RL processor initialization
  * -------------------------------------------------------------------- */
 
-void __init at91sam9rl_initialize(unsigned long main_clock)
+void __init at91sam9rl_map_io(void)
 {
        unsigned long cidr, sram_size;
 
@@ -275,7 +310,10 @@ void __init at91sam9rl_initialize(unsigned long main_clock)
 
        /* Map SRAM */
        iotable_init(at91sam9rl_sram_desc, ARRAY_SIZE(at91sam9rl_sram_desc));
+}
 
+void __init at91sam9rl_initialize(unsigned long main_clock)
+{
        at91_arch_reset = at91sam9_alt_reset;
        pm_power_off = at91sam9rl_poweroff;
        at91_extern_irq = (1 << AT91SAM9RL_ID_IRQ0);
index c49262bddd851db28d12415c73203a532ae3d431..c296045f2b6aa2099cca149b520192dc0ab89034 100644 (file)
@@ -155,10 +155,6 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
 
        /* Pullup pin is handled internally by USB device peripheral */
 
-       /* Clocks */
-       at91_clock_associate("utmi_clk", &at91_usba_udc_device.dev, "hclk");
-       at91_clock_associate("udphs_clk", &at91_usba_udc_device.dev, "pclk");
-
        platform_device_register(&at91_usba_udc_device);
 }
 #else
@@ -605,10 +601,6 @@ static struct platform_device at91sam9rl_tcb_device = {
 
 static void __init at91_add_device_tc(void)
 {
-       /* this chip has a separate clock and irq for each TC channel */
-       at91_clock_associate("tc0_clk", &at91sam9rl_tcb_device.dev, "t0_clk");
-       at91_clock_associate("tc1_clk", &at91sam9rl_tcb_device.dev, "t1_clk");
-       at91_clock_associate("tc2_clk", &at91sam9rl_tcb_device.dev, "t2_clk");
        platform_device_register(&at91sam9rl_tcb_device);
 }
 #else
@@ -892,12 +884,10 @@ void __init at91_add_device_ssc(unsigned id, unsigned pins)
        case AT91SAM9RL_ID_SSC0:
                pdev = &at91sam9rl_ssc0_device;
                configure_ssc0_pins(pins);
-               at91_clock_associate("ssc0_clk", &pdev->dev, "pclk");
                break;
        case AT91SAM9RL_ID_SSC1:
                pdev = &at91sam9rl_ssc1_device;
                configure_ssc1_pins(pins);
-               at91_clock_associate("ssc1_clk", &pdev->dev, "pclk");
                break;
        default:
                return;
@@ -1141,37 +1131,34 @@ struct platform_device *atmel_default_console_device;   /* the serial console devi
 void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (id) {
                case 0:         /* DBGU */
                        pdev = &at91sam9rl_dbgu_device;
                        configure_dbgu_pins();
-                       at91_clock_associate("mck", &pdev->dev, "usart");
                        break;
                case AT91SAM9RL_ID_US0:
                        pdev = &at91sam9rl_uart0_device;
                        configure_usart0_pins(pins);
-                       at91_clock_associate("usart0_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9RL_ID_US1:
                        pdev = &at91sam9rl_uart1_device;
                        configure_usart1_pins(pins);
-                       at91_clock_associate("usart1_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9RL_ID_US2:
                        pdev = &at91sam9rl_uart2_device;
                        configure_usart2_pins(pins);
-                       at91_clock_associate("usart2_clk", &pdev->dev, "usart");
                        break;
                case AT91SAM9RL_ID_US3:
                        pdev = &at91sam9rl_uart3_device;
                        configure_usart3_pins(pins);
-                       at91_clock_associate("usart3_clk", &pdev->dev, "usart");
                        break;
                default:
                        return;
        }
-       pdev->id = portnr;              /* update to mapped ID */
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;            /* update to mapped ID */
 
        if (portnr < ATMEL_MAX_UART)
                at91_uarts[portnr] = pdev;
@@ -1179,8 +1166,10 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
 
 void __init at91_set_serial_console(unsigned portnr)
 {
-       if (portnr < ATMEL_MAX_UART)
+       if (portnr < ATMEL_MAX_UART) {
                atmel_default_console_device = at91_uarts[portnr];
+               at91sam9rl_set_console_clock(portnr);
+       }
 }
 
 void __init at91_add_device_serial(void)
index ad3ec85b27906c5ac38c3d8f11432f0e87d61985..56ba3bd035aeff76f6bc0db6459c20d47ab9d09f 100644 (file)
@@ -37,11 +37,6 @@ unsigned long clk_get_rate(struct clk *clk)
        return AT91X40_MASTER_CLOCK;
 }
 
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       return NULL;
-}
-
 void __init at91x40_initialize(unsigned long main_clock)
 {
        at91_extern_irq = (1 << AT91X40_ID_IRQ0) | (1 << AT91X40_ID_IRQ1)
index 8a3fc84847c120b42980298067f74d8b3abc00fc..ab1d463aa47d4c3c72d6df44f590bec8a767d24e 100644 (file)
 
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
 
-static void __init onearm_map_io(void)
+static void __init onearm_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -92,9 +96,9 @@ static void __init onearm_board_init(void)
 
 MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = onearm_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = onearm_init_early,
        .init_irq       = onearm_init_irq,
        .init_machine   = onearm_board_init,
 MACHINE_END
index cba7f7771feed1b6fc2286b76a8b63ffbdc9f398..a4924de48c36300e0121371ef0435e1ff4a8e43d 100644 (file)
@@ -48,7 +48,7 @@
 #include "generic.h"
 
 
-static void __init afeb9260_map_io(void)
+static void __init afeb9260_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -218,9 +218,9 @@ static void __init afeb9260_board_init(void)
 
 MACHINE_START(AFEB9260, "Custom afeb9260 board")
        /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = afeb9260_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = afeb9260_init_early,
        .init_irq       = afeb9260_init_irq,
        .init_machine   = afeb9260_board_init,
 MACHINE_END
diff --git a/arch/arm/mach-at91/board-at572d940hf_ek.c b/arch/arm/mach-at91/board-at572d940hf_ek.c
deleted file mode 100644 (file)
index 3929f1c..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-at572d940hf_ek.c
- *
- * Copyright (C) 2008 Atmel Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2005 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/ds1305.h>
-#include <linux/irq.h>
-#include <linux/mtd/physmap.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/board.h>
-#include <mach/gpio.h>
-#include <mach/at91sam9_smc.h>
-
-#include "sam9_smc.h"
-#include "generic.h"
-
-
-static void __init eb_map_io(void)
-{
-       /* Initialize processor: 12.500 MHz crystal */
-       at572d940hf_initialize(12000000);
-
-       /* DBGU on ttyS0. (Rx & Tx only) */
-       at91_register_uart(0, 0, 0);
-
-       /* USART0 on ttyS1. (Rx & Tx only) */
-       at91_register_uart(AT572D940HF_ID_US0, 1, 0);
-
-       /* USART1 on ttyS2. (Rx & Tx only) */
-       at91_register_uart(AT572D940HF_ID_US1, 2, 0);
-
-       /* USART2 on ttyS3. (Tx & Rx only */
-       at91_register_uart(AT572D940HF_ID_US2, 3, 0);
-
-       /* set serial console to ttyS0 (ie, DBGU) */
-       at91_set_serial_console(0);
-}
-
-static void __init eb_init_irq(void)
-{
-       at572d940hf_init_interrupts(NULL);
-}
-
-
-/*
- * USB Host Port
- */
-static struct at91_usbh_data __initdata eb_usbh_data = {
-       .ports          = 2,
-};
-
-
-/*
- * USB Device Port
- */
-static struct at91_udc_data __initdata eb_udc_data = {
-       .vbus_pin       = 0,            /* no VBUS detection,UDC always on */
-       .pullup_pin     = 0,            /* pull-up driven by UDC */
-};
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct at91_mmc_data __initdata eb_mmc_data = {
-       .wire4          = 1,
-/*     .det_pin        = ... not connected */
-/*     .wp_pin         = ... not connected */
-/*     .vcc_pin        = ... not connected */
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct at91_eth_data __initdata eb_eth_data = {
-       .phy_irq_pin    = AT91_PIN_PB25,
-       .is_rmii        = 1,
-};
-
-/*
- * NOR flash
- */
-
-static struct mtd_partition eb_nor_partitions[] = {
-       {
-               .name           = "Raw Environment",
-               .offset         = 0,
-               .size           = SZ_4M,
-               .mask_flags     = 0,
-       },
-       {
-               .name           = "OS FS",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 3 * SZ_1M,
-               .mask_flags     = 0,
-       },
-       {
-               .name           = "APP FS",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = MTDPART_SIZ_FULL,
-               .mask_flags     = 0,
-       },
-};
-
-static void nor_flash_set_vpp(struct map_info* mi, int i) {
-};
-
-static struct physmap_flash_data nor_flash_data = {
-       .width          = 4,
-       .parts          = eb_nor_partitions,
-       .nr_parts       = ARRAY_SIZE(eb_nor_partitions),
-       .set_vpp        = nor_flash_set_vpp,
-};
-
-static struct resource nor_flash_resources[] = {
-       {
-               .start  = AT91_CHIPSELECT_0,
-               .end    = AT91_CHIPSELECT_0 + SZ_16M - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device nor_flash = {
-       .name           = "physmap-flash",
-       .id             = 0,
-       .dev            = {
-                               .platform_data = &nor_flash_data,
-                       },
-       .resource       = nor_flash_resources,
-       .num_resources  = ARRAY_SIZE(nor_flash_resources),
-};
-
-static struct sam9_smc_config __initdata eb_nor_smc_config = {
-       .ncs_read_setup         = 1,
-       .nrd_setup              = 1,
-       .ncs_write_setup        = 1,
-       .nwe_setup              = 1,
-
-       .ncs_read_pulse         = 7,
-       .nrd_pulse              = 7,
-       .ncs_write_pulse        = 7,
-       .nwe_pulse              = 7,
-
-       .read_cycle             = 9,
-       .write_cycle            = 9,
-
-       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_32,
-       .tdf_cycles             = 1,
-};
-
-static void __init eb_add_device_nor(void)
-{
-       /* configure chip-select 0 (NOR) */
-       sam9_smc_configure(0, &eb_nor_smc_config);
-       platform_device_register(&nor_flash);
-}
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata eb_nand_partition[] = {
-       {
-               .name   = "Partition 1",
-               .offset = 0,
-               .size   = SZ_16M,
-       },
-       {
-               .name   = "Partition 2",
-               .offset = MTDPART_OFS_NXTBLK,
-               .size   = MTDPART_SIZ_FULL,
-       }
-};
-
-static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
-{
-       *num_partitions = ARRAY_SIZE(eb_nand_partition);
-       return eb_nand_partition;
-}
-
-static struct atmel_nand_data __initdata eb_nand_data = {
-       .ale            = 22,
-       .cle            = 21,
-/*     .det_pin        = ... not connected */
-/*     .rdy_pin        = AT91_PIN_PC16, */
-       .enable_pin     = AT91_PIN_PA15,
-       .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
-};
-
-static struct sam9_smc_config __initdata eb_nand_smc_config = {
-       .ncs_read_setup         = 0,
-       .nrd_setup              = 0,
-       .ncs_write_setup        = 1,
-       .nwe_setup              = 1,
-
-       .ncs_read_pulse         = 3,
-       .nrd_pulse              = 3,
-       .ncs_write_pulse        = 3,
-       .nwe_pulse              = 3,
-
-       .read_cycle             = 5,
-       .write_cycle            = 5,
-
-       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
-       .tdf_cycles             = 12,
-};
-
-static void __init eb_add_device_nand(void)
-{
-       /* setup bus-width (8 or 16) */
-       if (eb_nand_data.bus_width_16)
-               eb_nand_smc_config.mode |= AT91_SMC_DBW_16;
-       else
-               eb_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
-       /* configure chip-select 3 (NAND) */
-       sam9_smc_configure(3, &eb_nand_smc_config);
-
-       at91_add_device_nand(&eb_nand_data);
-}
-
-
-/*
- * SPI devices
- */
-static struct resource rtc_resources[] = {
-       [0] = {
-               .start  = AT572D940HF_ID_IRQ1,
-               .end    = AT572D940HF_ID_IRQ1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct ds1305_platform_data ds1306_data = {
-       .is_ds1306      = true,
-       .en_1hz         = false,
-};
-
-static struct spi_board_info eb_spi_devices[] = {
-       {       /* RTC Dallas DS1306 */
-               .modalias       = "rtc-ds1305",
-               .chip_select    = 3,
-               .mode           = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA,
-               .max_speed_hz   = 500000,
-               .bus_num        = 0,
-               .irq            = AT572D940HF_ID_IRQ1,
-               .platform_data  = (void *) &ds1306_data,
-       },
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
-       {       /* Dataflash card */
-               .modalias       = "mtd_dataflash",
-               .chip_select    = 0,
-               .max_speed_hz   = 15 * 1000 * 1000,
-               .bus_num        = 0,
-       },
-#endif
-};
-
-static void __init eb_board_init(void)
-{
-       /* Serial */
-       at91_add_device_serial();
-       /* USB Host */
-       at91_add_device_usbh(&eb_usbh_data);
-       /* USB Device */
-       at91_add_device_udc(&eb_udc_data);
-       /* I2C */
-       at91_add_device_i2c(NULL, 0);
-       /* NOR */
-       eb_add_device_nor();
-       /* NAND */
-       eb_add_device_nand();
-       /* SPI */
-       at91_add_device_spi(eb_spi_devices, ARRAY_SIZE(eb_spi_devices));
-       /* MMC */
-       at91_add_device_mmc(0, &eb_mmc_data);
-       /* Ethernet */
-       at91_add_device_eth(&eb_eth_data);
-       /* mAgic */
-       at91_add_device_mAgic();
-}
-
-MACHINE_START(AT572D940HFEB, "Atmel AT91D940HF-EB")
-       /* Maintainer: Atmel <costa.antonior@gmail.com> */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
-       .timer          = &at91sam926x_timer,
-       .map_io         = eb_map_io,
-       .init_irq       = eb_init_irq,
-       .init_machine   = eb_board_init,
-MACHINE_END
index b54e3e6fceb6774df2318b663131625800b25b0a..148fccb9a25a4e9c5d10ec2740bd4e3a48195af0 100644 (file)
@@ -45,7 +45,7 @@
 #include "generic.h"
 
 
-static void __init cam60_map_io(void)
+static void __init cam60_init_early(void)
 {
        /* Initialize processor: 10 MHz crystal */
        at91sam9260_initialize(10000000);
@@ -198,9 +198,9 @@ static void __init cam60_board_init(void)
 
 MACHINE_START(CAM60, "KwikByte CAM60")
        /* Maintainer: KwikByte */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = cam60_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = cam60_init_early,
        .init_irq       = cam60_init_irq,
        .init_machine   = cam60_board_init,
 MACHINE_END
index e7274440ead99f8970e2abc801d2d752dced6d90..1904fdf87613d9803ffcae12cfd1618111f4aee5 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91cap9_matrix.h>
 #include <mach/at91sam9_smc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init cap9adk_map_io(void)
+static void __init cap9adk_init_early(void)
 {
        /* Initialize processor: 12 MHz crystal */
        at91cap9_initialize(12000000);
@@ -187,11 +188,6 @@ static struct atmel_nand_data __initdata cap9adk_nand_data = {
 //     .rdy_pin        = ... not connected
        .enable_pin     = AT91_PIN_PD15,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata cap9adk_nand_smc_config = {
@@ -219,6 +215,7 @@ static void __init cap9adk_add_device_nand(void)
        csa = at91_sys_read(AT91_MATRIX_EBICSA);
        at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
 
+       cap9adk_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (cap9adk_nand_data.bus_width_16)
                cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -399,9 +396,9 @@ static void __init cap9adk_board_init(void)
 
 MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
        /* Maintainer: Stelian Pop <stelian.pop@leadtechdesign.com> */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = cap9adk_map_io,
+       .map_io         = at91cap9_map_io,
+       .init_early     = cap9adk_init_early,
        .init_irq       = cap9adk_init_irq,
        .init_machine   = cap9adk_board_init,
 MACHINE_END
index 295e1e77fa60cc3106a17b685df37be064428f81..f36b18687494a5548ace1b4a534cee7cb284aa1d 100644 (file)
 #include "generic.h"
 
 
-static void __init carmeva_map_io(void)
+static void __init carmeva_init_early(void)
 {
        /* Initialize processor: 20.000 MHz crystal */
-       at91rm9200_initialize(20000000, AT91RM9200_BGA);
+       at91rm9200_initialize(20000000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -162,9 +162,9 @@ static void __init carmeva_board_init(void)
 
 MACHINE_START(CARMEVA, "Carmeva")
        /* Maintainer: Conitec Datasystems */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = carmeva_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = carmeva_init_early,
        .init_irq       = carmeva_init_irq,
        .init_machine   = carmeva_board_init,
 MACHINE_END
index 3838594578f3539d395cfd74bd4f9a90f9c21940..980511084fe4179e9965568f26cb9a6d174380e9 100644 (file)
@@ -47,7 +47,7 @@
 #include "sam9_smc.h"
 #include "generic.h"
 
-static void __init cpu9krea_map_io(void)
+static void __init cpu9krea_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -375,9 +375,9 @@ MACHINE_START(CPUAT9260, "Eukrea CPU9260")
 MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
 #endif
        /* Maintainer: Eric Benard - EUKREA Electromatique */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = cpu9krea_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = cpu9krea_init_early,
        .init_irq       = cpu9krea_init_irq,
        .init_machine   = cpu9krea_board_init,
 MACHINE_END
index 2f4dd8cdd484a50c1276fd48dcc61b68b3519c24..6daabe3907a1d7cdaa033147de021114ce6727d2 100644 (file)
@@ -38,6 +38,7 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
@@ -50,10 +51,13 @@ static struct gpio_led cpuat91_leds[] = {
        },
 };
 
-static void __init cpuat91_map_io(void)
+static void __init cpuat91_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -175,9 +179,9 @@ static void __init cpuat91_board_init(void)
 
 MACHINE_START(CPUAT91, "Eukrea")
        /* Maintainer: Eric Benard - EUKREA Electromatique */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = cpuat91_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = cpuat91_init_early,
        .init_irq       = cpuat91_init_irq,
        .init_machine   = cpuat91_board_init,
 MACHINE_END
index 464839dc39bd4d1c9acc0d38d17559d84a897e32..d98bcec1dfe000d6dc667081f36655a6206bf5fa 100644 (file)
 #include "generic.h"
 
 
-static void __init csb337_map_io(void)
+static void __init csb337_init_early(void)
 {
        /* Initialize processor: 3.6864 MHz crystal */
-       at91rm9200_initialize(3686400, AT91RM9200_BGA);
+       at91rm9200_initialize(3686400);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
@@ -257,9 +257,9 @@ static void __init csb337_board_init(void)
 
 MACHINE_START(CSB337, "Cogent CSB337")
        /* Maintainer: Bill Gatliff */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = csb337_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = csb337_init_early,
        .init_irq       = csb337_init_irq,
        .init_machine   = csb337_board_init,
 MACHINE_END
index 431688c6141267f3227f034baa9c9dab2bd9d9d3..019aab4e20b01394aba18eb89580e2ed729b08a6 100644 (file)
 #include "generic.h"
 
 
-static void __init csb637_map_io(void)
+static void __init csb637_init_early(void)
 {
        /* Initialize processor: 3.6864 MHz crystal */
-       at91rm9200_initialize(3686400, AT91RM9200_BGA);
+       at91rm9200_initialize(3686400);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -138,9 +138,9 @@ static void __init csb637_board_init(void)
 
 MACHINE_START(CSB637, "Cogent CSB637")
        /* Maintainer: Bill Gatliff */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = csb637_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = csb637_init_early,
        .init_irq       = csb637_init_irq,
        .init_machine   = csb637_board_init,
 MACHINE_END
index d8df59a3426d82a75de3255bf586292659072616..d2023f27c65254f83113588a105d221ccfabf705 100644 (file)
@@ -35,7 +35,7 @@ static void __init at91eb01_init_irq(void)
        at91x40_init_interrupts(NULL);
 }
 
-static void __init at91eb01_map_io(void)
+static void __init at91eb01_init_early(void)
 {
        at91x40_initialize(40000000);
 }
@@ -43,7 +43,7 @@ static void __init at91eb01_map_io(void)
 MACHINE_START(AT91EB01, "Atmel AT91 EB01")
        /* Maintainer: Greg Ungerer <gerg@snapgear.com> */
        .timer          = &at91x40_timer,
+       .init_early     = at91eb01_init_early,
        .init_irq       = at91eb01_init_irq,
-       .map_io         = at91eb01_map_io,
 MACHINE_END
 
index 6cf6566ae346610a78f29f7de0f0f698f7d16e09..e9484535cbc81f213b77bf617068721a037a3b9a 100644 (file)
 #include "generic.h"
 
 
-static void __init eb9200_map_io(void)
+static void __init eb9200_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_BGA);
+       at91rm9200_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -120,9 +120,9 @@ static void __init eb9200_board_init(void)
 }
 
 MACHINE_START(ATEB9200, "Embest ATEB9200")
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = eb9200_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = eb9200_init_early,
        .init_irq       = eb9200_init_irq,
        .init_machine   = eb9200_board_init,
 MACHINE_END
index de2fd04e7c8ae355940829879b0dcf008b3da999..a6f57faa10a7f1dbc202c6d320c03854fff54982 100644 (file)
 
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
 
-static void __init ecb_at91map_io(void)
+static void __init ecb_at91init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
@@ -168,9 +172,9 @@ static void __init ecb_at91board_init(void)
 
 MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
        /* Maintainer: emQbit.com */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = ecb_at91map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = ecb_at91init_early,
        .init_irq       = ecb_at91init_irq,
        .init_machine   = ecb_at91board_init,
 MACHINE_END
index a158a0ce458fb36d09a4afe58f184c0e428ed057..bfc0062d1483f61e0a1d7026ca9a859a41253840 100644 (file)
 
 #include <mach/board.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/cpu.h>
+
 #include "generic.h"
 
-static void __init eco920_map_io(void)
+static void __init eco920_init_early(void)
 {
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
@@ -86,21 +91,6 @@ static struct platform_device eco920_flash = {
        .num_resources  = 1,
 };
 
-static struct resource at91_beeper_resources[] = {
-       [0] = {
-               .start          = AT91RM9200_BASE_TC3,
-               .end            = AT91RM9200_BASE_TC3 + 0x39,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device at91_beeper = {
-       .name           = "at91_beeper",
-       .id             = 0,
-       .resource       = at91_beeper_resources,
-       .num_resources  = ARRAY_SIZE(at91_beeper_resources),
-};
-
 static struct spi_board_info eco920_spi_devices[] = {
        {       /* CAN controller */
                .modalias       = "tlv5638",
@@ -139,18 +129,14 @@ static void __init eco920_board_init(void)
                AT91_SMC_TDF_(1)        /* float time */
        );
 
-       at91_clock_associate("tc3_clk", &at91_beeper.dev, "at91_beeper");
-       at91_set_B_periph(AT91_PIN_PB6, 0);
-       platform_device_register(&at91_beeper);
-
        at91_add_device_spi(eco920_spi_devices, ARRAY_SIZE(eco920_spi_devices));
 }
 
 MACHINE_START(ECO920, "eco920")
        /* Maintainer: Sascha Hauer */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = eco920_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = eco920_init_early,
        .init_irq       = eco920_init_irq,
        .init_machine   = eco920_board_init,
 MACHINE_END
index c8a62dc8fa65965f7672673e58201ff00ed9bebd..466c063b8d218257eae472407a24c5b58773b9b9 100644 (file)
@@ -37,7 +37,7 @@
 
 #include "generic.h"
 
-static void __init flexibity_map_io(void)
+static void __init flexibity_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -154,9 +154,9 @@ static void __init flexibity_board_init(void)
 
 MACHINE_START(FLEXIBITY, "Flexibity Connect")
        /* Maintainer: Maxim Osipov */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = flexibity_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = flexibity_init_early,
        .init_irq       = flexibity_init_irq,
        .init_machine   = flexibity_board_init,
 MACHINE_END
index dfc7dfe738e4a5260ff64c2013010c19a81b4b04..e2d1dc9eff452f09d0459b3191ebaaac387709c0 100644 (file)
@@ -57,7 +57,7 @@
  */
 
 
-static void __init foxg20_map_io(void)
+static void __init foxg20_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -266,9 +266,9 @@ static void __init foxg20_board_init(void)
 
 MACHINE_START(ACMENETUSFOXG20, "Acme Systems srl FOX Board G20")
        /* Maintainer: Sergio Tanzilli */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = foxg20_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = foxg20_init_early,
        .init_irq       = foxg20_init_irq,
        .init_machine   = foxg20_board_init,
 MACHINE_END
index bc28136ee24966e19e6d8a3a271f04f7ed32ea92..1d4f36b3cb275d0b27ce83e8a187201efc36402b 100644 (file)
@@ -38,9 +38,9 @@
 #include "sam9_smc.h"
 #include "generic.h"
 
-static void __init gsia18s_map_io(void)
+static void __init gsia18s_init_early(void)
 {
-       stamp9g20_map_io();
+       stamp9g20_init_early();
 
        /*
         * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
@@ -576,9 +576,9 @@ static void __init gsia18s_board_init(void)
 }
 
 MACHINE_START(GSIA18S, "GS_IA18_S")
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = gsia18s_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = gsia18s_init_early,
        .init_irq       = init_irq,
        .init_machine   = gsia18s_board_init,
 MACHINE_END
index d2e1f4ec1fcc87dcc6aca97d6a664af6ed637d36..9b003ff744ba4c87d3746001de09125a36fe7657 100644 (file)
 
 #include <mach/board.h>
 #include <mach/gpio.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
 
-static void __init kafa_map_io(void)
+static void __init kafa_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
@@ -94,9 +98,9 @@ static void __init kafa_board_init(void)
 
 MACHINE_START(KAFA, "Sperry-Sun KAFA")
        /* Maintainer: Sergei Sharonov */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = kafa_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = kafa_init_early,
        .init_irq       = kafa_init_irq,
        .init_machine   = kafa_board_init,
 MACHINE_END
index a13d2063faff8e43dfeedab3531010e0118887b2..a813a74b65f9e296aba3d4d31af7f48913dd87e2 100644 (file)
 
 #include <mach/board.h>
 #include <mach/gpio.h>
-
+#include <mach/cpu.h>
 #include <mach/at91rm9200_mc.h>
 
 #include "generic.h"
 
 
-static void __init kb9202_map_io(void)
+static void __init kb9202_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 10 MHz crystal */
-       at91rm9200_initialize(10000000, AT91RM9200_PQFP);
+       at91rm9200_initialize(10000000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
@@ -136,9 +139,9 @@ static void __init kb9202_board_init(void)
 
 MACHINE_START(KB9200, "KB920x")
        /* Maintainer: KwikByte, Inc. */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = kb9202_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = kb9202_init_early,
        .init_irq       = kb9202_init_irq,
        .init_machine   = kb9202_board_init,
 MACHINE_END
index fe5f1d47e6e23884eb2ac6d3ab00d36aa264aba0..961e805db68c21f7bde7db486d43126e57e31cd5 100644 (file)
@@ -51,7 +51,7 @@
 #include "generic.h"
 
 
-static void __init neocore926_map_io(void)
+static void __init neocore926_init_early(void)
 {
        /* Initialize processor: 20 MHz crystal */
        at91sam9263_initialize(20000000);
@@ -387,9 +387,9 @@ static void __init neocore926_board_init(void)
 
 MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
        /* Maintainer: ADENEO */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = neocore926_map_io,
+       .map_io         = at91sam9263_map_io,
+       .init_early     = neocore926_init_early,
        .init_irq       = neocore926_init_irq,
        .init_machine   = neocore926_board_init,
 MACHINE_END
index feb65787c30be5502985a112e4b200d0f7de8ac0..21a21af258784336c94a7b374b883a26f6652d82 100644 (file)
@@ -37,9 +37,9 @@
 #include "generic.h"
 
 
-static void __init pcontrol_g20_map_io(void)
+static void __init pcontrol_g20_init_early(void)
 {
-       stamp9g20_map_io();
+       stamp9g20_init_early();
 
        /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback  A2 */
        at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
@@ -222,9 +222,9 @@ static void __init pcontrol_g20_board_init(void)
 
 MACHINE_START(PCONTROL_G20, "PControl G20")
        /* Maintainer: pgsellmann@portner-elektronik.at */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = pcontrol_g20_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = pcontrol_g20_init_early,
        .init_irq       = init_irq,
        .init_machine   = pcontrol_g20_board_init,
 MACHINE_END
index 55dad3a46547288cba52ed6debc5d384f55bc8e1..756cc2a745ddd16c5ac5f1f3a23cc10aac4fe158 100644 (file)
 #include "generic.h"
 
 
-static void __init picotux200_map_io(void)
+static void __init picotux200_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_BGA);
+       at91rm9200_initialize(18432000);
 
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -123,9 +123,9 @@ static void __init picotux200_board_init(void)
 
 MACHINE_START(PICOTUX2XX, "picotux 200")
        /* Maintainer: Kleinhenz Elektronik GmbH */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = picotux200_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = picotux200_init_early,
        .init_irq       = picotux200_init_irq,
        .init_machine   = picotux200_board_init,
 MACHINE_END
index 69d15a875b667f34a68ba4332db47c5a4f6bef4c..d1a6001b0bd86b7a931ff0c8f86e710a85ae67eb 100644 (file)
@@ -48,7 +48,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
        at91sam9260_initialize(12000000);
@@ -268,9 +268,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
        /* Maintainer: calao-systems */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 4c1047c8200df94466a81337779a4cfcfb1c7d7a..aef9627710b0cee79ce885abb8b6e1be60df1bf5 100644 (file)
 #include "generic.h"
 
 
-static void __init dk_map_io(void)
+static void __init dk_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_BGA);
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
@@ -227,9 +227,9 @@ static void __init dk_board_init(void)
 
 MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
        /* Maintainer: SAN People/Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = dk_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = dk_init_early,
        .init_irq       = dk_init_irq,
        .init_machine   = dk_board_init,
 MACHINE_END
index 9df1be8818c0bdf8eb9ff47086e0a68ee7c21294..015a02183080973619b389bf406c98ee87ba91af 100644 (file)
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_BGA);
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
@@ -193,9 +193,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
        /* Maintainer: SAN People/Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 25a26beaa728bbee99a15174925a73532ddad949..aaf1bf0989b3c1635e40e6314456cd7189594d77 100644 (file)
@@ -44,7 +44,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -212,9 +212,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
        /* Maintainer: Olimex */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index de1816e0e1d967c87825bf6c4de11c8370aaf057..d600dc123227f04dad183eb1606f798258eb2ba1 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -191,11 +192,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -218,6 +214,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -356,9 +353,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 14acc901e24cdd97ca4c939f5ae3bcfba189feff..f897f84d43dc490d393768c3c9ed6296687e5f44 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9261_initialize(18432000);
@@ -197,11 +198,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC15,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -224,6 +220,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -623,9 +620,9 @@ MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
 MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
 #endif
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9261_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index bfe490df58be9edf63ab20b001ccaf94c368ccd1..605b26f40a4ce6e947f0a322c2597e88cf3514de 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 16.367 MHz crystal */
        at91sam9263_initialize(16367660);
@@ -198,11 +199,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PA22,
        .enable_pin     = AT91_PIN_PD15,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -225,6 +221,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -454,9 +451,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9263_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index ca8198b3c168bb8a333dc3d08102b082a73e66c4..7624cf0d006b9030639d1a7d2a84d9a3b8f5893a 100644 (file)
@@ -43,6 +43,7 @@
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
@@ -60,7 +61,7 @@ static int inline ek_have_2mmc(void)
 }
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -175,11 +176,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC13,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -202,6 +198,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -406,18 +403,18 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
 
 MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 6c999dbd2bcfb20427387767dc5bdb623c48a489..063c95d0e8f02879c35792b548da42452056e183 100644 (file)
 #include <mach/gpio.h>
 #include <mach/at91sam9_smc.h>
 #include <mach/at91_shdwc.h>
+#include <mach/system_rev.h>
 
 #include "sam9_smc.h"
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
        at91sam9g45_initialize(12000000);
@@ -155,11 +156,6 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC8,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
 };
 
 static struct sam9_smc_config __initdata ek_nand_smc_config = {
@@ -182,6 +178,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
 
 static void __init ek_add_device_nand(void)
 {
+       ek_nand_data.bus_width_16 = !board_have_nand_8bit();
        /* setup bus-width (8 or 16) */
        if (ek_nand_data.bus_width_16)
                ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -424,9 +421,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9g45_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 3bf3408e94c18f370d5edb3991f7a8ff6dd0b208..effb399a80a689ce5993e7526715ebb875b0d4a3 100644 (file)
@@ -38,7 +38,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
        at91sam9rl_initialize(12000000);
@@ -329,9 +329,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
        /* Maintainer: Atmel */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9rl_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index 17f7d9b32142d73984f60cc554c874865a385e17..3eb0a1153cc8f2ee50c5f5e2f6afd1947173de78 100644 (file)
@@ -40,7 +40,7 @@
 
 #define SNAPPER9260_IO_EXP_GPIO(x)     (NR_BUILTIN_GPIO + (x))
 
-static void __init snapper9260_map_io(void)
+static void __init snapper9260_init_early(void)
 {
        at91sam9260_initialize(18432000);
 
@@ -178,9 +178,9 @@ static void __init snapper9260_board_init(void)
 }
 
 MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = snapper9260_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = snapper9260_init_early,
        .init_irq       = snapper9260_init_irq,
        .init_machine   = snapper9260_board_init,
 MACHINE_END
index f8902b118960d84f4d9bf6c57d3a28e9c302df64..5e5c85688f5f5a59ade095ec246952ef4750419e 100644 (file)
@@ -32,7 +32,7 @@
 #include "generic.h"
 
 
-void __init stamp9g20_map_io(void)
+void __init stamp9g20_init_early(void)
 {
        /* Initialize processor: 18.432 MHz crystal */
        at91sam9260_initialize(18432000);
@@ -44,9 +44,9 @@ void __init stamp9g20_map_io(void)
        at91_set_serial_console(0);
 }
 
-static void __init stamp9g20evb_map_io(void)
+static void __init stamp9g20evb_init_early(void)
 {
-       stamp9g20_map_io();
+       stamp9g20_init_early();
 
        /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
        at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
@@ -54,9 +54,9 @@ static void __init stamp9g20evb_map_io(void)
                                                | ATMEL_UART_DCD | ATMEL_UART_RI);
 }
 
-static void __init portuxg20_map_io(void)
+static void __init portuxg20_init_early(void)
 {
-       stamp9g20_map_io();
+       stamp9g20_init_early();
 
        /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
        at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
@@ -298,18 +298,18 @@ static void __init stamp9g20evb_board_init(void)
 
 MACHINE_START(PORTUXG20, "taskit PortuxG20")
        /* Maintainer: taskit GmbH */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = portuxg20_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = portuxg20_init_early,
        .init_irq       = init_irq,
        .init_machine   = portuxg20_board_init,
 MACHINE_END
 
 MACHINE_START(STAMP9G20, "taskit Stamp9G20")
        /* Maintainer: taskit GmbH */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = stamp9g20evb_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = stamp9g20evb_init_early,
        .init_irq       = init_irq,
        .init_machine   = stamp9g20evb_board_init,
 MACHINE_END
index 07784baeae841f2d98709b71cc1fe45917b820f1..0e784e6fedec3641acf2b2ebf502b4d682fe91dc 100644 (file)
@@ -48,7 +48,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.000 MHz crystal */
        at91sam9260_initialize(12000000);
@@ -228,9 +228,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(USB_A9260, "CALAO USB_A9260")
        /* Maintainer: calao-systems */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9260_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index b614508931fd92cc1b7b95a4da438d246cf5f86e..cf626dd14b2ccc6c914790641e523989cfe66413 100644 (file)
@@ -47,7 +47,7 @@
 #include "generic.h"
 
 
-static void __init ek_map_io(void)
+static void __init ek_init_early(void)
 {
        /* Initialize processor: 12.00 MHz crystal */
        at91sam9263_initialize(12000000);
@@ -244,9 +244,9 @@ static void __init ek_board_init(void)
 
 MACHINE_START(USB_A9263, "CALAO USB_A9263")
        /* Maintainer: calao-systems */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
+       .map_io         = at91sam9263_map_io,
+       .init_early     = ek_init_early,
        .init_irq       = ek_init_irq,
        .init_machine   = ek_board_init,
 MACHINE_END
index e0f0080eb639f30137d8aca6631271ad82dc639e..c208cc334d7df8421e34ea004b8380c374159791 100644 (file)
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/at91rm9200_mc.h>
+#include <mach/cpu.h>
 
 #include "generic.h"
 
 
-static void __init yl9200_map_io(void)
+static void __init yl9200_init_early(void)
 {
+       /* Set cpu type: PQFP */
+       at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
+
        /* Initialize processor: 18.432 MHz crystal */
-       at91rm9200_initialize(18432000, AT91RM9200_PQFP);
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
        at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
@@ -594,9 +598,9 @@ static void __init yl9200_board_init(void)
 
 MACHINE_START(YL9200, "uCdragon YL-9200")
        /* Maintainer: S.Birtles */
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
-       .map_io         = yl9200_map_io,
+       .map_io         = at91rm9200_map_io,
+       .init_early     = yl9200_init_early,
        .init_irq       = yl9200_init_irq,
        .init_machine   = yl9200_board_init,
 MACHINE_END
index 9113da6845f17482437ed984bd978b9b28378dfe..61873f3aa92d74f2aaa327a4f0e7d0021f502d02 100644 (file)
@@ -163,7 +163,7 @@ static struct clk udpck = {
        .parent         = &pllb,
        .mode           = pmc_sys_mode,
 };
-static struct clk utmi_clk = {
+struct clk utmi_clk = {
        .name           = "utmi_clk",
        .parent         = &main_clk,
        .pmc_mask       = AT91_PMC_UPLLEN,      /* in CKGR_UCKR */
@@ -182,7 +182,7 @@ static struct clk uhpck = {
  * memory, interfaces to on-chip peripherals, the AIC, and sometimes more
  * (e.g baud rate generation).  It's sourced from one of the primary clocks.
  */
-static struct clk mck = {
+struct clk mck = {
        .name           = "mck",
        .pmc_mask       = AT91_PMC_MCKRDY,      /* in PMC_SR */
 };
@@ -215,43 +215,6 @@ static struct clk __init *at91_css_to_clk(unsigned long css)
        return NULL;
 }
 
-/*
- * Associate a particular clock with a function (eg, "uart") and device.
- * The drivers can then request the same 'function' with several different
- * devices and not care about which clock name to use.
- */
-void __init at91_clock_associate(const char *id, struct device *dev, const char *func)
-{
-       struct clk *clk = clk_get(NULL, id);
-
-       if (!dev || !clk || !IS_ERR(clk_get(dev, func)))
-               return;
-
-       clk->function = func;
-       clk->dev = dev;
-}
-
-/* clocks cannot be de-registered no refcounting necessary */
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       struct clk *clk;
-
-       list_for_each_entry(clk, &clocks, node) {
-               if (strcmp(id, clk->name) == 0)
-                       return clk;
-               if (clk->function && (dev == clk->dev) && strcmp(id, clk->function) == 0)
-                       return clk;
-       }
-
-       return ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
-
 static void __clk_enable(struct clk *clk)
 {
        if (clk->parent)
@@ -498,32 +461,38 @@ postcore_initcall(at91_clk_debugfs_init);
 /*------------------------------------------------------------------------*/
 
 /* Register a new clock */
+static void __init at91_clk_add(struct clk *clk)
+{
+       list_add_tail(&clk->node, &clocks);
+
+       clk->cl.con_id = clk->name;
+       clk->cl.clk = clk;
+       clkdev_add(&clk->cl);
+}
+
 int __init clk_register(struct clk *clk)
 {
        if (clk_is_peripheral(clk)) {
                if (!clk->parent)
                        clk->parent = &mck;
                clk->mode = pmc_periph_mode;
-               list_add_tail(&clk->node, &clocks);
        }
        else if (clk_is_sys(clk)) {
                clk->parent = &mck;
                clk->mode = pmc_sys_mode;
-
-               list_add_tail(&clk->node, &clocks);
        }
 #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
        else if (clk_is_programmable(clk)) {
                clk->mode = pmc_sys_mode;
                init_programmable_clock(clk);
-               list_add_tail(&clk->node, &clocks);
        }
 #endif
 
+       at91_clk_add(clk);
+
        return 0;
 }
 
-
 /*------------------------------------------------------------------------*/
 
 static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg)
@@ -630,7 +599,7 @@ static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock)
                at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
        } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() ||
                   cpu_is_at91sam9263() || cpu_is_at91sam9g20() ||
-                  cpu_is_at91sam9g10() || cpu_is_at572d940hf()) {
+                  cpu_is_at91sam9g10()) {
                uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
                udpck.pmc_mask = AT91SAM926x_PMC_UDP;
        } else if (cpu_is_at91cap9()) {
@@ -754,19 +723,19 @@ int __init at91_clock_init(unsigned long main_clock)
 
        /* Register the PMC's standard clocks */
        for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
-               list_add_tail(&standard_pmc_clocks[i]->node, &clocks);
+               at91_clk_add(standard_pmc_clocks[i]);
 
        if (cpu_has_pllb())
-               list_add_tail(&pllb.node, &clocks);
+               at91_clk_add(&pllb);
 
        if (cpu_has_uhp())
-               list_add_tail(&uhpck.node, &clocks);
+               at91_clk_add(&uhpck);
 
        if (cpu_has_udpfs())
-               list_add_tail(&udpck.node, &clocks);
+               at91_clk_add(&udpck);
 
        if (cpu_has_utmi())
-               list_add_tail(&utmi_clk.node, &clocks);
+               at91_clk_add(&utmi_clk);
 
        /* MCK and CPU clock are "always on" */
        clk_enable(&mck);
index 6cf4b78e175d7a47775463d03f4f6c7146a2910e..c2e63e47dcbece02cf2c9ea296b52476b59ef938 100644 (file)
@@ -6,6 +6,8 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clkdev.h>
+
 #define CLK_TYPE_PRIMARY       0x1
 #define CLK_TYPE_PLL           0x2
 #define CLK_TYPE_PROGRAMMABLE  0x4
@@ -16,8 +18,7 @@
 struct clk {
        struct list_head node;
        const char      *name;          /* unique clock name */
-       const char      *function;      /* function of the clock */
-       struct device   *dev;           /* device associated with function */
+       struct clk_lookup cl;
        unsigned long   rate_hz;
        struct clk      *parent;
        u32             pmc_mask;
@@ -29,3 +30,18 @@ struct clk {
 
 
 extern int __init clk_register(struct clk *clk);
+extern struct clk mck;
+extern struct clk utmi_clk;
+
+#define CLKDEV_CON_ID(_id, _clk)                       \
+       {                                               \
+               .con_id = _id,                          \
+               .clk = _clk,                            \
+       }
+
+#define CLKDEV_CON_DEV_ID(_con_id, _dev_id, _clk)      \
+       {                                               \
+               .con_id = _con_id,                      \
+               .dev_id = _dev_id,                      \
+               .clk = _clk,                            \
+       }
index 0c66deb2db39a990646d833da4c751e7fc28e81c..8ff3418f3430d91e8b5ab765e8beff54db127be9 100644 (file)
@@ -8,8 +8,21 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/clkdev.h>
+
+ /* Map io */
+extern void __init at91rm9200_map_io(void);
+extern void __init at91sam9260_map_io(void);
+extern void __init at91sam9261_map_io(void);
+extern void __init at91sam9263_map_io(void);
+extern void __init at91sam9rl_map_io(void);
+extern void __init at91sam9g45_map_io(void);
+extern void __init at91x40_map_io(void);
+extern void __init at91cap9_map_io(void);
+
  /* Processors */
-extern void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks);
+extern void __init at91rm9200_set_type(int type);
+extern void __init at91rm9200_initialize(unsigned long main_clock);
 extern void __init at91sam9260_initialize(unsigned long main_clock);
 extern void __init at91sam9261_initialize(unsigned long main_clock);
 extern void __init at91sam9263_initialize(unsigned long main_clock);
@@ -17,7 +30,6 @@ extern void __init at91sam9rl_initialize(unsigned long main_clock);
 extern void __init at91sam9g45_initialize(unsigned long main_clock);
 extern void __init at91x40_initialize(unsigned long main_clock);
 extern void __init at91cap9_initialize(unsigned long main_clock);
-extern void __init at572d940hf_initialize(unsigned long main_clock);
 
  /* Interrupts */
 extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
@@ -28,7 +40,6 @@ extern void __init at91sam9rl_init_interrupts(unsigned int priority[]);
 extern void __init at91sam9g45_init_interrupts(unsigned int priority[]);
 extern void __init at91x40_init_interrupts(unsigned int priority[]);
 extern void __init at91cap9_init_interrupts(unsigned int priority[]);
-extern void __init at572d940hf_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
 
  /* Timer */
@@ -39,8 +50,19 @@ extern struct sys_timer at91x40_timer;
 
  /* Clocks */
 extern int __init at91_clock_init(unsigned long main_clock);
+/*
+ * function to specify the clock of the default console. As we do not
+ * use the device/driver bus, the dev_name is not intialize. So we need
+ * to link the clock to a specific con_id only "usart"
+ */
+extern void __init at91rm9200_set_console_clock(int id);
+extern void __init at91sam9260_set_console_clock(int id);
+extern void __init at91sam9261_set_console_clock(int id);
+extern void __init at91sam9263_set_console_clock(int id);
+extern void __init at91sam9rl_set_console_clock(int id);
+extern void __init at91sam9g45_set_console_clock(int id);
+extern void __init at91cap9_set_console_clock(int id);
 struct device;
-extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func);
 
  /* Power Management */
 extern void at91_irq_suspend(void);
diff --git a/arch/arm/mach-at91/include/mach/at572d940hf.h b/arch/arm/mach-at91/include/mach/at572d940hf.h
deleted file mode 100644 (file)
index be510cf..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * include/mach/at572d940hf.h
- *
- * Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2008 Atmel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#ifndef AT572D940HF_H
-#define AT572D940HF_H
-
-/*
- * Peripheral identifiers/interrupts.
- */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
-#define AT572D940HF_ID_PIOA    2       /* Parallel IO Controller A */
-#define AT572D940HF_ID_PIOB    3       /* Parallel IO Controller B */
-#define AT572D940HF_ID_PIOC    4       /* Parallel IO Controller C */
-#define AT572D940HF_ID_EMAC    5       /* MACB ethernet controller */
-#define AT572D940HF_ID_US0     6       /* USART 0 */
-#define AT572D940HF_ID_US1     7       /* USART 1 */
-#define AT572D940HF_ID_US2     8       /* USART 2 */
-#define AT572D940HF_ID_MCI     9       /* Multimedia Card Interface */
-#define AT572D940HF_ID_UDP     10      /* USB Device Port */
-#define AT572D940HF_ID_TWI0    11      /* Two-Wire Interface 0 */
-#define AT572D940HF_ID_SPI0    12      /* Serial Peripheral Interface 0 */
-#define AT572D940HF_ID_SPI1    13      /* Serial Peripheral Interface 1 */
-#define AT572D940HF_ID_SSC0    14      /* Serial Synchronous Controller 0 */
-#define AT572D940HF_ID_SSC1    15      /* Serial Synchronous Controller 1 */
-#define AT572D940HF_ID_SSC2    16      /* Serial Synchronous Controller 2 */
-#define AT572D940HF_ID_TC0     17      /* Timer Counter 0 */
-#define AT572D940HF_ID_TC1     18      /* Timer Counter 1 */
-#define AT572D940HF_ID_TC2     19      /* Timer Counter 2 */
-#define AT572D940HF_ID_UHP     20      /* USB Host port */
-#define AT572D940HF_ID_SSC3    21      /* Serial Synchronous Controller 3 */
-#define AT572D940HF_ID_TWI1    22      /* Two-Wire Interface 1 */
-#define AT572D940HF_ID_CAN0    23      /* CAN Controller 0 */
-#define AT572D940HF_ID_CAN1    24      /* CAN Controller 1 */
-#define AT572D940HF_ID_MHALT   25      /* mAgicV HALT line */
-#define AT572D940HF_ID_MSIRQ0  26      /* mAgicV SIRQ0 line */
-#define AT572D940HF_ID_MEXC    27      /* mAgicV exception line */
-#define AT572D940HF_ID_MEDMA   28      /* mAgicV end of DMA line */
-#define AT572D940HF_ID_IRQ0    29      /* External Interrupt Source (IRQ0) */
-#define AT572D940HF_ID_IRQ1    30      /* External Interrupt Source (IRQ1) */
-#define AT572D940HF_ID_IRQ2    31      /* External Interrupt Source (IRQ2) */
-
-
-/*
- * User Peripheral physical base addresses.
- */
-#define AT572D940HF_BASE_TCB   0xfffa0000
-#define AT572D940HF_BASE_TC0   0xfffa0000
-#define AT572D940HF_BASE_TC1   0xfffa0040
-#define AT572D940HF_BASE_TC2   0xfffa0080
-#define AT572D940HF_BASE_UDP   0xfffa4000
-#define AT572D940HF_BASE_MCI   0xfffa8000
-#define AT572D940HF_BASE_TWI0  0xfffac000
-#define AT572D940HF_BASE_US0   0xfffb0000
-#define AT572D940HF_BASE_US1   0xfffb4000
-#define AT572D940HF_BASE_US2   0xfffb8000
-#define AT572D940HF_BASE_SSC0  0xfffbc000
-#define AT572D940HF_BASE_SSC1  0xfffc0000
-#define AT572D940HF_BASE_SSC2  0xfffc4000
-#define AT572D940HF_BASE_SPI0  0xfffc8000
-#define AT572D940HF_BASE_SPI1  0xfffcc000
-#define AT572D940HF_BASE_SSC3  0xfffd0000
-#define AT572D940HF_BASE_TWI1  0xfffd4000
-#define AT572D940HF_BASE_EMAC  0xfffd8000
-#define AT572D940HF_BASE_CAN0  0xfffdc000
-#define AT572D940HF_BASE_CAN1  0xfffe0000
-#define AT91_BASE_SYS          0xffffea00
-
-
-/*
- * System Peripherals (offset from AT91_BASE_SYS)
- */
-#define AT91_SDRAMC0   (0xffffea00 - AT91_BASE_SYS)
-#define AT91_SMC       (0xffffec00 - AT91_BASE_SYS)
-#define AT91_MATRIX    (0xffffee00 - AT91_BASE_SYS)
-#define AT91_AIC       (0xfffff000 - AT91_BASE_SYS)
-#define AT91_DBGU      (0xfffff200 - AT91_BASE_SYS)
-#define AT91_PIOA      (0xfffff400 - AT91_BASE_SYS)
-#define AT91_PIOB      (0xfffff600 - AT91_BASE_SYS)
-#define AT91_PIOC      (0xfffff800 - AT91_BASE_SYS)
-#define AT91_PMC       (0xfffffc00 - AT91_BASE_SYS)
-#define AT91_RSTC      (0xfffffd00 - AT91_BASE_SYS)
-#define AT91_RTT       (0xfffffd20 - AT91_BASE_SYS)
-#define AT91_PIT       (0xfffffd30 - AT91_BASE_SYS)
-#define AT91_WDT       (0xfffffd40 - AT91_BASE_SYS)
-
-#define AT91_USART0    AT572D940HF_ID_US0
-#define AT91_USART1    AT572D940HF_ID_US1
-#define AT91_USART2    AT572D940HF_ID_US2
-
-
-/*
- * Internal Memory.
- */
-#define AT572D940HF_SRAM_BASE  0x00300000      /* Internal SRAM base address */
-#define AT572D940HF_SRAM_SIZE  (48 * SZ_1K)    /* Internal SRAM size (48Kb) */
-
-#define AT572D940HF_ROM_BASE   0x00400000      /* Internal ROM base address */
-#define AT572D940HF_ROM_SIZE   SZ_32K          /* Internal ROM size (32Kb) */
-
-#define AT572D940HF_UHP_BASE   0x00500000      /* USB Host controller */
-
-
-#endif
diff --git a/arch/arm/mach-at91/include/mach/at572d940hf_matrix.h b/arch/arm/mach-at91/include/mach/at572d940hf_matrix.h
deleted file mode 100644 (file)
index b6751df..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * include/mach//at572d940hf_matrix.h
- *
- * Antonio R. Costa <costa.antonior@gmail.com>
- * Copyright (C) 2008 Atmel
- *
- * Copyright (C) 2005 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef AT572D940HF_MATRIX_H
-#define AT572D940HF_MATRIX_H
-
-#define AT91_MATRIX_MCFG0      (AT91_MATRIX + 0x00)    /* Master Configuration Register 0 */
-#define AT91_MATRIX_MCFG1      (AT91_MATRIX + 0x04)    /* Master Configuration Register 1 */
-#define AT91_MATRIX_MCFG2      (AT91_MATRIX + 0x08)    /* Master Configuration Register 2 */
-#define AT91_MATRIX_MCFG3      (AT91_MATRIX + 0x0C)    /* Master Configuration Register 3 */
-#define AT91_MATRIX_MCFG4      (AT91_MATRIX + 0x10)    /* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5      (AT91_MATRIX + 0x14)    /* Master Configuration Register 5 */
-
-#define                AT91_MATRIX_ULBT        (7 << 0)        /* Undefined Length Burst Type */
-#define                        AT91_MATRIX_ULBT_INFINITE       (0 << 0)
-#define                        AT91_MATRIX_ULBT_SINGLE         (1 << 0)
-#define                        AT91_MATRIX_ULBT_FOUR           (2 << 0)
-#define                        AT91_MATRIX_ULBT_EIGHT          (3 << 0)
-#define                        AT91_MATRIX_ULBT_SIXTEEN        (4 << 0)
-
-#define AT91_MATRIX_SCFG0      (AT91_MATRIX + 0x40)    /* Slave Configuration Register 0 */
-#define AT91_MATRIX_SCFG1      (AT91_MATRIX + 0x44)    /* Slave Configuration Register 1 */
-#define AT91_MATRIX_SCFG2      (AT91_MATRIX + 0x48)    /* Slave Configuration Register 2 */
-#define AT91_MATRIX_SCFG3      (AT91_MATRIX + 0x4C)    /* Slave Configuration Register 3 */
-#define AT91_MATRIX_SCFG4      (AT91_MATRIX + 0x50)    /* Slave Configuration Register 4 */
-#define                AT91_MATRIX_SLOT_CYCLE          (0xff << 0)     /* Maximum Number of Allowed Cycles for a Burst */
-#define                AT91_MATRIX_DEFMSTR_TYPE        (3    << 16)    /* Default Master Type */
-#define                        AT91_MATRIX_DEFMSTR_TYPE_NONE   (0 << 16)
-#define                        AT91_MATRIX_DEFMSTR_TYPE_LAST   (1 << 16)
-#define                        AT91_MATRIX_DEFMSTR_TYPE_FIXED  (2 << 16)
-#define                AT91_MATRIX_FIXED_DEFMSTR       (0x7  << 18)    /* Fixed Index of Default Master */
-#define                AT91_MATRIX_ARBT                (3    << 24)    /* Arbitration Type */
-#define                        AT91_MATRIX_ARBT_ROUND_ROBIN    (0 << 24)
-#define                        AT91_MATRIX_ARBT_FIXED_PRIORITY (1 << 24)
-
-#define AT91_MATRIX_PRAS0      (AT91_MATRIX + 0x80)    /* Priority Register A for Slave 0 */
-#define AT91_MATRIX_PRAS1      (AT91_MATRIX + 0x88)    /* Priority Register A for Slave 1 */
-#define AT91_MATRIX_PRAS2      (AT91_MATRIX + 0x90)    /* Priority Register A for Slave 2 */
-#define AT91_MATRIX_PRAS3      (AT91_MATRIX + 0x98)    /* Priority Register A for Slave 3 */
-#define AT91_MATRIX_PRAS4      (AT91_MATRIX + 0xA0)    /* Priority Register A for Slave 4 */
-
-#define                AT91_MATRIX_M0PR                (3 << 0)        /* Master 0 Priority */
-#define                AT91_MATRIX_M1PR                (3 << 4)        /* Master 1 Priority */
-#define                AT91_MATRIX_M2PR                (3 << 8)        /* Master 2 Priority */
-#define                AT91_MATRIX_M3PR                (3 << 12)       /* Master 3 Priority */
-#define                AT91_MATRIX_M4PR                (3 << 16)       /* Master 4 Priority */
-#define                AT91_MATRIX_M5PR                (3 << 20)       /* Master 5 Priority */
-#define                AT91_MATRIX_M6PR                (3 << 24)       /* Master 6 Priority */
-
-#define AT91_MATRIX_MRCR       (AT91_MATRIX + 0x100)   /* Master Remap Control Register */
-#define                AT91_MATRIX_RCB0                (1 << 0)        /* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
-#define                AT91_MATRIX_RCB1                (1 << 1)        /* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
-
-#define AT91_MATRIX_SFR0       (AT91_MATRIX + 0x110)   /* Special Function Register 0 */
-#define AT91_MATRIX_SFR1       (AT91_MATRIX + 0x114)   /* Special Function Register 1 */
-#define AT91_MATRIX_SFR2       (AT91_MATRIX + 0x118)   /* Special Function Register 2 */
-#define AT91_MATRIX_SFR3       (AT91_MATRIX + 0x11C)   /* Special Function Register 3 */
-#define AT91_MATRIX_SFR4       (AT91_MATRIX + 0x120)   /* Special Function Register 4 */
-#define AT91_MATRIX_SFR5       (AT91_MATRIX + 0x124)   /* Special Function Register 5 */
-#define AT91_MATRIX_SFR6       (AT91_MATRIX + 0x128)   /* Special Function Register 6 */
-#define AT91_MATRIX_SFR7       (AT91_MATRIX + 0x12C)   /* Special Function Register 7 */
-#define AT91_MATRIX_SFR8       (AT91_MATRIX + 0x130)   /* Special Function Register 8 */
-#define AT91_MATRIX_SFR9       (AT91_MATRIX + 0x134)   /* Special Function Register 9 */
-#define AT91_MATRIX_SFR10      (AT91_MATRIX + 0x138)   /* Special Function Register 10 */
-#define AT91_MATRIX_SFR11      (AT91_MATRIX + 0x13C)   /* Special Function Register 11 */
-#define AT91_MATRIX_SFR12      (AT91_MATRIX + 0x140)   /* Special Function Register 12 */
-#define AT91_MATRIX_SFR13      (AT91_MATRIX + 0x144)   /* Special Function Register 13 */
-#define AT91_MATRIX_SFR14      (AT91_MATRIX + 0x148)   /* Special Function Register 14 */
-#define AT91_MATRIX_SFR15      (AT91_MATRIX + 0x14C)   /* Special Function Register 15 */
-
-
-/*
- * The following registers / bits are not defined in the Datasheet (Revision A)
- */
-
-#define AT91_MATRIX_TCR                (AT91_MATRIX + 0x100)   /* TCM Configuration Register */
-#define                AT91_MATRIX_ITCM_SIZE           (0xf << 0)      /* Size of ITCM enabled memory block */
-#define                        AT91_MATRIX_ITCM_0              (0 << 0)
-#define                        AT91_MATRIX_ITCM_16             (5 << 0)
-#define                        AT91_MATRIX_ITCM_32             (6 << 0)
-#define                        AT91_MATRIX_ITCM_64             (7 << 0)
-#define                AT91_MATRIX_DTCM_SIZE           (0xf << 4)      /* Size of DTCM enabled memory block */
-#define                        AT91_MATRIX_DTCM_0              (0 << 4)
-#define                        AT91_MATRIX_DTCM_16             (5 << 4)
-#define                        AT91_MATRIX_DTCM_32             (6 << 4)
-#define                        AT91_MATRIX_DTCM_64             (7 << 4)
-
-#define AT91_MATRIX_EBICSA     (AT91_MATRIX + 0x11C)   /* EBI Chip Select Assignment Register */
-#define                AT91_MATRIX_CS1A                (1 << 1)        /* Chip Select 1 Assignment */
-#define                        AT91_MATRIX_CS1A_SMC            (0 << 1)
-#define                        AT91_MATRIX_CS1A_SDRAMC         (1 << 1)
-#define                AT91_MATRIX_CS3A                (1 << 3)        /* Chip Select 3 Assignment */
-#define                        AT91_MATRIX_CS3A_SMC            (0 << 3)
-#define                        AT91_MATRIX_CS3A_SMC_SMARTMEDIA (1 << 3)
-#define                AT91_MATRIX_CS4A                (1 << 4)        /* Chip Select 4 Assignment */
-#define                        AT91_MATRIX_CS4A_SMC            (0 << 4)
-#define                        AT91_MATRIX_CS4A_SMC_CF1        (1 << 4)
-#define                AT91_MATRIX_CS5A                (1 << 5)        /* Chip Select 5 Assignment */
-#define                        AT91_MATRIX_CS5A_SMC            (0 << 5)
-#define                        AT91_MATRIX_CS5A_SMC_CF2        (1 << 5)
-#define                AT91_MATRIX_DBPUC               (1 << 8)        /* Data Bus Pull-up Configuration */
-
-#endif
index 9c6af97374851a72d2481a0fc4b03ba64781eff8..665993849a7b99f44fc97a8d06578b0578971ecc 100644 (file)
@@ -20,8 +20,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
 #define AT91CAP9_ID_PIOABCD    2       /* Parallel IO Controller A, B, C and D */
 #define AT91CAP9_ID_MPB0       3       /* MP Block Peripheral 0 */
 #define AT91CAP9_ID_MPB1       4       /* MP Block Peripheral 1 */
 #define AT91CAP9_UDPHS_FIFO    0x00600000      /* USB High Speed Device Port */
 #define AT91CAP9_UHP_BASE      0x00700000      /* USB Host controller */
 
-#define CONFIG_DRAM_BASE       AT91_CHIPSELECT_6
-
 #endif
index 78983155a074c74b18873deaa3d736b65f4a831e..99e0f8d02d7bc492727def41a71dfbe8e11e2536 100644 (file)
@@ -19,8 +19,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripheral */
 #define AT91RM9200_ID_PIOA     2       /* Parallel IO Controller A */
 #define AT91RM9200_ID_PIOB     3       /* Parallel IO Controller B */
 #define AT91RM9200_ID_PIOC     4       /* Parallel IO Controller C */
index 4e79036d3b801849ea8f547e6dd6fdf8b16d894e..8b6bf835cd733cf88ebc9fab564381d125b2a40a 100644 (file)
@@ -20,8 +20,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
 #define AT91SAM9260_ID_PIOA    2       /* Parallel IO Controller A */
 #define AT91SAM9260_ID_PIOB    3       /* Parallel IO Controller B */
 #define AT91SAM9260_ID_PIOC    4       /* Parallel IO Controller C */
index 2b561851812952fe60e8b44fa1d44641fcdd81bc..eafbddaf523c9e702d2316f66b62bd07e01f2df6 100644 (file)
@@ -18,8 +18,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
 #define AT91SAM9261_ID_PIOA    2       /* Parallel IO Controller A */
 #define AT91SAM9261_ID_PIOB    3       /* Parallel IO Controller B */
 #define AT91SAM9261_ID_PIOC    4       /* Parallel IO Controller C */
index 2091f1e42d43c32931f7f6b327f4a056a8f54bbf..e2d348213a7be7ca8796aa3dff77efda48e56f06 100644 (file)
@@ -18,8 +18,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Peripherals */
 #define AT91SAM9263_ID_PIOA    2       /* Parallel IO Controller A */
 #define AT91SAM9263_ID_PIOB    3       /* Parallel IO Controller B */
 #define AT91SAM9263_ID_PIOCDE  4       /* Parallel IO Controller C, D and E */
index a526869aee377a198d439d639091b3856f705f50..659304aa73d939176d6197acd548e50370e0e821 100644 (file)
@@ -18,8 +18,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Controller Interrupt */
 #define AT91SAM9G45_ID_PIOA    2       /* Parallel I/O Controller A */
 #define AT91SAM9G45_ID_PIOB    3       /* Parallel I/O Controller B */
 #define AT91SAM9G45_ID_PIOC    4       /* Parallel I/O Controller C */
 #define AT91SAM9G45_EHCI_BASE  0x00800000      /* USB Host controller (EHCI) */
 #define AT91SAM9G45_VDEC_BASE  0x00900000      /* Video Decoder Controller */
 
-#define CONFIG_DRAM_BASE       AT91_CHIPSELECT_6
-
 #define CONSISTENT_DMA_SIZE    SZ_4M
 
 /*
index 87ba8517ad98291a12749853cfc7379e021c4997..41dbbe61055c5c5ad50d1d66c1e7e0f08805af5c 100644 (file)
@@ -17,8 +17,6 @@
 /*
  * Peripheral identifiers/interrupts.
  */
-#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS            1       /* System Controller */
 #define AT91SAM9RL_ID_PIOA     2       /* Parallel IO Controller A */
 #define AT91SAM9RL_ID_PIOB     3       /* Parallel IO Controller B */
 #define AT91SAM9RL_ID_PIOC     4       /* Parallel IO Controller C */
index 063ac44a020423119b52749dc3c866b6dd7eb965..a152ff87e688ea48792be4733643b1b9fb2c5c89 100644 (file)
@@ -15,8 +15,6 @@
 /*
  *     IRQ list.
  */
-#define AT91_ID_FIQ            0       /* FIQ */
-#define AT91_ID_SYS            1       /* System Peripheral */
 #define AT91X40_ID_USART0      2       /* USART port 0 */
 #define AT91X40_ID_USART1      3       /* USART port 1 */
 #define AT91X40_ID_TC0         4       /* Timer/Counter 0 */
index 2b499eb343a12a082ad5d0a862c0fb3fb9e722a5..ed544a0d5a1d8b5ce5bc4681ed7e83ef704ab41d 100644 (file)
@@ -90,7 +90,7 @@ struct at91_eth_data {
 extern void __init at91_add_device_eth(struct at91_eth_data *data);
 
 #if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91SAM9G20) || defined(CONFIG_ARCH_AT91CAP9) \
-       || defined(CONFIG_ARCH_AT91SAM9G45) || defined(CONFIG_ARCH_AT572D940HF)
+       || defined(CONFIG_ARCH_AT91SAM9G45)
 #define eth_platform_data      at91_eth_data
 #endif
 
@@ -140,6 +140,7 @@ extern void __init at91_set_serial_console(unsigned portnr);
 extern struct platform_device *atmel_default_console_device;
 
 struct atmel_uart_data {
+       int                     num;            /* port num */
        short                   use_dma_tx;     /* use transmit DMA? */
        short                   use_dma_rx;     /* use receive DMA? */
        void __iomem            *regs;          /* virt. base address, if any */
@@ -203,9 +204,6 @@ extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
 extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
 extern void __init at91_pwm_leds(struct gpio_led *leds, int nr);
 
- /* AT572D940HF DSP */
-extern void __init at91_add_device_mAgic(void);
-
 /* FIXME: this needs a better location, but gets stuff building again */
 extern int at91_suspend_entering_slow_clock(void);
 
diff --git a/arch/arm/mach-at91/include/mach/clkdev.h b/arch/arm/mach-at91/include/mach/clkdev.h
new file mode 100644 (file)
index 0000000..04b37a8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_MACH_CLKDEV_H
+#define __ASM_MACH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
index 0700f2125305d99fd769f46726fe1e09afaa3dcc..df966c2bc2d448e032333ac566a5a2adbe3ee034 100644 (file)
@@ -34,8 +34,6 @@
 #define ARCH_ID_AT91SAM9XE256  0x329a93a0
 #define ARCH_ID_AT91SAM9XE512  0x329aa3a0
 
-#define ARCH_ID_AT572D940HF    0x0e0303e0
-
 #define ARCH_ID_AT91M40800     0x14080044
 #define ARCH_ID_AT91R40807     0x44080746
 #define ARCH_ID_AT91M40807     0x14080745
@@ -90,9 +88,16 @@ static inline unsigned long at91cap9_rev_identify(void)
 #endif
 
 #ifdef CONFIG_ARCH_AT91RM9200
+extern int rm9200_type;
+#define ARCH_REVISON_9200_BGA  (0 << 0)
+#define ARCH_REVISON_9200_PQFP (1 << 0)
 #define cpu_is_at91rm9200()    (at91_cpu_identify() == ARCH_ID_AT91RM9200)
+#define cpu_is_at91rm9200_bga()        (!cpu_is_at91rm9200_pqfp())
+#define cpu_is_at91rm9200_pqfp() (cpu_is_at91rm9200() && rm9200_type & ARCH_REVISON_9200_PQFP)
 #else
 #define cpu_is_at91rm9200()    (0)
+#define cpu_is_at91rm9200_bga()        (0)
+#define cpu_is_at91rm9200_pqfp() (0)
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9260
@@ -181,12 +186,6 @@ static inline unsigned long at91cap9_rev_identify(void)
 #define cpu_is_at91cap9_revC() (0)
 #endif
 
-#ifdef CONFIG_ARCH_AT572D940HF
-#define cpu_is_at572d940hf() (at91_cpu_identify() == ARCH_ID_AT572D940HF)
-#else
-#define cpu_is_at572d940hf() (0)
-#endif
-
 /*
  * Since this is ARM, we will never run on any AVR32 CPU. But these
  * definitions may reduce clutter in common drivers.
index 3d64a75e3ed5be8a0566b343653b3af965a47c6f..1008b9fb50741ecf77a979ff2fc239f78f781632 100644 (file)
 #include <mach/at91cap9.h>
 #elif defined(CONFIG_ARCH_AT91X40)
 #include <mach/at91x40.h>
-#elif defined(CONFIG_ARCH_AT572D940HF)
-#include <mach/at572d940hf.h>
 #else
 #error "Unsupported AT91 processor"
 #endif
 
 
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91_ID_FIQ            0       /* Advanced Interrupt Controller (FIQ) */
+#define AT91_ID_SYS            1       /* System Peripherals */
+
 #ifdef CONFIG_MMU
 /*
  * Remap the peripherals from address 0xFFF78000 .. 0xFFFFFFFF
 #define AT91_CHIPSELECT_6      0x70000000
 #define AT91_CHIPSELECT_7      0x80000000
 
-/* SDRAM */
-#ifdef CONFIG_DRAM_BASE
-#define AT91_SDRAM_BASE                CONFIG_DRAM_BASE
-#else
-#define AT91_SDRAM_BASE                AT91_CHIPSELECT_1
-#endif
-
 /* Clocks */
 #define AT91_SLOW_CLOCK                32768           /* slow clock */
 
index c2cfe5040642982891cfc6a0ea2d684ab33dd037..401c207f2f39c8e3af445183794d70e14c518e49 100644 (file)
@@ -23,6 +23,4 @@
 
 #include <mach/hardware.h>
 
-#define PLAT_PHYS_OFFSET       (AT91_SDRAM_BASE)
-
 #endif
index 6120f9c46d59aad836994464989a5aaa9ce2efc4..f62c0abca4b4fffa60a1c7fe25454f37b32795ec 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __MACH_STAMP9G20_H
 #define __MACH_STAMP9G20_H
 
-void stamp9g20_map_io(void);
+void stamp9g20_init_early(void);
 void stamp9g20_board_init(void);
 
 #endif
diff --git a/arch/arm/mach-at91/include/mach/system_rev.h b/arch/arm/mach-at91/include/mach/system_rev.h
new file mode 100644 (file)
index 0000000..b855ee7
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2 only
+ */
+
+#ifndef __ARCH_SYSTEM_REV_H__
+#define __ARCH_SYSTEM_REV_H__
+
+/*
+ * board revision encoding
+ * mach specific
+ * the 16-31 bit are reserved for at91 generic information
+ *
+ * bit 31:
+ *     0 => nand 16 bit
+ *     1 => nand 8 bit
+ */
+#define BOARD_HAVE_NAND_8BIT   (1 << 31)
+static int inline board_have_nand_8bit(void)
+{
+       return system_rev & BOARD_HAVE_NAND_8BIT;
+}
+
+#endif /* __ARCH_SYSTEM_REV_H__ */
index 05a6e8af80c4e1f3c4b4983c88821c1e1bd0ad26..31ac2d97f14cb24b85371b259a2c70b27fc6a461 100644 (file)
 #define AT91X40_MASTER_CLOCK   40000000
 #define CLOCK_TICK_RATE                (AT91X40_MASTER_CLOCK)
 
-#elif defined(CONFIG_ARCH_AT572D940HF)
-
-#define AT572D940HF_MASTER_CLOCK       80000000
-#define CLOCK_TICK_RATE                (AT572D940HF_MASTER_CLOCK/16)
-
 #endif
 
 #endif
index 04c779832c78efb86eb590cd063171925af91a25..4f3572a1c684422bbf00e4c2990d472285c7fba8 100644 (file)
@@ -50,13 +50,11 @@ struct tegra_kbc_platform_data {
        unsigned int debounce_cnt;
        unsigned int repeat_cnt;
 
-       unsigned int wake_cnt; /* 0:wake on any key >1:wake on wake_cfg */
-       const struct tegra_kbc_wake_key *wake_cfg;
-
        struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
        const struct matrix_keymap_data *keymap_data;
 
        bool wakeup;
        bool use_fn_map;
+       bool use_ghost_filter;
 };
 #endif
index 6e1907fa94f0405a788acd8896b9202a8a4c67c0..bb26f40493e697ffe9a6805ae65acd896b9e12e5 100644 (file)
@@ -204,7 +204,7 @@ static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
        },
 };
 
-#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
+#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, t_out, _sm)   \
 static struct nmk_i2c_controller u8500_i2c##id##_data = { \
        /*                              \
         * slave data setup time, which is      \
@@ -219,19 +219,21 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \
        .rft            = _rft,         \
        /* std. mode operation */       \
        .clk_freq       = clk,          \
+       /* Slave response timeout(ms) */\
+       .timeout        = t_out,        \
        .sm             = _sm,          \
 }
 
 /*
  * The board uses 4 i2c controllers, initialize all of
  * them with slave data setup time of 250 ns,
- * Tx & Rx FIFO threshold values as 1 and standard
+ * Tx & Rx FIFO threshold values as 8 and standard
  * mode of operation
  */
-U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(2,        0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(3,        0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
+U8500_I2C_CONTROLLER(0, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(2,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(3,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 
 static void __init mop500_i2c_init(void)
 {
index 1621db67a53dedec35b848a8230c6e276100fca6..8ba70ffc31ecaceb2adaf7d421eea9c900fe2b6a 100644 (file)
@@ -11,8 +11,8 @@
 enum i2c_freq_mode {
        I2C_FREQ_MODE_STANDARD,         /* up to 100 Kb/s */
        I2C_FREQ_MODE_FAST,             /* up to 400 Kb/s */
+       I2C_FREQ_MODE_HIGH_SPEED,       /* up to 3.4 Mb/s */
        I2C_FREQ_MODE_FAST_PLUS,        /* up to 1 Mb/s */
-       I2C_FREQ_MODE_HIGH_SPEED        /* up to 3.4 Mb/s */
 };
 
 /**
@@ -24,13 +24,15 @@ enum i2c_freq_mode {
  *             to the values of 14, 6, 2 for a 48 MHz i2c clk
  * @tft:       Tx FIFO Threshold in bytes
  * @rft:       Rx FIFO Threshold in bytes
+ * @timeout    Slave response timeout(ms)
  * @sm:                speed mode
  */
 struct nmk_i2c_controller {
        unsigned long   clk_freq;
        unsigned short  slsu;
-       unsigned char   tft;
-       unsigned char   rft;
+       unsigned char   tft;
+       unsigned char   rft;
+       int timeout;
        enum i2c_freq_mode      sm;
 };
 
index bfc9d071db9bce219985b62a5c80446ff7a1f3e5..aa677e2a3823d89272ed42a367400be93598c2fa 100644 (file)
@@ -1014,6 +1014,7 @@ static struct platform_device *__initdata at32_usarts[4];
 void __init at32_map_usart(unsigned int hw_id, unsigned int line, int flags)
 {
        struct platform_device *pdev;
+       struct atmel_uart_data *pdata;
 
        switch (hw_id) {
        case 0:
@@ -1042,7 +1043,8 @@ void __init at32_map_usart(unsigned int hw_id, unsigned int line, int flags)
                data->regs = (void __iomem *)pdev->resource[0].start;
        }
 
-       pdev->id = line;
+       pdata = pdev->dev.platform_data;
+       pdata->num = portnr;
        at32_usarts[line] = pdev;
 }
 
index 61740201b3115eb7988ff3eca6728195f5d90d8b..679458d9a622365afd30fe371c229567dedc83cb 100644 (file)
@@ -33,6 +33,7 @@ extern struct platform_device *atmel_default_console_device;
 #define        ATMEL_USART_CLK         0x04
 
 struct atmel_uart_data {
+       int             num;            /* port num */
        short           use_dma_tx;     /* use transmit DMA? */
        short           use_dma_rx;     /* use receive DMA? */
        void __iomem    *regs;          /* virtual base address, if any */
index 854fa49f1c3ec964f7f105fd9c0019d133cca420..8d85c8c6f857c5dd985bd4f2bbd07b4668b157fb 100644 (file)
@@ -136,7 +136,7 @@ SECTIONS
 
        . = ALIGN(16);
        INIT_DATA_SECTION(16)
-       PERCPU(32, PAGE_SIZE)
+       PERCPU_SECTION(32)
 
        .exit.data :
        {
index 728bbd9e7d4c1105b802cbc53558e54c350db93a..a6990cb0f098772c8739b8e7e738789414af7dc8 100644 (file)
@@ -102,7 +102,7 @@ SECTIONS
 #endif
        __vmlinux_end = .;              /* Last address of the physical file. */
 #ifdef CONFIG_ETRAX_ARCH_V32
-       PERCPU(32, PAGE_SIZE)
+       PERCPU_SECTION(32)
 
        .init.ramfs : {
                INIT_RAM_FS
index 0daae8af5787bfd44fe467689b2fdbd2e7b73289..7e958d829ec9810020c75eca7beef1cbfd44a3c2 100644 (file)
@@ -37,7 +37,7 @@ SECTIONS
   _einittext = .;
 
   INIT_DATA_SECTION(8)
-  PERCPU(L1_CACHE_BYTES, 4096)
+  PERCPU_SECTION(L1_CACHE_BYTES)
 
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
index cf95aec77460687134d40c0185cd86b95d7aceac..018e4a711d7927cef577e347dac93fb3a22afd75 100644 (file)
@@ -54,7 +54,7 @@ SECTIONS
   __init_begin = .;
   INIT_TEXT_SECTION(PAGE_SIZE)
   INIT_DATA_SECTION(16)
-  PERCPU(32, PAGE_SIZE)
+  PERCPU_SECTION(32)
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
   /* freed after init ends here */
index 75531da02a40a602cd3cabd5a11f041f7786b4a0..d66e34c718d0927a6eba9daa9a023b7e3bcd228a 100644 (file)
@@ -5,6 +5,7 @@ config M68K
        select HAVE_AOUT if MMU
        select GENERIC_ATOMIC64 if MMU
        select HAVE_GENERIC_HARDIRQS if !MMU
+       select GENERIC_IRQ_SHOW if !MMU
 
 config RWSEM_GENERIC_SPINLOCK
        bool
index 7d3779fdc5b6ffa68c6b7374fa106cbb50fd4bb8..6b0e2d349f0eb2439c0f6663fd643944e3707394 100644 (file)
@@ -246,23 +246,7 @@ static inline int __test_and_clear_bit_le(int nr, volatile void *addr)
        return retval;
 }
 
-#define ext2_set_bit_atomic(lock, nr, addr)            \
-       ({                                              \
-               int ret;                                \
-               spin_lock(lock);                        \
-               ret = __test_and_set_bit_le((nr), (addr));      \
-               spin_unlock(lock);                      \
-               ret;                                    \
-       })
-
-#define ext2_clear_bit_atomic(lock, nr, addr)          \
-       ({                                              \
-               int ret;                                \
-               spin_lock(lock);                        \
-               ret = __test_and_clear_bit_le((nr), (addr));    \
-               spin_unlock(lock);                      \
-               ret;                                    \
-       })
+#include <asm-generic/bitops/ext2-atomic.h>
 
 static inline int test_bit_le(int nr, const volatile void *addr)
 {
index cf20f3097af6f3e31c7c6ab76b7363b9dcc99615..353bf754a9725a490e12eb9528555d256fd797fd 100644 (file)
@@ -144,8 +144,10 @@ static inline void io_insl(unsigned int addr, void *buf, int len)
 #define IOMAP_NOCACHE_NONSER           2
 #define IOMAP_WRITETHROUGH             3
 
-extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag);
-
+static inline void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+{
+       return (void *) physaddr;
+}
 static inline void *ioremap(unsigned long physaddr, unsigned long size)
 {
        return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
@@ -163,7 +165,7 @@ static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size
        return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
 }
 
-extern void iounmap(void *addr);
+#define        iounmap(addr)   do { } while(0)
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
index 59a69a5c62f25243bb9ddbb3195ee1b3d1469bf8..983fed9d469b3979ed8f5e251631434e6ad1f61b 100644 (file)
@@ -1,5 +1,105 @@
-#ifdef CONFIG_MMU
-#include "asm-offsets_mm.c"
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#define ASM_OFFSETS_C
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/kbuild.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <linux/font.h>
+
+int main(void)
+{
+       /* offsets into the task struct */
+       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+       DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
+       DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
+
+       /* offsets into the thread struct */
+       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
+       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
+       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
+       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
+       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
+       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
+       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
+       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
+
+       /* offsets into the thread_info struct */
+       DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
+       DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
+
+       /* offsets into the pt_regs */
+       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
+       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
+       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
+       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
+       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
+       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
+       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
+       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
+       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
+       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
+       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
+
+       /* bitfields are a bit difficult */
+#ifdef CONFIG_COLDFIRE
+       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
 #else
-#include "asm-offsets_no.c"
+       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
+#endif
+
+       /* offsets into the irq_cpustat_t struct */
+       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
+
+       /* signal defines */
+       DEFINE(LSIGSEGV, SIGSEGV);
+       DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
+       DEFINE(LSIGTRAP, SIGTRAP);
+       DEFINE(LTRAP_TRACE, TRAP_TRACE);
+
+#ifdef CONFIG_MMU
+       /* offsets into the bi_record struct */
+       DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
+       DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
+       DEFINE(BIR_DATA, offsetof(struct bi_record, data));
+
+       /* offsets into font_desc (drivers/video/console/font.h) */
+       DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
+       DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
+       DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
+       DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
+       DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
+       DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
+
+       /* offsets into the custom struct */
+       DEFINE(CUSTOMBASE, &amiga_custom);
+       DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
+       DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
+       DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
+       DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
+       DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
+       DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
+       DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
+       DEFINE(CIAABASE, &ciaa);
+       DEFINE(CIABBASE, &ciab);
+       DEFINE(C_PRA, offsetof(struct CIA, pra));
+       DEFINE(ZTWOBASE, zTwoBase);
 #endif
+
+       return 0;
+}
diff --git a/arch/m68k/kernel/asm-offsets_mm.c b/arch/m68k/kernel/asm-offsets_mm.c
deleted file mode 100644 (file)
index 78e59b8..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- */
-
-#define ASM_OFFSETS_C
-
-#include <linux/stddef.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/kbuild.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/amigahw.h>
-#include <linux/font.h>
-
-int main(void)
-{
-       /* offsets into the task struct */
-       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
-       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-#ifdef CONFIG_MMU
-       DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
-#endif
-
-       /* offsets into the thread struct */
-       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
-       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
-       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
-       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
-       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
-       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
-       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
-       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
-       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
-
-       /* offsets into the thread_info struct */
-       DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
-       DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
-
-       /* offsets into the pt_regs */
-       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
-       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
-       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
-       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
-       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
-       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
-       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
-       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
-       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
-       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
-       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
-       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
-       /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
-
-       /* offsets into the irq_cpustat_t struct */
-       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
-
-       /* offsets into the bi_record struct */
-       DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
-       DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
-       DEFINE(BIR_DATA, offsetof(struct bi_record, data));
-
-       /* offsets into font_desc (drivers/video/console/font.h) */
-       DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
-       DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
-       DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
-       DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
-       DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
-       DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
-
-       /* signal defines */
-       DEFINE(LSIGSEGV, SIGSEGV);
-       DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
-       DEFINE(LSIGTRAP, SIGTRAP);
-       DEFINE(LTRAP_TRACE, TRAP_TRACE);
-
-       /* offsets into the custom struct */
-       DEFINE(CUSTOMBASE, &amiga_custom);
-       DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
-       DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
-       DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
-       DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
-       DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
-       DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
-       DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
-       DEFINE(CIAABASE, &ciaa);
-       DEFINE(CIABBASE, &ciab);
-       DEFINE(C_PRA, offsetof(struct CIA, pra));
-       DEFINE(ZTWOBASE, zTwoBase);
-
-       return 0;
-}
diff --git a/arch/m68k/kernel/asm-offsets_no.c b/arch/m68k/kernel/asm-offsets_no.c
deleted file mode 100644 (file)
index ffe02f4..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- */
-
-#include <linux/stddef.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/ptrace.h>
-#include <linux/hardirq.h>
-#include <linux/kbuild.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/thread_info.h>
-
-int main(void)
-{
-       /* offsets into the task struct */
-       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-
-       /* offsets into the irq_cpustat_t struct */
-       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
-
-       /* offsets into the thread struct */
-       DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
-       DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
-       DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
-       DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
-       DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
-       DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
-       DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
-       DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
-       DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
-
-       /* offsets into the pt_regs */
-       DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
-       DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
-       DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
-       DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
-       DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
-       DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
-       DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
-       DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
-       DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
-       DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
-       DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
-       DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
-
-#ifdef CONFIG_COLDFIRE
-       /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
-#else
-       /* bitfields are a bit difficult */
-       DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
-#endif
-
-       /* signal defines */
-       DEFINE(SIGSEGV, SIGSEGV);
-       DEFINE(SEGV_MAPERR, SEGV_MAPERR);
-       DEFINE(SIGTRAP, SIGTRAP);
-       DEFINE(TRAP_TRACE, TRAP_TRACE);
-
-       DEFINE(PT_PTRACED, PT_PTRACED);
-
-       /* Offsets in thread_info structure */
-       DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
-       DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
-
-       return 0;
-}
index 2783f25e38bda453345bfc4994cc0853bb071965..5f0f6b598b5a6d1ee347436f6f7232491ca9ae36 100644 (file)
@@ -24,7 +24,6 @@
  * linux 2.4 support David McCullough <davidm@snapgear.com>
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/errno.h>
 #include <asm/setup.h>
index 15dbc3e9d20c5594cdf96d9655898ef7ad378285..544b8717d49913bff339695db2d25f255d4734a1 100644 (file)
@@ -28,31 +28,3 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
 
        set_irq_regs(oldregs);
 }
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-       struct irqaction *ap;
-       int irq = *((loff_t *) v);
-
-       if (irq == 0)
-               seq_puts(p, "           CPU0\n");
-
-       if (irq < NR_IRQS) {
-               struct irq_desc *desc = irq_to_desc(irq);
-
-               ap = desc->action;
-               if (ap) {
-                       seq_printf(p, "%3d: ", irq);
-                       seq_printf(p, "%10u ", kstat_irqs(irq));
-                       seq_printf(p, "%14s  ", irq_desc_get_chip(desc)->name);
-
-                       seq_printf(p, "%s", ap->name);
-                       for (ap = ap->next; ap; ap = ap->next)
-                               seq_printf(p, ", %s", ap->name);
-                       seq_putc(p, '\n');
-               }
-       }
-
-       return 0;
-}
-
index 4752c28ce0acefbb42a3f374db1636d425fcda07..33f82769547c003e85a5a3084fc09441f38c6e90 100644 (file)
@@ -1,5 +1,33 @@
-#ifdef CONFIG_MMU
-#include "m68k_ksyms_mm.c"
-#else
-#include "m68k_ksyms_no.c"
+#include <linux/module.h>
+
+asmlinkage long long __ashldi3 (long long, int);
+asmlinkage long long __ashrdi3 (long long, int);
+asmlinkage long long __lshrdi3 (long long, int);
+asmlinkage long long __muldi3 (long long, long long);
+
+/* The following are special because they're not called
+   explicitly (the C compiler generates them).  Fortunately,
+   their interface isn't gonna change any time soon now, so
+   it's OK to leave it out of version control.  */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__muldi3);
+
+#if !defined(__mc68020__) && !defined(__mc68030__) && \
+    !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcpu32__)
+/*
+ * Simpler 68k and ColdFire parts also need a few other gcc functions.
+ */
+extern long long __divsi3(long long, long long);
+extern long long __modsi3(long long, long long);
+extern long long __mulsi3(long long, long long);
+extern long long __udivsi3(long long, long long);
+extern long long __umodsi3(long long, long long);
+
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__mulsi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
 #endif
diff --git a/arch/m68k/kernel/m68k_ksyms_mm.c b/arch/m68k/kernel/m68k_ksyms_mm.c
deleted file mode 100644 (file)
index d900e77..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <linux/module.h>
-
-asmlinkage long long __ashldi3 (long long, int);
-asmlinkage long long __ashrdi3 (long long, int);
-asmlinkage long long __lshrdi3 (long long, int);
-asmlinkage long long __muldi3 (long long, long long);
-
-/* The following are special because they're not called
-   explicitly (the C compiler generates them).  Fortunately,
-   their interface isn't gonna change any time soon now, so
-   it's OK to leave it out of version control.  */
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__muldi3);
-
diff --git a/arch/m68k/kernel/m68k_ksyms_no.c b/arch/m68k/kernel/m68k_ksyms_no.c
deleted file mode 100644 (file)
index 39fe0a7..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <linux/module.h>
-#include <linux/linkage.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-
-#include <asm/setup.h>
-#include <asm/machdep.h>
-#include <asm/pgalloc.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/checksum.h>
-#include <asm/current.h>
-
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(dump_fpu);
-
-EXPORT_SYMBOL(ip_fast_csum);
-
-EXPORT_SYMBOL(kernel_thread);
-
-/* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
-
-/* The following are special because they're not called
-   explicitly (the C compiler generates them).  Fortunately,
-   their interface isn't gonna change any time soon now, so
-   it's OK to leave it out of version control.  */
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-
-/*
- * libgcc functions - functions that are used internally by the
- * compiler...  (prototypes are not correct though, but that
- * doesn't really matter since they're not versioned).
- */
-extern void __ashldi3(void);
-extern void __ashrdi3(void);
-extern void __divsi3(void);
-extern void __lshrdi3(void);
-extern void __modsi3(void);
-extern void __muldi3(void);
-extern void __mulsi3(void);
-extern void __udivsi3(void);
-extern void __umodsi3(void);
-
-        /* gcc lib functions */
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__divsi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__modsi3);
-EXPORT_SYMBOL(__muldi3);
-EXPORT_SYMBOL(__mulsi3);
-EXPORT_SYMBOL(__udivsi3);
-EXPORT_SYMBOL(__umodsi3);
-
-#ifdef CONFIG_COLDFIRE
-extern unsigned int *dma_device_address;
-extern unsigned long dma_base_addr, _ramend;
-EXPORT_SYMBOL(dma_base_addr);
-EXPORT_SYMBOL(dma_device_address);
-EXPORT_SYMBOL(_ramend);
-
-extern asmlinkage void trap(void);
-extern void    *_ramvec;
-EXPORT_SYMBOL(trap);
-EXPORT_SYMBOL(_ramvec);
-#endif /* CONFIG_COLDFIRE */
index e2a63af5d517510820cfa9085d46b08bcd403f46..9b86ad11c68e38bca9566ca3911ffff471c2cc5a 100644 (file)
@@ -151,6 +151,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
        set_fs(fs);
        return retval;
 }
+EXPORT_SYMBOL(kernel_thread);
 
 void flush_thread(void)
 {
@@ -283,6 +284,7 @@ int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
 #endif
        return 1;
 }
+EXPORT_SYMBOL(dump_fpu);
 
 /*
  *     Generic dumping code. Used for panic and debug.
index 63013df33584d79a8047f623d7f93814b1a31626..8623f8dc16f8a03c9da88910537ae93fc47bc510 100644 (file)
@@ -1,5 +1,580 @@
+/*
+ * linux/arch/m68k/kernel/sys_m68k.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/m68k
+ * platform.
+ */
+
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/ipc.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/cachectl.h>
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <asm/cacheflush.h>
+
 #ifdef CONFIG_MMU
-#include "sys_m68k_mm.c"
+
+#include <asm/tlb.h>
+
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+                            unsigned long error_code);
+
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags,
+       unsigned long fd, unsigned long pgoff)
+{
+       /*
+        * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
+        * so we need to shift the argument down by 1; m68k mmap64(3)
+        * (in libc) expects the last argument of mmap2 in 4Kb units.
+        */
+       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
+}
+
+/* Convert virtual (user) address VADDR to physical address PADDR */
+#define virt_to_phys_040(vaddr)                                                \
+({                                                                     \
+  unsigned long _mmusr, _paddr;                                                \
+                                                                       \
+  __asm__ __volatile__ (".chip 68040\n\t"                              \
+                       "ptestr (%1)\n\t"                               \
+                       "movec %%mmusr,%0\n\t"                          \
+                       ".chip 68k"                                     \
+                       : "=r" (_mmusr)                                 \
+                       : "a" (vaddr));                                 \
+  _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;            \
+  _paddr;                                                              \
+})
+
+static inline int
+cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+  unsigned long paddr, i;
+
+  switch (scope)
+    {
+    case FLUSH_SCOPE_ALL:
+      switch (cache)
+       {
+       case FLUSH_CACHE_DATA:
+         /* This nop is needed for some broken versions of the 68040.  */
+         __asm__ __volatile__ ("nop\n\t"
+                               ".chip 68040\n\t"
+                               "cpusha %dc\n\t"
+                               ".chip 68k");
+         break;
+       case FLUSH_CACHE_INSN:
+         __asm__ __volatile__ ("nop\n\t"
+                               ".chip 68040\n\t"
+                               "cpusha %ic\n\t"
+                               ".chip 68k");
+         break;
+       default:
+       case FLUSH_CACHE_BOTH:
+         __asm__ __volatile__ ("nop\n\t"
+                               ".chip 68040\n\t"
+                               "cpusha %bc\n\t"
+                               ".chip 68k");
+         break;
+       }
+      break;
+
+    case FLUSH_SCOPE_LINE:
+      /* Find the physical address of the first mapped page in the
+        address range.  */
+      if ((paddr = virt_to_phys_040(addr))) {
+        paddr += addr & ~(PAGE_MASK | 15);
+        len = (len + (addr & 15) + 15) >> 4;
+      } else {
+       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+       if (len <= tmp)
+         return 0;
+       addr += tmp;
+       len -= tmp;
+       tmp = PAGE_SIZE;
+       for (;;)
+         {
+           if ((paddr = virt_to_phys_040(addr)))
+             break;
+           if (len <= tmp)
+             return 0;
+           addr += tmp;
+           len -= tmp;
+         }
+       len = (len + 15) >> 4;
+      }
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
+      while (len--)
+       {
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushl %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushl %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushl %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+         if (!--i && len)
+           {
+             /*
+              * No need to page align here since it is done by
+              * virt_to_phys_040().
+              */
+             addr += PAGE_SIZE;
+             i = PAGE_SIZE / 16;
+             /* Recompute physical address when crossing a page
+                boundary. */
+             for (;;)
+               {
+                 if ((paddr = virt_to_phys_040(addr)))
+                   break;
+                 if (len <= i)
+                   return 0;
+                 len -= i;
+                 addr += PAGE_SIZE;
+               }
+           }
+         else
+           paddr += 16;
+       }
+      break;
+
+    default:
+    case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+       {
+         if (!(paddr = virt_to_phys_040(addr)))
+           continue;
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushp %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushp %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ ("nop\n\t"
+                                   ".chip 68040\n\t"
+                                   "cpushp %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+       }
+      break;
+    }
+  return 0;
+}
+
+#define virt_to_phys_060(vaddr)                                \
+({                                                     \
+  unsigned long paddr;                                 \
+  __asm__ __volatile__ (".chip 68060\n\t"              \
+                       "plpar (%0)\n\t"                \
+                       ".chip 68k"                     \
+                       : "=a" (paddr)                  \
+                       : "0" (vaddr));                 \
+  (paddr); /* XXX */                                   \
+})
+
+static inline int
+cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+  unsigned long paddr, i;
+
+  /*
+   * 68060 manual says:
+   *  cpush %dc : flush DC, remains valid (with our %cacr setup)
+   *  cpush %ic : invalidate IC
+   *  cpush %bc : flush DC + invalidate IC
+   */
+  switch (scope)
+    {
+    case FLUSH_SCOPE_ALL:
+      switch (cache)
+       {
+       case FLUSH_CACHE_DATA:
+         __asm__ __volatile__ (".chip 68060\n\t"
+                               "cpusha %dc\n\t"
+                               ".chip 68k");
+         break;
+       case FLUSH_CACHE_INSN:
+         __asm__ __volatile__ (".chip 68060\n\t"
+                               "cpusha %ic\n\t"
+                               ".chip 68k");
+         break;
+       default:
+       case FLUSH_CACHE_BOTH:
+         __asm__ __volatile__ (".chip 68060\n\t"
+                               "cpusha %bc\n\t"
+                               ".chip 68k");
+         break;
+       }
+      break;
+
+    case FLUSH_SCOPE_LINE:
+      /* Find the physical address of the first mapped page in the
+        address range.  */
+      len += addr & 15;
+      addr &= -16;
+      if (!(paddr = virt_to_phys_060(addr))) {
+       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+       if (len <= tmp)
+         return 0;
+       addr += tmp;
+       len -= tmp;
+       tmp = PAGE_SIZE;
+       for (;;)
+         {
+           if ((paddr = virt_to_phys_060(addr)))
+             break;
+           if (len <= tmp)
+             return 0;
+           addr += tmp;
+           len -= tmp;
+         }
+      }
+      len = (len + 15) >> 4;
+      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
+      while (len--)
+       {
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushl %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushl %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushl %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+         if (!--i && len)
+           {
+
+             /*
+              * We just want to jump to the first cache line
+              * in the next page.
+              */
+             addr += PAGE_SIZE;
+             addr &= PAGE_MASK;
+
+             i = PAGE_SIZE / 16;
+             /* Recompute physical address when crossing a page
+                boundary. */
+             for (;;)
+               {
+                 if ((paddr = virt_to_phys_060(addr)))
+                   break;
+                 if (len <= i)
+                   return 0;
+                 len -= i;
+                 addr += PAGE_SIZE;
+               }
+           }
+         else
+           paddr += 16;
+       }
+      break;
+
+    default:
+    case FLUSH_SCOPE_PAGE:
+      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+      addr &= PAGE_MASK;       /* Workaround for bug in some
+                                  revisions of the 68060 */
+      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+       {
+         if (!(paddr = virt_to_phys_060(addr)))
+           continue;
+         switch (cache)
+           {
+           case FLUSH_CACHE_DATA:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushp %%dc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           case FLUSH_CACHE_INSN:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushp %%ic,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           default:
+           case FLUSH_CACHE_BOTH:
+             __asm__ __volatile__ (".chip 68060\n\t"
+                                   "cpushp %%bc,(%0)\n\t"
+                                   ".chip 68k"
+                                   : : "a" (paddr));
+             break;
+           }
+       }
+      break;
+    }
+  return 0;
+}
+
+/* sys_cacheflush -- flush (part of) the processor cache.  */
+asmlinkage int
+sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
+{
+       struct vm_area_struct *vma;
+       int ret = -EINVAL;
+
+       if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
+           cache & ~FLUSH_CACHE_BOTH)
+               goto out;
+
+       if (scope == FLUSH_SCOPE_ALL) {
+               /* Only the superuser may explicitly flush the whole cache. */
+               ret = -EPERM;
+               if (!capable(CAP_SYS_ADMIN))
+                       goto out;
+       } else {
+               /*
+                * Verify that the specified address region actually belongs
+                * to this process.
+                */
+               vma = find_vma (current->mm, addr);
+               ret = -EINVAL;
+               /* Check for overflow.  */
+               if (addr + len < addr)
+                       goto out;
+               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
+                       goto out;
+       }
+
+       if (CPU_IS_020_OR_030) {
+               if (scope == FLUSH_SCOPE_LINE && len < 256) {
+                       unsigned long cacr;
+                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
+                       if (cache & FLUSH_CACHE_INSN)
+                               cacr |= 4;
+                       if (cache & FLUSH_CACHE_DATA)
+                               cacr |= 0x400;
+                       len >>= 2;
+                       while (len--) {
+                               __asm__ __volatile__ ("movec %1, %%caar\n\t"
+                                                     "movec %0, %%cacr"
+                                                     : /* no outputs */
+                                                     : "r" (cacr), "r" (addr));
+                               addr += 4;
+                       }
+               } else {
+                       /* Flush the whole cache, even if page granularity requested. */
+                       unsigned long cacr;
+                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
+                       if (cache & FLUSH_CACHE_INSN)
+                               cacr |= 8;
+                       if (cache & FLUSH_CACHE_DATA)
+                               cacr |= 0x800;
+                       __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
+               }
+               ret = 0;
+               goto out;
+       } else {
+           /*
+            * 040 or 060: don't blindly trust 'scope', someone could
+            * try to flush a few megs of memory.
+            */
+
+           if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
+               scope=FLUSH_SCOPE_PAGE;
+           if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
+               scope=FLUSH_SCOPE_ALL;
+           if (CPU_IS_040) {
+               ret = cache_flush_040 (addr, scope, cache, len);
+           } else if (CPU_IS_060) {
+               ret = cache_flush_060 (addr, scope, cache, len);
+           }
+       }
+out:
+       return ret;
+}
+
+/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
+   D1 (newval).  */
+asmlinkage int
+sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
+                     unsigned long __user * mem)
+{
+       /* This was borrowed from ARM's implementation.  */
+       for (;;) {
+               struct mm_struct *mm = current->mm;
+               pgd_t *pgd;
+               pmd_t *pmd;
+               pte_t *pte;
+               spinlock_t *ptl;
+               unsigned long mem_value;
+
+               down_read(&mm->mmap_sem);
+               pgd = pgd_offset(mm, (unsigned long)mem);
+               if (!pgd_present(*pgd))
+                       goto bad_access;
+               pmd = pmd_offset(pgd, (unsigned long)mem);
+               if (!pmd_present(*pmd))
+                       goto bad_access;
+               pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
+               if (!pte_present(*pte) || !pte_dirty(*pte)
+                   || !pte_write(*pte)) {
+                       pte_unmap_unlock(pte, ptl);
+                       goto bad_access;
+               }
+
+               mem_value = *mem;
+               if (mem_value == oldval)
+                       *mem = newval;
+
+               pte_unmap_unlock(pte, ptl);
+               up_read(&mm->mmap_sem);
+               return mem_value;
+
+             bad_access:
+               up_read(&mm->mmap_sem);
+               /* This is not necessarily a bad access, we can get here if
+                  a memory we're trying to write to should be copied-on-write.
+                  Make the kernel do the necessary page stuff, then re-iterate.
+                  Simulate a write access fault to do that.  */
+               {
+                       /* The first argument of the function corresponds to
+                          D1, which is the first field of struct pt_regs.  */
+                       struct pt_regs *fp = (struct pt_regs *)&newval;
+
+                       /* '3' is an RMW flag.  */
+                       if (do_page_fault(fp, (unsigned long)mem, 3))
+                               /* If the do_page_fault() failed, we don't
+                                  have anything meaningful to return.
+                                  There should be a SIGSEGV pending for
+                                  the process.  */
+                               return 0xdeadbeef;
+               }
+       }
+}
+
 #else
-#include "sys_m68k_no.c"
-#endif
+
+/* sys_cacheflush -- flush (part of) the processor cache.  */
+asmlinkage int
+sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
+{
+       flush_cache_all();
+       return 0;
+}
+
+/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
+   D1 (newval).  */
+asmlinkage int
+sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
+                     unsigned long __user * mem)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long mem_value;
+
+       down_read(&mm->mmap_sem);
+
+       mem_value = *mem;
+       if (mem_value == oldval)
+               *mem = newval;
+
+       up_read(&mm->mmap_sem);
+       return mem_value;
+}
+
+#endif /* CONFIG_MMU */
+
+asmlinkage int sys_getpagesize(void)
+{
+       return PAGE_SIZE;
+}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename,
+                 const char *const argv[],
+                 const char *const envp[])
+{
+       register long __res asm ("%d0") = __NR_execve;
+       register long __a asm ("%d1") = (long)(filename);
+       register long __b asm ("%d2") = (long)(argv);
+       register long __c asm ("%d3") = (long)(envp);
+       asm volatile ("trap  #0" : "+d" (__res)
+                       : "d" (__a), "d" (__b), "d" (__c));
+       return __res;
+}
+
+asmlinkage unsigned long sys_get_thread_area(void)
+{
+       return current_thread_info()->tp_value;
+}
+
+asmlinkage int sys_set_thread_area(unsigned long tp)
+{
+       current_thread_info()->tp_value = tp;
+       return 0;
+}
+
+asmlinkage int sys_atomic_barrier(void)
+{
+       /* no code needed for uniprocs */
+       return 0;
+}
diff --git a/arch/m68k/kernel/sys_m68k_mm.c b/arch/m68k/kernel/sys_m68k_mm.c
deleted file mode 100644 (file)
index 3db2e7f..0000000
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * linux/arch/m68k/kernel/sys_m68k.c
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/m68k
- * platform.
- */
-
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/smp.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/syscalls.h>
-#include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/ipc.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/cachectl.h>
-#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/unistd.h>
-#include <linux/elf.h>
-#include <asm/tlb.h>
-
-asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
-                            unsigned long error_code);
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-       unsigned long prot, unsigned long flags,
-       unsigned long fd, unsigned long pgoff)
-{
-       /*
-        * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
-        * so we need to shift the argument down by 1; m68k mmap64(3)
-        * (in libc) expects the last argument of mmap2 in 4Kb units.
-        */
-       return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
-}
-
-/* Convert virtual (user) address VADDR to physical address PADDR */
-#define virt_to_phys_040(vaddr)                                                \
-({                                                                     \
-  unsigned long _mmusr, _paddr;                                                \
-                                                                       \
-  __asm__ __volatile__ (".chip 68040\n\t"                              \
-                       "ptestr (%1)\n\t"                               \
-                       "movec %%mmusr,%0\n\t"                          \
-                       ".chip 68k"                                     \
-                       : "=r" (_mmusr)                                 \
-                       : "a" (vaddr));                                 \
-  _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0;            \
-  _paddr;                                                              \
-})
-
-static inline int
-cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
-{
-  unsigned long paddr, i;
-
-  switch (scope)
-    {
-    case FLUSH_SCOPE_ALL:
-      switch (cache)
-       {
-       case FLUSH_CACHE_DATA:
-         /* This nop is needed for some broken versions of the 68040.  */
-         __asm__ __volatile__ ("nop\n\t"
-                               ".chip 68040\n\t"
-                               "cpusha %dc\n\t"
-                               ".chip 68k");
-         break;
-       case FLUSH_CACHE_INSN:
-         __asm__ __volatile__ ("nop\n\t"
-                               ".chip 68040\n\t"
-                               "cpusha %ic\n\t"
-                               ".chip 68k");
-         break;
-       default:
-       case FLUSH_CACHE_BOTH:
-         __asm__ __volatile__ ("nop\n\t"
-                               ".chip 68040\n\t"
-                               "cpusha %bc\n\t"
-                               ".chip 68k");
-         break;
-       }
-      break;
-
-    case FLUSH_SCOPE_LINE:
-      /* Find the physical address of the first mapped page in the
-        address range.  */
-      if ((paddr = virt_to_phys_040(addr))) {
-        paddr += addr & ~(PAGE_MASK | 15);
-        len = (len + (addr & 15) + 15) >> 4;
-      } else {
-       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
-
-       if (len <= tmp)
-         return 0;
-       addr += tmp;
-       len -= tmp;
-       tmp = PAGE_SIZE;
-       for (;;)
-         {
-           if ((paddr = virt_to_phys_040(addr)))
-             break;
-           if (len <= tmp)
-             return 0;
-           addr += tmp;
-           len -= tmp;
-         }
-       len = (len + 15) >> 4;
-      }
-      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
-      while (len--)
-       {
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushl %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushl %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushl %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-         if (!--i && len)
-           {
-             /*
-              * No need to page align here since it is done by
-              * virt_to_phys_040().
-              */
-             addr += PAGE_SIZE;
-             i = PAGE_SIZE / 16;
-             /* Recompute physical address when crossing a page
-                boundary. */
-             for (;;)
-               {
-                 if ((paddr = virt_to_phys_040(addr)))
-                   break;
-                 if (len <= i)
-                   return 0;
-                 len -= i;
-                 addr += PAGE_SIZE;
-               }
-           }
-         else
-           paddr += 16;
-       }
-      break;
-
-    default:
-    case FLUSH_SCOPE_PAGE:
-      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
-      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
-       {
-         if (!(paddr = virt_to_phys_040(addr)))
-           continue;
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushp %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushp %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ ("nop\n\t"
-                                   ".chip 68040\n\t"
-                                   "cpushp %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-       }
-      break;
-    }
-  return 0;
-}
-
-#define virt_to_phys_060(vaddr)                                \
-({                                                     \
-  unsigned long paddr;                                 \
-  __asm__ __volatile__ (".chip 68060\n\t"              \
-                       "plpar (%0)\n\t"                \
-                       ".chip 68k"                     \
-                       : "=a" (paddr)                  \
-                       : "0" (vaddr));                 \
-  (paddr); /* XXX */                                   \
-})
-
-static inline int
-cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
-{
-  unsigned long paddr, i;
-
-  /*
-   * 68060 manual says:
-   *  cpush %dc : flush DC, remains valid (with our %cacr setup)
-   *  cpush %ic : invalidate IC
-   *  cpush %bc : flush DC + invalidate IC
-   */
-  switch (scope)
-    {
-    case FLUSH_SCOPE_ALL:
-      switch (cache)
-       {
-       case FLUSH_CACHE_DATA:
-         __asm__ __volatile__ (".chip 68060\n\t"
-                               "cpusha %dc\n\t"
-                               ".chip 68k");
-         break;
-       case FLUSH_CACHE_INSN:
-         __asm__ __volatile__ (".chip 68060\n\t"
-                               "cpusha %ic\n\t"
-                               ".chip 68k");
-         break;
-       default:
-       case FLUSH_CACHE_BOTH:
-         __asm__ __volatile__ (".chip 68060\n\t"
-                               "cpusha %bc\n\t"
-                               ".chip 68k");
-         break;
-       }
-      break;
-
-    case FLUSH_SCOPE_LINE:
-      /* Find the physical address of the first mapped page in the
-        address range.  */
-      len += addr & 15;
-      addr &= -16;
-      if (!(paddr = virt_to_phys_060(addr))) {
-       unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
-
-       if (len <= tmp)
-         return 0;
-       addr += tmp;
-       len -= tmp;
-       tmp = PAGE_SIZE;
-       for (;;)
-         {
-           if ((paddr = virt_to_phys_060(addr)))
-             break;
-           if (len <= tmp)
-             return 0;
-           addr += tmp;
-           len -= tmp;
-         }
-      }
-      len = (len + 15) >> 4;
-      i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
-      while (len--)
-       {
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushl %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushl %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushl %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-         if (!--i && len)
-           {
-
-             /*
-              * We just want to jump to the first cache line
-              * in the next page.
-              */
-             addr += PAGE_SIZE;
-             addr &= PAGE_MASK;
-
-             i = PAGE_SIZE / 16;
-             /* Recompute physical address when crossing a page
-                boundary. */
-             for (;;)
-               {
-                 if ((paddr = virt_to_phys_060(addr)))
-                   break;
-                 if (len <= i)
-                   return 0;
-                 len -= i;
-                 addr += PAGE_SIZE;
-               }
-           }
-         else
-           paddr += 16;
-       }
-      break;
-
-    default:
-    case FLUSH_SCOPE_PAGE:
-      len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
-      addr &= PAGE_MASK;       /* Workaround for bug in some
-                                  revisions of the 68060 */
-      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
-       {
-         if (!(paddr = virt_to_phys_060(addr)))
-           continue;
-         switch (cache)
-           {
-           case FLUSH_CACHE_DATA:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushp %%dc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           case FLUSH_CACHE_INSN:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushp %%ic,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           default:
-           case FLUSH_CACHE_BOTH:
-             __asm__ __volatile__ (".chip 68060\n\t"
-                                   "cpushp %%bc,(%0)\n\t"
-                                   ".chip 68k"
-                                   : : "a" (paddr));
-             break;
-           }
-       }
-      break;
-    }
-  return 0;
-}
-
-/* sys_cacheflush -- flush (part of) the processor cache.  */
-asmlinkage int
-sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
-{
-       struct vm_area_struct *vma;
-       int ret = -EINVAL;
-
-       if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
-           cache & ~FLUSH_CACHE_BOTH)
-               goto out;
-
-       if (scope == FLUSH_SCOPE_ALL) {
-               /* Only the superuser may explicitly flush the whole cache. */
-               ret = -EPERM;
-               if (!capable(CAP_SYS_ADMIN))
-                       goto out;
-       } else {
-               /*
-                * Verify that the specified address region actually belongs
-                * to this process.
-                */
-               vma = find_vma (current->mm, addr);
-               ret = -EINVAL;
-               /* Check for overflow.  */
-               if (addr + len < addr)
-                       goto out;
-               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
-                       goto out;
-       }
-
-       if (CPU_IS_020_OR_030) {
-               if (scope == FLUSH_SCOPE_LINE && len < 256) {
-                       unsigned long cacr;
-                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
-                       if (cache & FLUSH_CACHE_INSN)
-                               cacr |= 4;
-                       if (cache & FLUSH_CACHE_DATA)
-                               cacr |= 0x400;
-                       len >>= 2;
-                       while (len--) {
-                               __asm__ __volatile__ ("movec %1, %%caar\n\t"
-                                                     "movec %0, %%cacr"
-                                                     : /* no outputs */
-                                                     : "r" (cacr), "r" (addr));
-                               addr += 4;
-                       }
-               } else {
-                       /* Flush the whole cache, even if page granularity requested. */
-                       unsigned long cacr;
-                       __asm__ ("movec %%cacr, %0" : "=r" (cacr));
-                       if (cache & FLUSH_CACHE_INSN)
-                               cacr |= 8;
-                       if (cache & FLUSH_CACHE_DATA)
-                               cacr |= 0x800;
-                       __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
-               }
-               ret = 0;
-               goto out;
-       } else {
-           /*
-            * 040 or 060: don't blindly trust 'scope', someone could
-            * try to flush a few megs of memory.
-            */
-
-           if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
-               scope=FLUSH_SCOPE_PAGE;
-           if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
-               scope=FLUSH_SCOPE_ALL;
-           if (CPU_IS_040) {
-               ret = cache_flush_040 (addr, scope, cache, len);
-           } else if (CPU_IS_060) {
-               ret = cache_flush_060 (addr, scope, cache, len);
-           }
-       }
-out:
-       return ret;
-}
-
-asmlinkage int sys_getpagesize(void)
-{
-       return PAGE_SIZE;
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register long __res asm ("%d0") = __NR_execve;
-       register long __a asm ("%d1") = (long)(filename);
-       register long __b asm ("%d2") = (long)(argv);
-       register long __c asm ("%d3") = (long)(envp);
-       asm volatile ("trap  #0" : "+d" (__res)
-                       : "d" (__a), "d" (__b), "d" (__c));
-       return __res;
-}
-
-asmlinkage unsigned long sys_get_thread_area(void)
-{
-       return current_thread_info()->tp_value;
-}
-
-asmlinkage int sys_set_thread_area(unsigned long tp)
-{
-       current_thread_info()->tp_value = tp;
-       return 0;
-}
-
-/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
-   D1 (newval).  */
-asmlinkage int
-sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
-                     unsigned long __user * mem)
-{
-       /* This was borrowed from ARM's implementation.  */
-       for (;;) {
-               struct mm_struct *mm = current->mm;
-               pgd_t *pgd;
-               pmd_t *pmd;
-               pte_t *pte;
-               spinlock_t *ptl;
-               unsigned long mem_value;
-
-               down_read(&mm->mmap_sem);
-               pgd = pgd_offset(mm, (unsigned long)mem);
-               if (!pgd_present(*pgd))
-                       goto bad_access;
-               pmd = pmd_offset(pgd, (unsigned long)mem);
-               if (!pmd_present(*pmd))
-                       goto bad_access;
-               pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
-               if (!pte_present(*pte) || !pte_dirty(*pte)
-                   || !pte_write(*pte)) {
-                       pte_unmap_unlock(pte, ptl);
-                       goto bad_access;
-               }
-
-               mem_value = *mem;
-               if (mem_value == oldval)
-                       *mem = newval;
-
-               pte_unmap_unlock(pte, ptl);
-               up_read(&mm->mmap_sem);
-               return mem_value;
-
-             bad_access:
-               up_read(&mm->mmap_sem);
-               /* This is not necessarily a bad access, we can get here if
-                  a memory we're trying to write to should be copied-on-write.
-                  Make the kernel do the necessary page stuff, then re-iterate.
-                  Simulate a write access fault to do that.  */
-               {
-                       /* The first argument of the function corresponds to
-                          D1, which is the first field of struct pt_regs.  */
-                       struct pt_regs *fp = (struct pt_regs *)&newval;
-
-                       /* '3' is an RMW flag.  */
-                       if (do_page_fault(fp, (unsigned long)mem, 3))
-                               /* If the do_page_fault() failed, we don't
-                                  have anything meaningful to return.
-                                  There should be a SIGSEGV pending for
-                                  the process.  */
-                               return 0xdeadbeef;
-               }
-       }
-}
-
-asmlinkage int sys_atomic_barrier(void)
-{
-       /* no code needed for uniprocs */
-       return 0;
-}
diff --git a/arch/m68k/kernel/sys_m68k_no.c b/arch/m68k/kernel/sys_m68k_no.c
deleted file mode 100644 (file)
index 68488ae..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * linux/arch/m68knommu/kernel/sys_m68k.c
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/m68k
- * platform.
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/syscalls.h>
-#include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/ipc.h>
-#include <linux/fs.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/cachectl.h>
-#include <asm/traps.h>
-#include <asm/cacheflush.h>
-#include <asm/unistd.h>
-
-/* sys_cacheflush -- flush (part of) the processor cache.  */
-asmlinkage int
-sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
-{
-       flush_cache_all();
-       return(0);
-}
-
-asmlinkage int sys_getpagesize(void)
-{
-       return PAGE_SIZE;
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
-                 const char *const argv[],
-                 const char *const envp[])
-{
-       register long __res asm ("%d0") = __NR_execve;
-       register long __a asm ("%d1") = (long)(filename);
-       register long __b asm ("%d2") = (long)(argv);
-       register long __c asm ("%d3") = (long)(envp);
-       asm volatile ("trap  #0" : "+d" (__res)
-                       : "d" (__a), "d" (__b), "d" (__c));
-       return __res;
-}
-
-asmlinkage unsigned long sys_get_thread_area(void)
-{
-       return current_thread_info()->tp_value;
-}
-
-asmlinkage int sys_set_thread_area(unsigned long tp)
-{
-       current_thread_info()->tp_value = tp;
-       return 0;
-}
-
-/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
-   D1 (newval).  */
-asmlinkage int
-sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
-                     unsigned long __user * mem)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long mem_value;
-
-       down_read(&mm->mmap_sem);
-
-       mem_value = *mem;
-       if (mem_value == oldval)
-               *mem = newval;
-
-       up_read(&mm->mmap_sem);
-       return mem_value;
-}
-
-asmlinkage int sys_atomic_barrier(void)
-{
-       /* no code needed for uniprocs */
-       return 0;
-}
index 5909e392cb1e7e46e0f791ecbbe39e39c1e2f470..6f7b09122a00141fd66099f25dfb3fc2716461f7 100644 (file)
@@ -11,7 +11,6 @@
  *  Linux/m68k support by Hamish Macdonald
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 
 #ifndef CONFIG_MMU
index 1f95881d843732f1abed9b0186687d793e59ecdc..df421e5014363243d887cee75fb7d4b71902152c 100644 (file)
@@ -1,5 +1,14 @@
+
+#
+# Makefile for m68k-specific library files..
+#
+
+lib-y  := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
+          memcpy.o memset.o memmove.o
+
 ifdef CONFIG_MMU
-include arch/m68k/lib/Makefile_mm
+lib-y  += string.o uaccess.o checksum_mm.o
 else
-include arch/m68k/lib/Makefile_no
+lib-y  += mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o delay.o checksum_no.o
 endif
+
diff --git a/arch/m68k/lib/Makefile_mm b/arch/m68k/lib/Makefile_mm
deleted file mode 100644 (file)
index af9abf8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for m68k-specific library files..
-#
-
-lib-y  := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
-          checksum.o string.o uaccess.o
diff --git a/arch/m68k/lib/Makefile_no b/arch/m68k/lib/Makefile_no
deleted file mode 100644 (file)
index 32d852e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for m68knommu specific library files..
-#
-
-lib-y  := ashldi3.o ashrdi3.o lshrdi3.o \
-          muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
-          checksum.o memcpy.o memmove.o memset.o delay.o
diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c
deleted file mode 100644 (file)
index 1297536..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CONFIG_MMU
-#include "checksum_mm.c"
-#else
-#include "checksum_no.c"
-#endif
index eccf25d3d73ec3c5c1e84f3a7d9f9383eab157f5..e4c6354da76520a96062eb2bb9a4e25ce59092a6 100644 (file)
@@ -101,6 +101,7 @@ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
 {
        return (__force __sum16)~do_csum(iph,ihl*4);
 }
+EXPORT_SYMBOL(ip_fast_csum);
 #endif
 
 /*
@@ -140,6 +141,7 @@ csum_partial_copy_from_user(const void __user *src, void *dst,
        memcpy(dst, (__force const void *)src, len);
        return csum_partial(dst, len, sum);
 }
+EXPORT_SYMBOL(csum_partial_copy_from_user);
 
 /*
  * copy from ds while checksumming, otherwise like csum_partial
@@ -151,3 +153,4 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
        memcpy(dst, src, len);
        return csum_partial(dst, len, sum);
 }
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
index b50dbcad47464534688b7414997d488e4ba721bd..62182c81e91c55bf106df98d14a00e4dc950ccd9 100644 (file)
@@ -1,62 +1,80 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
 
-#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/string.h>
 
-void * memcpy(void * to, const void * from, size_t n)
+void *memcpy(void *to, const void *from, size_t n)
 {
-#ifdef CONFIG_COLDFIRE
-  void *xto = to;
-  size_t temp;
+       void *xto = to;
+       size_t temp, temp1;
 
-  if (!n)
-    return xto;
-  if ((long) to & 1)
-    {
-      char *cto = to;
-      const char *cfrom = from;
-      *cto++ = *cfrom++;
-      to = cto;
-      from = cfrom;
-      n--;
-    }
-  if (n > 2 && (long) to & 2)
-    {
-      short *sto = to;
-      const short *sfrom = from;
-      *sto++ = *sfrom++;
-      to = sto;
-      from = sfrom;
-      n -= 2;
-    }
-  temp = n >> 2;
-  if (temp)
-    {
-      long *lto = to;
-      const long *lfrom = from;
-      for (; temp; temp--)
-       *lto++ = *lfrom++;
-      to = lto;
-      from = lfrom;
-    }
-  if (n & 2)
-    {
-      short *sto = to;
-      const short *sfrom = from;
-      *sto++ = *sfrom++;
-      to = sto;
-      from = sfrom;
-    }
-  if (n & 1)
-    {
-      char *cto = to;
-      const char *cfrom = from;
-      *cto = *cfrom;
-    }
-  return xto;
+       if (!n)
+               return xto;
+       if ((long)to & 1) {
+               char *cto = to;
+               const char *cfrom = from;
+               *cto++ = *cfrom++;
+               to = cto;
+               from = cfrom;
+               n--;
+       }
+       if (n > 2 && (long)to & 2) {
+               short *sto = to;
+               const short *sfrom = from;
+               *sto++ = *sfrom++;
+               to = sto;
+               from = sfrom;
+               n -= 2;
+       }
+       temp = n >> 2;
+       if (temp) {
+               long *lto = to;
+               const long *lfrom = from;
+#if defined(__mc68020__) || defined(__mc68030__) || \
+    defined(__mc68040__) || defined(__mc68060__) || defined(__mcpu32__)
+               asm volatile (
+                       "       movel %2,%3\n"
+                       "       andw  #7,%3\n"
+                       "       lsrl  #3,%2\n"
+                       "       negw  %3\n"
+                       "       jmp   %%pc@(1f,%3:w:2)\n"
+                       "4:     movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "       movel %0@+,%1@+\n"
+                       "1:     dbra  %2,4b\n"
+                       "       clrw  %2\n"
+                       "       subql #1,%2\n"
+                       "       jpl   4b"
+                       : "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
+                       : "0" (lfrom), "1" (lto), "2" (temp));
 #else
-  const char *c_from = from;
-  char *c_to = to;
-  while (n-- > 0)
-    *c_to++ = *c_from++;
-  return((void *) to);
+               for (; temp; temp--)
+                       *lto++ = *lfrom++;
 #endif
+               to = lto;
+               from = lfrom;
+       }
+       if (n & 2) {
+               short *sto = to;
+               const short *sfrom = from;
+               *sto++ = *sfrom++;
+               to = sto;
+               from = sfrom;
+       }
+       if (n & 1) {
+               char *cto = to;
+               const char *cfrom = from;
+               *cto = *cfrom;
+       }
+       return xto;
 }
+EXPORT_SYMBOL(memcpy);
index b3dcfe9dab7e63bd277c841ed1ca87ef65248e56..6519f7f349f665d9f2321b6c87beee45f8d15645 100644 (file)
@@ -4,8 +4,6 @@
  * for more details.
  */
 
-#define __IN_STRING_C
-
 #include <linux/module.h>
 #include <linux/string.h>
 
index 1389bf455633a2ed0b752ce04d61bcb3a58c4a54..f649e6a2e644686966e3b7c4ed01b245292c04c6 100644 (file)
@@ -1,47 +1,75 @@
-#include <linux/types.h>
+/*
+ * 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.
+ */
 
-void * memset(void * s, int c, size_t count)
+#include <linux/module.h>
+#include <linux/string.h>
+
+void *memset(void *s, int c, size_t count)
 {
-  void *xs = s;
-  size_t temp;
+       void *xs = s;
+       size_t temp;
 
-  if (!count)
-    return xs;
-  c &= 0xff;
-  c |= c << 8;
-  c |= c << 16;
-  if ((long) s & 1)
-    {
-      char *cs = s;
-      *cs++ = c;
-      s = cs;
-      count--;
-    }
-  if (count > 2 && (long) s & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-      count -= 2;
-    }
-  temp = count >> 2;
-  if (temp)
-    {
-      long *ls = s;
-      for (; temp; temp--)
-       *ls++ = c;
-      s = ls;
-    }
-  if (count & 2)
-    {
-      short *ss = s;
-      *ss++ = c;
-      s = ss;
-    }
-  if (count & 1)
-    {
-      char *cs = s;
-      *cs = c;
-    }
-  return xs;
+       if (!count)
+               return xs;
+       c &= 0xff;
+       c |= c << 8;
+       c |= c << 16;
+       if ((long)s & 1) {
+               char *cs = s;
+               *cs++ = c;
+               s = cs;
+               count--;
+       }
+       if (count > 2 && (long)s & 2) {
+               short *ss = s;
+               *ss++ = c;
+               s = ss;
+               count -= 2;
+       }
+       temp = count >> 2;
+       if (temp) {
+               long *ls = s;
+#if defined(__mc68020__) || defined(__mc68030__) || \
+    defined(__mc68040__) || defined(__mc68060__) || defined(__mcpu32__)
+               size_t temp1;
+               asm volatile (
+                       "       movel %1,%2\n"
+                       "       andw  #7,%2\n"
+                       "       lsrl  #3,%1\n"
+                       "       negw  %2\n"
+                       "       jmp   %%pc@(2f,%2:w:2)\n"
+                       "1:     movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "       movel %3,%0@+\n"
+                       "2:     dbra  %1,1b\n"
+                       "       clrw  %1\n"
+                       "       subql #1,%1\n"
+                       "       jpl   1b"
+                       : "=a" (ls), "=d" (temp), "=&d" (temp1)
+                       : "d" (c), "0" (ls), "1" (temp));
+#else
+               for (; temp; temp--)
+                       *ls++ = c;
+#endif
+               s = ls;
+       }
+       if (count & 2) {
+               short *ss = s;
+               *ss++ = c;
+               s = ss;
+       }
+       if (count & 1) {
+               char *cs = s;
+               *cs = c;
+       }
+       return xs;
 }
+EXPORT_SYMBOL(memset);
index 16e0eb338ee0e5303a44fa3180f0bcdcd08e3d0d..079bafca073effea75f2af80847d1f174bf674f5 100644 (file)
@@ -1,5 +1,98 @@
-#ifdef CONFIG_MMU
-#include "muldi3_mm.c"
+/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and 
+                          gcc-2.7.2.3/longlong.h which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#if defined(__mc68020__) || defined(__mc68030__) || \
+    defined(__mc68040__) || defined(__mc68060__) || defined(__mcpu32__)
+
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulu%.l %3,%1:%0"                                          \
+           : "=d" ((USItype)(w0)),                                     \
+             "=d" ((USItype)(w1))                                      \
+           : "%0" ((USItype)(u)),                                      \
+             "dmi" ((USItype)(v)))
+
 #else
-#include "muldi3_no.c"
+
+#define SI_TYPE_SIZE 32
+#define __BITS4 (SI_TYPE_SIZE / 4)
+#define __ll_B (1L << (SI_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
+#define __ll_highpart(t) ((USItype) (t) / __ll_B)
+
+#define umul_ppmm(w1, w0, u, v)                                                \
+  do {                                                                 \
+    USItype __x0, __x1, __x2, __x3;                                    \
+    USItype __ul, __vl, __uh, __vh;                                    \
+                                                                       \
+    __ul = __ll_lowpart (u);                                           \
+    __uh = __ll_highpart (u);                                          \
+    __vl = __ll_lowpart (v);                                           \
+    __vh = __ll_highpart (v);                                          \
+                                                                       \
+    __x0 = (USItype) __ul * __vl;                                      \
+    __x1 = (USItype) __ul * __vh;                                      \
+    __x2 = (USItype) __uh * __vl;                                      \
+    __x3 = (USItype) __uh * __vh;                                      \
+                                                                       \
+    __x1 += __ll_highpart (__x0);/* this can't give carry */           \
+    __x1 += __x2;              /* but this indeed can */               \
+    if (__x1 < __x2)           /* did we get it? */                    \
+      __x3 += __ll_B;          /* yes, add it in the proper pos. */    \
+                                                                       \
+    (w1) = __x3 + __ll_highpart (__x1);                                        \
+    (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0);         \
+  } while (0)
+
 #endif
+
+#define __umulsidi3(u, v) \
+  ({DIunion __w;                                                       \
+    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
+    __w.ll; })
+
+typedef         int SItype     __attribute__ ((mode (SI)));
+typedef unsigned int USItype   __attribute__ ((mode (SI)));
+typedef                 int DItype     __attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
+DItype
+__muldi3 (DItype u, DItype v)
+{
+  DIunion w;
+  DIunion uu, vv;
+
+  uu.ll = u,
+  vv.ll = v;
+
+  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
+  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+              + (USItype) uu.s.high * (USItype) vv.s.low);
+
+  return w.ll;
+}
diff --git a/arch/m68k/lib/muldi3_mm.c b/arch/m68k/lib/muldi3_mm.c
deleted file mode 100644 (file)
index be4f275..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and
-                          gcc-2.7.2.3/longlong.h which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-#define BITS_PER_UNIT 8
-
-#define umul_ppmm(w1, w0, u, v) \
-  __asm__ ("mulu%.l %3,%1:%0"                                          \
-           : "=d" ((USItype)(w0)),                                     \
-             "=d" ((USItype)(w1))                                      \
-           : "%0" ((USItype)(u)),                                      \
-             "dmi" ((USItype)(v)))
-
-#define __umulsidi3(u, v) \
-  ({DIunion __w;                                                       \
-    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
-    __w.ll; })
-
-typedef                 int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-DItype
-__muldi3 (DItype u, DItype v)
-{
-  DIunion w;
-  DIunion uu, vv;
-
-  uu.ll = u,
-  vv.ll = v;
-
-  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
-  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
-              + (USItype) uu.s.high * (USItype) vv.s.low);
-
-  return w.ll;
-}
diff --git a/arch/m68k/lib/muldi3_no.c b/arch/m68k/lib/muldi3_no.c
deleted file mode 100644 (file)
index 34af72c..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and 
-                          gcc-2.7.2.3/longlong.h which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-#define BITS_PER_UNIT 8
-#define SI_TYPE_SIZE 32
-
-#define __BITS4 (SI_TYPE_SIZE / 4)
-#define __ll_B (1L << (SI_TYPE_SIZE / 2))
-#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
-#define __ll_highpart(t) ((USItype) (t) / __ll_B)
-
-#define umul_ppmm(w1, w0, u, v)                                                \
-  do {                                                                 \
-    USItype __x0, __x1, __x2, __x3;                                    \
-    USItype __ul, __vl, __uh, __vh;                                    \
-                                                                       \
-    __ul = __ll_lowpart (u);                                           \
-    __uh = __ll_highpart (u);                                          \
-    __vl = __ll_lowpart (v);                                           \
-    __vh = __ll_highpart (v);                                          \
-                                                                       \
-    __x0 = (USItype) __ul * __vl;                                      \
-    __x1 = (USItype) __ul * __vh;                                      \
-    __x2 = (USItype) __uh * __vl;                                      \
-    __x3 = (USItype) __uh * __vh;                                      \
-                                                                       \
-    __x1 += __ll_highpart (__x0);/* this can't give carry */           \
-    __x1 += __x2;              /* but this indeed can */               \
-    if (__x1 < __x2)           /* did we get it? */                    \
-      __x3 += __ll_B;          /* yes, add it in the proper pos. */    \
-                                                                       \
-    (w1) = __x3 + __ll_highpart (__x1);                                        \
-    (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0);         \
-  } while (0)
-
-#define __umulsidi3(u, v) \
-  ({DIunion __w;                                                       \
-    umul_ppmm (__w.s.high, __w.s.low, u, v);                           \
-    __w.ll; })
-
-typedef         int SItype     __attribute__ ((mode (SI)));
-typedef unsigned int USItype   __attribute__ ((mode (SI)));
-typedef                 int DItype     __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
-  struct DIstruct s;
-  DItype ll;
-} DIunion;
-
-DItype
-__muldi3 (DItype u, DItype v)
-{
-  DIunion w;
-  DIunion uu, vv;
-
-  uu.ll = u,
-  vv.ll = v;
-
-  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
-  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
-              + (USItype) uu.s.high * (USItype) vv.s.low);
-
-  return w.ll;
-}
index d399c5f25636f46473ea06a3ee796ec3bd2888cd..b9a57abfad08dc545f703b16f3cb2241727dccf9 100644 (file)
@@ -20,226 +20,3 @@ char *strcat(char *dest, const char *src)
        return __kernel_strcpy(dest + __kernel_strlen(dest), src);
 }
 EXPORT_SYMBOL(strcat);
-
-void *memset(void *s, int c, size_t count)
-{
-       void *xs = s;
-       size_t temp, temp1;
-
-       if (!count)
-               return xs;
-       c &= 0xff;
-       c |= c << 8;
-       c |= c << 16;
-       if ((long)s & 1) {
-               char *cs = s;
-               *cs++ = c;
-               s = cs;
-               count--;
-       }
-       if (count > 2 && (long)s & 2) {
-               short *ss = s;
-               *ss++ = c;
-               s = ss;
-               count -= 2;
-       }
-       temp = count >> 2;
-       if (temp) {
-               long *ls = s;
-
-               asm volatile (
-                       "       movel %1,%2\n"
-                       "       andw  #7,%2\n"
-                       "       lsrl  #3,%1\n"
-                       "       negw  %2\n"
-                       "       jmp   %%pc@(2f,%2:w:2)\n"
-                       "1:     movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "       movel %3,%0@+\n"
-                       "2:     dbra  %1,1b\n"
-                       "       clrw  %1\n"
-                       "       subql #1,%1\n"
-                       "       jpl   1b"
-                       : "=a" (ls), "=d" (temp), "=&d" (temp1)
-                       : "d" (c), "0" (ls), "1" (temp));
-               s = ls;
-       }
-       if (count & 2) {
-               short *ss = s;
-               *ss++ = c;
-               s = ss;
-       }
-       if (count & 1) {
-               char *cs = s;
-               *cs = c;
-       }
-       return xs;
-}
-EXPORT_SYMBOL(memset);
-
-void *memcpy(void *to, const void *from, size_t n)
-{
-       void *xto = to;
-       size_t temp, temp1;
-
-       if (!n)
-               return xto;
-       if ((long)to & 1) {
-               char *cto = to;
-               const char *cfrom = from;
-               *cto++ = *cfrom++;
-               to = cto;
-               from = cfrom;
-               n--;
-       }
-       if (n > 2 && (long)to & 2) {
-               short *sto = to;
-               const short *sfrom = from;
-               *sto++ = *sfrom++;
-               to = sto;
-               from = sfrom;
-               n -= 2;
-       }
-       temp = n >> 2;
-       if (temp) {
-               long *lto = to;
-               const long *lfrom = from;
-
-               asm volatile (
-                       "       movel %2,%3\n"
-                       "       andw  #7,%3\n"
-                       "       lsrl  #3,%2\n"
-                       "       negw  %3\n"
-                       "       jmp   %%pc@(1f,%3:w:2)\n"
-                       "4:     movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "       movel %0@+,%1@+\n"
-                       "1:     dbra  %2,4b\n"
-                       "       clrw  %2\n"
-                       "       subql #1,%2\n"
-                       "       jpl   4b"
-                       : "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
-                       : "0" (lfrom), "1" (lto), "2" (temp));
-               to = lto;
-               from = lfrom;
-       }
-       if (n & 2) {
-               short *sto = to;
-               const short *sfrom = from;
-               *sto++ = *sfrom++;
-               to = sto;
-               from = sfrom;
-       }
-       if (n & 1) {
-               char *cto = to;
-               const char *cfrom = from;
-               *cto = *cfrom;
-       }
-       return xto;
-}
-EXPORT_SYMBOL(memcpy);
-
-void *memmove(void *dest, const void *src, size_t n)
-{
-       void *xdest = dest;
-       size_t temp;
-
-       if (!n)
-               return xdest;
-
-       if (dest < src) {
-               if ((long)dest & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *cdest++ = *csrc++;
-                       dest = cdest;
-                       src = csrc;
-                       n--;
-               }
-               if (n > 2 && (long)dest & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *sdest++ = *ssrc++;
-                       dest = sdest;
-                       src = ssrc;
-                       n -= 2;
-               }
-               temp = n >> 2;
-               if (temp) {
-                       long *ldest = dest;
-                       const long *lsrc = src;
-                       temp--;
-                       do
-                               *ldest++ = *lsrc++;
-                       while (temp--);
-                       dest = ldest;
-                       src = lsrc;
-               }
-               if (n & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *sdest++ = *ssrc++;
-                       dest = sdest;
-                       src = ssrc;
-               }
-               if (n & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *cdest = *csrc;
-               }
-       } else {
-               dest = (char *)dest + n;
-               src = (const char *)src + n;
-               if ((long)dest & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *--cdest = *--csrc;
-                       dest = cdest;
-                       src = csrc;
-                       n--;
-               }
-               if (n > 2 && (long)dest & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *--sdest = *--ssrc;
-                       dest = sdest;
-                       src = ssrc;
-                       n -= 2;
-               }
-               temp = n >> 2;
-               if (temp) {
-                       long *ldest = dest;
-                       const long *lsrc = src;
-                       temp--;
-                       do
-                               *--ldest = *--lsrc;
-                       while (temp--);
-                       dest = ldest;
-                       src = lsrc;
-               }
-               if (n & 2) {
-                       short *sdest = dest;
-                       const short *ssrc = src;
-                       *--sdest = *--ssrc;
-                       dest = sdest;
-                       src = ssrc;
-               }
-               if (n & 1) {
-                       char *cdest = dest;
-                       const char *csrc = src;
-                       *--cdest = *--csrc;
-               }
-       }
-       return xdest;
-}
-EXPORT_SYMBOL(memmove);
index b60270e4954bb256e17ca0af97341d3d1766efec..09cadf1058d5c6b948a8dd3b1016c6f6bc79068f 100644 (file)
@@ -1,5 +1,9 @@
-ifdef CONFIG_MMU
-include arch/m68k/mm/Makefile_mm
-else
-include arch/m68k/mm/Makefile_no
-endif
+#
+# Makefile for the linux m68k-specific parts of the memory manager.
+#
+
+obj-y  := init.o
+
+obj-$(CONFIG_MMU)              += cache.o fault.o hwtest.o
+obj-$(CONFIG_MMU_MOTOROLA)     += kmap.o memory.o motorola.o
+obj-$(CONFIG_MMU_SUN3)         += sun3kmap.o sun3mmu.o
diff --git a/arch/m68k/mm/Makefile_mm b/arch/m68k/mm/Makefile_mm
deleted file mode 100644 (file)
index 5eaa43c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the linux m68k-specific parts of the memory manager.
-#
-
-obj-y          := cache.o init.o fault.o hwtest.o
-
-obj-$(CONFIG_MMU_MOTOROLA)     += kmap.o memory.o motorola.o
-obj-$(CONFIG_MMU_SUN3)         += sun3kmap.o sun3mmu.o
diff --git a/arch/m68k/mm/Makefile_no b/arch/m68k/mm/Makefile_no
deleted file mode 100644 (file)
index b54ab6b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the linux m68knommu specific parts of the memory manager.
-#
-
-obj-y += init.o kmap.o
index 8a6653f56bd8b29c286b3f973191d53557721e78..7cbd7bd1f8bcd74352fda4c1db5c3f928d230936 100644 (file)
 #include <asm/system.h>
 #include <asm/machdep.h>
 
-#undef DEBUG
-
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void free_initmem(void);
-
 /*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-static unsigned long empty_bad_page_table;
-
-static unsigned long empty_bad_page;
-
 unsigned long empty_zero_page;
 
 extern unsigned long memory_start;
@@ -77,22 +59,9 @@ void __init paging_init(void)
         * Make sure start_mem is page aligned, otherwise bootmem and
         * page_alloc get different views of the world.
         */
-#ifdef DEBUG
-       unsigned long start_mem = PAGE_ALIGN(memory_start);
-#endif
        unsigned long end_mem   = memory_end & PAGE_MASK;
+       unsigned long zones_size[MAX_NR_ZONES] = {0, };
 
-#ifdef DEBUG
-       printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n",
-               start_mem, end_mem);
-#endif
-
-       /*
-        * Initialize the bad page table and bad page to point
-        * to a couple of allocated pages.
-        */
-       empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-       empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
        empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
        memset((void *)empty_zero_page, 0, PAGE_SIZE);
 
@@ -101,19 +70,8 @@ void __init paging_init(void)
         */
        set_fs (USER_DS);
 
-#ifdef DEBUG
-       printk (KERN_DEBUG "before free_area_init\n");
-
-       printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
-               start_mem, end_mem);
-#endif
-
-       {
-               unsigned long zones_size[MAX_NR_ZONES] = {0, };
-
-               zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
-               free_area_init(zones_size);
-       }
+       zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+       free_area_init(zones_size);
 }
 
 void __init mem_init(void)
@@ -166,8 +124,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-void
-free_initmem()
+void free_initmem(void)
 {
 #ifdef CONFIG_RAMKERNEL
        unsigned long addr;
index a373d136b2b28547421a276b2789bc0d1f93b97d..69345849454b9c03991258aa1eff409472896e2b 100644 (file)
@@ -1,5 +1,367 @@
-#ifdef CONFIG_MMU
-#include "kmap_mm.c"
+/*
+ *  linux/arch/m68k/mm/kmap.c
+ *
+ *  Copyright (C) 1997 Roman Hodek
+ *
+ *  10/01/99 cleaned up the code and changing to the same interface
+ *          used by other architectures                /Roman Zippel
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#undef DEBUG
+
+#define PTRTREESIZE    (256*1024)
+
+/*
+ * For 040/060 we can use the virtual memory area like other architectures,
+ * but for 020/030 we want to use early termination page descriptor and we
+ * can't mix this with normal page descriptors, so we have to copy that code
+ * (mm/vmalloc.c) and return appriorate aligned addresses.
+ */
+
+#ifdef CPU_M68040_OR_M68060_ONLY
+
+#define IO_SIZE                PAGE_SIZE
+
+static inline struct vm_struct *get_io_area(unsigned long size)
+{
+       return get_vm_area(size, VM_IOREMAP);
+}
+
+
+static inline void free_io_area(void *addr)
+{
+       vfree((void *)(PAGE_MASK & (unsigned long)addr));
+}
+
 #else
-#include "kmap_no.c"
+
+#define IO_SIZE                (256*1024)
+
+static struct vm_struct *iolist;
+
+static struct vm_struct *get_io_area(unsigned long size)
+{
+       unsigned long addr;
+       struct vm_struct **p, *tmp, *area;
+
+       area = kmalloc(sizeof(*area), GFP_KERNEL);
+       if (!area)
+               return NULL;
+       addr = KMAP_START;
+       for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
+               if (size + addr < (unsigned long)tmp->addr)
+                       break;
+               if (addr > KMAP_END-size) {
+                       kfree(area);
+                       return NULL;
+               }
+               addr = tmp->size + (unsigned long)tmp->addr;
+       }
+       area->addr = (void *)addr;
+       area->size = size + IO_SIZE;
+       area->next = *p;
+       *p = area;
+       return area;
+}
+
+static inline void free_io_area(void *addr)
+{
+       struct vm_struct **p, *tmp;
+
+       if (!addr)
+               return;
+       addr = (void *)((unsigned long)addr & -IO_SIZE);
+       for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
+               if (tmp->addr == addr) {
+                       *p = tmp->next;
+                       __iounmap(tmp->addr, tmp->size);
+                       kfree(tmp);
+                       return;
+               }
+       }
+}
+
 #endif
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+/* Rewritten by Andreas Schwab to remove all races. */
+
+void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+{
+       struct vm_struct *area;
+       unsigned long virtaddr, retaddr;
+       long offset;
+       pgd_t *pgd_dir;
+       pmd_t *pmd_dir;
+       pte_t *pte_dir;
+
+       /*
+        * Don't allow mappings that wrap..
+        */
+       if (!size || physaddr > (unsigned long)(-size))
+               return NULL;
+
+#ifdef CONFIG_AMIGA
+       if (MACH_IS_AMIGA) {
+               if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
+                   && (cacheflag == IOMAP_NOCACHE_SER))
+                       return (void __iomem *)physaddr;
+       }
+#endif
+
+#ifdef DEBUG
+       printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
+#endif
+       /*
+        * Mappings have to be aligned
+        */
+       offset = physaddr & (IO_SIZE - 1);
+       physaddr &= -IO_SIZE;
+       size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
+
+       /*
+        * Ok, go for it..
+        */
+       area = get_io_area(size);
+       if (!area)
+               return NULL;
+
+       virtaddr = (unsigned long)area->addr;
+       retaddr = virtaddr + offset;
+#ifdef DEBUG
+       printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
+#endif
+
+       /*
+        * add cache and table flags to physical address
+        */
+       if (CPU_IS_040_OR_060) {
+               physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
+                            _PAGE_ACCESSED | _PAGE_DIRTY);
+               switch (cacheflag) {
+               case IOMAP_FULL_CACHING:
+                       physaddr |= _PAGE_CACHE040;
+                       break;
+               case IOMAP_NOCACHE_SER:
+               default:
+                       physaddr |= _PAGE_NOCACHE_S;
+                       break;
+               case IOMAP_NOCACHE_NONSER:
+                       physaddr |= _PAGE_NOCACHE;
+                       break;
+               case IOMAP_WRITETHROUGH:
+                       physaddr |= _PAGE_CACHE040W;
+                       break;
+               }
+       } else {
+               physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+               switch (cacheflag) {
+               case IOMAP_NOCACHE_SER:
+               case IOMAP_NOCACHE_NONSER:
+               default:
+                       physaddr |= _PAGE_NOCACHE030;
+                       break;
+               case IOMAP_FULL_CACHING:
+               case IOMAP_WRITETHROUGH:
+                       break;
+               }
+       }
+
+       while ((long)size > 0) {
+#ifdef DEBUG
+               if (!(virtaddr & (PTRTREESIZE-1)))
+                       printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
+#endif
+               pgd_dir = pgd_offset_k(virtaddr);
+               pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr);
+               if (!pmd_dir) {
+                       printk("ioremap: no mem for pmd_dir\n");
+                       return NULL;
+               }
+
+               if (CPU_IS_020_OR_030) {
+                       pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
+                       physaddr += PTRTREESIZE;
+                       virtaddr += PTRTREESIZE;
+                       size -= PTRTREESIZE;
+               } else {
+                       pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
+                       if (!pte_dir) {
+                               printk("ioremap: no mem for pte_dir\n");
+                               return NULL;
+                       }
+
+                       pte_val(*pte_dir) = physaddr;
+                       virtaddr += PAGE_SIZE;
+                       physaddr += PAGE_SIZE;
+                       size -= PAGE_SIZE;
+               }
+       }
+#ifdef DEBUG
+       printk("\n");
+#endif
+       flush_tlb_all();
+
+       return (void __iomem *)retaddr;
+}
+EXPORT_SYMBOL(__ioremap);
+
+/*
+ * Unmap a ioremap()ed region again
+ */
+void iounmap(void __iomem *addr)
+{
+#ifdef CONFIG_AMIGA
+       if ((!MACH_IS_AMIGA) ||
+           (((unsigned long)addr < 0x40000000) ||
+            ((unsigned long)addr > 0x60000000)))
+                       free_io_area((__force void *)addr);
+#else
+       free_io_area((__force void *)addr);
+#endif
+}
+EXPORT_SYMBOL(iounmap);
+
+/*
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wans't used anyway and might be added later.
+ */
+void __iounmap(void *addr, unsigned long size)
+{
+       unsigned long virtaddr = (unsigned long)addr;
+       pgd_t *pgd_dir;
+       pmd_t *pmd_dir;
+       pte_t *pte_dir;
+
+       while ((long)size > 0) {
+               pgd_dir = pgd_offset_k(virtaddr);
+               if (pgd_bad(*pgd_dir)) {
+                       printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+                       pgd_clear(pgd_dir);
+                       return;
+               }
+               pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+               if (CPU_IS_020_OR_030) {
+                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+                       int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
+
+                       if (pmd_type == _PAGE_PRESENT) {
+                               pmd_dir->pmd[pmd_off] = 0;
+                               virtaddr += PTRTREESIZE;
+                               size -= PTRTREESIZE;
+                               continue;
+                       } else if (pmd_type == 0)
+                               continue;
+               }
+
+               if (pmd_bad(*pmd_dir)) {
+                       printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+                       pmd_clear(pmd_dir);
+                       return;
+               }
+               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
+
+               pte_val(*pte_dir) = 0;
+               virtaddr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       flush_tlb_all();
+}
+
+/*
+ * Set new cache mode for some kernel address space.
+ * The caller must push data for that range itself, if such data may already
+ * be in the cache.
+ */
+void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
+{
+       unsigned long virtaddr = (unsigned long)addr;
+       pgd_t *pgd_dir;
+       pmd_t *pmd_dir;
+       pte_t *pte_dir;
+
+       if (CPU_IS_040_OR_060) {
+               switch (cmode) {
+               case IOMAP_FULL_CACHING:
+                       cmode = _PAGE_CACHE040;
+                       break;
+               case IOMAP_NOCACHE_SER:
+               default:
+                       cmode = _PAGE_NOCACHE_S;
+                       break;
+               case IOMAP_NOCACHE_NONSER:
+                       cmode = _PAGE_NOCACHE;
+                       break;
+               case IOMAP_WRITETHROUGH:
+                       cmode = _PAGE_CACHE040W;
+                       break;
+               }
+       } else {
+               switch (cmode) {
+               case IOMAP_NOCACHE_SER:
+               case IOMAP_NOCACHE_NONSER:
+               default:
+                       cmode = _PAGE_NOCACHE030;
+                       break;
+               case IOMAP_FULL_CACHING:
+               case IOMAP_WRITETHROUGH:
+                       cmode = 0;
+               }
+       }
+
+       while ((long)size > 0) {
+               pgd_dir = pgd_offset_k(virtaddr);
+               if (pgd_bad(*pgd_dir)) {
+                       printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+                       pgd_clear(pgd_dir);
+                       return;
+               }
+               pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+               if (CPU_IS_020_OR_030) {
+                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+
+                       if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+                               pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
+                                                        _CACHEMASK040) | cmode;
+                               virtaddr += PTRTREESIZE;
+                               size -= PTRTREESIZE;
+                               continue;
+                       }
+               }
+
+               if (pmd_bad(*pmd_dir)) {
+                       printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+                       pmd_clear(pmd_dir);
+                       return;
+               }
+               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
+
+               pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
+               virtaddr += PAGE_SIZE;
+               size -= PAGE_SIZE;
+       }
+
+       flush_tlb_all();
+}
+EXPORT_SYMBOL(kernel_set_cachemode);
diff --git a/arch/m68k/mm/kmap_mm.c b/arch/m68k/mm/kmap_mm.c
deleted file mode 100644 (file)
index 6934584..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- *  linux/arch/m68k/mm/kmap.c
- *
- *  Copyright (C) 1997 Roman Hodek
- *
- *  10/01/99 cleaned up the code and changing to the same interface
- *          used by other architectures                /Roman Zippel
- */
-
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#undef DEBUG
-
-#define PTRTREESIZE    (256*1024)
-
-/*
- * For 040/060 we can use the virtual memory area like other architectures,
- * but for 020/030 we want to use early termination page descriptor and we
- * can't mix this with normal page descriptors, so we have to copy that code
- * (mm/vmalloc.c) and return appriorate aligned addresses.
- */
-
-#ifdef CPU_M68040_OR_M68060_ONLY
-
-#define IO_SIZE                PAGE_SIZE
-
-static inline struct vm_struct *get_io_area(unsigned long size)
-{
-       return get_vm_area(size, VM_IOREMAP);
-}
-
-
-static inline void free_io_area(void *addr)
-{
-       vfree((void *)(PAGE_MASK & (unsigned long)addr));
-}
-
-#else
-
-#define IO_SIZE                (256*1024)
-
-static struct vm_struct *iolist;
-
-static struct vm_struct *get_io_area(unsigned long size)
-{
-       unsigned long addr;
-       struct vm_struct **p, *tmp, *area;
-
-       area = kmalloc(sizeof(*area), GFP_KERNEL);
-       if (!area)
-               return NULL;
-       addr = KMAP_START;
-       for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
-               if (size + addr < (unsigned long)tmp->addr)
-                       break;
-               if (addr > KMAP_END-size) {
-                       kfree(area);
-                       return NULL;
-               }
-               addr = tmp->size + (unsigned long)tmp->addr;
-       }
-       area->addr = (void *)addr;
-       area->size = size + IO_SIZE;
-       area->next = *p;
-       *p = area;
-       return area;
-}
-
-static inline void free_io_area(void *addr)
-{
-       struct vm_struct **p, *tmp;
-
-       if (!addr)
-               return;
-       addr = (void *)((unsigned long)addr & -IO_SIZE);
-       for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
-               if (tmp->addr == addr) {
-                       *p = tmp->next;
-                       __iounmap(tmp->addr, tmp->size);
-                       kfree(tmp);
-                       return;
-               }
-       }
-}
-
-#endif
-
-/*
- * Map some physical address range into the kernel address space.
- */
-/* Rewritten by Andreas Schwab to remove all races. */
-
-void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
-{
-       struct vm_struct *area;
-       unsigned long virtaddr, retaddr;
-       long offset;
-       pgd_t *pgd_dir;
-       pmd_t *pmd_dir;
-       pte_t *pte_dir;
-
-       /*
-        * Don't allow mappings that wrap..
-        */
-       if (!size || physaddr > (unsigned long)(-size))
-               return NULL;
-
-#ifdef CONFIG_AMIGA
-       if (MACH_IS_AMIGA) {
-               if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
-                   && (cacheflag == IOMAP_NOCACHE_SER))
-                       return (void __iomem *)physaddr;
-       }
-#endif
-
-#ifdef DEBUG
-       printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
-#endif
-       /*
-        * Mappings have to be aligned
-        */
-       offset = physaddr & (IO_SIZE - 1);
-       physaddr &= -IO_SIZE;
-       size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
-
-       /*
-        * Ok, go for it..
-        */
-       area = get_io_area(size);
-       if (!area)
-               return NULL;
-
-       virtaddr = (unsigned long)area->addr;
-       retaddr = virtaddr + offset;
-#ifdef DEBUG
-       printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
-#endif
-
-       /*
-        * add cache and table flags to physical address
-        */
-       if (CPU_IS_040_OR_060) {
-               physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
-                            _PAGE_ACCESSED | _PAGE_DIRTY);
-               switch (cacheflag) {
-               case IOMAP_FULL_CACHING:
-                       physaddr |= _PAGE_CACHE040;
-                       break;
-               case IOMAP_NOCACHE_SER:
-               default:
-                       physaddr |= _PAGE_NOCACHE_S;
-                       break;
-               case IOMAP_NOCACHE_NONSER:
-                       physaddr |= _PAGE_NOCACHE;
-                       break;
-               case IOMAP_WRITETHROUGH:
-                       physaddr |= _PAGE_CACHE040W;
-                       break;
-               }
-       } else {
-               physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
-               switch (cacheflag) {
-               case IOMAP_NOCACHE_SER:
-               case IOMAP_NOCACHE_NONSER:
-               default:
-                       physaddr |= _PAGE_NOCACHE030;
-                       break;
-               case IOMAP_FULL_CACHING:
-               case IOMAP_WRITETHROUGH:
-                       break;
-               }
-       }
-
-       while ((long)size > 0) {
-#ifdef DEBUG
-               if (!(virtaddr & (PTRTREESIZE-1)))
-                       printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
-#endif
-               pgd_dir = pgd_offset_k(virtaddr);
-               pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr);
-               if (!pmd_dir) {
-                       printk("ioremap: no mem for pmd_dir\n");
-                       return NULL;
-               }
-
-               if (CPU_IS_020_OR_030) {
-                       pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
-                       physaddr += PTRTREESIZE;
-                       virtaddr += PTRTREESIZE;
-                       size -= PTRTREESIZE;
-               } else {
-                       pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
-                       if (!pte_dir) {
-                               printk("ioremap: no mem for pte_dir\n");
-                               return NULL;
-                       }
-
-                       pte_val(*pte_dir) = physaddr;
-                       virtaddr += PAGE_SIZE;
-                       physaddr += PAGE_SIZE;
-                       size -= PAGE_SIZE;
-               }
-       }
-#ifdef DEBUG
-       printk("\n");
-#endif
-       flush_tlb_all();
-
-       return (void __iomem *)retaddr;
-}
-EXPORT_SYMBOL(__ioremap);
-
-/*
- * Unmap a ioremap()ed region again
- */
-void iounmap(void __iomem *addr)
-{
-#ifdef CONFIG_AMIGA
-       if ((!MACH_IS_AMIGA) ||
-           (((unsigned long)addr < 0x40000000) ||
-            ((unsigned long)addr > 0x60000000)))
-                       free_io_area((__force void *)addr);
-#else
-       free_io_area((__force void *)addr);
-#endif
-}
-EXPORT_SYMBOL(iounmap);
-
-/*
- * __iounmap unmaps nearly everything, so be careful
- * it doesn't free currently pointer/page tables anymore but it
- * wans't used anyway and might be added later.
- */
-void __iounmap(void *addr, unsigned long size)
-{
-       unsigned long virtaddr = (unsigned long)addr;
-       pgd_t *pgd_dir;
-       pmd_t *pmd_dir;
-       pte_t *pte_dir;
-
-       while ((long)size > 0) {
-               pgd_dir = pgd_offset_k(virtaddr);
-               if (pgd_bad(*pgd_dir)) {
-                       printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
-                       pgd_clear(pgd_dir);
-                       return;
-               }
-               pmd_dir = pmd_offset(pgd_dir, virtaddr);
-
-               if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
-                       int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
-
-                       if (pmd_type == _PAGE_PRESENT) {
-                               pmd_dir->pmd[pmd_off] = 0;
-                               virtaddr += PTRTREESIZE;
-                               size -= PTRTREESIZE;
-                               continue;
-                       } else if (pmd_type == 0)
-                               continue;
-               }
-
-               if (pmd_bad(*pmd_dir)) {
-                       printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
-                       pmd_clear(pmd_dir);
-                       return;
-               }
-               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
-
-               pte_val(*pte_dir) = 0;
-               virtaddr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       flush_tlb_all();
-}
-
-/*
- * Set new cache mode for some kernel address space.
- * The caller must push data for that range itself, if such data may already
- * be in the cache.
- */
-void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
-{
-       unsigned long virtaddr = (unsigned long)addr;
-       pgd_t *pgd_dir;
-       pmd_t *pmd_dir;
-       pte_t *pte_dir;
-
-       if (CPU_IS_040_OR_060) {
-               switch (cmode) {
-               case IOMAP_FULL_CACHING:
-                       cmode = _PAGE_CACHE040;
-                       break;
-               case IOMAP_NOCACHE_SER:
-               default:
-                       cmode = _PAGE_NOCACHE_S;
-                       break;
-               case IOMAP_NOCACHE_NONSER:
-                       cmode = _PAGE_NOCACHE;
-                       break;
-               case IOMAP_WRITETHROUGH:
-                       cmode = _PAGE_CACHE040W;
-                       break;
-               }
-       } else {
-               switch (cmode) {
-               case IOMAP_NOCACHE_SER:
-               case IOMAP_NOCACHE_NONSER:
-               default:
-                       cmode = _PAGE_NOCACHE030;
-                       break;
-               case IOMAP_FULL_CACHING:
-               case IOMAP_WRITETHROUGH:
-                       cmode = 0;
-               }
-       }
-
-       while ((long)size > 0) {
-               pgd_dir = pgd_offset_k(virtaddr);
-               if (pgd_bad(*pgd_dir)) {
-                       printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
-                       pgd_clear(pgd_dir);
-                       return;
-               }
-               pmd_dir = pmd_offset(pgd_dir, virtaddr);
-
-               if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
-
-                       if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
-                               pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
-                                                        _CACHEMASK040) | cmode;
-                               virtaddr += PTRTREESIZE;
-                               size -= PTRTREESIZE;
-                               continue;
-                       }
-               }
-
-               if (pmd_bad(*pmd_dir)) {
-                       printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
-                       pmd_clear(pmd_dir);
-                       return;
-               }
-               pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
-
-               pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
-               virtaddr += PAGE_SIZE;
-               size -= PAGE_SIZE;
-       }
-
-       flush_tlb_all();
-}
-EXPORT_SYMBOL(kernel_set_cachemode);
diff --git a/arch/m68k/mm/kmap_no.c b/arch/m68k/mm/kmap_no.c
deleted file mode 100644 (file)
index ece8d5a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- *  linux/arch/m68knommu/mm/kmap.c
- *
- *  Copyright (C) 2000 Lineo, <davidm@snapgear.com>
- *  Copyright (C) 2000-2002 David McCullough <davidm@snapgear.com>
- */
-
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#undef DEBUG
-
-/*
- * Map some physical address range into the kernel address space.
- */
-void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
-{
-       return (void *)physaddr;
-}
-
-/*
- * Unmap a ioremap()ed region again.
- */
-void iounmap(void *addr)
-{
-}
-
-/*
- * Set new cache mode for some kernel address space.
- * The caller must push data for that range itself, if such data may already
- * be in the cache.
- */
-void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
-{
-}
index 676960cf022aa46d14dc62093d6825c3f4a15a14..f68dce766c0a34ca4fd54ea8185724e49394c22b 100644 (file)
@@ -10,7 +10,6 @@
  * Linux/m68k support by Hamish Macdonald
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
@@ -80,7 +79,7 @@ ENTRY(system_call)
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
-       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
        jne     do_trace
        cmpl    #NR_syscalls,%d0
        jcc     badsys
@@ -107,12 +106,12 @@ Luser_return:
        andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
 1:
-       move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       move    %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
        jne     Lwork_to_do
        RESTORE_ALL
 
 Lwork_to_do:
-       movel   %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       movel   %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
        btst    #TIF_NEED_RESCHED,%d1
        jne     reschedule
 
index 46c1b18c9dcbfc80d9a16a2126b468c3f9cfea46..a07b14feed9245398cc3f57e928a7d2140324426 100644 (file)
@@ -12,7 +12,6 @@
  * M68360 Port by SED Systems, and Lineo.
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
@@ -76,7 +75,7 @@ ENTRY(system_call)
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
-       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       btst    #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
        jne     do_trace
        cmpl    #NR_syscalls,%d0
        jcc     badsys
@@ -103,12 +102,12 @@ Luser_return:
        andl    #-THREAD_SIZE,%d1
        movel   %d1,%a2
 1:
-       move    %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       move    %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
        jne     Lwork_to_do
        RESTORE_ALL
 
 Lwork_to_do:
-       movel   %a2@(TI_FLAGS),%d1      /* thread_info->flags */
+       movel   %a2@(TINFO_FLAGS),%d1   /* thread_info->flags */
        btst    #TIF_NEED_RESCHED,%d1
        jne     reschedule
 
index e88b95e2cc6227475934938ede809416793cc05c..df5ce20d181ce8c8b5e8eedf79a7cd4b1f8242ca 100644 (file)
@@ -9,6 +9,7 @@
 /***************************************************************************/
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <asm/dma.h>
 #include <asm/coldfire.h>
 #include <asm/mcfsim.h>
@@ -33,7 +34,9 @@ unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
        MCFDMA_BASE3,
 #endif
 };
+EXPORT_SYMBOL(dma_base_addr);
 
 unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+EXPORT_SYMBOL(dma_device_address);
 
 /***************************************************************************/
index eab63f09965b0593db1bfb67a08dbd12db21562b..27c2b001161e1d31b43bc7a2ba6640ba4ceb4139 100644 (file)
@@ -26,7 +26,6 @@
  * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be>
  */
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <asm/unistd.h>
 #include <asm/thread_info.h>
@@ -78,7 +77,7 @@ ENTRY(system_call)
        movel   %d2,%a0
        movel   %a0@,%a1                /* save top of frame */
        movel   %sp,%a1@(TASK_THREAD+THREAD_ESP0)
-       btst    #(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+       btst    #(TIF_SYSCALL_TRACE%8),%a0@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
        bnes    1f
 
        movel   %d3,%a0
@@ -113,11 +112,11 @@ ret_from_exception:
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
        movel   %d1,%a0
-       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
        andl    #(1<<TIF_NEED_RESCHED),%d1
        jeq     Lkernel_return
 
-       movel   %a0@(TI_PREEMPTCOUNT),%d1
+       movel   %a0@(TINFO_PREEMPT),%d1
        cmpl    #0,%d1
        jne     Lkernel_return
 
@@ -137,14 +136,14 @@ Luser_return:
        movel   %sp,%d1                 /* get thread_info pointer */
        andl    #-THREAD_SIZE,%d1       /* at base of kernel stack */
        movel   %d1,%a0
-       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
        jne     Lwork_to_do             /* still work to do */
 
 Lreturn:
        RESTORE_USER
 
 Lwork_to_do:
-       movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
+       movel   %a0@(TINFO_FLAGS),%d1   /* get thread_info->flags */
        move    #0x2000,%sr             /* enable intrs again */
        btst    #TIF_NEED_RESCHED,%d1
        jne     reschedule
index 6ae91a4991842466a3d86ae47cde14b6c2d31db1..c33483824a2eed3573c6d1c8b1c07545b136a800 100644 (file)
@@ -8,7 +8,6 @@
 
 /*****************************************************************************/
 
-#include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <asm/asm-offsets.h>
index 01af3876cf90f2e73f684b37a794f8501c800beb..a81176f44c74d4e39be2eaf8d939ccdf1aa5157b 100644 (file)
@@ -118,7 +118,7 @@ SECTIONS
                EXIT_DATA
        }
 
-       PERCPU(1 << CONFIG_MIPS_L1_CACHE_SHIFT, PAGE_SIZE)
+       PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
        /* freed after init ends here */
index 968bcd2cb0226c325cc37837518e25dafe4ed6b9..6f702a6ab3955531ff31f65fb7ace7c37f01aa1f 100644 (file)
@@ -70,7 +70,7 @@ SECTIONS
        .exit.text : { EXIT_TEXT; }
        .exit.data : { EXIT_DATA; }
 
-  PERCPU(32, PAGE_SIZE)
+  PERCPU_SECTION(32)
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
   /* freed after init ends here */
index e1a55849bfa7832d8b58fac498012cd8cc44a438..fa6f2b8163e03cc1bdc953bbb1e2b8282b826c7a 100644 (file)
@@ -149,7 +149,7 @@ SECTIONS
                EXIT_DATA
        }
 
-       PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(L1_CACHE_BYTES)
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
        /* freed after init ends here */
index b9150f07d2664a9a763ebeda3564b1c08f18fb17..920276c0f6a1d47396451a5a3e9ac0d71d8b3c4c 100644 (file)
@@ -160,7 +160,7 @@ SECTIONS
                INIT_RAM_FS
        }
 
-       PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(L1_CACHE_BYTES)
 
        . = ALIGN(8);
        .machine.desc : AT(ADDR(.machine.desc) - LOAD_OFFSET) {
index 4a7f14079e03b989bd4cd4b1a012b082e07447b3..ff2d2371b2e92a7dcf931bc0bfcd43a76589dedb 100644 (file)
@@ -230,17 +230,6 @@ config SYSVIPC_COMPAT
 config AUDIT_ARCH
        def_bool y
 
-config S390_EXEC_PROTECT
-       def_bool y
-       prompt "Data execute protection"
-       help
-         This option allows to enable a buffer overflow protection for user
-         space programs and it also selects the addressing mode option above.
-         The kernel parameter noexec=on will enable this feature and also
-         switch the addressing modes, default is disabled. Enabling this (via
-         kernel parameter) on machines earlier than IBM System z9 this will
-         reduce system performance.
-
 comment "Code generation options"
 
 choice
index 5c91995b74e4b598e7eb5e974492ecb13087ff6a..24bff4f1cc52ba906a9a6432af6f4e1ebf16c818 100644 (file)
@@ -130,9 +130,7 @@ static void appldata_work_fn(struct work_struct *work)
 {
        struct list_head *lh;
        struct appldata_ops *ops;
-       int i;
 
-       i = 0;
        get_online_cpus();
        mutex_lock(&appldata_ops_mutex);
        list_for_each(lh, &appldata_ops_list) {
index 7488e52efa97628481e95d6c0dca90e8ed30cd0a..81d7908416cf769202a40541d6a1779560712df5 100644 (file)
@@ -167,7 +167,6 @@ static inline unsigned long __cmpxchg(void *ptr, unsigned long old,
 #ifdef CONFIG_64BIT
 #define cmpxchg64(ptr, o, n)                                           \
 ({                                                                     \
-       BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
        cmpxchg((ptr), (o), (n));                                       \
 })
 #else /* CONFIG_64BIT */
index 10c029cfcc7d3c7d8e8feda790c6c3e885fa34a9..64b61bf72e936ff6839a975162c47483a417328d 100644 (file)
@@ -196,18 +196,6 @@ do {                                                               \
 } while (0)
 #endif /* __s390x__ */
 
-/*
- * An executable for which elf_read_implies_exec() returns TRUE will
- * have the READ_IMPLIES_EXEC personality flag set automatically.
- */
-#define elf_read_implies_exec(ex, executable_stack)    \
-({                                                     \
-       if (current->mm->context.noexec &&              \
-           executable_stack != EXSTACK_DISABLE_X)      \
-               disable_noexec(current->mm, current);   \
-       current->mm->context.noexec == 0;               \
-})
-
 #define STACK_RND_MASK 0x7ffUL
 
 #define ARCH_DLINFO                                                        \
index b56403c2df281d098aa67dc89d3ca9511b6ea5ea..799ed0f1643d135c843f3a1cdc41204063289f0f 100644 (file)
@@ -111,21 +111,10 @@ static inline void huge_ptep_invalidate(struct mm_struct *mm,
 {
        pmd_t *pmdp = (pmd_t *) ptep;
 
-       if (!MACHINE_HAS_IDTE) {
-               __pmd_csp(pmdp);
-               if (mm->context.noexec) {
-                       pmdp = get_shadow_table(pmdp);
-                       __pmd_csp(pmdp);
-               }
-               return;
-       }
-
-       __pmd_idte(address, pmdp);
-       if (mm->context.noexec) {
-               pmdp = get_shadow_table(pmdp);
+       if (MACHINE_HAS_IDTE)
                __pmd_idte(address, pmdp);
-       }
-       return;
+       else
+               __pmd_csp(pmdp);
 }
 
 #define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
index db14a311f1d21d2c03c8d093c5c55220c71c18b2..1544b90bd6d610a4cdb51cfe8ef6c1c38afb739f 100644 (file)
@@ -15,6 +15,7 @@ enum interruption_class {
        EXTINT_VRT,
        EXTINT_SCP,
        EXTINT_IUC,
+       EXTINT_CPM,
        IOINT_QAI,
        IOINT_QDI,
        IOINT_DAS,
index 65e172f8209d902798e05a884bc3c5ce8ef7f80c..228cf0b295dbbffd445068e08bd64a13cf9b9cda 100644 (file)
@@ -124,7 +124,7 @@ struct _lowcore {
        /* Address space pointer. */
        __u32   kernel_asce;                    /* 0x02ac */
        __u32   user_asce;                      /* 0x02b0 */
-       __u32   user_exec_asce;                 /* 0x02b4 */
+       __u32   current_pid;                    /* 0x02b4 */
 
        /* SMP info area */
        __u32   cpu_nr;                         /* 0x02b8 */
@@ -255,7 +255,7 @@ struct _lowcore {
        /* Address space pointer. */
        __u64   kernel_asce;                    /* 0x0310 */
        __u64   user_asce;                      /* 0x0318 */
-       __u64   user_exec_asce;                 /* 0x0320 */
+       __u64   current_pid;                    /* 0x0320 */
 
        /* SMP info area */
        __u32   cpu_nr;                         /* 0x0328 */
index 78522cdefdd42334c7b4f72be1180a6a2ed2f327..82d0847896a0cc096f38331e83cb9bd3b3dfbae4 100644 (file)
@@ -5,19 +5,18 @@ typedef struct {
        atomic_t attach_count;
        unsigned int flush_mm;
        spinlock_t list_lock;
-       struct list_head crst_list;
        struct list_head pgtable_list;
        unsigned long asce_bits;
        unsigned long asce_limit;
        unsigned long vdso_base;
-       int noexec;
-       int has_pgste;   /* The mmu context has extended page tables */
-       int alloc_pgste; /* cloned contexts will have extended page tables */
+       /* Cloned contexts will be created with extended page tables. */
+       unsigned int alloc_pgste:1;
+       /* The mmu context has extended page tables. */
+       unsigned int has_pgste:1;
 } mm_context_t;
 
 #define INIT_MM_CONTEXT(name)                                                \
        .context.list_lock    = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \
-       .context.crst_list    = LIST_HEAD_INIT(name.context.crst_list),       \
        .context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list),
 
 #endif
index 8c277caa8d3aa81d0d8f14c28b2e71f12ec3e791..5682f160ff82caa965a9bd1e3c3aa0b28d403021 100644 (file)
@@ -35,11 +35,9 @@ static inline int init_new_context(struct task_struct *tsk,
                 * and if has_pgste is set, it will create extended page
                 * tables.
                 */
-               mm->context.noexec = 0;
                mm->context.has_pgste = 1;
                mm->context.alloc_pgste = 1;
        } else {
-               mm->context.noexec = (user_mode == SECONDARY_SPACE_MODE);
                mm->context.has_pgste = 0;
                mm->context.alloc_pgste = 0;
        }
@@ -63,10 +61,8 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
        S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
        if (user_mode != HOME_SPACE_MODE) {
                /* Load primary space page table origin. */
-               pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd;
-               S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd);
                asm volatile(LCTL_OPCODE" 1,1,%0\n"
-                            : : "m" (S390_lowcore.user_exec_asce) );
+                            : : "m" (S390_lowcore.user_asce) );
        } else
                /* Load home space page table origin. */
                asm volatile(LCTL_OPCODE" 13,13,%0"
index 3c987e9ec8d69e61d4eaaa5f21e409613662324c..accb372ddc7e4095e768a3756b6fafeb418ee4ac 100644 (file)
@@ -90,6 +90,7 @@ static inline void copy_page(void *to, void *from)
  */
 
 typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct { unsigned long pgste; } pgste_t;
 typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pud; } pud_t;
@@ -97,18 +98,21 @@ typedef struct { unsigned long pgd; } pgd_t;
 typedef pte_t *pgtable_t;
 
 #define pgprot_val(x)  ((x).pgprot)
+#define pgste_val(x)   ((x).pgste)
 #define pte_val(x)     ((x).pte)
 #define pmd_val(x)     ((x).pmd)
 #define pud_val(x)     ((x).pud)
 #define pgd_val(x)      ((x).pgd)
 
+#define __pgste(x)     ((pgste_t) { (x) } )
 #define __pte(x)        ((pte_t) { (x) } )
 #define __pmd(x)        ((pmd_t) { (x) } )
+#define __pud(x)       ((pud_t) { (x) } )
 #define __pgd(x)        ((pgd_t) { (x) } )
 #define __pgprot(x)     ((pgprot_t) { (x) } )
 
-static inline void
-page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
+static inline void page_set_storage_key(unsigned long addr,
+                                       unsigned char skey, int mapped)
 {
        if (!mapped)
                asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0"
@@ -117,15 +121,59 @@ page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
                asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
 }
 
-static inline unsigned int
-page_get_storage_key(unsigned long addr)
+static inline unsigned char page_get_storage_key(unsigned long addr)
 {
-       unsigned int skey;
+       unsigned char skey;
 
-       asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0));
+       asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr));
        return skey;
 }
 
+static inline int page_reset_referenced(unsigned long addr)
+{
+       unsigned int ipm;
+
+       asm volatile(
+               "       rrbe    0,%1\n"
+               "       ipm     %0\n"
+               : "=d" (ipm) : "a" (addr) : "cc");
+       return !!(ipm & 0x20000000);
+}
+
+/* Bits int the storage key */
+#define _PAGE_CHANGED          0x02    /* HW changed bit               */
+#define _PAGE_REFERENCED       0x04    /* HW referenced bit            */
+#define _PAGE_FP_BIT           0x08    /* HW fetch protection bit      */
+#define _PAGE_ACC_BITS         0xf0    /* HW access control bits       */
+
+/*
+ * Test and clear dirty bit in storage key.
+ * We can't clear the changed bit atomically. This is a potential
+ * race against modification of the referenced bit. This function
+ * should therefore only be called if it is not mapped in any
+ * address space.
+ */
+#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
+static inline int page_test_and_clear_dirty(unsigned long pfn, int mapped)
+{
+       unsigned char skey;
+
+       skey = page_get_storage_key(pfn << PAGE_SHIFT);
+       if (!(skey & _PAGE_CHANGED))
+               return 0;
+       page_set_storage_key(pfn << PAGE_SHIFT, skey & ~_PAGE_CHANGED, mapped);
+       return 1;
+}
+
+/*
+ * Test and clear referenced bit in storage key.
+ */
+#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
+static inline int page_test_and_clear_young(unsigned long pfn)
+{
+       return page_reset_referenced(pfn << PAGE_SHIFT);
+}
+
 struct page;
 void arch_free_page(struct page *page, int order);
 void arch_alloc_page(struct page *page, int order);
index f7ad8719d02dcd211bc18c39806d86a5dceb985a..5325c89a5843b52c73cd0ef36dd6cc67c1a10928 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef __ARCH_S390_PERCPU__
 #define __ARCH_S390_PERCPU__
 
+#include <linux/preempt.h>
+#include <asm/cmpxchg.h>
+
 /*
  * s390 uses its own implementation for per cpu data, the offset of
  * the cpu local data area is cached in the cpu's lowcore memory.
 #define ARCH_NEEDS_WEAK_PER_CPU
 #endif
 
+#define arch_irqsafe_cpu_to_op(pcp, val, op)                           \
+do {                                                                   \
+       typedef typeof(pcp) pcp_op_T__;                                 \
+       pcp_op_T__ old__, new__, prev__;                                \
+       pcp_op_T__ *ptr__;                                              \
+       preempt_disable();                                              \
+       ptr__ = __this_cpu_ptr(&(pcp));                                 \
+       prev__ = *ptr__;                                                \
+       do {                                                            \
+               old__ = prev__;                                         \
+               new__ = old__ op (val);                                 \
+               switch (sizeof(*ptr__)) {                               \
+               case 8:                                                 \
+                       prev__ = cmpxchg64(ptr__, old__, new__);        \
+                       break;                                          \
+               default:                                                \
+                       prev__ = cmpxchg(ptr__, old__, new__);          \
+               }                                                       \
+       } while (prev__ != old__);                                      \
+       preempt_enable();                                               \
+} while (0)
+
+#define irqsafe_cpu_add_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+#define irqsafe_cpu_add_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+#define irqsafe_cpu_add_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+#define irqsafe_cpu_add_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+
+#define irqsafe_cpu_and_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+#define irqsafe_cpu_and_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+#define irqsafe_cpu_and_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+#define irqsafe_cpu_and_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+
+#define irqsafe_cpu_or_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+#define irqsafe_cpu_or_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+#define irqsafe_cpu_or_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+#define irqsafe_cpu_or_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+
+#define irqsafe_cpu_xor_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+#define irqsafe_cpu_xor_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+#define irqsafe_cpu_xor_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+#define irqsafe_cpu_xor_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+
+#define arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)                      \
+({                                                                     \
+       typedef typeof(pcp) pcp_op_T__;                                 \
+       pcp_op_T__ ret__;                                               \
+       pcp_op_T__ *ptr__;                                              \
+       preempt_disable();                                              \
+       ptr__ = __this_cpu_ptr(&(pcp));                                 \
+       switch (sizeof(*ptr__)) {                                       \
+       case 8:                                                         \
+               ret__ = cmpxchg64(ptr__, oval, nval);                   \
+               break;                                                  \
+       default:                                                        \
+               ret__ = cmpxchg(ptr__, oval, nval);                     \
+       }                                                               \
+       preempt_enable();                                               \
+       ret__;                                                          \
+})
+
+#define irqsafe_cpu_cmpxchg_1(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_2(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_4(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+
 #include <asm-generic/percpu.h>
 
 #endif /* __ARCH_S390_PERCPU__ */
index 082eb4e50e8b3f53a59cc8343e619bfc6a60b6cc..f6314af3b354ca4375547db504367bc547c351eb 100644 (file)
 
 #define check_pgt_cache()      do {} while (0)
 
-unsigned long *crst_table_alloc(struct mm_struct *, int);
+unsigned long *crst_table_alloc(struct mm_struct *);
 void crst_table_free(struct mm_struct *, unsigned long *);
 void crst_table_free_rcu(struct mm_struct *, unsigned long *);
 
 unsigned long *page_table_alloc(struct mm_struct *);
 void page_table_free(struct mm_struct *, unsigned long *);
 void page_table_free_rcu(struct mm_struct *, unsigned long *);
-void disable_noexec(struct mm_struct *, struct task_struct *);
 
 static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
 {
@@ -50,9 +49,6 @@ static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
 static inline void crst_table_init(unsigned long *crst, unsigned long entry)
 {
        clear_table(crst, entry, sizeof(unsigned long)*2048);
-       crst = get_shadow_table(crst);
-       if (crst)
-               clear_table(crst, entry, sizeof(unsigned long)*2048);
 }
 
 #ifndef __s390x__
@@ -69,10 +65,7 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm)
 #define pmd_free(mm, x)                                do { } while (0)
 
 #define pgd_populate(mm, pgd, pud)             BUG()
-#define pgd_populate_kernel(mm, pgd, pud)      BUG()
-
 #define pud_populate(mm, pud, pmd)             BUG()
-#define pud_populate_kernel(mm, pud, pmd)      BUG()
 
 #else /* __s390x__ */
 
@@ -90,7 +83,7 @@ void crst_table_downgrade(struct mm_struct *, unsigned long limit);
 
 static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-       unsigned long *table = crst_table_alloc(mm, mm->context.noexec);
+       unsigned long *table = crst_table_alloc(mm);
        if (table)
                crst_table_init(table, _REGION3_ENTRY_EMPTY);
        return (pud_t *) table;
@@ -99,43 +92,21 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
-       unsigned long *table = crst_table_alloc(mm, mm->context.noexec);
+       unsigned long *table = crst_table_alloc(mm);
        if (table)
                crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
        return (pmd_t *) table;
 }
 #define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd)
 
-static inline void pgd_populate_kernel(struct mm_struct *mm,
-                                      pgd_t *pgd, pud_t *pud)
-{
-       pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud);
-}
-
 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
 {
-       pgd_populate_kernel(mm, pgd, pud);
-       if (mm->context.noexec) {
-               pgd = get_shadow_table(pgd);
-               pud = get_shadow_table(pud);
-               pgd_populate_kernel(mm, pgd, pud);
-       }
-}
-
-static inline void pud_populate_kernel(struct mm_struct *mm,
-                                      pud_t *pud, pmd_t *pmd)
-{
-       pud_val(*pud) = _REGION3_ENTRY | __pa(pmd);
+       pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud);
 }
 
 static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 {
-       pud_populate_kernel(mm, pud, pmd);
-       if (mm->context.noexec) {
-               pud = get_shadow_table(pud);
-               pmd = get_shadow_table(pmd);
-               pud_populate_kernel(mm, pud, pmd);
-       }
+       pud_val(*pud) = _REGION3_ENTRY | __pa(pmd);
 }
 
 #endif /* __s390x__ */
@@ -143,29 +114,19 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
        spin_lock_init(&mm->context.list_lock);
-       INIT_LIST_HEAD(&mm->context.crst_list);
        INIT_LIST_HEAD(&mm->context.pgtable_list);
-       return (pgd_t *)
-               crst_table_alloc(mm, user_mode == SECONDARY_SPACE_MODE);
+       return (pgd_t *) crst_table_alloc(mm);
 }
 #define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd)
 
-static inline void pmd_populate_kernel(struct mm_struct *mm,
-                                      pmd_t *pmd, pte_t *pte)
-{
-       pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte);
-}
-
 static inline void pmd_populate(struct mm_struct *mm,
                                pmd_t *pmd, pgtable_t pte)
 {
-       pmd_populate_kernel(mm, pmd, pte);
-       if (mm->context.noexec) {
-               pmd = get_shadow_table(pmd);
-               pmd_populate_kernel(mm, pmd, pte + PTRS_PER_PTE);
-       }
+       pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte);
 }
 
+#define pmd_populate_kernel(mm, pmd, pte) pmd_populate(mm, pmd, pte)
+
 #define pmd_pgtable(pmd) \
        (pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE)
 
index 02ace3491c51cca92625f2a39f30fe9aa9741ddb..c4773a2ef3d3ab2f3c672ed70dcc6c7117855c4f 100644 (file)
@@ -31,9 +31,8 @@
 #ifndef __ASSEMBLY__
 #include <linux/sched.h>
 #include <linux/mm_types.h>
-#include <asm/bitops.h>
 #include <asm/bug.h>
-#include <asm/processor.h>
+#include <asm/page.h>
 
 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
 extern void paging_init(void);
@@ -243,11 +242,13 @@ extern unsigned long VMALLOC_START;
 /* Software bits in the page table entry */
 #define _PAGE_SWT      0x001           /* SW pte type bit t */
 #define _PAGE_SWX      0x002           /* SW pte type bit x */
-#define _PAGE_SPECIAL  0x004           /* SW associated with special page */
+#define _PAGE_SWC      0x004           /* SW pte changed bit (for KVM) */
+#define _PAGE_SWR      0x008           /* SW pte referenced bit (for KVM) */
+#define _PAGE_SPECIAL  0x010           /* SW associated with special page */
 #define __HAVE_ARCH_PTE_SPECIAL
 
 /* Set of bits not changed in pte_modify */
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_SWC | _PAGE_SWR)
 
 /* Six different types of pages. */
 #define _PAGE_TYPE_EMPTY       0x400
@@ -256,8 +257,6 @@ extern unsigned long VMALLOC_START;
 #define _PAGE_TYPE_FILE                0x601   /* bit 0x002 is used for offset !! */
 #define _PAGE_TYPE_RO          0x200
 #define _PAGE_TYPE_RW          0x000
-#define _PAGE_TYPE_EX_RO       0x202
-#define _PAGE_TYPE_EX_RW       0x002
 
 /*
  * Only four types for huge pages, using the invalid bit and protection bit
@@ -287,8 +286,6 @@ extern unsigned long VMALLOC_START;
  * _PAGE_TYPE_FILE     11?1   ->   11?1
  * _PAGE_TYPE_RO       0100   ->   1100
  * _PAGE_TYPE_RW       0000   ->   1000
- * _PAGE_TYPE_EX_RO    0110   ->   1110
- * _PAGE_TYPE_EX_RW    0010   ->   1010
  *
  * pte_none is true for bits combinations 1000, 1010, 1100, 1110
  * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
@@ -297,14 +294,17 @@ extern unsigned long VMALLOC_START;
  */
 
 /* Page status table bits for virtualization */
-#define RCP_PCL_BIT    55
-#define RCP_HR_BIT     54
-#define RCP_HC_BIT     53
-#define RCP_GR_BIT     50
-#define RCP_GC_BIT     49
-
-/* User dirty bit for KVM's migration feature */
-#define KVM_UD_BIT     47
+#define RCP_ACC_BITS   0xf000000000000000UL
+#define RCP_FP_BIT     0x0800000000000000UL
+#define RCP_PCL_BIT    0x0080000000000000UL
+#define RCP_HR_BIT     0x0040000000000000UL
+#define RCP_HC_BIT     0x0020000000000000UL
+#define RCP_GR_BIT     0x0004000000000000UL
+#define RCP_GC_BIT     0x0002000000000000UL
+
+/* User dirty / referenced bit for KVM's migration feature */
+#define KVM_UR_BIT     0x0000800000000000UL
+#define KVM_UC_BIT     0x0000400000000000UL
 
 #ifndef __s390x__
 
@@ -377,85 +377,54 @@ extern unsigned long VMALLOC_START;
 #define _ASCE_USER_BITS                (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \
                                 _ASCE_ALT_EVENT)
 
-/* Bits int the storage key */
-#define _PAGE_CHANGED    0x02          /* HW changed bit                   */
-#define _PAGE_REFERENCED 0x04          /* HW referenced bit                */
-
 /*
  * Page protection definitions.
  */
 #define PAGE_NONE      __pgprot(_PAGE_TYPE_NONE)
 #define PAGE_RO                __pgprot(_PAGE_TYPE_RO)
 #define PAGE_RW                __pgprot(_PAGE_TYPE_RW)
-#define PAGE_EX_RO     __pgprot(_PAGE_TYPE_EX_RO)
-#define PAGE_EX_RW     __pgprot(_PAGE_TYPE_EX_RW)
 
 #define PAGE_KERNEL    PAGE_RW
 #define PAGE_COPY      PAGE_RO
 
 /*
- * Dependent on the EXEC_PROTECT option s390 can do execute protection.
- * Write permission always implies read permission. In theory with a
- * primary/secondary page table execute only can be implemented but
- * it would cost an additional bit in the pte to distinguish all the
- * different pte types. To avoid that execute permission currently
- * implies read permission as well.
+ * On s390 the page table entry has an invalid bit and a read-only bit.
+ * Read permission implies execute permission and write permission
+ * implies read permission.
  */
          /*xwr*/
 #define __P000 PAGE_NONE
 #define __P001 PAGE_RO
 #define __P010 PAGE_RO
 #define __P011 PAGE_RO
-#define __P100 PAGE_EX_RO
-#define __P101 PAGE_EX_RO
-#define __P110 PAGE_EX_RO
-#define __P111 PAGE_EX_RO
+#define __P100 PAGE_RO
+#define __P101 PAGE_RO
+#define __P110 PAGE_RO
+#define __P111 PAGE_RO
 
 #define __S000 PAGE_NONE
 #define __S001 PAGE_RO
 #define __S010 PAGE_RW
 #define __S011 PAGE_RW
-#define __S100 PAGE_EX_RO
-#define __S101 PAGE_EX_RO
-#define __S110 PAGE_EX_RW
-#define __S111 PAGE_EX_RW
-
-#ifndef __s390x__
-# define PxD_SHADOW_SHIFT      1
-#else /* __s390x__ */
-# define PxD_SHADOW_SHIFT      2
-#endif /* __s390x__ */
+#define __S100 PAGE_RO
+#define __S101 PAGE_RO
+#define __S110 PAGE_RW
+#define __S111 PAGE_RW
 
-static inline void *get_shadow_table(void *table)
+static inline int mm_exclusive(struct mm_struct *mm)
 {
-       unsigned long addr, offset;
-       struct page *page;
-
-       addr = (unsigned long) table;
-       offset = addr & ((PAGE_SIZE << PxD_SHADOW_SHIFT) - 1);
-       page = virt_to_page((void *)(addr ^ offset));
-       return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL);
+       return likely(mm == current->active_mm &&
+                     atomic_read(&mm->context.attach_count) <= 1);
 }
 
-/*
- * Certain architectures need to do special things when PTEs
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
-                             pte_t *ptep, pte_t entry)
+static inline int mm_has_pgste(struct mm_struct *mm)
 {
-       *ptep = entry;
-       if (mm->context.noexec) {
-               if (!(pte_val(entry) & _PAGE_INVALID) &&
-                   (pte_val(entry) & _PAGE_SWX))
-                       pte_val(entry) |= _PAGE_RO;
-               else
-                       pte_val(entry) = _PAGE_TYPE_EMPTY;
-               ptep[PTRS_PER_PTE] = entry;
-       }
+#ifdef CONFIG_PGSTE
+       if (unlikely(mm->context.has_pgste))
+               return 1;
+#endif
+       return 0;
 }
-
 /*
  * pgd/pmd/pte query functions
  */
@@ -568,52 +537,127 @@ static inline int pte_special(pte_t pte)
 }
 
 #define __HAVE_ARCH_PTE_SAME
-#define pte_same(a,b)  (pte_val(a) == pte_val(b))
+static inline int pte_same(pte_t a, pte_t b)
+{
+       return pte_val(a) == pte_val(b);
+}
 
-static inline void rcp_lock(pte_t *ptep)
+static inline pgste_t pgste_get_lock(pte_t *ptep)
 {
+       unsigned long new = 0;
 #ifdef CONFIG_PGSTE
-       unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+       unsigned long old;
+
        preempt_disable();
-       while (test_and_set_bit(RCP_PCL_BIT, pgste))
-               ;
+       asm(
+               "       lg      %0,%2\n"
+               "0:     lgr     %1,%0\n"
+               "       nihh    %0,0xff7f\n"    /* clear RCP_PCL_BIT in old */
+               "       oihh    %1,0x0080\n"    /* set RCP_PCL_BIT in new */
+               "       csg     %0,%1,%2\n"
+               "       jl      0b\n"
+               : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE])
+               : "Q" (ptep[PTRS_PER_PTE]) : "cc");
 #endif
+       return __pgste(new);
 }
 
-static inline void rcp_unlock(pte_t *ptep)
+static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
-       unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-       clear_bit(RCP_PCL_BIT, pgste);
+       asm(
+               "       nihh    %1,0xff7f\n"    /* clear RCP_PCL_BIT */
+               "       stg     %1,%0\n"
+               : "=Q" (ptep[PTRS_PER_PTE])
+               : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE]) : "cc");
        preempt_enable();
 #endif
 }
 
-/* forward declaration for SetPageUptodate in page-flags.h*/
-static inline void page_clear_dirty(struct page *page, int mapped);
-#include <linux/page-flags.h>
-
-static inline void ptep_rcp_copy(pte_t *ptep)
+static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
 {
 #ifdef CONFIG_PGSTE
-       struct page *page = virt_to_page(pte_val(*ptep));
-       unsigned int skey;
-       unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-
-       skey = page_get_storage_key(page_to_phys(page));
-       if (skey & _PAGE_CHANGED) {
-               set_bit_simple(RCP_GC_BIT, pgste);
-               set_bit_simple(KVM_UD_BIT, pgste);
+       unsigned long pfn, bits;
+       unsigned char skey;
+
+       pfn = pte_val(*ptep) >> PAGE_SHIFT;
+       skey = page_get_storage_key(pfn);
+       bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
+       /* Clear page changed & referenced bit in the storage key */
+       if (bits) {
+               skey ^= bits;
+               page_set_storage_key(pfn, skey, 1);
        }
-       if (skey & _PAGE_REFERENCED)
-               set_bit_simple(RCP_GR_BIT, pgste);
-       if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
-               SetPageDirty(page);
-               set_bit_simple(KVM_UD_BIT, pgste);
-       }
-       if (test_and_clear_bit_simple(RCP_HR_BIT, pgste))
-               SetPageReferenced(page);
+       /* Transfer page changed & referenced bit to guest bits in pgste */
+       pgste_val(pgste) |= bits << 48;         /* RCP_GR_BIT & RCP_GC_BIT */
+       /* Get host changed & referenced bits from pgste */
+       bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52;
+       /* Clear host bits in pgste. */
+       pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT);
+       pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT);
+       /* Copy page access key and fetch protection bit to pgste */
+       pgste_val(pgste) |=
+               (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
+       /* Transfer changed and referenced to kvm user bits */
+       pgste_val(pgste) |= bits << 45;         /* KVM_UR_BIT & KVM_UC_BIT */
+       /* Transfer changed & referenced to pte sofware bits */
+       pte_val(*ptep) |= bits << 1;            /* _PAGE_SWR & _PAGE_SWC */
 #endif
+       return pgste;
+
+}
+
+static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
+{
+#ifdef CONFIG_PGSTE
+       int young;
+
+       young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
+       /* Transfer page referenced bit to pte software bit (host view) */
+       if (young || (pgste_val(pgste) & RCP_HR_BIT))
+               pte_val(*ptep) |= _PAGE_SWR;
+       /* Clear host referenced bit in pgste. */
+       pgste_val(pgste) &= ~RCP_HR_BIT;
+       /* Transfer page referenced bit to guest bit in pgste */
+       pgste_val(pgste) |= (unsigned long) young << 50; /* set RCP_GR_BIT */
+#endif
+       return pgste;
+
+}
+
+static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste)
+{
+#ifdef CONFIG_PGSTE
+       unsigned long pfn;
+       unsigned long okey, nkey;
+
+       pfn = pte_val(*ptep) >> PAGE_SHIFT;
+       okey = nkey = page_get_storage_key(pfn);
+       nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT);
+       /* Set page access key and fetch protection bit from pgste */
+       nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56;
+       if (okey != nkey)
+               page_set_storage_key(pfn, nkey, 1);
+#endif
+}
+
+/*
+ * Certain architectures need to do special things when PTEs
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t entry)
+{
+       pgste_t pgste;
+
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_get_lock(ptep);
+               pgste_set_pte(ptep, pgste);
+               *ptep = entry;
+               pgste_set_unlock(ptep, pgste);
+       } else
+               *ptep = entry;
 }
 
 /*
@@ -627,19 +671,19 @@ static inline int pte_write(pte_t pte)
 
 static inline int pte_dirty(pte_t pte)
 {
-       /* A pte is neither clean nor dirty on s/390. The dirty bit
-        * is in the storage key. See page_test_and_clear_dirty for
-        * details.
-        */
+#ifdef CONFIG_PGSTE
+       if (pte_val(pte) & _PAGE_SWC)
+               return 1;
+#endif
        return 0;
 }
 
 static inline int pte_young(pte_t pte)
 {
-       /* A pte is neither young nor old on s/390. The young bit
-        * is in the storage key. See page_test_and_clear_young for
-        * details.
-        */
+#ifdef CONFIG_PGSTE
+       if (pte_val(pte) & _PAGE_SWR)
+               return 1;
+#endif
        return 0;
 }
 
@@ -647,64 +691,30 @@ static inline int pte_young(pte_t pte)
  * pgd/pmd/pte modification functions
  */
 
-#ifndef __s390x__
-
-#define pgd_clear(pgd)         do { } while (0)
-#define pud_clear(pud)         do { } while (0)
-
-#else /* __s390x__ */
-
-static inline void pgd_clear_kernel(pgd_t * pgd)
+static inline void pgd_clear(pgd_t *pgd)
 {
+#ifdef __s390x__
        if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2)
                pgd_val(*pgd) = _REGION2_ENTRY_EMPTY;
+#endif
 }
 
-static inline void pgd_clear(pgd_t * pgd)
-{
-       pgd_t *shadow = get_shadow_table(pgd);
-
-       pgd_clear_kernel(pgd);
-       if (shadow)
-               pgd_clear_kernel(shadow);
-}
-
-static inline void pud_clear_kernel(pud_t *pud)
+static inline void pud_clear(pud_t *pud)
 {
+#ifdef __s390x__
        if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
                pud_val(*pud) = _REGION3_ENTRY_EMPTY;
+#endif
 }
 
-static inline void pud_clear(pud_t *pud)
-{
-       pud_t *shadow = get_shadow_table(pud);
-
-       pud_clear_kernel(pud);
-       if (shadow)
-               pud_clear_kernel(shadow);
-}
-
-#endif /* __s390x__ */
-
-static inline void pmd_clear_kernel(pmd_t * pmdp)
+static inline void pmd_clear(pmd_t *pmdp)
 {
        pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY;
 }
 
-static inline void pmd_clear(pmd_t *pmd)
-{
-       pmd_t *shadow = get_shadow_table(pmd);
-
-       pmd_clear_kernel(pmd);
-       if (shadow)
-               pmd_clear_kernel(shadow);
-}
-
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
        pte_val(*ptep) = _PAGE_TYPE_EMPTY;
-       if (mm->context.noexec)
-               pte_val(ptep[PTRS_PER_PTE]) = _PAGE_TYPE_EMPTY;
 }
 
 /*
@@ -734,35 +744,27 @@ static inline pte_t pte_mkwrite(pte_t pte)
 
 static inline pte_t pte_mkclean(pte_t pte)
 {
-       /* The only user of pte_mkclean is the fork() code.
-          We must *not* clear the *physical* page dirty bit
-          just because fork() wants to clear the dirty bit in
-          *one* of the page's mappings.  So we just do nothing. */
+#ifdef CONFIG_PGSTE
+       pte_val(pte) &= ~_PAGE_SWC;
+#endif
        return pte;
 }
 
 static inline pte_t pte_mkdirty(pte_t pte)
 {
-       /* We do not explicitly set the dirty bit because the
-        * sske instruction is slow. It is faster to let the
-        * next instruction set the dirty bit.
-        */
        return pte;
 }
 
 static inline pte_t pte_mkold(pte_t pte)
 {
-       /* S/390 doesn't keep its dirty/referenced bit in the pte.
-        * There is no point in clearing the real referenced bit.
-        */
+#ifdef CONFIG_PGSTE
+       pte_val(pte) &= ~_PAGE_SWR;
+#endif
        return pte;
 }
 
 static inline pte_t pte_mkyoung(pte_t pte)
 {
-       /* S/390 doesn't keep its dirty/referenced bit in the pte.
-        * There is no point in setting the real referenced bit.
-        */
        return pte;
 }
 
@@ -800,62 +802,60 @@ static inline pte_t pte_mkhuge(pte_t pte)
 }
 #endif
 
-#ifdef CONFIG_PGSTE
 /*
- * Get (and clear) the user dirty bit for a PTE.
+ * Get (and clear) the user dirty bit for a pte.
  */
-static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
-                                                    pte_t *ptep)
+static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm,
+                                                pte_t *ptep)
 {
-       int dirty;
-       unsigned long *pgste;
-       struct page *page;
-       unsigned int skey;
-
-       if (!mm->context.has_pgste)
-               return -EINVAL;
-       rcp_lock(ptep);
-       pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-       page = virt_to_page(pte_val(*ptep));
-       skey = page_get_storage_key(page_to_phys(page));
-       if (skey & _PAGE_CHANGED) {
-               set_bit_simple(RCP_GC_BIT, pgste);
-               set_bit_simple(KVM_UD_BIT, pgste);
+       pgste_t pgste;
+       int dirty = 0;
+
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_get_lock(ptep);
+               pgste = pgste_update_all(ptep, pgste);
+               dirty = !!(pgste_val(pgste) & KVM_UC_BIT);
+               pgste_val(pgste) &= ~KVM_UC_BIT;
+               pgste_set_unlock(ptep, pgste);
+               return dirty;
        }
-       if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
-               SetPageDirty(page);
-               set_bit_simple(KVM_UD_BIT, pgste);
-       }
-       dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste);
-       if (skey & _PAGE_CHANGED)
-               page_clear_dirty(page, 1);
-       rcp_unlock(ptep);
        return dirty;
 }
-#endif
+
+/*
+ * Get (and clear) the user referenced bit for a pte.
+ */
+static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
+                                                pte_t *ptep)
+{
+       pgste_t pgste;
+       int young = 0;
+
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_get_lock(ptep);
+               pgste = pgste_update_young(ptep, pgste);
+               young = !!(pgste_val(pgste) & KVM_UR_BIT);
+               pgste_val(pgste) &= ~KVM_UR_BIT;
+               pgste_set_unlock(ptep, pgste);
+       }
+       return young;
+}
 
 #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)
 {
-#ifdef CONFIG_PGSTE
-       unsigned long physpage;
-       int young;
-       unsigned long *pgste;
+       pgste_t pgste;
+       pte_t pte;
 
-       if (!vma->vm_mm->context.has_pgste)
-               return 0;
-       physpage = pte_val(*ptep) & PAGE_MASK;
-       pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-
-       young = ((page_get_storage_key(physpage) & _PAGE_REFERENCED) != 0);
-       rcp_lock(ptep);
-       if (young)
-               set_bit_simple(RCP_GR_BIT, pgste);
-       young |= test_and_clear_bit_simple(RCP_HR_BIT, pgste);
-       rcp_unlock(ptep);
-       return young;
-#endif
+       if (mm_has_pgste(vma->vm_mm)) {
+               pgste = pgste_get_lock(ptep);
+               pgste = pgste_update_young(ptep, pgste);
+               pte = *ptep;
+               *ptep = pte_mkold(pte);
+               pgste_set_unlock(ptep, pgste);
+               return pte_young(pte);
+       }
        return 0;
 }
 
@@ -867,10 +867,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
         * On s390 reference bits are in storage key and never in TLB
         * With virtualization we handle the reference bit, without we
         * we can simply return */
-#ifdef CONFIG_PGSTE
        return ptep_test_and_clear_young(vma, address, ptep);
-#endif
-       return 0;
 }
 
 static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
@@ -890,25 +887,6 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
        }
 }
 
-static inline void ptep_invalidate(struct mm_struct *mm,
-                                  unsigned long address, pte_t *ptep)
-{
-       if (mm->context.has_pgste) {
-               rcp_lock(ptep);
-               __ptep_ipte(address, ptep);
-               ptep_rcp_copy(ptep);
-               pte_val(*ptep) = _PAGE_TYPE_EMPTY;
-               rcp_unlock(ptep);
-               return;
-       }
-       __ptep_ipte(address, ptep);
-       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
-       if (mm->context.noexec) {
-               __ptep_ipte(address, ptep + PTRS_PER_PTE);
-               pte_val(*(ptep + PTRS_PER_PTE)) = _PAGE_TYPE_EMPTY;
-       }
-}
-
 /*
  * This is hard to understand. ptep_get_and_clear and ptep_clear_flush
  * both clear the TLB for the unmapped pte. The reason is that
@@ -923,24 +901,72 @@ static inline void ptep_invalidate(struct mm_struct *mm,
  * is a nop.
  */
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-#define ptep_get_and_clear(__mm, __address, __ptep)                    \
-({                                                                     \
-       pte_t __pte = *(__ptep);                                        \
-       (__mm)->context.flush_mm = 1;                                   \
-       if (atomic_read(&(__mm)->context.attach_count) > 1 ||           \
-           (__mm) != current->active_mm)                               \
-               ptep_invalidate(__mm, __address, __ptep);               \
-       else                                                            \
-               pte_clear((__mm), (__address), (__ptep));               \
-       __pte;                                                          \
-})
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+                                      unsigned long address, pte_t *ptep)
+{
+       pgste_t pgste;
+       pte_t pte;
+
+       mm->context.flush_mm = 1;
+       if (mm_has_pgste(mm))
+               pgste = pgste_get_lock(ptep);
+
+       pte = *ptep;
+       if (!mm_exclusive(mm))
+               __ptep_ipte(address, ptep);
+       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_update_all(&pte, pgste);
+               pgste_set_unlock(ptep, pgste);
+       }
+       return pte;
+}
+
+#define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
+static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
+                                          unsigned long address,
+                                          pte_t *ptep)
+{
+       pte_t pte;
+
+       mm->context.flush_mm = 1;
+       if (mm_has_pgste(mm))
+               pgste_get_lock(ptep);
+
+       pte = *ptep;
+       if (!mm_exclusive(mm))
+               __ptep_ipte(address, ptep);
+       return pte;
+}
+
+static inline void ptep_modify_prot_commit(struct mm_struct *mm,
+                                          unsigned long address,
+                                          pte_t *ptep, pte_t pte)
+{
+       *ptep = pte;
+       if (mm_has_pgste(mm))
+               pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE));
+}
 
 #define __HAVE_ARCH_PTEP_CLEAR_FLUSH
 static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
                                     unsigned long address, pte_t *ptep)
 {
-       pte_t pte = *ptep;
-       ptep_invalidate(vma->vm_mm, address, ptep);
+       pgste_t pgste;
+       pte_t pte;
+
+       if (mm_has_pgste(vma->vm_mm))
+               pgste = pgste_get_lock(ptep);
+
+       pte = *ptep;
+       __ptep_ipte(address, ptep);
+       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+
+       if (mm_has_pgste(vma->vm_mm)) {
+               pgste = pgste_update_all(&pte, pgste);
+               pgste_set_unlock(ptep, pgste);
+       }
        return pte;
 }
 
@@ -953,76 +979,67 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
  */
 #define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
 static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
-                                           unsigned long addr,
+                                           unsigned long address,
                                            pte_t *ptep, int full)
 {
-       pte_t pte = *ptep;
+       pgste_t pgste;
+       pte_t pte;
+
+       if (mm_has_pgste(mm))
+               pgste = pgste_get_lock(ptep);
+
+       pte = *ptep;
+       if (!full)
+               __ptep_ipte(address, ptep);
+       pte_val(*ptep) = _PAGE_TYPE_EMPTY;
 
-       if (full)
-               pte_clear(mm, addr, ptep);
-       else
-               ptep_invalidate(mm, addr, ptep);
+       if (mm_has_pgste(mm)) {
+               pgste = pgste_update_all(&pte, pgste);
+               pgste_set_unlock(ptep, pgste);
+       }
        return pte;
 }
 
 #define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define ptep_set_wrprotect(__mm, __addr, __ptep)                       \
-({                                                                     \
-       pte_t __pte = *(__ptep);                                        \
-       if (pte_write(__pte)) {                                         \
-               (__mm)->context.flush_mm = 1;                           \
-               if (atomic_read(&(__mm)->context.attach_count) > 1 ||   \
-                   (__mm) != current->active_mm)                       \
-                       ptep_invalidate(__mm, __addr, __ptep);          \
-               set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \
-       }                                                               \
-})
+static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
+                                      unsigned long address, pte_t *ptep)
+{
+       pgste_t pgste;
+       pte_t pte = *ptep;
 
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-#define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
-({                                                                     \
-       int __changed = !pte_same(*(__ptep), __entry);                  \
-       if (__changed) {                                                \
-               ptep_invalidate((__vma)->vm_mm, __addr, __ptep);        \
-               set_pte_at((__vma)->vm_mm, __addr, __ptep, __entry);    \
-       }                                                               \
-       __changed;                                                      \
-})
+       if (pte_write(pte)) {
+               mm->context.flush_mm = 1;
+               if (mm_has_pgste(mm))
+                       pgste = pgste_get_lock(ptep);
 
-/*
- * Test and clear dirty bit in storage key.
- * We can't clear the changed bit atomically. This is a potential
- * race against modification of the referenced bit. This function
- * should therefore only be called if it is not mapped in any
- * address space.
- */
-#define __HAVE_ARCH_PAGE_TEST_DIRTY
-static inline int page_test_dirty(struct page *page)
-{
-       return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0;
-}
+               if (!mm_exclusive(mm))
+                       __ptep_ipte(address, ptep);
+               *ptep = pte_wrprotect(pte);
 
-#define __HAVE_ARCH_PAGE_CLEAR_DIRTY
-static inline void page_clear_dirty(struct page *page, int mapped)
-{
-       page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, mapped);
+               if (mm_has_pgste(mm))
+                       pgste_set_unlock(ptep, pgste);
+       }
+       return pte;
 }
 
-/*
- * Test and clear referenced bit in storage key.
- */
-#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
-static inline int page_test_and_clear_young(struct page *page)
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline int ptep_set_access_flags(struct vm_area_struct *vma,
+                                       unsigned long address, pte_t *ptep,
+                                       pte_t entry, int dirty)
 {
-       unsigned long physpage = page_to_phys(page);
-       int ccode;
-
-       asm volatile(
-               "       rrbe    0,%1\n"
-               "       ipm     %0\n"
-               "       srl     %0,28\n"
-               : "=d" (ccode) : "a" (physpage) : "cc" );
-       return ccode & 2;
+       pgste_t pgste;
+
+       if (pte_same(*ptep, entry))
+               return 0;
+       if (mm_has_pgste(vma->vm_mm))
+               pgste = pgste_get_lock(ptep);
+
+       __ptep_ipte(address, ptep);
+       *ptep = entry;
+
+       if (mm_has_pgste(vma->vm_mm))
+               pgste_set_unlock(ptep, pgste);
+       return 1;
 }
 
 /*
index 2c79b64162713b63e95b7a80b825e29660813d91..1300c30253349bdc03bc7273441790209ff3c61c 100644 (file)
@@ -84,6 +84,7 @@ struct thread_struct {
        struct per_event per_event;     /* Cause of the last PER trap */
         /* pfault_wait is used to block the process on a pfault event */
        unsigned long pfault_wait;
+       struct list_head list;
 };
 
 typedef struct thread_struct thread_struct;
index 29d5d6d4becc7e12a4a5a0b9801a0de554c44b68..b7a4f2eb00573388070f1dda84d6014b638103f8 100644 (file)
@@ -50,7 +50,7 @@ static inline void __tlb_flush_full(struct mm_struct *mm)
        /*
         * If the process only ran on the local cpu, do a local flush.
         */
-       local_cpumask = cpumask_of_cpu(smp_processor_id());
+       cpumask_copy(&local_cpumask, cpumask_of(smp_processor_id()));
        if (cpumask_equal(mm_cpumask(mm), &local_cpumask))
                __tlb_flush_local();
        else
@@ -80,16 +80,11 @@ static inline void __tlb_flush_mm(struct mm_struct * mm)
         * on all cpus instead of doing a local flush if the mm
         * only ran on the local cpu.
         */
-       if (MACHINE_HAS_IDTE) {
-               if (mm->context.noexec)
-                       __tlb_flush_idte((unsigned long)
-                                        get_shadow_table(mm->pgd) |
-                                        mm->context.asce_bits);
+       if (MACHINE_HAS_IDTE)
                __tlb_flush_idte((unsigned long) mm->pgd |
                                 mm->context.asce_bits);
-               return;
-       }
-       __tlb_flush_full(mm);
+       else
+               __tlb_flush_full(mm);
 }
 
 static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
index e821525723775c8f2ca745daffddd21f91f62d41..9208e69245a0b0e5a3853fdb38486d119e298ccb 100644 (file)
 
 /* Ignore system calls that are also reachable via sys_socket */
 #define __IGNORE_recvmmsg
+#define __IGNORE_sendmmsg
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index fe03c140002a56ea8643ee17ab481381a749ce2b..edfbd17d70826b3c761b0cd8f2e46d7c24a58781 100644 (file)
@@ -124,13 +124,11 @@ int main(void)
        DEFINE(__LC_LAST_UPDATE_TIMER, offsetof(struct _lowcore, last_update_timer));
        DEFINE(__LC_LAST_UPDATE_CLOCK, offsetof(struct _lowcore, last_update_clock));
        DEFINE(__LC_CURRENT, offsetof(struct _lowcore, current_task));
+       DEFINE(__LC_CURRENT_PID, offsetof(struct _lowcore, current_pid));
        DEFINE(__LC_THREAD_INFO, offsetof(struct _lowcore, thread_info));
        DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack));
        DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack));
        DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));
-       DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce));
-       DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
-       DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce));
        DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
        DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
        DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
index 1b67fc6ebdc25f1407e569f3114bc3cb4827fd72..0476174dfff59695ee00f9985e6ebadb6da05b9a 100644 (file)
@@ -212,6 +212,7 @@ __switch_to:
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        lm      %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        st      %r3,__LC_CURRENT                # store task struct of next
+       mvc     __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
        st      %r5,__LC_THREAD_INFO            # store thread info of next
        ahi     %r5,STACK_SIZE                  # end of kernel stack of next
        st      %r5,__LC_KERNEL_STACK           # store end of kernel stack
index 9fd864563499bb7e46f0cd85d4a03550b32a15ac..d61967e2eab01582b9509db83ebeba935ec16a3a 100644 (file)
@@ -220,6 +220,7 @@ __switch_to:
        lctl    %c4,%c4,__TASK_pid(%r3)         # load pid to control reg. 4
        lmg     %r6,%r15,__SF_GPRS(%r15)        # load gprs of next task
        stg     %r3,__LC_CURRENT                # store task struct of next
+       mvc     __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
        stg     %r5,__LC_THREAD_INFO            # store thread info of next
        aghi    %r5,STACK_SIZE                  # end of kernel stack of next
        stg     %r5,__LC_KERNEL_STACK           # store end of kernel stack
index ea5099c9709c1213cc16f7b5ab2fc8a74372de09..e204f9597aafa1df6fd51fe3a971ff41b3272f3d 100644 (file)
@@ -32,6 +32,7 @@ static const struct irq_class intrclass_names[] = {
        {.name = "VRT", .desc = "[EXT] Virtio" },
        {.name = "SCP", .desc = "[EXT] Service Call" },
        {.name = "IUC", .desc = "[EXT] IUCV" },
+       {.name = "CPM", .desc = "[EXT] CPU Measurement" },
        {.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" },
        {.name = "QDI", .desc = "[I/O] QDIO Interrupt" },
        {.name = "DAS", .desc = "[I/O] DASD" },
index a895e69379f75233a84ab98681fbd9dc6421fbe1..541a7509faebd47f7b9d5a72a1f779c3efa2e1f4 100644 (file)
@@ -9,41 +9,26 @@
 
 #include <linux/compiler.h>
 #include <linux/cpu.h>
-#include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/fs.h>
 #include <linux/smp.h>
-#include <linux/stddef.h>
 #include <linux/slab.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/vmalloc.h>
-#include <linux/user.h>
 #include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/notifier.h>
 #include <linux/tick.h>
-#include <linux/elfcore.h>
-#include <linux/kernel_stat.h>
 #include <linux/personality.h>
 #include <linux/syscalls.h>
 #include <linux/compat.h>
 #include <linux/kprobes.h>
 #include <linux/random.h>
-#include <asm/compat.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
+#include <linux/module.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/irq.h>
 #include <asm/timer.h>
 #include <asm/nmi.h>
+#include <asm/compat.h>
 #include <asm/smp.h>
 #include "entry.h"
 
index f5434d1ecb3166136eaf77e509d04e327b39165b..0c35dee10b00e93b005114c7b0d031531b7fc253 100644 (file)
@@ -305,8 +305,7 @@ static int set_amode_and_uaccess(unsigned long user_amode,
  */
 static int __init early_parse_switch_amode(char *p)
 {
-       if (user_mode != SECONDARY_SPACE_MODE)
-               user_mode = PRIMARY_SPACE_MODE;
+       user_mode = PRIMARY_SPACE_MODE;
        return 0;
 }
 early_param("switch_amode", early_parse_switch_amode);
@@ -315,10 +314,6 @@ static int __init early_parse_user_mode(char *p)
 {
        if (p && strcmp(p, "primary") == 0)
                user_mode = PRIMARY_SPACE_MODE;
-#ifdef CONFIG_S390_EXEC_PROTECT
-       else if (p && strcmp(p, "secondary") == 0)
-               user_mode = SECONDARY_SPACE_MODE;
-#endif
        else if (!p || strcmp(p, "home") == 0)
                user_mode = HOME_SPACE_MODE;
        else
@@ -327,31 +322,9 @@ static int __init early_parse_user_mode(char *p)
 }
 early_param("user_mode", early_parse_user_mode);
 
-#ifdef CONFIG_S390_EXEC_PROTECT
-/*
- * Enable execute protection?
- */
-static int __init early_parse_noexec(char *p)
-{
-       if (!strncmp(p, "off", 3))
-               return 0;
-       user_mode = SECONDARY_SPACE_MODE;
-       return 0;
-}
-early_param("noexec", early_parse_noexec);
-#endif /* CONFIG_S390_EXEC_PROTECT */
-
 static void setup_addressing_mode(void)
 {
-       if (user_mode == SECONDARY_SPACE_MODE) {
-               if (set_amode_and_uaccess(PSW_ASC_SECONDARY,
-                                         PSW32_ASC_SECONDARY))
-                       pr_info("Execute protection active, "
-                               "mvcos available\n");
-               else
-                       pr_info("Execute protection active, "
-                               "mvcos not available\n");
-       } else if (user_mode == PRIMARY_SPACE_MODE) {
+       if (user_mode == PRIMARY_SPACE_MODE) {
                if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY))
                        pr_info("Address spaces switched, "
                                "mvcos available\n");
index 63c7d9ff220d1545dea5d3cded8e96a3216af3aa..f8e85ecbc4590e8f8d45a78f7ab776e9480227a4 100644 (file)
@@ -335,7 +335,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail)
                smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN;
                if (!cpu_stopped(logical_cpu))
                        continue;
-               cpu_set(logical_cpu, cpu_present_map);
+               set_cpu_present(logical_cpu, true);
                smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
                logical_cpu = cpumask_next(logical_cpu, &avail);
                if (logical_cpu >= nr_cpu_ids)
@@ -367,7 +367,7 @@ static int smp_rescan_cpus_sclp(cpumask_t avail)
                        continue;
                __cpu_logical_map[logical_cpu] = cpu_id;
                smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN;
-               cpu_set(logical_cpu, cpu_present_map);
+               set_cpu_present(logical_cpu, true);
                if (cpu >= info->configured)
                        smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
                else
@@ -385,7 +385,7 @@ static int __smp_rescan_cpus(void)
 {
        cpumask_t avail;
 
-       cpus_xor(avail, cpu_possible_map, cpu_present_map);
+       cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
        if (smp_use_sigp_detection)
                return smp_rescan_cpus_sigp(avail);
        else
@@ -467,7 +467,7 @@ int __cpuinit start_secondary(void *cpuvoid)
        notify_cpu_starting(smp_processor_id());
        /* Mark this cpu as online */
        ipi_call_lock();
-       cpu_set(smp_processor_id(), cpu_online_map);
+       set_cpu_online(smp_processor_id(), true);
        ipi_call_unlock();
        /* Switch on interrupts */
        local_irq_enable();
@@ -644,7 +644,7 @@ int __cpu_disable(void)
        struct ec_creg_mask_parms cr_parms;
        int cpu = smp_processor_id();
 
-       cpu_clear(cpu, cpu_online_map);
+       set_cpu_online(cpu, false);
 
        /* Disable pfault pseudo page faults on this cpu. */
        pfault_fini();
@@ -654,8 +654,8 @@ int __cpu_disable(void)
 
        /* disable all external interrupts */
        cr_parms.orvals[0] = 0;
-       cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 |
-                               1 << 11 | 1 << 10 | 1 <<  6 | 1 <<  4);
+       cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 11 |
+                               1 << 10 | 1 <<  9 | 1 <<  6 | 1 <<  4);
        /* disable all I/O interrupts */
        cr_parms.orvals[6] = 0;
        cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 |
@@ -681,7 +681,7 @@ void __cpu_die(unsigned int cpu)
        atomic_dec(&init_mm.context.attach_count);
 }
 
-void cpu_die(void)
+void __noreturn cpu_die(void)
 {
        idle_task_exit();
        while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
@@ -738,8 +738,8 @@ void __init smp_prepare_boot_cpu(void)
        BUG_ON(smp_processor_id() != 0);
 
        current_thread_info()->cpu = 0;
-       cpu_set(0, cpu_present_map);
-       cpu_set(0, cpu_online_map);
+       set_cpu_present(0, true);
+       set_cpu_online(0, true);
        S390_lowcore.percpu_offset = __per_cpu_offset[0];
        current_set[0] = current;
        smp_cpu_state[0] = CPU_STATE_CONFIGURED;
@@ -1016,21 +1016,21 @@ int __ref smp_rescan_cpus(void)
 
        get_online_cpus();
        mutex_lock(&smp_cpu_state_mutex);
-       newcpus = cpu_present_map;
+       cpumask_copy(&newcpus, cpu_present_mask);
        rc = __smp_rescan_cpus();
        if (rc)
                goto out;
-       cpus_andnot(newcpus, cpu_present_map, newcpus);
-       for_each_cpu_mask(cpu, newcpus) {
+       cpumask_andnot(&newcpus, cpu_present_mask, &newcpus);
+       for_each_cpu(cpu, &newcpus) {
                rc = smp_add_present_cpu(cpu);
                if (rc)
-                       cpu_clear(cpu, cpu_present_map);
+                       set_cpu_present(cpu, false);
        }
        rc = 0;
 out:
        mutex_unlock(&smp_cpu_state_mutex);
        put_online_cpus();
-       if (!cpus_empty(newcpus))
+       if (!cpumask_empty(&newcpus))
                topology_schedule_update();
        return rc;
 }
index 87be655557aa48d4e0a0237e245977ffde9b0620..a59557f1fb5fd5a9c5e6fec4fc9b41169612205b 100644 (file)
@@ -810,7 +810,7 @@ static int etr_sync_clock_stop(struct etr_aib *aib, int port)
        etr_sync.etr_port = port;
        get_online_cpus();
        atomic_set(&etr_sync.cpus, num_online_cpus() - 1);
-       rc = stop_machine(etr_sync_clock, &etr_sync, &cpu_online_map);
+       rc = stop_machine(etr_sync_clock, &etr_sync, cpu_online_mask);
        put_online_cpus();
        return rc;
 }
@@ -1579,7 +1579,7 @@ static void stp_work_fn(struct work_struct *work)
        memset(&stp_sync, 0, sizeof(stp_sync));
        get_online_cpus();
        atomic_set(&stp_sync.cpus, num_online_cpus() - 1);
-       stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map);
+       stop_machine(stp_sync_clock, &stp_sync, cpu_online_mask);
        put_online_cpus();
 
        if (!check_sync_clock())
index 94b06c31fc8a389c752bcefe843d237ed1871a1a..2eafb8c7a746f2a018ca7dcb75475d7aefa0951d 100644 (file)
@@ -52,20 +52,20 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
 {
        cpumask_t mask;
 
-       cpus_clear(mask);
+       cpumask_clear(&mask);
        if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) {
                cpumask_copy(&mask, cpumask_of(cpu));
                return mask;
        }
        while (info) {
-               if (cpu_isset(cpu, info->mask)) {
+               if (cpumask_test_cpu(cpu, &info->mask)) {
                        mask = info->mask;
                        break;
                }
                info = info->next;
        }
-       if (cpus_empty(mask))
-               mask = cpumask_of_cpu(cpu);
+       if (cpumask_empty(&mask))
+               cpumask_copy(&mask, cpumask_of(cpu));
        return mask;
 }
 
@@ -85,10 +85,10 @@ static void add_cpus_to_mask(struct topology_cpu *tl_cpu,
                        if (cpu_logical_map(lcpu) != rcpu)
                                continue;
 #ifdef CONFIG_SCHED_BOOK
-                       cpu_set(lcpu, book->mask);
+                       cpumask_set_cpu(lcpu, &book->mask);
                        cpu_book_id[lcpu] = book->id;
 #endif
-                       cpu_set(lcpu, core->mask);
+                       cpumask_set_cpu(lcpu, &core->mask);
                        cpu_core_id[lcpu] = core->id;
                        smp_cpu_polarization[lcpu] = tl_cpu->pp;
                }
@@ -101,13 +101,13 @@ static void clear_masks(void)
 
        info = &core_info;
        while (info) {
-               cpus_clear(info->mask);
+               cpumask_clear(&info->mask);
                info = info->next;
        }
 #ifdef CONFIG_SCHED_BOOK
        info = &book_info;
        while (info) {
-               cpus_clear(info->mask);
+               cpumask_clear(&info->mask);
                info = info->next;
        }
 #endif
index d13e8755a8cce46e1a97a260893aaa6fd10c8767..8ad2b34ad151324346a07fdefa5e3682c5a33e35 100644 (file)
@@ -22,6 +22,9 @@ obj-y += vdso32_wrapper.o
 extra-y += vdso32.lds
 CPPFLAGS_vdso32.lds += -P -C -U$(ARCH)
 
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
 # Force dependency (incbin is bad)
 $(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
 
index 449352dda9cdb9a81209d3ff3f49cf61c0356a82..2a8ddfd12a5b97c6273b171f55da81b1fbdee940 100644 (file)
@@ -22,6 +22,9 @@ obj-y += vdso64_wrapper.o
 extra-y += vdso64.lds
 CPPFLAGS_vdso64.lds += -P -C -U$(ARCH)
 
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
 # Force dependency (incbin is bad)
 $(obj)/vdso64_wrapper.o : $(obj)/vdso64.so
 
index 1bc18cdb525b3d838d9b47f7b98fc3474101355f..56fe6bc81fee45804a61c37fb189ccf73a0b72e8 100644 (file)
@@ -77,7 +77,7 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);
        INIT_DATA_SECTION(0x100)
 
-       PERCPU(0x100, PAGE_SIZE)
+       PERCPU_SECTION(0x100)
        . = ALIGN(PAGE_SIZE);
        __init_end = .;         /* freed after init ends here */
 
index 3cc95dd0a3a6a1cb7bc133f0890786bf2324e4bf..075ddada4911bd05369d292d3e04d4b95eb56771 100644 (file)
@@ -412,6 +412,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
        struct dcss_segment *seg;
        int rc, diag_cc;
 
+       start_addr = end_addr = 0;
        seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA);
        if (seg == NULL) {
                rc = -ENOMEM;
@@ -573,6 +574,7 @@ segment_modify_shared (char *name, int do_nonshared)
        unsigned long start_addr, end_addr, dummy;
        int rc, diag_cc;
 
+       start_addr = end_addr = 0;
        mutex_lock(&dcss_lock);
        seg = segment_by_name (name);
        if (seg == NULL) {
@@ -681,8 +683,6 @@ void
 segment_save(char *name)
 {
        struct dcss_segment *seg;
-       int startpfn = 0;
-       int endpfn = 0;
        char cmd1[160];
        char cmd2[80];
        int i, response;
@@ -698,8 +698,6 @@ segment_save(char *name)
                goto out;
        }
 
-       startpfn = seg->start_addr >> PAGE_SHIFT;
-       endpfn = (seg->end) >> PAGE_SHIFT;
        sprintf(cmd1, "DEFSEG %s", name);
        for (i=0; i<seg->segcnt; i++) {
                sprintf(cmd1+strlen(cmd1), " %lX-%lX %s",
index ab988135e5c682a90370f998d5d72956fd40961c..a0f9e730f26aec574eace4abac04c74eed59bf5c 100644 (file)
@@ -225,33 +225,6 @@ static noinline void do_sigbus(struct pt_regs *regs, long int_code,
        force_sig_info(SIGBUS, &si, tsk);
 }
 
-#ifdef CONFIG_S390_EXEC_PROTECT
-static noinline int signal_return(struct pt_regs *regs, long int_code,
-                                 unsigned long trans_exc_code)
-{
-       u16 instruction;
-       int rc;
-
-       rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
-
-       if (!rc && instruction == 0x0a77) {
-               clear_tsk_thread_flag(current, TIF_PER_TRAP);
-               if (is_compat_task())
-                       sys32_sigreturn();
-               else
-                       sys_sigreturn();
-       } else if (!rc && instruction == 0x0aad) {
-               clear_tsk_thread_flag(current, TIF_PER_TRAP);
-               if (is_compat_task())
-                       sys32_rt_sigreturn();
-               else
-                       sys_rt_sigreturn();
-       } else
-               do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
-       return 0;
-}
-#endif /* CONFIG_S390_EXEC_PROTECT */
-
 static noinline void do_fault_error(struct pt_regs *regs, long int_code,
                                    unsigned long trans_exc_code, int fault)
 {
@@ -259,13 +232,6 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
 
        switch (fault) {
        case VM_FAULT_BADACCESS:
-#ifdef CONFIG_S390_EXEC_PROTECT
-               if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
-                   (trans_exc_code & 3) == 0) {
-                       signal_return(regs, int_code, trans_exc_code);
-                       break;
-               }
-#endif /* CONFIG_S390_EXEC_PROTECT */
        case VM_FAULT_BADMAP:
                /* Bad memory access. Check if it is kernel or user space. */
                if (regs->psw.mask & PSW_MASK_PSTATE) {
@@ -414,11 +380,6 @@ void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
        int access, fault;
 
        access = VM_READ | VM_EXEC | VM_WRITE;
-#ifdef CONFIG_S390_EXEC_PROTECT
-       if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
-           (trans_exc_code & 3) == 0)
-               access = VM_EXEC;
-#endif
        fault = do_exception(regs, access, trans_exc_code);
        if (unlikely(fault))
                do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
@@ -491,22 +452,28 @@ static int __init nopfault(char *str)
 
 __setup("nopfault", nopfault);
 
-typedef struct {
-       __u16 refdiagc;
-       __u16 reffcode;
-       __u16 refdwlen;
-       __u16 refversn;
-       __u64 refgaddr;
-       __u64 refselmk;
-       __u64 refcmpmk;
-       __u64 reserved;
-} __attribute__ ((packed, aligned(8))) pfault_refbk_t;
+struct pfault_refbk {
+       u16 refdiagc;
+       u16 reffcode;
+       u16 refdwlen;
+       u16 refversn;
+       u64 refgaddr;
+       u64 refselmk;
+       u64 refcmpmk;
+       u64 reserved;
+} __attribute__ ((packed, aligned(8)));
 
 int pfault_init(void)
 {
-       pfault_refbk_t refbk =
-               { 0x258, 0, 5, 2, __LC_CURRENT, 1ULL << 48, 1ULL << 48,
-                 __PF_RES_FIELD };
+       struct pfault_refbk refbk = {
+               .refdiagc = 0x258,
+               .reffcode = 0,
+               .refdwlen = 5,
+               .refversn = 2,
+               .refgaddr = __LC_CURRENT_PID,
+               .refselmk = 1ULL << 48,
+               .refcmpmk = 1ULL << 48,
+               .reserved = __PF_RES_FIELD };
         int rc;
 
        if (!MACHINE_IS_VM || pfault_disable)
@@ -524,8 +491,12 @@ int pfault_init(void)
 
 void pfault_fini(void)
 {
-       pfault_refbk_t refbk =
-       { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+       struct pfault_refbk refbk = {
+               .refdiagc = 0x258,
+               .reffcode = 1,
+               .refdwlen = 5,
+               .refversn = 2,
+       };
 
        if (!MACHINE_IS_VM || pfault_disable)
                return;
@@ -537,11 +508,15 @@ void pfault_fini(void)
                : : "a" (&refbk), "m" (refbk) : "cc");
 }
 
+static DEFINE_SPINLOCK(pfault_lock);
+static LIST_HEAD(pfault_list);
+
 static void pfault_interrupt(unsigned int ext_int_code,
                             unsigned int param32, unsigned long param64)
 {
        struct task_struct *tsk;
        __u16 subcode;
+       pid_t pid;
 
        /*
         * Get the external interruption subcode & pfault
@@ -553,44 +528,79 @@ static void pfault_interrupt(unsigned int ext_int_code,
        if ((subcode & 0xff00) != __SUBCODE_MASK)
                return;
        kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++;
-
-       /*
-        * Get the token (= address of the task structure of the affected task).
-        */
-#ifdef CONFIG_64BIT
-       tsk = (struct task_struct *) param64;
-#else
-       tsk = (struct task_struct *) param32;
-#endif
-
+       if (subcode & 0x0080) {
+               /* Get the token (= pid of the affected task). */
+               pid = sizeof(void *) == 4 ? param32 : param64;
+               rcu_read_lock();
+               tsk = find_task_by_pid_ns(pid, &init_pid_ns);
+               if (tsk)
+                       get_task_struct(tsk);
+               rcu_read_unlock();
+               if (!tsk)
+                       return;
+       } else {
+               tsk = current;
+       }
+       spin_lock(&pfault_lock);
        if (subcode & 0x0080) {
                /* signal bit is set -> a page has been swapped in by VM */
-               if (xchg(&tsk->thread.pfault_wait, -1) != 0) {
+               if (tsk->thread.pfault_wait == 1) {
                        /* Initial interrupt was faster than the completion
                         * interrupt. pfault_wait is valid. Set pfault_wait
                         * back to zero and wake up the process. This can
                         * safely be done because the task is still sleeping
                         * and can't produce new pfaults. */
                        tsk->thread.pfault_wait = 0;
+                       list_del(&tsk->thread.list);
                        wake_up_process(tsk);
-                       put_task_struct(tsk);
+               } else {
+                       /* Completion interrupt was faster than initial
+                        * interrupt. Set pfault_wait to -1 so the initial
+                        * interrupt doesn't put the task to sleep. */
+                       tsk->thread.pfault_wait = -1;
                }
+               put_task_struct(tsk);
        } else {
                /* signal bit not set -> a real page is missing. */
-               get_task_struct(tsk);
-               set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-               if (xchg(&tsk->thread.pfault_wait, 1) != 0) {
+               if (tsk->thread.pfault_wait == -1) {
                        /* Completion interrupt was faster than the initial
-                        * interrupt (swapped in a -1 for pfault_wait). Set
-                        * pfault_wait back to zero and exit. This can be
-                        * done safely because tsk is running in kernel 
-                        * mode and can't produce new pfaults. */
+                        * interrupt (pfault_wait == -1). Set pfault_wait
+                        * back to zero and exit. */
                        tsk->thread.pfault_wait = 0;
-                       set_task_state(tsk, TASK_RUNNING);
-                       put_task_struct(tsk);
-               } else
+               } else {
+                       /* Initial interrupt arrived before completion
+                        * interrupt. Let the task sleep. */
+                       tsk->thread.pfault_wait = 1;
+                       list_add(&tsk->thread.list, &pfault_list);
+                       set_task_state(tsk, TASK_UNINTERRUPTIBLE);
                        set_tsk_need_resched(tsk);
+               }
+       }
+       spin_unlock(&pfault_lock);
+}
+
+static int __cpuinit pfault_cpu_notify(struct notifier_block *self,
+                                      unsigned long action, void *hcpu)
+{
+       struct thread_struct *thread, *next;
+       struct task_struct *tsk;
+
+       switch (action) {
+       case CPU_DEAD:
+       case CPU_DEAD_FROZEN:
+               spin_lock_irq(&pfault_lock);
+               list_for_each_entry_safe(thread, next, &pfault_list, list) {
+                       thread->pfault_wait = 0;
+                       list_del(&thread->list);
+                       tsk = container_of(thread, struct task_struct, thread);
+                       wake_up_process(tsk);
+               }
+               spin_unlock_irq(&pfault_lock);
+               break;
+       default:
+               break;
        }
+       return NOTIFY_OK;
 }
 
 static int __init pfault_irq_init(void)
@@ -599,22 +609,21 @@ static int __init pfault_irq_init(void)
 
        if (!MACHINE_IS_VM)
                return 0;
-       /*
-        * Try to get pfault pseudo page faults going.
-        */
        rc = register_external_interrupt(0x2603, pfault_interrupt);
-       if (rc) {
-               pfault_disable = 1;
-               return rc;
-       }
-       if (pfault_init() == 0)
-               return 0;
+       if (rc)
+               goto out_extint;
+       rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP;
+       if (rc)
+               goto out_pfault;
+       hotcpu_notifier(pfault_cpu_notify, 0);
+       return 0;
 
-       /* Tough luck, no pfault. */
-       pfault_disable = 1;
+out_pfault:
        unregister_external_interrupt(0x2603, pfault_interrupt);
-       return 0;
+out_extint:
+       pfault_disable = 1;
+       return rc;
 }
 early_initcall(pfault_irq_init);
 
-#endif
+#endif /* CONFIG_PFAULT */
index 639cd21f2218d6431030472a03509acb2ba8a41b..a4d856db9154fb6654115a10f6f2c39c8962e5ae 100644 (file)
@@ -13,7 +13,6 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                                   pte_t *pteptr, pte_t pteval)
 {
        pmd_t *pmdp = (pmd_t *) pteptr;
-       pte_t shadow_pteval = pteval;
        unsigned long mask;
 
        if (!MACHINE_HAS_HPAGE) {
@@ -21,18 +20,9 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
                mask = pte_val(pteval) &
                                (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
                pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
-               if (mm->context.noexec) {
-                       pteptr += PTRS_PER_PTE;
-                       pte_val(shadow_pteval) =
-                                       (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
-               }
        }
 
        pmd_val(*pmdp) = pte_val(pteval);
-       if (mm->context.noexec) {
-               pmdp = get_shadow_table(pmdp);
-               pmd_val(*pmdp) = pte_val(shadow_pteval);
-       }
 }
 
 int arch_prepare_hugepage(struct page *page)
index bb409332a484add0f68a1c20734d81968273f0e6..dfefc2171691aa6cdc27c95878a1cd12a0d39053 100644 (file)
@@ -175,7 +175,8 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
                pmd = pmd_offset(pud, address);
                pte = pte_offset_kernel(pmd, address);
                if (!enable) {
-                       ptep_invalidate(&init_mm, address, pte);
+                       __ptep_ipte(address, pte);
+                       pte_val(*pte) = _PAGE_TYPE_EMPTY;
                        continue;
                }
                *pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW));
index f05edcc3beff42c53cae96eb1850001915ff5bbc..d013ed39743b1bfe57faaa31f51c933f31d5639a 100644 (file)
@@ -28,7 +28,7 @@ static void change_page_attr(unsigned long addr, int numpages,
 
                pte = *ptep;
                pte = set(pte);
-               ptep_invalidate(&init_mm, addr, ptep);
+               __ptep_ipte(addr, ptep);
                *ptep = pte;
                addr += PAGE_SIZE;
        }
index e1850c28cd68453b2bde08189269e21702b3aa42..8d4330642512554edffaccd51cd7954f18897e1d 100644 (file)
@@ -40,7 +40,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist);
 
 static void __page_table_free(struct mm_struct *mm, unsigned long *table);
-static void __crst_table_free(struct mm_struct *mm, unsigned long *table);
 
 static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm)
 {
@@ -67,7 +66,7 @@ static void rcu_table_freelist_callback(struct rcu_head *head)
        while (batch->pgt_index > 0)
                __page_table_free(batch->mm, batch->table[--batch->pgt_index]);
        while (batch->crst_index < RCU_FREELIST_SIZE)
-               __crst_table_free(batch->mm, batch->table[batch->crst_index++]);
+               crst_table_free(batch->mm, batch->table[batch->crst_index++]);
        free_page((unsigned long) batch);
 }
 
@@ -125,63 +124,33 @@ static int __init parse_vmalloc(char *arg)
 }
 early_param("vmalloc", parse_vmalloc);
 
-unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
+unsigned long *crst_table_alloc(struct mm_struct *mm)
 {
        struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
 
        if (!page)
                return NULL;
-       page->index = 0;
-       if (noexec) {
-               struct page *shadow = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
-               if (!shadow) {
-                       __free_pages(page, ALLOC_ORDER);
-                       return NULL;
-               }
-               page->index = page_to_phys(shadow);
-       }
-       spin_lock_bh(&mm->context.list_lock);
-       list_add(&page->lru, &mm->context.crst_list);
-       spin_unlock_bh(&mm->context.list_lock);
        return (unsigned long *) page_to_phys(page);
 }
 
-static void __crst_table_free(struct mm_struct *mm, unsigned long *table)
-{
-       unsigned long *shadow = get_shadow_table(table);
-
-       if (shadow)
-               free_pages((unsigned long) shadow, ALLOC_ORDER);
-       free_pages((unsigned long) table, ALLOC_ORDER);
-}
-
 void crst_table_free(struct mm_struct *mm, unsigned long *table)
 {
-       struct page *page = virt_to_page(table);
-
-       spin_lock_bh(&mm->context.list_lock);
-       list_del(&page->lru);
-       spin_unlock_bh(&mm->context.list_lock);
-       __crst_table_free(mm, table);
+       free_pages((unsigned long) table, ALLOC_ORDER);
 }
 
 void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table)
 {
        struct rcu_table_freelist *batch;
-       struct page *page = virt_to_page(table);
 
-       spin_lock_bh(&mm->context.list_lock);
-       list_del(&page->lru);
-       spin_unlock_bh(&mm->context.list_lock);
        if (atomic_read(&mm->mm_users) < 2 &&
            cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
-               __crst_table_free(mm, table);
+               crst_table_free(mm, table);
                return;
        }
        batch = rcu_table_freelist_get(mm);
        if (!batch) {
                smp_call_function(smp_sync, NULL, 1);
-               __crst_table_free(mm, table);
+               crst_table_free(mm, table);
                return;
        }
        batch->table[--batch->crst_index] = table;
@@ -197,7 +166,7 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
 
        BUG_ON(limit > (1UL << 53));
 repeat:
-       table = crst_table_alloc(mm, mm->context.noexec);
+       table = crst_table_alloc(mm);
        if (!table)
                return -ENOMEM;
        spin_lock_bh(&mm->page_table_lock);
@@ -273,7 +242,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
        unsigned long *table;
        unsigned long bits;
 
-       bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+       bits = (mm->context.has_pgste) ? 3UL : 1UL;
        spin_lock_bh(&mm->context.list_lock);
        page = NULL;
        if (!list_empty(&mm->context.pgtable_list)) {
@@ -329,7 +298,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
        struct page *page;
        unsigned long bits;
 
-       bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+       bits = (mm->context.has_pgste) ? 3UL : 1UL;
        bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
        page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
        spin_lock_bh(&mm->context.list_lock);
@@ -366,7 +335,7 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table)
                page_table_free(mm, table);
                return;
        }
-       bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+       bits = (mm->context.has_pgste) ? 3UL : 1UL;
        bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
        page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
        spin_lock_bh(&mm->context.list_lock);
@@ -379,25 +348,6 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table)
                rcu_table_freelist_finish();
 }
 
-void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
-{
-       struct page *page;
-
-       spin_lock_bh(&mm->context.list_lock);
-       /* Free shadow region and segment tables. */
-       list_for_each_entry(page, &mm->context.crst_list, lru)
-               if (page->index) {
-                       free_pages((unsigned long) page->index, ALLOC_ORDER);
-                       page->index = 0;
-               }
-       /* "Free" second halves of page tables. */
-       list_for_each_entry(page, &mm->context.pgtable_list, lru)
-               page->flags &= ~SECOND_HALVES;
-       spin_unlock_bh(&mm->context.list_lock);
-       mm->context.noexec = 0;
-       update_mm(mm, tsk);
-}
-
 /*
  * switch on pgstes for its userspace process (for kvm)
  */
index 34c43f23b28cedbb88ba405466a00144f32379fe..8c1970d1dd912231f9215c3455c9e4de9200809d 100644 (file)
@@ -95,7 +95,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                        pu_dir = vmem_pud_alloc();
                        if (!pu_dir)
                                goto out;
-                       pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+                       pgd_populate(&init_mm, pg_dir, pu_dir);
                }
 
                pu_dir = pud_offset(pg_dir, address);
@@ -103,7 +103,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                        pm_dir = vmem_pmd_alloc();
                        if (!pm_dir)
                                goto out;
-                       pud_populate_kernel(&init_mm, pu_dir, pm_dir);
+                       pud_populate(&init_mm, pu_dir, pm_dir);
                }
 
                pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
@@ -123,7 +123,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
                        pt_dir = vmem_pte_alloc();
                        if (!pt_dir)
                                goto out;
-                       pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+                       pmd_populate(&init_mm, pm_dir, pt_dir);
                }
 
                pt_dir = pte_offset_kernel(pm_dir, address);
@@ -159,7 +159,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
                        continue;
 
                if (pmd_huge(*pm_dir)) {
-                       pmd_clear_kernel(pm_dir);
+                       pmd_clear(pm_dir);
                        address += HPAGE_SIZE - PAGE_SIZE;
                        continue;
                }
@@ -192,7 +192,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
                        pu_dir = vmem_pud_alloc();
                        if (!pu_dir)
                                goto out;
-                       pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+                       pgd_populate(&init_mm, pg_dir, pu_dir);
                }
 
                pu_dir = pud_offset(pg_dir, address);
@@ -200,7 +200,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
                        pm_dir = vmem_pmd_alloc();
                        if (!pm_dir)
                                goto out;
-                       pud_populate_kernel(&init_mm, pu_dir, pm_dir);
+                       pud_populate(&init_mm, pu_dir, pm_dir);
                }
 
                pm_dir = pmd_offset(pu_dir, address);
@@ -208,7 +208,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
                        pt_dir = vmem_pte_alloc();
                        if (!pt_dir)
                                goto out;
-                       pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+                       pmd_populate(&init_mm, pm_dir, pt_dir);
                }
 
                pt_dir = pte_offset_kernel(pm_dir, address);
index 33cbd373cce4f39e1181299b9098c2334fc231ec..053caa0fd2768cd6eee4a5daa0ac54bf964e3252 100644 (file)
@@ -5,6 +5,7 @@
  * Author: Heinz Graalfs <graalfs@de.ibm.com>
  */
 
+#include <linux/kernel_stat.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/smp.h>
@@ -674,17 +675,11 @@ int hwsampler_activate(unsigned int cpu)
 static void hws_ext_handler(unsigned int ext_int_code,
                            unsigned int param32, unsigned long param64)
 {
-       int cpu;
        struct hws_cpu_buffer *cb;
 
-       cpu = smp_processor_id();
-       cb = &per_cpu(sampler_cpu_buffer, cpu);
-
-       atomic_xchg(
-                       &cb->ext_params,
-                       atomic_read(&cb->ext_params)
-                               | S390_lowcore.ext_params);
-
+       kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
+       cb = &__get_cpu_var(sampler_cpu_buffer);
+       atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
        if (hws_wq)
                queue_work(hws_wq, &cb->worker);
 }
@@ -764,7 +759,7 @@ static int worker_check_error(unsigned int cpu, int ext_params)
        if (!sdbt || !*sdbt)
                return -EINVAL;
 
-       if (ext_params & EI_IEA)
+       if (ext_params & EI_PRA)
                cb->req_alert++;
 
        if (ext_params & EI_LSDA)
@@ -1009,7 +1004,7 @@ int hwsampler_deallocate()
        if (hws_state != HWS_STOPPED)
                goto deallocate_exit;
 
-       smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+       ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
        deallocate_sdbt();
 
        hws_state = HWS_DEALLOCATED;
@@ -1123,7 +1118,7 @@ int hwsampler_shutdown()
                mutex_lock(&hws_sem);
 
                if (hws_state == HWS_STOPPED) {
-                       smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+                       ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
                        deallocate_sdbt();
                }
                if (hws_wq) {
@@ -1198,7 +1193,7 @@ start_all_exit:
        hws_oom = 1;
        hws_flush_all = 0;
        /* now let them in, 1407 CPUMF external interrupts */
-       smp_ctl_set_bit(0, 5); /* set CR0 bit 58 */
+       ctl_set_bit(0, 5); /* set CR0 bit 58 */
 
        return 0;
 }
index af4d46187a79f18bb8ae350294ccb5923f5410fb..731c10ce67b56dd482e95c2ecdb239de023ea831 100644 (file)
@@ -66,7 +66,7 @@ SECTIONS
                __machvec_end = .;
        }
 
-       PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(L1_CACHE_BYTES)
 
        /*
         * .exit.text is discarded at runtime, not link time, to deal with
index 92b557afe535a59e95d8ab185d5d51c254d4d081..c0220759003e13d302a52ebd1ec5e75dd641c531 100644 (file)
@@ -108,7 +108,7 @@ SECTIONS
                __sun4v_2insn_patch_end = .;
        }
 
-       PERCPU(SMP_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(SMP_CACHE_BYTES)
 
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
index 38f64fafdc10a9d8a3271a50d333b9787074ce19..631f10de12feee423e5c3376f56813cc35fb6053 100644 (file)
@@ -60,7 +60,7 @@ SECTIONS
   . = ALIGN(PAGE_SIZE);
   VMLINUX_SYMBOL(_sinitdata) = .;
   INIT_DATA_SECTION(16) :data =0
-  PERCPU(L2_CACHE_BYTES, PAGE_SIZE)
+  PERCPU_SECTION(L2_CACHE_BYTES)
   . = ALIGN(PAGE_SIZE);
   VMLINUX_SYMBOL(_einitdata) = .;
 
index a9da516a527416e12cfdc887939e2eb8cbd5020f..795ea8e869f40ddf7afab4bd18ffafb5b15b85aa 100644 (file)
@@ -29,10 +29,10 @@ config X86_64
        def_bool 64BIT
 
 config RWSEM_XCHGADD_ALGORITHM
-       def_bool X86_XADD
+       def_bool X86_XADD && 64BIT
 
 config RWSEM_GENERIC_SPINLOCK
-       def_bool !X86_XADD
+       def_bool !RWSEM_XCHGADD_ALGORITHM
 
 config 3_LEVEL_PGTABLES
        bool "Three-level pagetables (EXPERIMENTAL)" if !64BIT
index 34bede8aad4a9ca9c23df9261be3a7c3d8ac20ec..4938de5512d20add327d2865e9c60ce6fb21181a 100644 (file)
@@ -42,7 +42,7 @@
        INIT_SETUP(0)
   }
 
-  PERCPU(32, 32)
+  PERCPU_SECTION(32)
        
   .initcall.init : {
        INIT_CALLS
index 12d55e773eb605ff85c67c8cbf8d453697e01871..48142971b25d095b9724a06a6eff47b2cf302532 100644 (file)
@@ -8,11 +8,6 @@
 
 #ifdef CONFIG_X86_32
 #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
-/*
- * For 32-bit UML - mark functions implemented in assembly that use
- * regparm input parameters:
- */
-#define asmregparm __attribute__((regparm(3)))
 
 /*
  * Make sure the compiler doesn't do anything stupid with the
index 53278b0dfdf660103f8f9c234b0d97691ae48611..a0a9779084d16ec7b9e11b03d6435026428817dc 100644 (file)
@@ -509,6 +509,11 @@ do {                                                                       \
  * it in software.  The address used in the cmpxchg16 instruction must be
  * aligned to a 16 byte boundary.
  */
+#ifdef CONFIG_SMP
+#define CMPXCHG16B_EMU_CALL "call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP3
+#else
+#define CMPXCHG16B_EMU_CALL "call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP2
+#endif
 #define percpu_cmpxchg16b_double(pcp1, o1, o2, n1, n2)                 \
 ({                                                                     \
        char __ret;                                                     \
@@ -517,7 +522,7 @@ do {                                                                        \
        typeof(o2) __o2 = o2;                                           \
        typeof(o2) __n2 = n2;                                           \
        typeof(o2) __dummy;                                             \
-       alternative_io("call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP4,     \
+       alternative_io(CMPXCHG16B_EMU_CALL,                             \
                       "cmpxchg16b " __percpu_prefix "(%%rsi)\n\tsetz %0\n\t",  \
                       X86_FEATURE_CX16,                                \
                       ASM_OUTPUT2("=a"(__ret), "=d"(__dummy)),         \
index 9488dcff7aec8261b994076cdd59638da5097f73..e5293394b548426b2ec26f577825d71fe73465c0 100644 (file)
@@ -676,7 +676,7 @@ void mask_ioapic_entries(void)
        int apic, pin;
 
        for (apic = 0; apic < nr_ioapics; apic++) {
-               if (ioapics[apic].saved_registers)
+               if (!ioapics[apic].saved_registers)
                        continue;
 
                for (pin = 0; pin < ioapics[apic].nr_registers; pin++) {
@@ -699,7 +699,7 @@ int restore_ioapic_entries(void)
        int apic, pin;
 
        for (apic = 0; apic < nr_ioapics; apic++) {
-               if (ioapics[apic].saved_registers)
+               if (!ioapics[apic].saved_registers)
                        continue;
 
                for (pin = 0; pin < ioapics[apic].nr_registers; pin++)
index f65e5b521dbd4b3d28c8dc30faecec02073e56fb..807c2a2b80f12d711240cc56b4b292b9cb616b89 100644 (file)
@@ -1363,7 +1363,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
  * We must return the syscall number to actually look up in the table.
  * This can be -1L to skip running any syscall at all.
  */
-asmregparm long syscall_trace_enter(struct pt_regs *regs)
+long syscall_trace_enter(struct pt_regs *regs)
 {
        long ret = 0;
 
@@ -1408,7 +1408,7 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
        return ret ?: regs->orig_ax;
 }
 
-asmregparm void syscall_trace_leave(struct pt_regs *regs)
+void syscall_trace_leave(struct pt_regs *regs)
 {
        bool step;
 
index 49927a863cc18089d1f1ab156c63e1080af841d7..61682f0ac264853cabc8e3b72a8a8ddf1d387bc4 100644 (file)
@@ -326,7 +326,7 @@ SECTIONS
        }
 
 #if !defined(CONFIG_X86_64) || !defined(CONFIG_SMP)
-       PERCPU(INTERNODE_CACHE_BYTES, PAGE_SIZE)
+       PERCPU_SECTION(INTERNODE_CACHE_BYTES)
 #endif
 
        . = ALIGN(PAGE_SIZE);
index a2820065927eaa642224af0d748491506fdd473d..88ecea3facb4e8c81f507a667ed55feda6cfcb1a 100644 (file)
@@ -155,7 +155,7 @@ SECTIONS
     INIT_RAM_FS
   }
 
-  PERCPU(XCHAL_ICACHE_LINESIZE, PAGE_SIZE)
+  PERCPU_SECTION(XCHAL_ICACHE_LINESIZE)
 
   /* We need this dummy segment here */
 
index 29af660d968b7664f8d182454a6dbc23a6708fa9..021abe6d8527ae93bd6ff52eda0565f936741094 100644 (file)
@@ -309,7 +309,7 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
        pcmcia_disable_device(pdev);
 }
 
-static struct pcmcia_device_id pcmcia_devices[] = {
+static const struct pcmcia_device_id pcmcia_devices[] = {
        PCMCIA_DEVICE_FUNC_ID(4),
        PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),        /* Corsair */
        PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000),        /* Hitachi */
index 4104b7feae6741c585af6d87db7c1333478e6891..aed1904ea67b54f54d1c033073a6af281f3b0070 100644 (file)
@@ -930,7 +930,7 @@ static void bluecard_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }
 
-static struct pcmcia_device_id bluecard_ids[] = {
+static const struct pcmcia_device_id bluecard_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e),
        PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c),
        PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab),
index 0c8a655874914d0604784d09c32c3b1651de03f5..4fc01949d39981a77b6e9dca90606ab94ae259b8 100644 (file)
@@ -761,7 +761,7 @@ static void bt3c_release(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id bt3c_ids[] = {
+static const struct pcmcia_device_id bt3c_ids[] = {
        PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
        PCMCIA_DEVICE_NULL
 };
index f8a0708e23110446de1f8a4ccc5e344306b88820..526b61807d945dda8a6983758b348fe7ea0bd233 100644 (file)
@@ -689,7 +689,7 @@ static void btuart_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }
 
-static struct pcmcia_device_id btuart_ids[] = {
+static const struct pcmcia_device_id btuart_ids[] = {
        /* don't use this driver. Use serial_cs + hci_uart instead */
        PCMCIA_DEVICE_NULL
 };
index 26ee0cf88d20487c0c830b5dec0c753bbf11a3b8..5e4c2de9fc3f778bf71c71c89d9222edce4bcd36 100644 (file)
@@ -636,7 +636,7 @@ static void dtl1_release(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id dtl1_ids[] = {
+static const struct pcmcia_device_id dtl1_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
        PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
        PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
index b0a0dccc98c16e479d679414d2bcf617570bab9f..b427711be4be385c2704d4c971dc5cd512ed85c4 100644 (file)
@@ -903,6 +903,9 @@ static struct pci_device_id agp_intel_pci_table[] = {
        ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB),
        ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB),
        ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB),
+       ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB),
+       ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB),
+       ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB),
        { }
 };
 
index 5feebe2800e9a5147fa04e951ff40dfd62e1688d..999803ce10dc5cae9c3571c155de3a5d1276a5c7 100644 (file)
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG  0x0126
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB           0x0108  /* Server */
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG           0x010A
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB               0x0150  /* Desktop */
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG           0x0152
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG           0x0162
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB             0x0154  /* Mobile */
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG         0x0156
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG         0x0166
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB             0x0158  /* Server */
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG         0x015A
 
 int intel_gmch_probe(struct pci_dev *pdev,
                               struct agp_bridge_data *bridge);
index 0d09b537bb9a5cbd52691874b7b8a77534ee1720..85151019dde12572e458260b6d56068fd0e271c4 100644 (file)
@@ -1420,6 +1420,16 @@ static const struct intel_gtt_driver_description {
            "Sandybridge", &sandybridge_gtt_driver },
        { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
            "Sandybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG,
+           "Ivybridge", &sandybridge_gtt_driver },
        { 0, NULL, NULL }
 };
 
index f845a8f718b39af2bd1277e331d50143e24ae9fc..a32c492baf5cc15001ad6882dc25a14d1be86419 100644 (file)
@@ -80,7 +80,7 @@ static void uninorth_tlbflush(struct agp_memory *mem)
                               ctrl | UNI_N_CFG_GART_INVAL);
        pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, ctrl);
 
-       if (uninorth_rev <= 0x30) {
+       if (!mem && uninorth_rev <= 0x30) {
                pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
                                       ctrl | UNI_N_CFG_GART_2xRESET);
                pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
index 90bd01671c70e230be0fdf47211b9d7d3eae1885..a7584860e9a731b36c6b64f39f106a51dd0ec023 100644 (file)
@@ -1869,7 +1869,7 @@ static const struct file_operations cm4000_fops = {
        .llseek = no_llseek,
 };
 
-static struct pcmcia_device_id cm4000_ids[] = {
+static const struct pcmcia_device_id cm4000_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002),
        PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39),
        PCMCIA_DEVICE_NULL,
index 5d8d59e865f4b15cea3194ec8ef23c8f5d07c736..8dd48a2be911db2626dd972c44fa2421c609ba8b 100644 (file)
@@ -633,7 +633,7 @@ static const struct file_operations reader_fops = {
        .llseek         = no_llseek,
 };
 
-static struct pcmcia_device_id cm4040_ids[] = {
+static const struct pcmcia_device_id cm4040_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0200),
        PCMCIA_DEVICE_PROD_ID12("OMNIKEY", "CardMan 4040",
                                0xE32CDD8C, 0x8F23318B),
index b575411c69b2e813024251628cc7faad4cfe7ec6..15781396af25a7ae301d04a92024e74b3e94f373 100644 (file)
@@ -2758,7 +2758,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
        }
 }
 
-static struct pcmcia_device_id mgslpc_ids[] = {
+static const struct pcmcia_device_id mgslpc_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
        PCMCIA_DEVICE_NULL
 };
index c64c3807f51665a111ae3bb10728d227d1e6581d..e0b25de1e339249773287c13d8f457d1f9e94352 100644 (file)
@@ -74,6 +74,8 @@ config ZCRYPT
          + PCI-X Cryptographic Coprocessor (PCIXCC)
          + Crypto Express2 Coprocessor (CEX2C)
          + Crypto Express2 Accelerator (CEX2A)
+         + Crypto Express3 Coprocessor (CEX3C)
+         + Crypto Express3 Accelerator (CEX3A)
 
 config ZCRYPT_MONOLITHIC
        bool "Monolithic zcrypt module"
index adc9358c9bec4a2b1f0d86a7a7ebb32655c36184..0a9357c66ff8703b76123487c8ef8d05b373c136 100644 (file)
@@ -1412,6 +1412,64 @@ end:
 }
 EXPORT_SYMBOL(drm_detect_monitor_audio);
 
+/**
+ * drm_add_display_info - pull display info out if present
+ * @edid: EDID data
+ * @info: display info (attached to connector)
+ *
+ * Grab any available display info and stuff it into the drm_display_info
+ * structure that's part of the connector.  Useful for tracking bpp and
+ * color spaces.
+ */
+static void drm_add_display_info(struct edid *edid,
+                                struct drm_display_info *info)
+{
+       info->width_mm = edid->width_cm * 10;
+       info->height_mm = edid->height_cm * 10;
+
+       /* driver figures it out in this case */
+       info->bpc = 0;
+       info->color_formats = 0;
+
+       /* Only defined for 1.4 with digital displays */
+       if (edid->revision < 4)
+               return;
+
+       if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
+               return;
+
+       switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
+       case DRM_EDID_DIGITAL_DEPTH_6:
+               info->bpc = 6;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_8:
+               info->bpc = 8;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_10:
+               info->bpc = 10;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_12:
+               info->bpc = 12;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_14:
+               info->bpc = 14;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_16:
+               info->bpc = 16;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_UNDEF:
+       default:
+               info->bpc = 0;
+               break;
+       }
+
+       info->color_formats = DRM_COLOR_FORMAT_RGB444;
+       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444)
+               info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
+       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
+               info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
+}
+
 /**
  * drm_add_edid_modes - add modes from EDID data, if available
  * @connector: connector we're probing
@@ -1460,8 +1518,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
 
-       connector->display_info.width_mm = edid->width_cm * 10;
-       connector->display_info.height_mm = edid->height_cm * 10;
+       drm_add_display_info(edid, &connector->display_info);
 
        return num_modes;
 }
index 140b9525b48a47a83cf159c010f9818969ee3877..802b61ac31390d92b2affaf14f787b75f8caab2f 100644 (file)
@@ -70,174 +70,50 @@ fail:
 }
 EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
 
-/**
- * drm_fb_helper_connector_parse_command_line - parse command line for connector
- * @connector - connector to parse line for
- * @mode_option - per connector mode option
- *
- * This parses the connector specific then generic command lines for
- * modes and options to configure the connector.
- *
- * This uses the same parameters as the fb modedb.c, except for extra
- *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
- *
- * enable/enable Digital/disable bit at the end
- */
-static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
-                                                      const char *mode_option)
-{
-       const char *name;
-       unsigned int namelen;
-       int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
-       unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
-       int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
-       int i;
-       enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
-       struct drm_connector *connector;
-
-       if (!fb_helper_conn)
-               return false;
-       connector = fb_helper_conn->connector;
-
-       cmdline_mode = &fb_helper_conn->cmdline_mode;
-       if (!mode_option)
-               mode_option = fb_mode_option;
-
-       if (!mode_option) {
-               cmdline_mode->specified = false;
-               return false;
-       }
-
-       name = mode_option;
-       namelen = strlen(name);
-       for (i = namelen-1; i >= 0; i--) {
-               switch (name[i]) {
-               case '@':
-                       namelen = i;
-                       if (!refresh_specified && !bpp_specified &&
-                           !yres_specified) {
-                               refresh = simple_strtol(&name[i+1], NULL, 10);
-                               refresh_specified = 1;
-                               if (cvt || rb)
-                                       cvt = 0;
-                       } else
-                               goto done;
-                       break;
-               case '-':
-                       namelen = i;
-                       if (!bpp_specified && !yres_specified) {
-                               bpp = simple_strtol(&name[i+1], NULL, 10);
-                               bpp_specified = 1;
-                               if (cvt || rb)
-                                       cvt = 0;
-                       } else
-                               goto done;
-                       break;
-               case 'x':
-                       if (!yres_specified) {
-                               yres = simple_strtol(&name[i+1], NULL, 10);
-                               yres_specified = 1;
-                       } else
-                               goto done;
-               case '0' ... '9':
-                       break;
-               case 'M':
-                       if (!yres_specified)
-                               cvt = 1;
-                       break;
-               case 'R':
-                       if (cvt)
-                               rb = 1;
-                       break;
-               case 'm':
-                       if (!cvt)
-                               margins = 1;
-                       break;
-               case 'i':
-                       if (!cvt)
-                               interlace = 1;
-                       break;
-               case 'e':
-                       force = DRM_FORCE_ON;
-                       break;
-               case 'D':
-                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
-                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
-                               force = DRM_FORCE_ON;
-                       else
-                               force = DRM_FORCE_ON_DIGITAL;
-                       break;
-               case 'd':
-                       force = DRM_FORCE_OFF;
-                       break;
-               default:
-                       goto done;
-               }
-       }
-       if (i < 0 && yres_specified) {
-               xres = simple_strtol(name, NULL, 10);
-               res_specified = 1;
-       }
-done:
-
-       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
-               drm_get_connector_name(connector), xres, yres,
-               (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
-               "", (margins) ? " with margins" : "", (interlace) ?
-               " interlaced" : "");
-
-       if (force) {
-               const char *s;
-               switch (force) {
-               case DRM_FORCE_OFF: s = "OFF"; break;
-               case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
-               default:
-               case DRM_FORCE_ON: s = "ON"; break;
-               }
-
-               DRM_INFO("forcing %s connector %s\n",
-                        drm_get_connector_name(connector), s);
-               connector->force = force;
-       }
-
-       if (res_specified) {
-               cmdline_mode->specified = true;
-               cmdline_mode->xres = xres;
-               cmdline_mode->yres = yres;
-       }
-
-       if (refresh_specified) {
-               cmdline_mode->refresh_specified = true;
-               cmdline_mode->refresh = refresh;
-       }
-
-       if (bpp_specified) {
-               cmdline_mode->bpp_specified = true;
-               cmdline_mode->bpp = bpp;
-       }
-       cmdline_mode->rb = rb ? true : false;
-       cmdline_mode->cvt = cvt  ? true : false;
-       cmdline_mode->interlace = interlace ? true : false;
-
-       return true;
-}
-
 static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
 {
        struct drm_fb_helper_connector *fb_helper_conn;
        int i;
 
        for (i = 0; i < fb_helper->connector_count; i++) {
+               struct drm_cmdline_mode *mode;
+               struct drm_connector *connector;
                char *option = NULL;
 
                fb_helper_conn = fb_helper->connector_info[i];
+               connector = fb_helper_conn->connector;
+               mode = &fb_helper_conn->cmdline_mode;
 
                /* do something on return - turn off connector maybe */
-               if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
+               if (fb_get_options(drm_get_connector_name(connector), &option))
                        continue;
 
-               drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
+               if (drm_mode_parse_command_line_for_connector(option,
+                                                             connector,
+                                                             mode)) {
+                       if (mode->force) {
+                               const char *s;
+                               switch (mode->force) {
+                               case DRM_FORCE_OFF: s = "OFF"; break;
+                               case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
+                               default:
+                               case DRM_FORCE_ON: s = "ON"; break;
+                               }
+
+                               DRM_INFO("forcing %s connector %s\n",
+                                        drm_get_connector_name(connector), s);
+                               connector->force = mode->force;
+                       }
+
+                       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+                                     drm_get_connector_name(connector),
+                                     mode->xres, mode->yres,
+                                     mode->refresh_specified ? mode->refresh : 60,
+                                     mode->rb ? " reduced blanking" : "",
+                                     mode->margins ? " with margins" : "",
+                                     mode->interlace ?  " interlaced" : "");
+               }
+
        }
        return 0;
 }
@@ -901,7 +777,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
        /* first up get a count of crtcs now in use and new min/maxes width/heights */
        for (i = 0; i < fb_helper->connector_count; i++) {
                struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
-               struct drm_fb_helper_cmdline_mode *cmdline_mode;
+               struct drm_cmdline_mode *cmdline_mode;
 
                cmdline_mode = &fb_helper_conn->cmdline_mode;
 
@@ -1123,7 +999,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn
 
 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 {
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
+       struct drm_cmdline_mode *cmdline_mode;
        cmdline_mode = &fb_connector->cmdline_mode;
        return cmdline_mode->specified;
 }
@@ -1131,7 +1007,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
                                                      int width, int height)
 {
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
+       struct drm_cmdline_mode *cmdline_mode;
        struct drm_display_mode *mode = NULL;
 
        cmdline_mode = &fb_helper_conn->cmdline_mode;
@@ -1163,19 +1039,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
        }
 
 create_mode:
-       if (cmdline_mode->cvt)
-               mode = drm_cvt_mode(fb_helper_conn->connector->dev,
-                                   cmdline_mode->xres, cmdline_mode->yres,
-                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                                   cmdline_mode->rb, cmdline_mode->interlace,
-                                   cmdline_mode->margins);
-       else
-               mode = drm_gtf_mode(fb_helper_conn->connector->dev,
-                                   cmdline_mode->xres, cmdline_mode->yres,
-                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                                   cmdline_mode->interlace,
-                                   cmdline_mode->margins);
-       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
+                                                cmdline_mode);
        list_add(&mode->head, &fb_helper_conn->connector->modes);
        return mode;
 }
index a1f12cb043deb233484f9a4957300fa475c3a024..2022a5c966bb050d89084a699cc6e6ab8508a026 100644 (file)
@@ -684,10 +684,11 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
         */
        *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);
 
-       DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %d.%d -> %d.%d [e %d us, %d rep]\n",
-                 crtc, (int) vbl_status, hpos, vpos, raw_time.tv_sec,
-                 raw_time.tv_usec, vblank_time->tv_sec, vblank_time->tv_usec,
-                 (int) duration_ns/1000, i);
+       DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
+                 crtc, (int)vbl_status, hpos, vpos,
+                 (long)raw_time.tv_sec, (long)raw_time.tv_usec,
+                 (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
+                 (int)duration_ns/1000, i);
 
        vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
        if (invbl)
index 25bf87390f53bd86ed3bd32db419f1ecf65de732..c2d32f20e2fb606838f5799b538f57baa765ce9e 100644 (file)
@@ -974,3 +974,159 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
        }
 }
 EXPORT_SYMBOL(drm_mode_connector_list_update);
+
+/**
+ * drm_mode_parse_command_line_for_connector - parse command line for connector
+ * @mode_option - per connector mode option
+ * @connector - connector to parse line for
+ *
+ * This parses the connector specific then generic command lines for
+ * modes and options to configure the connector.
+ *
+ * This uses the same parameters as the fb modedb.c, except for extra
+ *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
+ *
+ * enable/enable Digital/disable bit at the end
+ */
+bool drm_mode_parse_command_line_for_connector(const char *mode_option,
+                                              struct drm_connector *connector,
+                                              struct drm_cmdline_mode *mode)
+{
+       const char *name;
+       unsigned int namelen;
+       int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
+       unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
+       int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
+       int i;
+       enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
+
+#ifdef CONFIG_FB
+       if (!mode_option)
+               mode_option = fb_mode_option;
+#endif
+
+       if (!mode_option) {
+               mode->specified = false;
+               return false;
+       }
+
+       name = mode_option;
+       namelen = strlen(name);
+       for (i = namelen-1; i >= 0; i--) {
+               switch (name[i]) {
+               case '@':
+                       namelen = i;
+                       if (!refresh_specified && !bpp_specified &&
+                           !yres_specified) {
+                               refresh = simple_strtol(&name[i+1], NULL, 10);
+                               refresh_specified = 1;
+                               if (cvt || rb)
+                                       cvt = 0;
+                       } else
+                               goto done;
+                       break;
+               case '-':
+                       namelen = i;
+                       if (!bpp_specified && !yres_specified) {
+                               bpp = simple_strtol(&name[i+1], NULL, 10);
+                               bpp_specified = 1;
+                               if (cvt || rb)
+                                       cvt = 0;
+                       } else
+                               goto done;
+                       break;
+               case 'x':
+                       if (!yres_specified) {
+                               yres = simple_strtol(&name[i+1], NULL, 10);
+                               yres_specified = 1;
+                       } else
+                               goto done;
+               case '0' ... '9':
+                       break;
+               case 'M':
+                       if (!yres_specified)
+                               cvt = 1;
+                       break;
+               case 'R':
+                       if (cvt)
+                               rb = 1;
+                       break;
+               case 'm':
+                       if (!cvt)
+                               margins = 1;
+                       break;
+               case 'i':
+                       if (!cvt)
+                               interlace = 1;
+                       break;
+               case 'e':
+                       force = DRM_FORCE_ON;
+                       break;
+               case 'D':
+                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
+                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+                               force = DRM_FORCE_ON;
+                       else
+                               force = DRM_FORCE_ON_DIGITAL;
+                       break;
+               case 'd':
+                       force = DRM_FORCE_OFF;
+                       break;
+               default:
+                       goto done;
+               }
+       }
+       if (i < 0 && yres_specified) {
+               xres = simple_strtol(name, NULL, 10);
+               res_specified = 1;
+       }
+done:
+       if (res_specified) {
+               mode->specified = true;
+               mode->xres = xres;
+               mode->yres = yres;
+       }
+
+       if (refresh_specified) {
+               mode->refresh_specified = true;
+               mode->refresh = refresh;
+       }
+
+       if (bpp_specified) {
+               mode->bpp_specified = true;
+               mode->bpp = bpp;
+       }
+       mode->rb = rb ? true : false;
+       mode->cvt = cvt  ? true : false;
+       mode->interlace = interlace ? true : false;
+       mode->force = force;
+
+       return true;
+}
+EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
+
+struct drm_display_mode *
+drm_mode_create_from_cmdline_mode(struct drm_device *dev,
+                                 struct drm_cmdline_mode *cmd)
+{
+       struct drm_display_mode *mode;
+
+       if (cmd->cvt)
+               mode = drm_cvt_mode(dev,
+                                   cmd->xres, cmd->yres,
+                                   cmd->refresh_specified ? cmd->refresh : 60,
+                                   cmd->rb, cmd->interlace,
+                                   cmd->margins);
+       else
+               mode = drm_gtf_mode(dev,
+                                   cmd->xres, cmd->yres,
+                                   cmd->refresh_specified ? cmd->refresh : 60,
+                                   cmd->interlace,
+                                   cmd->margins);
+       if (!mode)
+               return NULL;
+
+       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       return mode;
+}
+EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
index 001273d57f2d689b6b08f9dd8916a10211b427a0..6d7b083c5b776d482d3b0a21f60a43adebd8f66d 100644 (file)
@@ -62,6 +62,26 @@ struct idr drm_minors_idr;
 struct class *drm_class;
 struct proc_dir_entry *drm_proc_root;
 struct dentry *drm_debugfs_root;
+
+int drm_err(const char *func, const char *format, ...)
+{
+       struct va_format vaf;
+       va_list args;
+       int r;
+
+       va_start(args, format);
+
+       vaf.fmt = format;
+       vaf.va = &args;
+
+       r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
+
+       va_end(args);
+
+       return r;
+}
+EXPORT_SYMBOL(drm_err);
+
 void drm_ut_debug_printk(unsigned int request_level,
                         const char *prefix,
                         const char *function_name,
@@ -78,6 +98,7 @@ void drm_ut_debug_printk(unsigned int request_level,
        }
 }
 EXPORT_SYMBOL(drm_ut_debug_printk);
+
 static int drm_minor_get_id(struct drm_device *dev, int type)
 {
        int new_id;
index 87c8e29465e30a7963afdd03c1aa0666ed89d55d..51c2257b11e6d7cfb990b6a667b8fa00e59dd92e 100644 (file)
@@ -106,11 +106,12 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj)
     }
 }
 
-static const char *agp_type_str(int type)
+static const char *cache_level_str(int type)
 {
        switch (type) {
-       case 0: return " uncached";
-       case 1: return " snooped";
+       case I915_CACHE_NONE: return " uncached";
+       case I915_CACHE_LLC: return " snooped (LLC)";
+       case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)";
        default: return "";
        }
 }
@@ -127,7 +128,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                   obj->base.write_domain,
                   obj->last_rendering_seqno,
                   obj->last_fenced_seqno,
-                  agp_type_str(obj->agp_type == AGP_USER_CACHED_MEMORY),
+                  cache_level_str(obj->cache_level),
                   obj->dirty ? " dirty" : "",
                   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
        if (obj->base.name)
@@ -714,7 +715,7 @@ static void print_error_buffers(struct seq_file *m,
                           dirty_flag(err->dirty),
                           purgeable_flag(err->purgeable),
                           ring_str(err->ring),
-                          agp_type_str(err->agp_type));
+                          cache_level_str(err->cache_level));
 
                if (err->name)
                        seq_printf(m, " (name: %d)", err->name);
@@ -852,6 +853,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
 
        if (IS_GEN5(dev)) {
                u16 rgvswctl = I915_READ16(MEMSWCTL);
@@ -873,7 +875,11 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                int max_freq;
 
                /* RPSTAT1 is in the GT power well */
-               __gen6_gt_force_wake_get(dev_priv);
+               ret = mutex_lock_interruptible(&dev->struct_mutex);
+               if (ret)
+                       return ret;
+
+               gen6_gt_force_wake_get(dev_priv);
 
                rpstat = I915_READ(GEN6_RPSTAT1);
                rpupei = I915_READ(GEN6_RP_CUR_UP_EI);
@@ -883,6 +889,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                rpcurdown = I915_READ(GEN6_RP_CUR_DOWN);
                rpprevdown = I915_READ(GEN6_RP_PREV_DOWN);
 
+               gen6_gt_force_wake_put(dev_priv);
+               mutex_unlock(&dev->struct_mutex);
+
                seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
                seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat);
                seq_printf(m, "Render p-state ratio: %d\n",
@@ -917,8 +926,6 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                max_freq = rp_state_cap & 0xff;
                seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
                           max_freq * 50);
-
-               __gen6_gt_force_wake_put(dev_priv);
        } else {
                seq_printf(m, "no P-state info available\n");
        }
@@ -1058,6 +1065,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
                case FBC_MULTIPLE_PIPES:
                        seq_printf(m, "multiple pipes are enabled");
                        break;
+               case FBC_MODULE_PARAM:
+                       seq_printf(m, "disabled per module param (default off)");
+                       break;
                default:
                        seq_printf(m, "unknown reason");
                }
@@ -1186,6 +1196,42 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
        return 0;
 }
 
+static int i915_context_status(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+       if (ret)
+               return ret;
+
+       seq_printf(m, "power context ");
+       describe_obj(m, dev_priv->pwrctx);
+       seq_printf(m, "\n");
+
+       seq_printf(m, "render context ");
+       describe_obj(m, dev_priv->renderctx);
+       seq_printf(m, "\n");
+
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return 0;
+}
+
+static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       seq_printf(m, "forcewake count = %d\n",
+                  atomic_read(&dev_priv->forcewake_count));
+
+       return 0;
+}
+
 static int
 i915_wedged_open(struct inode *inode,
                 struct file *filp)
@@ -1288,6 +1334,67 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
        return drm_add_fake_info_node(minor, ent, &i915_wedged_fops);
 }
 
+static int i915_forcewake_open(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       if (!IS_GEN6(dev))
+               return 0;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+       gen6_gt_force_wake_get(dev_priv);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+int i915_forcewake_release(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!IS_GEN6(dev))
+               return 0;
+
+       /*
+        * It's bad that we can potentially hang userspace if struct_mutex gets
+        * forever stuck.  However, if we cannot acquire this lock it means that
+        * almost certainly the driver has hung, is not unload-able. Therefore
+        * hanging here is probably a minor inconvenience not to be seen my
+        * almost every user.
+        */
+       mutex_lock(&dev->struct_mutex);
+       gen6_gt_force_wake_put(dev_priv);
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static const struct file_operations i915_forcewake_fops = {
+       .owner = THIS_MODULE,
+       .open = i915_forcewake_open,
+       .release = i915_forcewake_release,
+};
+
+static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
+{
+       struct drm_device *dev = minor->dev;
+       struct dentry *ent;
+
+       ent = debugfs_create_file("i915_forcewake_user",
+                                 S_IRUSR,
+                                 root, dev,
+                                 &i915_forcewake_fops);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+
+       return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
+}
+
 static struct drm_info_list i915_debugfs_list[] = {
        {"i915_capabilities", i915_capabilities, 0},
        {"i915_gem_objects", i915_gem_object_info, 0},
@@ -1324,6 +1431,8 @@ static struct drm_info_list i915_debugfs_list[] = {
        {"i915_sr_status", i915_sr_status, 0},
        {"i915_opregion", i915_opregion, 0},
        {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
+       {"i915_context_status", i915_context_status, 0},
+       {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
@@ -1335,6 +1444,10 @@ int i915_debugfs_init(struct drm_minor *minor)
        if (ret)
                return ret;
 
+       ret = i915_forcewake_create(minor->debugfs_root, minor);
+       if (ret)
+               return ret;
+
        return drm_debugfs_create_files(i915_debugfs_list,
                                        I915_DEBUGFS_ENTRIES,
                                        minor->debugfs_root, minor);
@@ -1344,6 +1457,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
 {
        drm_debugfs_remove_files(i915_debugfs_list,
                                 I915_DEBUGFS_ENTRIES, minor);
+       drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops,
+                                1, minor);
        drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops,
                                 1, minor);
 }
index 12876f2795d2b373d9cac4130ec0052b44db23e6..0239e9974bf29cf8053c54fd42cb0239b21e65d6 100644 (file)
@@ -571,7 +571,7 @@ static int i915_quiescent(struct drm_device *dev)
        struct intel_ring_buffer *ring = LP_RING(dev->dev_private);
 
        i915_kernel_lost_context(dev);
-       return intel_wait_ring_buffer(ring, ring->size - 8);
+       return intel_wait_ring_idle(ring);
 }
 
 static int i915_flush_ioctl(struct drm_device *dev, void *data,
@@ -1176,11 +1176,11 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
        return can_switch;
 }
 
-static int i915_load_modeset_init(struct drm_device *dev)
+static int i915_load_gem_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long prealloc_size, gtt_size, mappable_size;
-       int ret = 0;
+       int ret;
 
        prealloc_size = dev_priv->mm.gtt->stolen_size;
        gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
@@ -1204,7 +1204,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
        ret = i915_gem_init_ringbuffer(dev);
        mutex_unlock(&dev->struct_mutex);
        if (ret)
-               goto out;
+               return ret;
 
        /* Try to set up FBC with a reasonable compressed buffer size */
        if (I915_HAS_FBC(dev) && i915_powersave) {
@@ -1222,6 +1222,13 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        /* Allow hardware batchbuffers unless told otherwise. */
        dev_priv->allow_batchbuffer = 1;
+       return 0;
+}
+
+static int i915_load_modeset_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
 
        ret = intel_parse_bios(dev);
        if (ret)
@@ -1236,7 +1243,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
         */
        ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
        if (ret && ret != -ENODEV)
-               goto cleanup_ringbuffer;
+               goto out;
 
        intel_register_dsm_handler();
 
@@ -1253,10 +1260,40 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        intel_modeset_init(dev);
 
-       ret = drm_irq_install(dev);
+       ret = i915_load_gem_init(dev);
        if (ret)
                goto cleanup_vga_switcheroo;
 
+       intel_modeset_gem_init(dev);
+
+       if (IS_IVYBRIDGE(dev)) {
+               /* Share pre & uninstall handlers with ILK/SNB */
+               dev->driver->irq_handler = ivybridge_irq_handler;
+               dev->driver->irq_preinstall = ironlake_irq_preinstall;
+               dev->driver->irq_postinstall = ivybridge_irq_postinstall;
+               dev->driver->irq_uninstall = ironlake_irq_uninstall;
+               dev->driver->enable_vblank = ivybridge_enable_vblank;
+               dev->driver->disable_vblank = ivybridge_disable_vblank;
+       } else if (HAS_PCH_SPLIT(dev)) {
+               dev->driver->irq_handler = ironlake_irq_handler;
+               dev->driver->irq_preinstall = ironlake_irq_preinstall;
+               dev->driver->irq_postinstall = ironlake_irq_postinstall;
+               dev->driver->irq_uninstall = ironlake_irq_uninstall;
+               dev->driver->enable_vblank = ironlake_enable_vblank;
+               dev->driver->disable_vblank = ironlake_disable_vblank;
+       } else {
+               dev->driver->irq_preinstall = i915_driver_irq_preinstall;
+               dev->driver->irq_postinstall = i915_driver_irq_postinstall;
+               dev->driver->irq_uninstall = i915_driver_irq_uninstall;
+               dev->driver->irq_handler = i915_driver_irq_handler;
+               dev->driver->enable_vblank = i915_enable_vblank;
+               dev->driver->disable_vblank = i915_disable_vblank;
+       }
+
+       ret = drm_irq_install(dev);
+       if (ret)
+               goto cleanup_gem;
+
        /* Always safe in the mode setting case. */
        /* FIXME: do pre/post-mode set stuff in core KMS code */
        dev->vblank_disable_allowed = 1;
@@ -1274,14 +1311,14 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
 cleanup_irq:
        drm_irq_uninstall(dev);
+cleanup_gem:
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_cleanup_ringbuffer(dev);
+       mutex_unlock(&dev->struct_mutex);
 cleanup_vga_switcheroo:
        vga_switcheroo_unregister_client(dev->pdev);
 cleanup_vga_client:
        vga_client_register(dev->pdev, NULL, NULL, NULL);
-cleanup_ringbuffer:
-       mutex_lock(&dev->struct_mutex);
-       i915_gem_cleanup_ringbuffer(dev);
-       mutex_unlock(&dev->struct_mutex);
 out:
        return ret;
 }
@@ -1982,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        dev->driver->get_vblank_counter = i915_get_vblank_counter;
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
-       if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
+       if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) {
                dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
                dev->driver->get_vblank_counter = gm45_get_vblank_counter;
        }
@@ -2025,6 +2062,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->error_lock);
+       spin_lock_init(&dev_priv->rps_lock);
 
        if (IS_MOBILE(dev) || !IS_GEN2(dev))
                dev_priv->num_pipe = 2;
index 32d1b3e829c8d35433f0b170052e9be96f358a1c..0defd42705943e1776b3e9447a770048142d1a73 100644 (file)
@@ -52,9 +52,12 @@ module_param_named(powersave, i915_powersave, int, 0600);
 unsigned int i915_semaphores = 0;
 module_param_named(semaphores, i915_semaphores, int, 0600);
 
-unsigned int i915_enable_rc6 = 0;
+unsigned int i915_enable_rc6 = 1;
 module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
 
+unsigned int i915_enable_fbc = 0;
+module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
+
 unsigned int i915_lvds_downclock = 0;
 module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
 
@@ -169,7 +172,7 @@ static const struct intel_device_info intel_ironlake_d_info = {
 static const struct intel_device_info intel_ironlake_m_info = {
        .gen = 5, .is_mobile = 1,
        .need_gfx_hws = 1, .has_hotplug = 1,
-       .has_fbc = 0, /* disabled due to buggy hardware */
+       .has_fbc = 1,
        .has_bsd_ring = 1,
 };
 
@@ -188,6 +191,21 @@ static const struct intel_device_info intel_sandybridge_m_info = {
        .has_blt_ring = 1,
 };
 
+static const struct intel_device_info intel_ivybridge_d_info = {
+       .is_ivybridge = 1, .gen = 7,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
+};
+
+static const struct intel_device_info intel_ivybridge_m_info = {
+       .is_ivybridge = 1, .gen = 7, .is_mobile = 1,
+       .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_fbc = 0,   /* FBC is not enabled on Ivybridge mobile yet */
+       .has_bsd_ring = 1,
+       .has_blt_ring = 1,
+};
+
 static const struct pci_device_id pciidlist[] = {              /* aka */
        INTEL_VGA_DEVICE(0x3577, &intel_i830_info),             /* I830_M */
        INTEL_VGA_DEVICE(0x2562, &intel_845g_info),             /* 845_G */
@@ -227,6 +245,11 @@ static const struct pci_device_id pciidlist[] = {          /* aka */
        INTEL_VGA_DEVICE(0x0116, &intel_sandybridge_m_info),
        INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info),
        INTEL_VGA_DEVICE(0x010A, &intel_sandybridge_d_info),
+       INTEL_VGA_DEVICE(0x0156, &intel_ivybridge_m_info), /* GT1 mobile */
+       INTEL_VGA_DEVICE(0x0166, &intel_ivybridge_m_info), /* GT2 mobile */
+       INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */
+       INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
+       INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
        {0, 0, 0}
 };
 
@@ -235,7 +258,9 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 #endif
 
 #define INTEL_PCH_DEVICE_ID_MASK       0xff00
+#define INTEL_PCH_IBX_DEVICE_ID_TYPE   0x3b00
 #define INTEL_PCH_CPT_DEVICE_ID_TYPE   0x1c00
+#define INTEL_PCH_PPT_DEVICE_ID_TYPE   0x1e00
 
 void intel_detect_pch (struct drm_device *dev)
 {
@@ -254,16 +279,23 @@ void intel_detect_pch (struct drm_device *dev)
                        int id;
                        id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
 
-                       if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
+                       if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
+                               dev_priv->pch_type = PCH_IBX;
+                               DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
+                       } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_CPT;
                                DRM_DEBUG_KMS("Found CougarPoint PCH\n");
+                       } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
+                               /* PantherPoint is CPT compatible */
+                               dev_priv->pch_type = PCH_CPT;
+                               DRM_DEBUG_KMS("Found PatherPoint PCH\n");
                        }
                }
                pci_dev_put(pch);
        }
 }
 
-void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
 {
        int count;
 
@@ -279,12 +311,38 @@ void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
                udelay(10);
 }
 
-void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+/*
+ * Generally this is called implicitly by the register read function. However,
+ * if some sequence requires the GT to not power down then this function should
+ * be called at the beginning of the sequence followed by a call to
+ * gen6_gt_force_wake_put() at the end of the sequence.
+ */
+void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+{
+       WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
+       /* Forcewake is atomic in case we get in here without the lock */
+       if (atomic_add_return(1, &dev_priv->forcewake_count) == 1)
+               __gen6_gt_force_wake_get(dev_priv);
+}
+
+static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
 {
        I915_WRITE_NOTRACE(FORCEWAKE, 0);
        POSTING_READ(FORCEWAKE);
 }
 
+/*
+ * see gen6_gt_force_wake_get()
+ */
+void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+{
+       WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
+       if (atomic_dec_and_test(&dev_priv->forcewake_count))
+               __gen6_gt_force_wake_put(dev_priv);
+}
+
 void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
 {
        int loop = 500;
index 1c1b27c97e5cee3aa26138a1d5c6ebf8ba5f85c0..ee660355ae6839839713ae3ecca369cf60f81a6d 100644 (file)
@@ -188,7 +188,7 @@ struct drm_i915_error_state {
                u32 dirty:1;
                u32 purgeable:1;
                u32 ring:4;
-               u32 agp_type:1;
+               u32 cache_level:2;
        } *active_bo, *pinned_bo;
        u32 active_bo_count, pinned_bo_count;
        struct intel_overlay_error_state *overlay;
@@ -203,12 +203,19 @@ struct drm_i915_display_funcs {
        int (*get_display_clock_speed)(struct drm_device *dev);
        int (*get_fifo_size)(struct drm_device *dev, int plane);
        void (*update_wm)(struct drm_device *dev);
+       int (*crtc_mode_set)(struct drm_crtc *crtc,
+                            struct drm_display_mode *mode,
+                            struct drm_display_mode *adjusted_mode,
+                            int x, int y,
+                            struct drm_framebuffer *old_fb);
+       void (*fdi_link_train)(struct drm_crtc *crtc);
+       void (*init_clock_gating)(struct drm_device *dev);
+       void (*init_pch_clock_gating)(struct drm_device *dev);
        /* clock updates for mode set */
        /* cursor updates */
        /* render clock increase/decrease */
        /* display clock increase/decrease */
        /* pll clock increase/decrease */
-       /* clock gating init */
 };
 
 struct intel_device_info {
@@ -223,6 +230,7 @@ struct intel_device_info {
        u8 is_pineview : 1;
        u8 is_broadwater : 1;
        u8 is_crestline : 1;
+       u8 is_ivybridge : 1;
        u8 has_fbc : 1;
        u8 has_pipe_cxsr : 1;
        u8 has_hotplug : 1;
@@ -242,6 +250,7 @@ enum no_fbc_reason {
        FBC_BAD_PLANE, /* fbc not supported on plane */
        FBC_NOT_TILED, /* buffer not tiled */
        FBC_MULTIPLE_PIPES, /* more than one pipe active */
+       FBC_MODULE_PARAM,
 };
 
 enum intel_pch {
@@ -676,6 +685,10 @@ typedef struct drm_i915_private {
 
        bool mchbar_need_disable;
 
+       struct work_struct rps_work;
+       spinlock_t rps_lock;
+       u32 pm_iir;
+
        u8 cur_delay;
        u8 min_delay;
        u8 max_delay;
@@ -703,8 +716,16 @@ typedef struct drm_i915_private {
        struct intel_fbdev *fbdev;
 
        struct drm_property *broadcast_rgb_property;
+
+       atomic_t forcewake_count;
 } drm_i915_private_t;
 
+enum i915_cache_level {
+       I915_CACHE_NONE,
+       I915_CACHE_LLC,
+       I915_CACHE_LLC_MLC, /* gen6+ */
+};
+
 struct drm_i915_gem_object {
        struct drm_gem_object base;
 
@@ -791,6 +812,8 @@ struct drm_i915_gem_object {
        unsigned int pending_fenced_gpu_access:1;
        unsigned int fenced_gpu_access:1;
 
+       unsigned int cache_level:2;
+
        struct page **pages;
 
        /**
@@ -827,8 +850,6 @@ struct drm_i915_gem_object {
        /** Record of address bit 17 of each page at last unbind. */
        unsigned long *bit_17;
 
-       /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
-       uint32_t agp_type;
 
        /**
         * If present, while GEM_DOMAIN_CPU is in the read domain this array
@@ -915,13 +936,21 @@ enum intel_chip_family {
 #define IS_G33(dev)            (INTEL_INFO(dev)->is_g33)
 #define IS_IRONLAKE_D(dev)     ((dev)->pci_device == 0x0042)
 #define IS_IRONLAKE_M(dev)     ((dev)->pci_device == 0x0046)
+#define IS_IVYBRIDGE(dev)      (INTEL_INFO(dev)->is_ivybridge)
 #define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
 
+/*
+ * The genX designation typically refers to the render engine, so render
+ * capability related checks should use IS_GEN, while display and other checks
+ * have their own (e.g. HAS_PCH_SPLIT for ILK+ display, IS_foo for particular
+ * chips, etc.).
+ */
 #define IS_GEN2(dev)   (INTEL_INFO(dev)->gen == 2)
 #define IS_GEN3(dev)   (INTEL_INFO(dev)->gen == 3)
 #define IS_GEN4(dev)   (INTEL_INFO(dev)->gen == 4)
 #define IS_GEN5(dev)   (INTEL_INFO(dev)->gen == 5)
 #define IS_GEN6(dev)   (INTEL_INFO(dev)->gen == 6)
+#define IS_GEN7(dev)   (INTEL_INFO(dev)->gen == 7)
 
 #define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
 #define HAS_BLT(dev)            (INTEL_INFO(dev)->has_blt_ring)
@@ -948,8 +977,8 @@ enum intel_chip_family {
 #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
 #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
 
-#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
-#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev))
+#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
 
 #define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
 #define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
@@ -967,6 +996,7 @@ extern unsigned int i915_lvds_downclock;
 extern unsigned int i915_panel_use_ssc;
 extern int i915_vbt_sdvo_panel_type;
 extern unsigned int i915_enable_rc6;
+extern unsigned int i915_enable_fbc;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
@@ -1010,12 +1040,27 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
 extern void i915_driver_irq_preinstall(struct drm_device * dev);
 extern int i915_driver_irq_postinstall(struct drm_device *dev);
 extern void i915_driver_irq_uninstall(struct drm_device * dev);
+
+extern irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS);
+extern void ironlake_irq_preinstall(struct drm_device *dev);
+extern int ironlake_irq_postinstall(struct drm_device *dev);
+extern void ironlake_irq_uninstall(struct drm_device *dev);
+
+extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS);
+extern void ivybridge_irq_preinstall(struct drm_device *dev);
+extern int ivybridge_irq_postinstall(struct drm_device *dev);
+extern void ivybridge_irq_uninstall(struct drm_device *dev);
+
 extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern int i915_enable_vblank(struct drm_device *dev, int crtc);
 extern void i915_disable_vblank(struct drm_device *dev, int crtc);
+extern int ironlake_enable_vblank(struct drm_device *dev, int crtc);
+extern void ironlake_disable_vblank(struct drm_device *dev, int crtc);
+extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc);
+extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc);
 extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
 extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc);
 extern int i915_vblank_swap(struct drm_device *dev, void *data,
@@ -1265,6 +1310,7 @@ static inline void intel_unregister_dsm_handler(void) { return; }
 
 /* modesetting */
 extern void intel_modeset_init(struct drm_device *dev);
+extern void intel_modeset_gem_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
 extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
 extern void i8xx_disable_fbc(struct drm_device *dev);
@@ -1312,13 +1358,34 @@ extern void intel_display_print_error_state(struct seq_file *m,
                LOCK_TEST_WITH_RETURN(dev, file);                       \
 } while (0)
 
+/* On SNB platform, before reading ring registers forcewake bit
+ * must be set to prevent GT core from power down and stale values being
+ * returned.
+ */
+void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
+void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
+void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
+
+/* We give fast paths for the really cool registers */
+#define NEEDS_FORCE_WAKE(dev_priv, reg) \
+       (((dev_priv)->info->gen >= 6) && \
+       ((reg) < 0x40000) && \
+       ((reg) != FORCEWAKE))
 
 #define __i915_read(x, y) \
 static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
-       u##x val = read##y(dev_priv->regs + reg); \
+       u##x val = 0; \
+       if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+               gen6_gt_force_wake_get(dev_priv); \
+               val = read##y(dev_priv->regs + reg); \
+               gen6_gt_force_wake_put(dev_priv); \
+       } else { \
+               val = read##y(dev_priv->regs + reg); \
+       } \
        trace_i915_reg_rw(false, reg, val, sizeof(val)); \
        return val; \
 }
+
 __i915_read(8, b)
 __i915_read(16, w)
 __i915_read(32, l)
@@ -1328,6 +1395,9 @@ __i915_read(64, q)
 #define __i915_write(x, y) \
 static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
        trace_i915_reg_rw(true, reg, val, sizeof(val)); \
+       if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+               __gen6_gt_wait_for_fifo(dev_priv); \
+       } \
        write##y(val, dev_priv->regs + reg); \
 }
 __i915_write(8, b)
@@ -1356,33 +1426,4 @@ __i915_write(64, q)
 #define POSTING_READ16(reg)    (void)I915_READ16_NOTRACE(reg)
 
 
-/* On SNB platform, before reading ring registers forcewake bit
- * must be set to prevent GT core from power down and stale values being
- * returned.
- */
-void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
-void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
-void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
-
-static inline u32 i915_gt_read(struct drm_i915_private *dev_priv, u32 reg)
-{
-       u32 val;
-
-       if (dev_priv->info->gen >= 6) {
-               __gen6_gt_force_wake_get(dev_priv);
-               val = I915_READ(reg);
-               __gen6_gt_force_wake_put(dev_priv);
-       } else
-               val = I915_READ(reg);
-
-       return val;
-}
-
-static inline void i915_gt_write(struct drm_i915_private *dev_priv,
-                               u32 reg, u32 val)
-{
-       if (dev_priv->info->gen >= 6)
-               __gen6_gt_wait_for_fifo(dev_priv);
-       I915_WRITE(reg, val);
-}
 #endif
index 7ce3f353af33657e612f40887a89aefb9b936dda..c6289034e29afd78472830324f84b6e25b9b30dc 100644 (file)
@@ -2673,6 +2673,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
 update:
        obj->tiling_changed = false;
        switch (INTEL_INFO(dev)->gen) {
+       case 7:
        case 6:
                ret = sandybridge_write_fence_reg(obj, pipelined);
                break;
@@ -2706,6 +2707,7 @@ i915_gem_clear_fence_reg(struct drm_device *dev,
        uint32_t fence_reg = reg - dev_priv->fence_regs;
 
        switch (INTEL_INFO(dev)->gen) {
+       case 7:
        case 6:
                I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0);
                break;
@@ -2878,6 +2880,17 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj)
        if (obj->pages == NULL)
                return;
 
+       /* If the GPU is snooping the contents of the CPU cache,
+        * we do not need to manually clear the CPU cache lines.  However,
+        * the caches are only snooped when the render cache is
+        * flushed/invalidated.  As we always have to emit invalidations
+        * and flushes when moving into and out of the RENDER domain, correct
+        * snooping behaviour occurs naturally as the result of our domain
+        * tracking.
+        */
+       if (obj->cache_level != I915_CACHE_NONE)
+               return;
+
        trace_i915_gem_object_clflush(obj);
 
        drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE);
@@ -3569,7 +3582,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
        obj->base.write_domain = I915_GEM_DOMAIN_CPU;
        obj->base.read_domains = I915_GEM_DOMAIN_CPU;
 
-       obj->agp_type = AGP_USER_MEMORY;
+       obj->cache_level = I915_CACHE_NONE;
        obj->base.driver_private = NULL;
        obj->fence_reg = I915_FENCE_REG_NONE;
        INIT_LIST_HEAD(&obj->mm_list);
@@ -3845,25 +3858,10 @@ i915_gem_load(struct drm_device *dev)
                dev_priv->num_fence_regs = 8;
 
        /* Initialize fence registers to zero */
-       switch (INTEL_INFO(dev)->gen) {
-       case 6:
-               for (i = 0; i < 16; i++)
-                       I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0);
-               break;
-       case 5:
-       case 4:
-               for (i = 0; i < 16; i++)
-                       I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
-               break;
-       case 3:
-               if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-                       for (i = 0; i < 8; i++)
-                               I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
-       case 2:
-               for (i = 0; i < 8; i++)
-                       I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
-               break;
+       for (i = 0; i < dev_priv->num_fence_regs; i++) {
+               i915_gem_clear_fence_reg(dev, &dev_priv->fence_regs[i]);
        }
+
        i915_gem_detect_bit_6_swizzle(dev);
        init_waitqueue_head(&dev_priv->pending_flip_queue);
 
index b0abdc64aa9f63aba4b018626da562421deb2a84..e46b645773cfcb7ca65352996d49761a8cf7872f 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+/* XXX kill agp_type! */
+static unsigned int cache_level_to_agp_type(struct drm_device *dev,
+                                           enum i915_cache_level cache_level)
+{
+       switch (cache_level) {
+       case I915_CACHE_LLC_MLC:
+               if (INTEL_INFO(dev)->gen >= 6)
+                       return AGP_USER_CACHED_MEMORY_LLC_MLC;
+               /* Older chipsets do not have this extra level of CPU
+                * cacheing, so fallthrough and request the PTE simply
+                * as cached.
+                */
+       case I915_CACHE_LLC:
+               return AGP_USER_CACHED_MEMORY;
+       default:
+       case I915_CACHE_NONE:
+               return AGP_USER_MEMORY;
+       }
+}
+
 void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -39,6 +59,9 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
                              (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
 
        list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+               unsigned int agp_type =
+                       cache_level_to_agp_type(dev, obj->cache_level);
+
                i915_gem_clflush_object(obj);
 
                if (dev_priv->mm.gtt->needs_dmar) {
@@ -46,15 +69,14 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 
                        intel_gtt_insert_sg_entries(obj->sg_list,
                                                    obj->num_sg,
-                                                   obj->gtt_space->start
-                                                       >> PAGE_SHIFT,
-                                                   obj->agp_type);
+                                                   obj->gtt_space->start >> PAGE_SHIFT,
+                                                   agp_type);
                } else
                        intel_gtt_insert_pages(obj->gtt_space->start
                                                   >> PAGE_SHIFT,
                                               obj->base.size >> PAGE_SHIFT,
                                               obj->pages,
-                                              obj->agp_type);
+                                              agp_type);
        }
 
        intel_gtt_chipset_flush();
@@ -64,6 +86,7 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned int agp_type = cache_level_to_agp_type(dev, obj->cache_level);
        int ret;
 
        if (dev_priv->mm.gtt->needs_dmar) {
@@ -77,12 +100,12 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
                intel_gtt_insert_sg_entries(obj->sg_list,
                                            obj->num_sg,
                                            obj->gtt_space->start >> PAGE_SHIFT,
-                                           obj->agp_type);
+                                           agp_type);
        } else
                intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
                                       obj->base.size >> PAGE_SHIFT,
                                       obj->pages,
-                                      obj->agp_type);
+                                      agp_type);
 
        return 0;
 }
index 281ad3d6115d08a3f40a666b60673b0d22cd6d6e..82d70fd9e933b8aff68afeffca08dca89e937fe2 100644 (file)
@@ -92,7 +92,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
        uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
        uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
-       if (IS_GEN5(dev) || IS_GEN6(dev)) {
+       if (INTEL_INFO(dev)->gen >= 5) {
                /* On Ironlake whatever DRAM config, GPU always do
                 * same swizzling setup.
                 */
index 188b497e50768d56a3a93f2422000c03a0bcaddf..b79619a7b78880f9823ba87de0ec888608630515 100644 (file)
@@ -367,22 +367,30 @@ static void notify_ring(struct drm_device *dev,
                  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 }
 
-static void gen6_pm_irq_handler(struct drm_device *dev)
+static void gen6_pm_rps_work(struct work_struct *work)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+                                                   rps_work);
        u8 new_delay = dev_priv->cur_delay;
-       u32 pm_iir;
+       u32 pm_iir, pm_imr;
+
+       spin_lock_irq(&dev_priv->rps_lock);
+       pm_iir = dev_priv->pm_iir;
+       dev_priv->pm_iir = 0;
+       pm_imr = I915_READ(GEN6_PMIMR);
+       spin_unlock_irq(&dev_priv->rps_lock);
 
-       pm_iir = I915_READ(GEN6_PMIIR);
        if (!pm_iir)
                return;
 
+       mutex_lock(&dev_priv->dev->struct_mutex);
        if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
                if (dev_priv->cur_delay != dev_priv->max_delay)
                        new_delay = dev_priv->cur_delay + 1;
                if (new_delay > dev_priv->max_delay)
                        new_delay = dev_priv->max_delay;
        } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) {
+               gen6_gt_force_wake_get(dev_priv);
                if (dev_priv->cur_delay != dev_priv->min_delay)
                        new_delay = dev_priv->cur_delay - 1;
                if (new_delay < dev_priv->min_delay) {
@@ -396,13 +404,19 @@ static void gen6_pm_irq_handler(struct drm_device *dev)
                        I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
                                   I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
                }
-
+               gen6_gt_force_wake_put(dev_priv);
        }
 
-       gen6_set_rps(dev, new_delay);
+       gen6_set_rps(dev_priv->dev, new_delay);
        dev_priv->cur_delay = new_delay;
 
-       I915_WRITE(GEN6_PMIIR, pm_iir);
+       /*
+        * rps_lock not held here because clearing is non-destructive. There is
+        * an *extremely* unlikely race with gen6_rps_enable() that is prevented
+        * by holding struct_mutex for the duration of the write.
+        */
+       I915_WRITE(GEN6_PMIMR, pm_imr & ~pm_iir);
+       mutex_unlock(&dev_priv->dev->struct_mutex);
 }
 
 static void pch_irq_handler(struct drm_device *dev)
@@ -448,8 +462,97 @@ static void pch_irq_handler(struct drm_device *dev)
                DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
 }
 
-static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
+irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
+{
+       struct drm_device *dev = (struct drm_device *) arg;
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       int ret = IRQ_NONE;
+       u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
+       struct drm_i915_master_private *master_priv;
+
+       atomic_inc(&dev_priv->irq_received);
+
+       /* disable master interrupt before clearing iir  */
+       de_ier = I915_READ(DEIER);
+       I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
+       POSTING_READ(DEIER);
+
+       de_iir = I915_READ(DEIIR);
+       gt_iir = I915_READ(GTIIR);
+       pch_iir = I915_READ(SDEIIR);
+       pm_iir = I915_READ(GEN6_PMIIR);
+
+       if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0)
+               goto done;
+
+       ret = IRQ_HANDLED;
+
+       if (dev->primary->master) {
+               master_priv = dev->primary->master->driver_priv;
+               if (master_priv->sarea_priv)
+                       master_priv->sarea_priv->last_dispatch =
+                               READ_BREADCRUMB(dev_priv);
+       }
+
+       if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
+               notify_ring(dev, &dev_priv->ring[RCS]);
+       if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT)
+               notify_ring(dev, &dev_priv->ring[VCS]);
+       if (gt_iir & GT_BLT_USER_INTERRUPT)
+               notify_ring(dev, &dev_priv->ring[BCS]);
+
+       if (de_iir & DE_GSE_IVB)
+               intel_opregion_gse_intr(dev);
+
+       if (de_iir & DE_PLANEA_FLIP_DONE_IVB) {
+               intel_prepare_page_flip(dev, 0);
+               intel_finish_page_flip_plane(dev, 0);
+       }
+
+       if (de_iir & DE_PLANEB_FLIP_DONE_IVB) {
+               intel_prepare_page_flip(dev, 1);
+               intel_finish_page_flip_plane(dev, 1);
+       }
+
+       if (de_iir & DE_PIPEA_VBLANK_IVB)
+               drm_handle_vblank(dev, 0);
+
+       if (de_iir & DE_PIPEB_VBLANK_IVB);
+               drm_handle_vblank(dev, 1);
+
+       /* check event from PCH */
+       if (de_iir & DE_PCH_EVENT_IVB) {
+               if (pch_iir & SDE_HOTPLUG_MASK_CPT)
+                       queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+               pch_irq_handler(dev);
+       }
+
+       if (pm_iir & GEN6_PM_DEFERRED_EVENTS) {
+               unsigned long flags;
+               spin_lock_irqsave(&dev_priv->rps_lock, flags);
+               WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
+               I915_WRITE(GEN6_PMIMR, pm_iir);
+               dev_priv->pm_iir |= pm_iir;
+               spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+               queue_work(dev_priv->wq, &dev_priv->rps_work);
+       }
+
+       /* should clear PCH hotplug event before clear CPU irq */
+       I915_WRITE(SDEIIR, pch_iir);
+       I915_WRITE(GTIIR, gt_iir);
+       I915_WRITE(DEIIR, de_iir);
+       I915_WRITE(GEN6_PMIIR, pm_iir);
+
+done:
+       I915_WRITE(DEIER, de_ier);
+       POSTING_READ(DEIER);
+
+       return ret;
+}
+
+irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
 {
+       struct drm_device *dev = (struct drm_device *) arg;
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        int ret = IRQ_NONE;
        u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
@@ -457,6 +560,8 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
        struct drm_i915_master_private *master_priv;
        u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
 
+       atomic_inc(&dev_priv->irq_received);
+
        if (IS_GEN6(dev))
                bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
 
@@ -526,13 +631,30 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
                i915_handle_rps_change(dev);
        }
 
-       if (IS_GEN6(dev))
-               gen6_pm_irq_handler(dev);
+       if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) {
+               /*
+                * IIR bits should never already be set because IMR should
+                * prevent an interrupt from being shown in IIR. The warning
+                * displays a case where we've unsafely cleared
+                * dev_priv->pm_iir. Although missing an interrupt of the same
+                * type is not a problem, it displays a problem in the logic.
+                *
+                * The mask bit in IMR is cleared by rps_work.
+                */
+               unsigned long flags;
+               spin_lock_irqsave(&dev_priv->rps_lock, flags);
+               WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
+               I915_WRITE(GEN6_PMIMR, pm_iir);
+               dev_priv->pm_iir |= pm_iir;
+               spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+               queue_work(dev_priv->wq, &dev_priv->rps_work);
+       }
 
        /* should clear PCH hotplug event before clear CPU irq */
        I915_WRITE(SDEIIR, pch_iir);
        I915_WRITE(GTIIR, gt_iir);
        I915_WRITE(DEIIR, de_iir);
+       I915_WRITE(GEN6_PMIIR, pm_iir);
 
 done:
        I915_WRITE(DEIER, de_ier);
@@ -676,7 +798,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err,
                err->dirty = obj->dirty;
                err->purgeable = obj->madv != I915_MADV_WILLNEED;
                err->ring = obj->ring ? obj->ring->id : 0;
-               err->agp_type = obj->agp_type == AGP_USER_CACHED_MEMORY;
+               err->cache_level = obj->cache_level;
 
                if (++i == count)
                        break;
@@ -1103,9 +1225,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 
        atomic_inc(&dev_priv->irq_received);
 
-       if (HAS_PCH_SPLIT(dev))
-               return ironlake_irq_handler(dev);
-
        iir = I915_READ(IIR);
 
        if (INTEL_INFO(dev)->gen >= 4)
@@ -1344,10 +1463,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
                return -EINVAL;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       if (HAS_PCH_SPLIT(dev))
-               ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
-                                           DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
-       else if (INTEL_INFO(dev)->gen >= 4)
+       if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, pipe,
                                     PIPE_START_VBLANK_INTERRUPT_ENABLE);
        else
@@ -1362,6 +1478,38 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
        return 0;
 }
 
+int ironlake_enable_vblank(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
+                                   DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+       return 0;
+}
+
+int ivybridge_enable_vblank(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
+
+       if (!i915_pipe_enabled(dev, pipe))
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
+                                   DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+       return 0;
+}
+
 /* Called from drm generic code, passed 'crtc' which
  * we use as a pipe index
  */
@@ -1375,13 +1523,31 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
                I915_WRITE(INSTPM,
                           INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS);
 
-       if (HAS_PCH_SPLIT(dev))
-               ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
-                                            DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
-       else
-               i915_disable_pipestat(dev_priv, pipe,
-                                     PIPE_VBLANK_INTERRUPT_ENABLE |
-                                     PIPE_START_VBLANK_INTERRUPT_ENABLE);
+       i915_disable_pipestat(dev_priv, pipe,
+                             PIPE_VBLANK_INTERRUPT_ENABLE |
+                             PIPE_START_VBLANK_INTERRUPT_ENABLE);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+void ironlake_disable_vblank(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
+                                    DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+void ivybridge_disable_vblank(struct drm_device *dev, int pipe)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
+                                    DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
@@ -1562,10 +1728,17 @@ repeat:
 
 /* drm_dma.h hooks
 */
-static void ironlake_irq_preinstall(struct drm_device *dev)
+void ironlake_irq_preinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 
+       atomic_set(&dev_priv->irq_received, 0);
+
+       INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+       INIT_WORK(&dev_priv->error_work, i915_error_work_func);
+       if (IS_GEN6(dev) || IS_IVYBRIDGE(dev))
+               INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
+
        I915_WRITE(HWSTAM, 0xeffe);
 
        /* XXX hotplug from PCH */
@@ -1585,7 +1758,7 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
        POSTING_READ(SDEIER);
 }
 
-static int ironlake_irq_postinstall(struct drm_device *dev)
+int ironlake_irq_postinstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
        /* enable kind of interrupts always enabled */
@@ -1594,6 +1767,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        u32 render_irqs;
        u32 hotplug_mask;
 
+       DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
+       if (HAS_BSD(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
+       if (HAS_BLT(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
+
+       dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
        dev_priv->irq_mask = ~display_mask;
 
        /* should always can generate irq */
@@ -1650,6 +1830,56 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
+int ivybridge_irq_postinstall(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       /* enable kind of interrupts always enabled */
+       u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
+               DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB |
+               DE_PLANEB_FLIP_DONE_IVB;
+       u32 render_irqs;
+       u32 hotplug_mask;
+
+       DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
+       if (HAS_BSD(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
+       if (HAS_BLT(dev))
+               DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
+
+       dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+       dev_priv->irq_mask = ~display_mask;
+
+       /* should always can generate irq */
+       I915_WRITE(DEIIR, I915_READ(DEIIR));
+       I915_WRITE(DEIMR, dev_priv->irq_mask);
+       I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB |
+                  DE_PIPEB_VBLANK_IVB);
+       POSTING_READ(DEIER);
+
+       dev_priv->gt_irq_mask = ~0;
+
+       I915_WRITE(GTIIR, I915_READ(GTIIR));
+       I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+
+       render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT |
+               GT_BLT_USER_INTERRUPT;
+       I915_WRITE(GTIER, render_irqs);
+       POSTING_READ(GTIER);
+
+       hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
+                       SDE_PORTB_HOTPLUG_CPT |
+                       SDE_PORTC_HOTPLUG_CPT |
+                       SDE_PORTD_HOTPLUG_CPT);
+       dev_priv->pch_irq_mask = ~hotplug_mask;
+
+       I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+       I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
+       I915_WRITE(SDEIER, hotplug_mask);
+       POSTING_READ(SDEIER);
+
+       return 0;
+}
+
 void i915_driver_irq_preinstall(struct drm_device * dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -1660,11 +1890,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
        INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
        INIT_WORK(&dev_priv->error_work, i915_error_work_func);
 
-       if (HAS_PCH_SPLIT(dev)) {
-               ironlake_irq_preinstall(dev);
-               return;
-       }
-
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -1688,17 +1913,8 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
        u32 error_mask;
 
-       DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
-       if (HAS_BSD(dev))
-               DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
-       if (HAS_BLT(dev))
-               DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
-
        dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
 
-       if (HAS_PCH_SPLIT(dev))
-               return ironlake_irq_postinstall(dev);
-
        /* Unmask the interrupts that we always want on. */
        dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX;
 
@@ -1767,9 +1983,15 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
-static void ironlake_irq_uninstall(struct drm_device *dev)
+void ironlake_irq_uninstall(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+       if (!dev_priv)
+               return;
+
+       dev_priv->vblank_pipe = 0;
+
        I915_WRITE(HWSTAM, 0xffffffff);
 
        I915_WRITE(DEIMR, 0xffffffff);
@@ -1791,11 +2013,6 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
 
        dev_priv->vblank_pipe = 0;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               ironlake_irq_uninstall(dev);
-               return;
-       }
-
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
index f39ac3a0fa9339e3d5ae4276e5ec354ad410746b..2f967af8e62edced1deff2dc906c8ca28203e20a 100644 (file)
 #define RING_MAX_IDLE(base)    ((base)+0x54)
 #define RING_HWS_PGA(base)     ((base)+0x80)
 #define RING_HWS_PGA_GEN6(base)        ((base)+0x2080)
+#define RENDER_HWS_PGA_GEN7    (0x04080)
+#define BSD_HWS_PGA_GEN7       (0x04180)
+#define BLT_HWS_PGA_GEN7       (0x04280)
 #define RING_ACTHD(base)       ((base)+0x74)
 #define RING_NOPID(base)       ((base)+0x94)
 #define RING_IMR(base)         ((base)+0xa8)
 #define DE_PIPEA_VSYNC          (1 << 3)
 #define DE_PIPEA_FIFO_UNDERRUN  (1 << 0)
 
+/* More Ivybridge lolz */
+#define DE_ERR_DEBUG_IVB               (1<<30)
+#define DE_GSE_IVB                     (1<<29)
+#define DE_PCH_EVENT_IVB               (1<<28)
+#define DE_DP_A_HOTPLUG_IVB            (1<<27)
+#define DE_AUX_CHANNEL_A_IVB           (1<<26)
+#define DE_SPRITEB_FLIP_DONE_IVB       (1<<9)
+#define DE_SPRITEA_FLIP_DONE_IVB       (1<<4)
+#define DE_PLANEB_FLIP_DONE_IVB                (1<<8)
+#define DE_PLANEA_FLIP_DONE_IVB                (1<<3)
+#define DE_PIPEB_VBLANK_IVB            (1<<5)
+#define DE_PIPEA_VBLANK_IVB            (1<<0)
+
 #define DEISR   0x44000
 #define DEIMR   0x44004
 #define DEIIR   0x44008
 #define  ILK_eDP_A_DISABLE             (1<<24)
 #define  ILK_DESKTOP                   (1<<23)
 #define ILK_DSPCLK_GATE                0x42020
+#define  IVB_VRHUNIT_CLK_GATE  (1<<28)
 #define  ILK_DPARB_CLK_GATE    (1<<5)
 #define  ILK_DPFD_CLK_GATE     (1<<7)
 
 #define  TRANS_6BPC             (2<<5)
 #define  TRANS_12BPC            (3<<5)
 
+#define SOUTH_CHICKEN2         0xc2004
+#define  DPLS_EDP_PPS_FIX_DIS  (1<<0)
+
 #define _FDI_RXA_CHICKEN         0xc200c
 #define _FDI_RXB_CHICKEN         0xc2010
 #define  FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1)
 #define  FDI_TX_ENHANCE_FRAME_ENABLE    (1<<18)
 /* Ironlake: hardwired to 1 */
 #define  FDI_TX_PLL_ENABLE              (1<<14)
+
+/* Ivybridge has different bits for lolz */
+#define  FDI_LINK_TRAIN_PATTERN_1_IVB       (0<<8)
+#define  FDI_LINK_TRAIN_PATTERN_2_IVB       (1<<8)
+#define  FDI_LINK_TRAIN_PATTERN_IDLE_IVB    (2<<8)
+#define  FDI_LINK_TRAIN_NONE_IVB            (3<<8)
+
 /* both Tx and Rx */
+#define  FDI_LINK_TRAIN_AUTO           (1<<10)
 #define  FDI_SCRAMBLING_ENABLE          (0<<7)
 #define  FDI_SCRAMBLING_DISABLE         (1<<7)
 
 #define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
 #define  FDI_RX_ENABLE          (1<<31)
 /* train, dp width same as FDI_TX */
+#define  FDI_FS_ERRC_ENABLE            (1<<27)
+#define  FDI_FE_ERRC_ENABLE            (1<<26)
 #define  FDI_DP_PORT_WIDTH_X8           (7<<19)
 #define  FDI_8BPC                       (0<<16)
 #define  FDI_10BPC                      (1<<16)
 #define GEN6_PMINTRMSK                         0xA168
 
 #define GEN6_PMISR                             0x44020
-#define GEN6_PMIMR                             0x44024
+#define GEN6_PMIMR                             0x44024 /* rps_lock */
 #define GEN6_PMIIR                             0x44028
 #define GEN6_PMIER                             0x4402C
 #define  GEN6_PM_MBOX_EVENT                    (1<<25)
 #define  GEN6_PM_RP_DOWN_THRESHOLD             (1<<4)
 #define  GEN6_PM_RP_UP_EI_EXPIRED              (1<<2)
 #define  GEN6_PM_RP_DOWN_EI_EXPIRED            (1<<1)
+#define  GEN6_PM_DEFERRED_EVENTS               (GEN6_PM_RP_UP_THRESHOLD | \
+                                                GEN6_PM_RP_DOWN_THRESHOLD | \
+                                                GEN6_PM_RP_DOWN_TIMEOUT)
 
 #define GEN6_PCODE_MAILBOX                     0x138124
 #define   GEN6_PCODE_READY                     (1<<31)
index da474153a0a228626cef23e08b5d3c9566642dee..60a94d2b526482532667dc7b4fba4bf8f5cfbe5c 100644 (file)
@@ -863,8 +863,7 @@ int i915_restore_state(struct drm_device *dev)
                I915_WRITE(IMR, dev_priv->saveIMR);
        }
 
-       /* Clock gating state */
-       intel_enable_clock_gating(dev);
+       intel_init_clock_gating(dev);
 
        if (IS_IRONLAKE_M(dev)) {
                ironlake_enable_drps(dev);
index fb5b4d426ae0793baa93836cffe2aaf93c6f9241..927442a11925f990fcb45b5cba763a3cb7d521bc 100644 (file)
@@ -214,9 +214,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
            i915_lvds_downclock) {
                dev_priv->lvds_downclock_avail = 1;
                dev_priv->lvds_downclock = temp_downclock;
-               DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
-                               "Normal Clock %dKHz, downclock %dKHz\n",
-                               temp_downclock, panel_fixed_mode->clock);
+               DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
+                             "Normal Clock %dKHz, downclock %dKHz\n",
+                             temp_downclock, panel_fixed_mode->clock);
        }
        return;
 }
index d03fc05b39c0e008236406a9820f459103154f10..e93f93cc7e78725b4fbe52ba4e5c0b2f522a3768 100644 (file)
@@ -305,13 +305,11 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
 }
 
 static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
+intel_crt_load_detect(struct intel_crt *crt)
 {
-       struct drm_encoder *encoder = &crt->base.base;
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = crt->base.base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t pipe = intel_crtc->pipe;
+       uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
        uint32_t save_bclrpat;
        uint32_t save_vtotal;
        uint32_t vtotal, vactive;
@@ -432,7 +430,6 @@ intel_crt_detect(struct drm_connector *connector, bool force)
        struct drm_device *dev = connector->dev;
        struct intel_crt *crt = intel_attached_crt(connector);
        struct drm_crtc *crtc;
-       int dpms_mode;
        enum drm_connector_status status;
 
        if (I915_HAS_HOTPLUG(dev)) {
@@ -454,17 +451,18 @@ intel_crt_detect(struct drm_connector *connector, bool force)
        /* for pre-945g platforms use load detect */
        crtc = crt->base.base.crtc;
        if (crtc && crtc->enabled) {
-               status = intel_crt_load_detect(crtc, crt);
+               status = intel_crt_load_detect(crt);
        } else {
-               crtc = intel_get_load_detect_pipe(&crt->base, connector,
-                                                 NULL, &dpms_mode);
-               if (crtc) {
+               struct intel_load_detect_pipe tmp;
+
+               if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
+                                              &tmp)) {
                        if (intel_crt_detect_ddc(connector))
                                status = connector_status_connected;
                        else
-                               status = intel_crt_load_detect(crtc, crt);
-                       intel_release_load_detect_pipe(&crt->base,
-                                                      connector, dpms_mode);
+                               status = intel_crt_load_detect(crt);
+                       intel_release_load_detect_pipe(&crt->base, connector,
+                                                      &tmp);
                } else
                        status = connector_status_unknown;
        }
index 2166ee071ddbe99655c3c977beecec68bb6a7a19..f553ddfdc16819fa343b4780c27de14fa37d1337 100644 (file)
@@ -76,255 +76,6 @@ struct intel_limit {
                      int, int, intel_clock_t *);
 };
 
-#define I8XX_DOT_MIN             25000
-#define I8XX_DOT_MAX            350000
-#define I8XX_VCO_MIN            930000
-#define I8XX_VCO_MAX           1400000
-#define I8XX_N_MIN                   3
-#define I8XX_N_MAX                  16
-#define I8XX_M_MIN                  96
-#define I8XX_M_MAX                 140
-#define I8XX_M1_MIN                 18
-#define I8XX_M1_MAX                 26
-#define I8XX_M2_MIN                  6
-#define I8XX_M2_MAX                 16
-#define I8XX_P_MIN                   4
-#define I8XX_P_MAX                 128
-#define I8XX_P1_MIN                  2
-#define I8XX_P1_MAX                 33
-#define I8XX_P1_LVDS_MIN             1
-#define I8XX_P1_LVDS_MAX             6
-#define I8XX_P2_SLOW                 4
-#define I8XX_P2_FAST                 2
-#define I8XX_P2_LVDS_SLOW            14
-#define I8XX_P2_LVDS_FAST            7
-#define I8XX_P2_SLOW_LIMIT      165000
-
-#define I9XX_DOT_MIN             20000
-#define I9XX_DOT_MAX            400000
-#define I9XX_VCO_MIN           1400000
-#define I9XX_VCO_MAX           2800000
-#define PINEVIEW_VCO_MIN               1700000
-#define PINEVIEW_VCO_MAX               3500000
-#define I9XX_N_MIN                   1
-#define I9XX_N_MAX                   6
-/* Pineview's Ncounter is a ring counter */
-#define PINEVIEW_N_MIN               3
-#define PINEVIEW_N_MAX               6
-#define I9XX_M_MIN                  70
-#define I9XX_M_MAX                 120
-#define PINEVIEW_M_MIN               2
-#define PINEVIEW_M_MAX             256
-#define I9XX_M1_MIN                 10
-#define I9XX_M1_MAX                 22
-#define I9XX_M2_MIN                  5
-#define I9XX_M2_MAX                  9
-/* Pineview M1 is reserved, and must be 0 */
-#define PINEVIEW_M1_MIN                      0
-#define PINEVIEW_M1_MAX                      0
-#define PINEVIEW_M2_MIN                      0
-#define PINEVIEW_M2_MAX                      254
-#define I9XX_P_SDVO_DAC_MIN          5
-#define I9XX_P_SDVO_DAC_MAX         80
-#define I9XX_P_LVDS_MIN                      7
-#define I9XX_P_LVDS_MAX                     98
-#define PINEVIEW_P_LVDS_MIN                  7
-#define PINEVIEW_P_LVDS_MAX                 112
-#define I9XX_P1_MIN                  1
-#define I9XX_P1_MAX                  8
-#define I9XX_P2_SDVO_DAC_SLOW               10
-#define I9XX_P2_SDVO_DAC_FAST                5
-#define I9XX_P2_SDVO_DAC_SLOW_LIMIT     200000
-#define I9XX_P2_LVDS_SLOW                   14
-#define I9XX_P2_LVDS_FAST                    7
-#define I9XX_P2_LVDS_SLOW_LIMIT                 112000
-
-/*The parameter is for SDVO on G4x platform*/
-#define G4X_DOT_SDVO_MIN           25000
-#define G4X_DOT_SDVO_MAX           270000
-#define G4X_VCO_MIN                1750000
-#define G4X_VCO_MAX                3500000
-#define G4X_N_SDVO_MIN             1
-#define G4X_N_SDVO_MAX             4
-#define G4X_M_SDVO_MIN             104
-#define G4X_M_SDVO_MAX             138
-#define G4X_M1_SDVO_MIN            17
-#define G4X_M1_SDVO_MAX            23
-#define G4X_M2_SDVO_MIN            5
-#define G4X_M2_SDVO_MAX            11
-#define G4X_P_SDVO_MIN             10
-#define G4X_P_SDVO_MAX             30
-#define G4X_P1_SDVO_MIN            1
-#define G4X_P1_SDVO_MAX            3
-#define G4X_P2_SDVO_SLOW           10
-#define G4X_P2_SDVO_FAST           10
-#define G4X_P2_SDVO_LIMIT          270000
-
-/*The parameter is for HDMI_DAC on G4x platform*/
-#define G4X_DOT_HDMI_DAC_MIN           22000
-#define G4X_DOT_HDMI_DAC_MAX           400000
-#define G4X_N_HDMI_DAC_MIN             1
-#define G4X_N_HDMI_DAC_MAX             4
-#define G4X_M_HDMI_DAC_MIN             104
-#define G4X_M_HDMI_DAC_MAX             138
-#define G4X_M1_HDMI_DAC_MIN            16
-#define G4X_M1_HDMI_DAC_MAX            23
-#define G4X_M2_HDMI_DAC_MIN            5
-#define G4X_M2_HDMI_DAC_MAX            11
-#define G4X_P_HDMI_DAC_MIN             5
-#define G4X_P_HDMI_DAC_MAX             80
-#define G4X_P1_HDMI_DAC_MIN            1
-#define G4X_P1_HDMI_DAC_MAX            8
-#define G4X_P2_HDMI_DAC_SLOW           10
-#define G4X_P2_HDMI_DAC_FAST           5
-#define G4X_P2_HDMI_DAC_LIMIT          165000
-
-/*The parameter is for SINGLE_CHANNEL_LVDS on G4x platform*/
-#define G4X_DOT_SINGLE_CHANNEL_LVDS_MIN           20000
-#define G4X_DOT_SINGLE_CHANNEL_LVDS_MAX           115000
-#define G4X_N_SINGLE_CHANNEL_LVDS_MIN             1
-#define G4X_N_SINGLE_CHANNEL_LVDS_MAX             3
-#define G4X_M_SINGLE_CHANNEL_LVDS_MIN             104
-#define G4X_M_SINGLE_CHANNEL_LVDS_MAX             138
-#define G4X_M1_SINGLE_CHANNEL_LVDS_MIN            17
-#define G4X_M1_SINGLE_CHANNEL_LVDS_MAX            23
-#define G4X_M2_SINGLE_CHANNEL_LVDS_MIN            5
-#define G4X_M2_SINGLE_CHANNEL_LVDS_MAX            11
-#define G4X_P_SINGLE_CHANNEL_LVDS_MIN             28
-#define G4X_P_SINGLE_CHANNEL_LVDS_MAX             112
-#define G4X_P1_SINGLE_CHANNEL_LVDS_MIN            2
-#define G4X_P1_SINGLE_CHANNEL_LVDS_MAX            8
-#define G4X_P2_SINGLE_CHANNEL_LVDS_SLOW           14
-#define G4X_P2_SINGLE_CHANNEL_LVDS_FAST           14
-#define G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT          0
-
-/*The parameter is for DUAL_CHANNEL_LVDS on G4x platform*/
-#define G4X_DOT_DUAL_CHANNEL_LVDS_MIN           80000
-#define G4X_DOT_DUAL_CHANNEL_LVDS_MAX           224000
-#define G4X_N_DUAL_CHANNEL_LVDS_MIN             1
-#define G4X_N_DUAL_CHANNEL_LVDS_MAX             3
-#define G4X_M_DUAL_CHANNEL_LVDS_MIN             104
-#define G4X_M_DUAL_CHANNEL_LVDS_MAX             138
-#define G4X_M1_DUAL_CHANNEL_LVDS_MIN            17
-#define G4X_M1_DUAL_CHANNEL_LVDS_MAX            23
-#define G4X_M2_DUAL_CHANNEL_LVDS_MIN            5
-#define G4X_M2_DUAL_CHANNEL_LVDS_MAX            11
-#define G4X_P_DUAL_CHANNEL_LVDS_MIN             14
-#define G4X_P_DUAL_CHANNEL_LVDS_MAX             42
-#define G4X_P1_DUAL_CHANNEL_LVDS_MIN            2
-#define G4X_P1_DUAL_CHANNEL_LVDS_MAX            6
-#define G4X_P2_DUAL_CHANNEL_LVDS_SLOW           7
-#define G4X_P2_DUAL_CHANNEL_LVDS_FAST           7
-#define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT          0
-
-/*The parameter is for DISPLAY PORT on G4x platform*/
-#define G4X_DOT_DISPLAY_PORT_MIN           161670
-#define G4X_DOT_DISPLAY_PORT_MAX           227000
-#define G4X_N_DISPLAY_PORT_MIN             1
-#define G4X_N_DISPLAY_PORT_MAX             2
-#define G4X_M_DISPLAY_PORT_MIN             97
-#define G4X_M_DISPLAY_PORT_MAX             108
-#define G4X_M1_DISPLAY_PORT_MIN            0x10
-#define G4X_M1_DISPLAY_PORT_MAX            0x12
-#define G4X_M2_DISPLAY_PORT_MIN            0x05
-#define G4X_M2_DISPLAY_PORT_MAX            0x06
-#define G4X_P_DISPLAY_PORT_MIN             10
-#define G4X_P_DISPLAY_PORT_MAX             20
-#define G4X_P1_DISPLAY_PORT_MIN            1
-#define G4X_P1_DISPLAY_PORT_MAX            2
-#define G4X_P2_DISPLAY_PORT_SLOW           10
-#define G4X_P2_DISPLAY_PORT_FAST           10
-#define G4X_P2_DISPLAY_PORT_LIMIT          0
-
-/* Ironlake / Sandybridge */
-/* as we calculate clock using (register_value + 2) for
-   N/M1/M2, so here the range value for them is (actual_value-2).
- */
-#define IRONLAKE_DOT_MIN         25000
-#define IRONLAKE_DOT_MAX         350000
-#define IRONLAKE_VCO_MIN         1760000
-#define IRONLAKE_VCO_MAX         3510000
-#define IRONLAKE_M1_MIN          12
-#define IRONLAKE_M1_MAX          22
-#define IRONLAKE_M2_MIN          5
-#define IRONLAKE_M2_MAX          9
-#define IRONLAKE_P2_DOT_LIMIT    225000 /* 225Mhz */
-
-/* We have parameter ranges for different type of outputs. */
-
-/* DAC & HDMI Refclk 120Mhz */
-#define IRONLAKE_DAC_N_MIN     1
-#define IRONLAKE_DAC_N_MAX     5
-#define IRONLAKE_DAC_M_MIN     79
-#define IRONLAKE_DAC_M_MAX     127
-#define IRONLAKE_DAC_P_MIN     5
-#define IRONLAKE_DAC_P_MAX     80
-#define IRONLAKE_DAC_P1_MIN    1
-#define IRONLAKE_DAC_P1_MAX    8
-#define IRONLAKE_DAC_P2_SLOW   10
-#define IRONLAKE_DAC_P2_FAST   5
-
-/* LVDS single-channel 120Mhz refclk */
-#define IRONLAKE_LVDS_S_N_MIN  1
-#define IRONLAKE_LVDS_S_N_MAX  3
-#define IRONLAKE_LVDS_S_M_MIN  79
-#define IRONLAKE_LVDS_S_M_MAX  118
-#define IRONLAKE_LVDS_S_P_MIN  28
-#define IRONLAKE_LVDS_S_P_MAX  112
-#define IRONLAKE_LVDS_S_P1_MIN 2
-#define IRONLAKE_LVDS_S_P1_MAX 8
-#define IRONLAKE_LVDS_S_P2_SLOW        14
-#define IRONLAKE_LVDS_S_P2_FAST        14
-
-/* LVDS dual-channel 120Mhz refclk */
-#define IRONLAKE_LVDS_D_N_MIN  1
-#define IRONLAKE_LVDS_D_N_MAX  3
-#define IRONLAKE_LVDS_D_M_MIN  79
-#define IRONLAKE_LVDS_D_M_MAX  127
-#define IRONLAKE_LVDS_D_P_MIN  14
-#define IRONLAKE_LVDS_D_P_MAX  56
-#define IRONLAKE_LVDS_D_P1_MIN 2
-#define IRONLAKE_LVDS_D_P1_MAX 8
-#define IRONLAKE_LVDS_D_P2_SLOW        7
-#define IRONLAKE_LVDS_D_P2_FAST        7
-
-/* LVDS single-channel 100Mhz refclk */
-#define IRONLAKE_LVDS_S_SSC_N_MIN      1
-#define IRONLAKE_LVDS_S_SSC_N_MAX      2
-#define IRONLAKE_LVDS_S_SSC_M_MIN      79
-#define IRONLAKE_LVDS_S_SSC_M_MAX      126
-#define IRONLAKE_LVDS_S_SSC_P_MIN      28
-#define IRONLAKE_LVDS_S_SSC_P_MAX      112
-#define IRONLAKE_LVDS_S_SSC_P1_MIN     2
-#define IRONLAKE_LVDS_S_SSC_P1_MAX     8
-#define IRONLAKE_LVDS_S_SSC_P2_SLOW    14
-#define IRONLAKE_LVDS_S_SSC_P2_FAST    14
-
-/* LVDS dual-channel 100Mhz refclk */
-#define IRONLAKE_LVDS_D_SSC_N_MIN      1
-#define IRONLAKE_LVDS_D_SSC_N_MAX      3
-#define IRONLAKE_LVDS_D_SSC_M_MIN      79
-#define IRONLAKE_LVDS_D_SSC_M_MAX      126
-#define IRONLAKE_LVDS_D_SSC_P_MIN      14
-#define IRONLAKE_LVDS_D_SSC_P_MAX      42
-#define IRONLAKE_LVDS_D_SSC_P1_MIN     2
-#define IRONLAKE_LVDS_D_SSC_P1_MAX     6
-#define IRONLAKE_LVDS_D_SSC_P2_SLOW    7
-#define IRONLAKE_LVDS_D_SSC_P2_FAST    7
-
-/* DisplayPort */
-#define IRONLAKE_DP_N_MIN              1
-#define IRONLAKE_DP_N_MAX              2
-#define IRONLAKE_DP_M_MIN              81
-#define IRONLAKE_DP_M_MAX              90
-#define IRONLAKE_DP_P_MIN              10
-#define IRONLAKE_DP_P_MAX              20
-#define IRONLAKE_DP_P2_FAST            10
-#define IRONLAKE_DP_P2_SLOW            10
-#define IRONLAKE_DP_P2_LIMIT           0
-#define IRONLAKE_DP_P1_MIN             1
-#define IRONLAKE_DP_P1_MAX             2
-
 /* FDI */
 #define IRONLAKE_FDI_FREQ              2700000 /* in kHz for mode->clock */
 
@@ -353,292 +104,253 @@ intel_fdi_link_freq(struct drm_device *dev)
 }
 
 static const intel_limit_t intel_limits_i8xx_dvo = {
-        .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
-        .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
-        .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
-        .m   = { .min = I8XX_M_MIN,            .max = I8XX_M_MAX },
-        .m1  = { .min = I8XX_M1_MIN,           .max = I8XX_M1_MAX },
-        .m2  = { .min = I8XX_M2_MIN,           .max = I8XX_M2_MAX },
-        .p   = { .min = I8XX_P_MIN,            .max = I8XX_P_MAX },
-        .p1  = { .min = I8XX_P1_MIN,           .max = I8XX_P1_MAX },
-       .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
-                .p2_slow = I8XX_P2_SLOW,       .p2_fast = I8XX_P2_FAST },
+        .dot = { .min = 25000, .max = 350000 },
+        .vco = { .min = 930000, .max = 1400000 },
+        .n = { .min = 3, .max = 16 },
+        .m = { .min = 96, .max = 140 },
+        .m1 = { .min = 18, .max = 26 },
+        .m2 = { .min = 6, .max = 16 },
+        .p = { .min = 4, .max = 128 },
+        .p1 = { .min = 2, .max = 33 },
+       .p2 = { .dot_limit = 165000,
+               .p2_slow = 4, .p2_fast = 2 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_i8xx_lvds = {
-        .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
-        .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
-        .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
-        .m   = { .min = I8XX_M_MIN,            .max = I8XX_M_MAX },
-        .m1  = { .min = I8XX_M1_MIN,           .max = I8XX_M1_MAX },
-        .m2  = { .min = I8XX_M2_MIN,           .max = I8XX_M2_MAX },
-        .p   = { .min = I8XX_P_MIN,            .max = I8XX_P_MAX },
-        .p1  = { .min = I8XX_P1_LVDS_MIN,      .max = I8XX_P1_LVDS_MAX },
-       .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
-                .p2_slow = I8XX_P2_LVDS_SLOW,  .p2_fast = I8XX_P2_LVDS_FAST },
+        .dot = { .min = 25000, .max = 350000 },
+        .vco = { .min = 930000, .max = 1400000 },
+        .n = { .min = 3, .max = 16 },
+        .m = { .min = 96, .max = 140 },
+        .m1 = { .min = 18, .max = 26 },
+        .m2 = { .min = 6, .max = 16 },
+        .p = { .min = 4, .max = 128 },
+        .p1 = { .min = 1, .max = 6 },
+       .p2 = { .dot_limit = 165000,
+               .p2_slow = 14, .p2_fast = 7 },
        .find_pll = intel_find_best_PLL,
 };
-       
+
 static const intel_limit_t intel_limits_i9xx_sdvo = {
-        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
-        .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
-        .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
-        .m   = { .min = I9XX_M_MIN,            .max = I9XX_M_MAX },
-        .m1  = { .min = I9XX_M1_MIN,           .max = I9XX_M1_MAX },
-        .m2  = { .min = I9XX_M2_MIN,           .max = I9XX_M2_MAX },
-        .p   = { .min = I9XX_P_SDVO_DAC_MIN,   .max = I9XX_P_SDVO_DAC_MAX },
-        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
-       .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
-                .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+        .dot = { .min = 20000, .max = 400000 },
+        .vco = { .min = 1400000, .max = 2800000 },
+        .n = { .min = 1, .max = 6 },
+        .m = { .min = 70, .max = 120 },
+        .m1 = { .min = 10, .max = 22 },
+        .m2 = { .min = 5, .max = 9 },
+        .p = { .min = 5, .max = 80 },
+        .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 200000,
+               .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_i9xx_lvds = {
-        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
-        .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
-        .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
-        .m   = { .min = I9XX_M_MIN,            .max = I9XX_M_MAX },
-        .m1  = { .min = I9XX_M1_MIN,           .max = I9XX_M1_MAX },
-        .m2  = { .min = I9XX_M2_MIN,           .max = I9XX_M2_MAX },
-        .p   = { .min = I9XX_P_LVDS_MIN,       .max = I9XX_P_LVDS_MAX },
-        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
-       /* The single-channel range is 25-112Mhz, and dual-channel
-        * is 80-224Mhz.  Prefer single channel as much as possible.
-        */
-       .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
-                .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_FAST },
+        .dot = { .min = 20000, .max = 400000 },
+        .vco = { .min = 1400000, .max = 2800000 },
+        .n = { .min = 1, .max = 6 },
+        .m = { .min = 70, .max = 120 },
+        .m1 = { .min = 10, .max = 22 },
+        .m2 = { .min = 5, .max = 9 },
+        .p = { .min = 7, .max = 98 },
+        .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 112000,
+               .p2_slow = 14, .p2_fast = 7 },
        .find_pll = intel_find_best_PLL,
 };
 
-    /* below parameter and function is for G4X Chipset Family*/
+
 static const intel_limit_t intel_limits_g4x_sdvo = {
-       .dot = { .min = G4X_DOT_SDVO_MIN,       .max = G4X_DOT_SDVO_MAX },
-       .vco = { .min = G4X_VCO_MIN,            .max = G4X_VCO_MAX},
-       .n   = { .min = G4X_N_SDVO_MIN,         .max = G4X_N_SDVO_MAX },
-       .m   = { .min = G4X_M_SDVO_MIN,         .max = G4X_M_SDVO_MAX },
-       .m1  = { .min = G4X_M1_SDVO_MIN,        .max = G4X_M1_SDVO_MAX },
-       .m2  = { .min = G4X_M2_SDVO_MIN,        .max = G4X_M2_SDVO_MAX },
-       .p   = { .min = G4X_P_SDVO_MIN,         .max = G4X_P_SDVO_MAX },
-       .p1  = { .min = G4X_P1_SDVO_MIN,        .max = G4X_P1_SDVO_MAX},
-       .p2  = { .dot_limit = G4X_P2_SDVO_LIMIT,
-                .p2_slow = G4X_P2_SDVO_SLOW,
-                .p2_fast = G4X_P2_SDVO_FAST
+       .dot = { .min = 25000, .max = 270000 },
+       .vco = { .min = 1750000, .max = 3500000},
+       .n = { .min = 1, .max = 4 },
+       .m = { .min = 104, .max = 138 },
+       .m1 = { .min = 17, .max = 23 },
+       .m2 = { .min = 5, .max = 11 },
+       .p = { .min = 10, .max = 30 },
+       .p1 = { .min = 1, .max = 3},
+       .p2 = { .dot_limit = 270000,
+               .p2_slow = 10,
+               .p2_fast = 10
        },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_hdmi = {
-       .dot = { .min = G4X_DOT_HDMI_DAC_MIN,   .max = G4X_DOT_HDMI_DAC_MAX },
-       .vco = { .min = G4X_VCO_MIN,            .max = G4X_VCO_MAX},
-       .n   = { .min = G4X_N_HDMI_DAC_MIN,     .max = G4X_N_HDMI_DAC_MAX },
-       .m   = { .min = G4X_M_HDMI_DAC_MIN,     .max = G4X_M_HDMI_DAC_MAX },
-       .m1  = { .min = G4X_M1_HDMI_DAC_MIN,    .max = G4X_M1_HDMI_DAC_MAX },
-       .m2  = { .min = G4X_M2_HDMI_DAC_MIN,    .max = G4X_M2_HDMI_DAC_MAX },
-       .p   = { .min = G4X_P_HDMI_DAC_MIN,     .max = G4X_P_HDMI_DAC_MAX },
-       .p1  = { .min = G4X_P1_HDMI_DAC_MIN,    .max = G4X_P1_HDMI_DAC_MAX},
-       .p2  = { .dot_limit = G4X_P2_HDMI_DAC_LIMIT,
-                .p2_slow = G4X_P2_HDMI_DAC_SLOW,
-                .p2_fast = G4X_P2_HDMI_DAC_FAST
-       },
+       .dot = { .min = 22000, .max = 400000 },
+       .vco = { .min = 1750000, .max = 3500000},
+       .n = { .min = 1, .max = 4 },
+       .m = { .min = 104, .max = 138 },
+       .m1 = { .min = 16, .max = 23 },
+       .m2 = { .min = 5, .max = 11 },
+       .p = { .min = 5, .max = 80 },
+       .p1 = { .min = 1, .max = 8},
+       .p2 = { .dot_limit = 165000,
+               .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
-       .dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_DOT_SINGLE_CHANNEL_LVDS_MAX },
-       .vco = { .min = G4X_VCO_MIN,
-                .max = G4X_VCO_MAX },
-       .n   = { .min = G4X_N_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_N_SINGLE_CHANNEL_LVDS_MAX },
-       .m   = { .min = G4X_M_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_M_SINGLE_CHANNEL_LVDS_MAX },
-       .m1  = { .min = G4X_M1_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_M1_SINGLE_CHANNEL_LVDS_MAX },
-       .m2  = { .min = G4X_M2_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_M2_SINGLE_CHANNEL_LVDS_MAX },
-       .p   = { .min = G4X_P_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_P_SINGLE_CHANNEL_LVDS_MAX },
-       .p1  = { .min = G4X_P1_SINGLE_CHANNEL_LVDS_MIN,
-                .max = G4X_P1_SINGLE_CHANNEL_LVDS_MAX },
-       .p2  = { .dot_limit = G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT,
-                .p2_slow = G4X_P2_SINGLE_CHANNEL_LVDS_SLOW,
-                .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
+       .dot = { .min = 20000, .max = 115000 },
+       .vco = { .min = 1750000, .max = 3500000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 104, .max = 138 },
+       .m1 = { .min = 17, .max = 23 },
+       .m2 = { .min = 5, .max = 11 },
+       .p = { .min = 28, .max = 112 },
+       .p1 = { .min = 2, .max = 8 },
+       .p2 = { .dot_limit = 0,
+               .p2_slow = 14, .p2_fast = 14
        },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
-       .dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_DOT_DUAL_CHANNEL_LVDS_MAX },
-       .vco = { .min = G4X_VCO_MIN,
-                .max = G4X_VCO_MAX },
-       .n   = { .min = G4X_N_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_N_DUAL_CHANNEL_LVDS_MAX },
-       .m   = { .min = G4X_M_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_M_DUAL_CHANNEL_LVDS_MAX },
-       .m1  = { .min = G4X_M1_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_M1_DUAL_CHANNEL_LVDS_MAX },
-       .m2  = { .min = G4X_M2_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_M2_DUAL_CHANNEL_LVDS_MAX },
-       .p   = { .min = G4X_P_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_P_DUAL_CHANNEL_LVDS_MAX },
-       .p1  = { .min = G4X_P1_DUAL_CHANNEL_LVDS_MIN,
-                .max = G4X_P1_DUAL_CHANNEL_LVDS_MAX },
-       .p2  = { .dot_limit = G4X_P2_DUAL_CHANNEL_LVDS_LIMIT,
-                .p2_slow = G4X_P2_DUAL_CHANNEL_LVDS_SLOW,
-                .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
+       .dot = { .min = 80000, .max = 224000 },
+       .vco = { .min = 1750000, .max = 3500000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 104, .max = 138 },
+       .m1 = { .min = 17, .max = 23 },
+       .m2 = { .min = 5, .max = 11 },
+       .p = { .min = 14, .max = 42 },
+       .p1 = { .min = 2, .max = 6 },
+       .p2 = { .dot_limit = 0,
+               .p2_slow = 7, .p2_fast = 7
        },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_g4x_display_port = {
-        .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN,
-                 .max = G4X_DOT_DISPLAY_PORT_MAX },
-        .vco = { .min = G4X_VCO_MIN,
-                 .max = G4X_VCO_MAX},
-        .n   = { .min = G4X_N_DISPLAY_PORT_MIN,
-                 .max = G4X_N_DISPLAY_PORT_MAX },
-        .m   = { .min = G4X_M_DISPLAY_PORT_MIN,
-                 .max = G4X_M_DISPLAY_PORT_MAX },
-        .m1  = { .min = G4X_M1_DISPLAY_PORT_MIN,
-                 .max = G4X_M1_DISPLAY_PORT_MAX },
-        .m2  = { .min = G4X_M2_DISPLAY_PORT_MIN,
-                 .max = G4X_M2_DISPLAY_PORT_MAX },
-        .p   = { .min = G4X_P_DISPLAY_PORT_MIN,
-                 .max = G4X_P_DISPLAY_PORT_MAX },
-        .p1  = { .min = G4X_P1_DISPLAY_PORT_MIN,
-                 .max = G4X_P1_DISPLAY_PORT_MAX},
-        .p2  = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT,
-                 .p2_slow = G4X_P2_DISPLAY_PORT_SLOW,
-                 .p2_fast = G4X_P2_DISPLAY_PORT_FAST },
+        .dot = { .min = 161670, .max = 227000 },
+        .vco = { .min = 1750000, .max = 3500000},
+        .n = { .min = 1, .max = 2 },
+        .m = { .min = 97, .max = 108 },
+        .m1 = { .min = 0x10, .max = 0x12 },
+        .m2 = { .min = 0x05, .max = 0x06 },
+        .p = { .min = 10, .max = 20 },
+        .p1 = { .min = 1, .max = 2},
+        .p2 = { .dot_limit = 0,
+               .p2_slow = 10, .p2_fast = 10 },
         .find_pll = intel_find_pll_g4x_dp,
 };
 
 static const intel_limit_t intel_limits_pineview_sdvo = {
-        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX},
-        .vco = { .min = PINEVIEW_VCO_MIN,              .max = PINEVIEW_VCO_MAX },
-        .n   = { .min = PINEVIEW_N_MIN,                .max = PINEVIEW_N_MAX },
-        .m   = { .min = PINEVIEW_M_MIN,                .max = PINEVIEW_M_MAX },
-        .m1  = { .min = PINEVIEW_M1_MIN,               .max = PINEVIEW_M1_MAX },
-        .m2  = { .min = PINEVIEW_M2_MIN,               .max = PINEVIEW_M2_MAX },
-        .p   = { .min = I9XX_P_SDVO_DAC_MIN,    .max = I9XX_P_SDVO_DAC_MAX },
-        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
-       .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
-                .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+        .dot = { .min = 20000, .max = 400000},
+        .vco = { .min = 1700000, .max = 3500000 },
+       /* Pineview's Ncounter is a ring counter */
+        .n = { .min = 3, .max = 6 },
+        .m = { .min = 2, .max = 256 },
+       /* Pineview only has one combined m divider, which we treat as m2. */
+        .m1 = { .min = 0, .max = 0 },
+        .m2 = { .min = 0, .max = 254 },
+        .p = { .min = 5, .max = 80 },
+        .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 200000,
+               .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_pineview_lvds = {
-        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
-        .vco = { .min = PINEVIEW_VCO_MIN,              .max = PINEVIEW_VCO_MAX },
-        .n   = { .min = PINEVIEW_N_MIN,                .max = PINEVIEW_N_MAX },
-        .m   = { .min = PINEVIEW_M_MIN,                .max = PINEVIEW_M_MAX },
-        .m1  = { .min = PINEVIEW_M1_MIN,               .max = PINEVIEW_M1_MAX },
-        .m2  = { .min = PINEVIEW_M2_MIN,               .max = PINEVIEW_M2_MAX },
-        .p   = { .min = PINEVIEW_P_LVDS_MIN,   .max = PINEVIEW_P_LVDS_MAX },
-        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
-       /* Pineview only supports single-channel mode. */
-       .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
-                .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_SLOW },
+        .dot = { .min = 20000, .max = 400000 },
+        .vco = { .min = 1700000, .max = 3500000 },
+        .n = { .min = 3, .max = 6 },
+        .m = { .min = 2, .max = 256 },
+        .m1 = { .min = 0, .max = 0 },
+        .m2 = { .min = 0, .max = 254 },
+        .p = { .min = 7, .max = 112 },
+        .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 112000,
+               .p2_slow = 14, .p2_fast = 14 },
        .find_pll = intel_find_best_PLL,
 };
 
+/* Ironlake / Sandybridge
+ *
+ * We calculate clock using (register_value + 2) for N/M1/M2, so here
+ * the range value for them is (actual_value - 2).
+ */
 static const intel_limit_t intel_limits_ironlake_dac = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_DAC_N_MIN,        .max = IRONLAKE_DAC_N_MAX },
-       .m   = { .min = IRONLAKE_DAC_M_MIN,        .max = IRONLAKE_DAC_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_DAC_P_MIN,        .max = IRONLAKE_DAC_P_MAX },
-       .p1  = { .min = IRONLAKE_DAC_P1_MIN,       .max = IRONLAKE_DAC_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_DAC_P2_SLOW,
-                .p2_fast = IRONLAKE_DAC_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 5 },
+       .m = { .min = 79, .max = 127 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 5, .max = 80 },
+       .p1 = { .min = 1, .max = 8 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_ironlake_single_lvds = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_LVDS_S_N_MIN,     .max = IRONLAKE_LVDS_S_N_MAX },
-       .m   = { .min = IRONLAKE_LVDS_S_M_MIN,     .max = IRONLAKE_LVDS_S_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_LVDS_S_P_MIN,     .max = IRONLAKE_LVDS_S_P_MAX },
-       .p1  = { .min = IRONLAKE_LVDS_S_P1_MIN,    .max = IRONLAKE_LVDS_S_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_LVDS_S_P2_SLOW,
-                .p2_fast = IRONLAKE_LVDS_S_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 79, .max = 118 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 28, .max = 112 },
+       .p1 = { .min = 2, .max = 8 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 14, .p2_fast = 14 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_ironlake_dual_lvds = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_LVDS_D_N_MIN,     .max = IRONLAKE_LVDS_D_N_MAX },
-       .m   = { .min = IRONLAKE_LVDS_D_M_MIN,     .max = IRONLAKE_LVDS_D_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_LVDS_D_P_MIN,     .max = IRONLAKE_LVDS_D_P_MAX },
-       .p1  = { .min = IRONLAKE_LVDS_D_P1_MIN,    .max = IRONLAKE_LVDS_D_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_LVDS_D_P2_SLOW,
-                .p2_fast = IRONLAKE_LVDS_D_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 79, .max = 127 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 14, .max = 56 },
+       .p1 = { .min = 2, .max = 8 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 7, .p2_fast = 7 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
+/* LVDS 100mhz refclk limits. */
 static const intel_limit_t intel_limits_ironlake_single_lvds_100m = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX },
-       .m   = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX },
-       .p1  = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW,
-                .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 2 },
+       .m = { .min = 79, .max = 126 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 28, .max = 112 },
+       .p1 = { .min = 2,.max = 8 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 14, .p2_fast = 14 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
-       .dot = { .min = IRONLAKE_DOT_MIN,          .max = IRONLAKE_DOT_MAX },
-       .vco = { .min = IRONLAKE_VCO_MIN,          .max = IRONLAKE_VCO_MAX },
-       .n   = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX },
-       .m   = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX },
-       .m1  = { .min = IRONLAKE_M1_MIN,           .max = IRONLAKE_M1_MAX },
-       .m2  = { .min = IRONLAKE_M2_MIN,           .max = IRONLAKE_M2_MAX },
-       .p   = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX },
-       .p1  = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX },
-       .p2  = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
-                .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW,
-                .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000 },
+       .n = { .min = 1, .max = 3 },
+       .m = { .min = 79, .max = 126 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 14, .max = 42 },
+       .p1 = { .min = 2,.max = 6 },
+       .p2 = { .dot_limit = 225000,
+               .p2_slow = 7, .p2_fast = 7 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_ironlake_display_port = {
-        .dot = { .min = IRONLAKE_DOT_MIN,
-                 .max = IRONLAKE_DOT_MAX },
-        .vco = { .min = IRONLAKE_VCO_MIN,
-                 .max = IRONLAKE_VCO_MAX},
-        .n   = { .min = IRONLAKE_DP_N_MIN,
-                 .max = IRONLAKE_DP_N_MAX },
-        .m   = { .min = IRONLAKE_DP_M_MIN,
-                 .max = IRONLAKE_DP_M_MAX },
-        .m1  = { .min = IRONLAKE_M1_MIN,
-                 .max = IRONLAKE_M1_MAX },
-        .m2  = { .min = IRONLAKE_M2_MIN,
-                 .max = IRONLAKE_M2_MAX },
-        .p   = { .min = IRONLAKE_DP_P_MIN,
-                 .max = IRONLAKE_DP_P_MAX },
-        .p1  = { .min = IRONLAKE_DP_P1_MIN,
-                 .max = IRONLAKE_DP_P1_MAX},
-        .p2  = { .dot_limit = IRONLAKE_DP_P2_LIMIT,
-                 .p2_slow = IRONLAKE_DP_P2_SLOW,
-                 .p2_fast = IRONLAKE_DP_P2_FAST },
+        .dot = { .min = 25000, .max = 350000 },
+        .vco = { .min = 1760000, .max = 3510000},
+        .n = { .min = 1, .max = 2 },
+        .m = { .min = 81, .max = 90 },
+        .m1 = { .min = 12, .max = 22 },
+        .m2 = { .min = 5, .max = 9 },
+        .p = { .min = 10, .max = 20 },
+        .p1 = { .min = 1, .max = 2},
+        .p2 = { .dot_limit = 0,
+               .p2_slow = 10, .p2_fast = 10 },
         .find_pll = intel_find_pll_ironlake_dp,
 };
 
@@ -1828,7 +1540,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
        u32 blt_ecoskpd;
 
        /* Make sure blitter notifies FBC of writes */
-       __gen6_gt_force_wake_get(dev_priv);
+       gen6_gt_force_wake_get(dev_priv);
        blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
        blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
                GEN6_BLITTER_LOCK_SHIFT;
@@ -1839,7 +1551,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
                         GEN6_BLITTER_LOCK_SHIFT);
        I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
        POSTING_READ(GEN6_BLITTER_ECOSKPD);
-       __gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv);
 }
 
 static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
@@ -2019,6 +1731,11 @@ static void intel_update_fbc(struct drm_device *dev)
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 
+       if (!i915_enable_fbc) {
+               DRM_DEBUG_KMS("fbc disabled per module param (default off)\n");
+               dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
+               goto out_disable;
+       }
        if (intel_fb->obj->base.size > dev_priv->cfb_size) {
                DRM_DEBUG_KMS("framebuffer too large, disabling "
                              "compression\n");
@@ -2339,8 +2056,13 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
        /* enable normal train */
        reg = FDI_TX_CTL(pipe);
        temp = I915_READ(reg);
-       temp &= ~FDI_LINK_TRAIN_NONE;
-       temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       if (IS_IVYBRIDGE(dev)) {
+               temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+               temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
+       } else {
+               temp &= ~FDI_LINK_TRAIN_NONE;
+               temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+       }
        I915_WRITE(reg, temp);
 
        reg = FDI_RX_CTL(pipe);
@@ -2357,6 +2079,11 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
        /* wait one idle pattern time */
        POSTING_READ(reg);
        udelay(1000);
+
+       /* IVB wants error correction enabled */
+       if (IS_IVYBRIDGE(dev))
+               I915_WRITE(reg, I915_READ(reg) | FDI_FS_ERRC_ENABLE |
+                          FDI_FE_ERRC_ENABLE);
 }
 
 /* The FDI link training functions for ILK/Ibexpeak. */
@@ -2584,7 +2311,116 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        DRM_DEBUG_KMS("FDI train done.\n");
 }
 
-static void ironlake_fdi_enable(struct drm_crtc *crtc)
+/* Manual link training for Ivy Bridge A0 parts */
+static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       u32 reg, temp, i;
+
+       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+          for train result */
+       reg = FDI_RX_IMR(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_RX_SYMBOL_LOCK;
+       temp &= ~FDI_RX_BIT_LOCK;
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
+       udelay(150);
+
+       /* enable CPU FDI TX and PCH FDI RX */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~(7 << 19);
+       temp |= (intel_crtc->fdi_lanes - 1) << 19;
+       temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
+       temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
+       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       I915_WRITE(reg, temp | FDI_TX_ENABLE);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_AUTO;
+       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+       temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+       I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+       POSTING_READ(reg);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
+               udelay(500);
+
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_BIT_LOCK ||
+                   (I915_READ(reg) & FDI_RX_BIT_LOCK)) {
+                       I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
+                       DRM_DEBUG_KMS("FDI train 1 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_ERROR("FDI train 1 fail!\n");
+
+       /* Train 2 */
+       reg = FDI_TX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+       temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
+       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       I915_WRITE(reg, temp);
+
+       reg = FDI_RX_CTL(pipe);
+       temp = I915_READ(reg);
+       temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+       temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
+       I915_WRITE(reg, temp);
+
+       POSTING_READ(reg);
+       udelay(150);
+
+       for (i = 0; i < 4; i++ ) {
+               reg = FDI_TX_CTL(pipe);
+               temp = I915_READ(reg);
+               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+               temp |= snb_b_fdi_train_param[i];
+               I915_WRITE(reg, temp);
+
+               POSTING_READ(reg);
+               udelay(500);
+
+               reg = FDI_RX_IIR(pipe);
+               temp = I915_READ(reg);
+               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+               if (temp & FDI_RX_SYMBOL_LOCK) {
+                       I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
+                       DRM_DEBUG_KMS("FDI train 2 done.\n");
+                       break;
+               }
+       }
+       if (i == 4)
+               DRM_ERROR("FDI train 2 fail!\n");
+
+       DRM_DEBUG_KMS("FDI train done.\n");
+}
+
+static void ironlake_fdi_pll_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2757,10 +2593,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
        u32 reg, temp;
 
        /* For PCH output, training FDI link */
-       if (IS_GEN6(dev))
-               gen6_fdi_link_train(crtc);
-       else
-               ironlake_fdi_link_train(crtc);
+       dev_priv->display.fdi_link_train(crtc);
 
        intel_enable_pch_pll(dev_priv, pipe);
 
@@ -2850,7 +2683,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        is_pch_port = intel_crtc_driving_pch(crtc);
 
        if (is_pch_port)
-               ironlake_fdi_enable(crtc);
+               ironlake_fdi_pll_enable(crtc);
        else
                ironlake_fdi_disable(crtc);
 
@@ -2873,7 +2706,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
                ironlake_pch_enable(crtc);
 
        intel_crtc_load_lut(crtc);
+
+       mutex_lock(&dev->struct_mutex);
        intel_update_fbc(dev);
+       mutex_unlock(&dev->struct_mutex);
+
        intel_crtc_update_cursor(crtc, true);
 }
 
@@ -2969,8 +2806,11 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 
        intel_crtc->active = false;
        intel_update_watermarks(dev);
+
+       mutex_lock(&dev->struct_mutex);
        intel_update_fbc(dev);
        intel_clear_scanline_wait(dev);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -3497,11 +3337,11 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
                1000;
        entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size);
 
-       DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required);
+       DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required);
 
        wm_size = fifo_size - (entries_required + wm->guard_size);
 
-       DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
+       DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size);
 
        /* Don't promote wm_size to unsigned... */
        if (wm_size > (long)wm->max_wm)
@@ -3823,13 +3663,13 @@ static bool g4x_check_srwm(struct drm_device *dev,
                      display_wm, cursor_wm);
 
        if (display_wm > display->max_wm) {
-               DRM_DEBUG_KMS("display watermark is too large(%d), disabling\n",
+               DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n",
                              display_wm, display->max_wm);
                return false;
        }
 
        if (cursor_wm > cursor->max_wm) {
-               DRM_DEBUG_KMS("cursor watermark is too large(%d), disabling\n",
+               DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n",
                              cursor_wm, cursor->max_wm);
                return false;
        }
@@ -4516,34 +4356,28 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
        return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
 }
 
-static int intel_crtc_mode_set(struct drm_crtc *crtc,
-                              struct drm_display_mode *mode,
-                              struct drm_display_mode *adjusted_mode,
-                              int x, int y,
-                              struct drm_framebuffer *old_fb)
+static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
+                             struct drm_display_mode *mode,
+                             struct drm_display_mode *adjusted_mode,
+                             int x, int y,
+                             struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
-       u32 fp_reg, dpll_reg;
        int refclk, num_connectors = 0;
        intel_clock_t clock, reduced_clock;
        u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
        bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
        bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
-       struct intel_encoder *has_edp_encoder = NULL;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *encoder;
        const intel_limit_t *limit;
        int ret;
-       struct fdi_m_n m_n = {0};
-       u32 reg, temp;
+       u32 temp;
        u32 lvds_sync = 0;
-       int target_clock;
-
-       drm_vblank_pre_modeset(dev, pipe);
 
        list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
                if (encoder->base.crtc != crtc)
@@ -4571,9 +4405,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                case INTEL_OUTPUT_DISPLAYPORT:
                        is_dp = true;
                        break;
-               case INTEL_OUTPUT_EDP:
-                       has_edp_encoder = encoder;
-                       break;
                }
 
                num_connectors++;
@@ -4585,9 +4416,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                              refclk / 1000);
        } else if (!IS_GEN2(dev)) {
                refclk = 96000;
-               if (HAS_PCH_SPLIT(dev) &&
-                   (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)))
-                       refclk = 120000; /* 120Mhz refclk */
        } else {
                refclk = 48000;
        }
@@ -4601,7 +4429,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
        if (!ok) {
                DRM_ERROR("Couldn't find PLL settings for mode!\n");
-               drm_vblank_post_modeset(dev, pipe);
                return -EINVAL;
        }
 
@@ -4645,143 +4472,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
-       /* FDI link */
-       if (HAS_PCH_SPLIT(dev)) {
-               int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
-               int lane = 0, link_bw, bpp;
-               /* CPU eDP doesn't require FDI link, so just set DP M/N
-                  according to current link config */
-               if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                       target_clock = mode->clock;
-                       intel_edp_link_config(has_edp_encoder,
-                                             &lane, &link_bw);
-               } else {
-                       /* [e]DP over FDI requires target mode clock
-                          instead of link clock */
-                       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
-                               target_clock = mode->clock;
-                       else
-                               target_clock = adjusted_mode->clock;
-
-                       /* FDI is a binary signal running at ~2.7GHz, encoding
-                        * each output octet as 10 bits. The actual frequency
-                        * is stored as a divider into a 100MHz clock, and the
-                        * mode pixel clock is stored in units of 1KHz.
-                        * Hence the bw of each lane in terms of the mode signal
-                        * is:
-                        */
-                       link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
-               }
-
-               /* determine panel color depth */
-               temp = I915_READ(PIPECONF(pipe));
-               temp &= ~PIPE_BPC_MASK;
-               if (is_lvds) {
-                       /* the BPC will be 6 if it is 18-bit LVDS panel */
-                       if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
-                               temp |= PIPE_8BPC;
-                       else
-                               temp |= PIPE_6BPC;
-               } else if (has_edp_encoder) {
-                       switch (dev_priv->edp.bpp/3) {
-                       case 8:
-                               temp |= PIPE_8BPC;
-                               break;
-                       case 10:
-                               temp |= PIPE_10BPC;
-                               break;
-                       case 6:
-                               temp |= PIPE_6BPC;
-                               break;
-                       case 12:
-                               temp |= PIPE_12BPC;
-                               break;
-                       }
-               } else
-                       temp |= PIPE_8BPC;
-               I915_WRITE(PIPECONF(pipe), temp);
-
-               switch (temp & PIPE_BPC_MASK) {
-               case PIPE_8BPC:
-                       bpp = 24;
-                       break;
-               case PIPE_10BPC:
-                       bpp = 30;
-                       break;
-               case PIPE_6BPC:
-                       bpp = 18;
-                       break;
-               case PIPE_12BPC:
-                       bpp = 36;
-                       break;
-               default:
-                       DRM_ERROR("unknown pipe bpc value\n");
-                       bpp = 24;
-               }
-
-               if (!lane) {
-                       /* 
-                        * Account for spread spectrum to avoid
-                        * oversubscribing the link. Max center spread
-                        * is 2.5%; use 5% for safety's sake.
-                        */
-                       u32 bps = target_clock * bpp * 21 / 20;
-                       lane = bps / (link_bw * 8) + 1;
-               }
-
-               intel_crtc->fdi_lanes = lane;
-
-               if (pixel_multiplier > 1)
-                       link_bw *= pixel_multiplier;
-               ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
-       }
-
-       /* Ironlake: try to setup display ref clock before DPLL
-        * enabling. This is only under driver's control after
-        * PCH B stepping, previous chipset stepping should be
-        * ignoring this setting.
-        */
-       if (HAS_PCH_SPLIT(dev)) {
-               temp = I915_READ(PCH_DREF_CONTROL);
-               /* Always enable nonspread source */
-               temp &= ~DREF_NONSPREAD_SOURCE_MASK;
-               temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-               temp &= ~DREF_SSC_SOURCE_MASK;
-               temp |= DREF_SSC_SOURCE_ENABLE;
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-
-               POSTING_READ(PCH_DREF_CONTROL);
-               udelay(200);
-
-               if (has_edp_encoder) {
-                       if (intel_panel_use_ssc(dev_priv)) {
-                               temp |= DREF_SSC1_ENABLE;
-                               I915_WRITE(PCH_DREF_CONTROL, temp);
-
-                               POSTING_READ(PCH_DREF_CONTROL);
-                               udelay(200);
-                       }
-                       temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-
-                       /* Enable CPU source on CPU attached eDP */
-                       if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                               if (intel_panel_use_ssc(dev_priv))
-                                       temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-                               else
-                                       temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-                       } else {
-                               /* Enable SSC on PCH eDP if needed */
-                               if (intel_panel_use_ssc(dev_priv)) {
-                                       DRM_ERROR("enabling SSC on PCH\n");
-                                       temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
-                               }
-                       }
-                       I915_WRITE(PCH_DREF_CONTROL, temp);
-                       POSTING_READ(PCH_DREF_CONTROL);
-                       udelay(200);
-               }
-       }
-
        if (IS_PINEVIEW(dev)) {
                fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
                if (has_reduced_clock)
@@ -4794,25 +4484,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                reduced_clock.m2;
        }
 
-       /* Enable autotuning of the PLL clock (if permissible) */
-       if (HAS_PCH_SPLIT(dev)) {
-               int factor = 21;
-
-               if (is_lvds) {
-                       if ((intel_panel_use_ssc(dev_priv) &&
-                            dev_priv->lvds_ssc_freq == 100) ||
-                           (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
-                               factor = 25;
-               } else if (is_sdvo && is_tv)
-                       factor = 20;
-
-               if (clock.m1 < factor * clock.n)
-                       fp |= FP_CB_TUNE;
-       }
-
-       dpll = 0;
-       if (!HAS_PCH_SPLIT(dev))
-               dpll = DPLL_VGA_MODE_DIS;
+       dpll = DPLL_VGA_MODE_DIS;
 
        if (!IS_GEN2(dev)) {
                if (is_lvds)
@@ -4824,12 +4496,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        if (pixel_multiplier > 1) {
                                if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
                                        dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
-                               else if (HAS_PCH_SPLIT(dev))
-                                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
                        }
                        dpll |= DPLL_DVO_HIGH_SPEED;
                }
-               if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+               if (is_dp)
                        dpll |= DPLL_DVO_HIGH_SPEED;
 
                /* compute bitmask from p1 value */
@@ -4837,9 +4507,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
                else {
                        dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-                       /* also FPA1 */
-                       if (HAS_PCH_SPLIT(dev))
-                               dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
                        if (IS_G4X(dev) && has_reduced_clock)
                                dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
                }
@@ -4857,7 +4524,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
                        break;
                }
-               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
+               if (INTEL_INFO(dev)->gen >= 4)
                        dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
        } else {
                if (is_lvds) {
@@ -4891,12 +4558,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        /* Ironlake's plane is forced to pipe, bit 24 is to
           enable color space conversion */
-       if (!HAS_PCH_SPLIT(dev)) {
-               if (pipe == 0)
-                       dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
-               else
-                       dspcntr |= DISPPLANE_SEL_PIPE_B;
-       }
+       if (pipe == 0)
+               dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
+       else
+               dspcntr |= DISPPLANE_SEL_PIPE_B;
 
        if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
                /* Enable pixel doubling when the dot clock is > 90% of the (display)
@@ -4912,74 +4577,28 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        pipeconf &= ~PIPECONF_DOUBLE_WIDE;
        }
 
-       if (!HAS_PCH_SPLIT(dev))
-               dpll |= DPLL_VCO_ENABLE;
+       dpll |= DPLL_VCO_ENABLE;
 
        DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
        drm_mode_debug_printmodeline(mode);
 
-       /* assign to Ironlake registers */
-       if (HAS_PCH_SPLIT(dev)) {
-               fp_reg = PCH_FP0(pipe);
-               dpll_reg = PCH_DPLL(pipe);
-       } else {
-               fp_reg = FP0(pipe);
-               dpll_reg = DPLL(pipe);
-       }
-
-       /* PCH eDP needs FDI, but CPU eDP does not */
-       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-               I915_WRITE(fp_reg, fp);
-               I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
-
-               POSTING_READ(dpll_reg);
-               udelay(150);
-       }
-
-       /* enable transcoder DPLL */
-       if (HAS_PCH_CPT(dev)) {
-               temp = I915_READ(PCH_DPLL_SEL);
-               switch (pipe) {
-               case 0:
-                       temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
-                       break;
-               case 1:
-                       temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
-                       break;
-               case 2:
-                       /* FIXME: manage transcoder PLLs? */
-                       temp |= TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL;
-                       break;
-               default:
-                       BUG();
-               }
-               I915_WRITE(PCH_DPLL_SEL, temp);
+       I915_WRITE(FP0(pipe), fp);
+       I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
 
-               POSTING_READ(PCH_DPLL_SEL);
-               udelay(150);
-       }
+       POSTING_READ(DPLL(pipe));
+       udelay(150);
 
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
         * This is an exception to the general rule that mode_set doesn't turn
         * things on.
         */
        if (is_lvds) {
-               reg = LVDS;
-               if (HAS_PCH_SPLIT(dev))
-                       reg = PCH_LVDS;
-
-               temp = I915_READ(reg);
+               temp = I915_READ(LVDS);
                temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
                if (pipe == 1) {
-                       if (HAS_PCH_CPT(dev))
-                               temp |= PORT_TRANS_B_SEL_CPT;
-                       else
-                               temp |= LVDS_PIPEB_SELECT;
+                       temp |= LVDS_PIPEB_SELECT;
                } else {
-                       if (HAS_PCH_CPT(dev))
-                               temp &= ~PORT_TRANS_SEL_MASK;
-                       else
-                               temp &= ~LVDS_PIPEB_SELECT;
+                       temp &= ~LVDS_PIPEB_SELECT;
                }
                /* set the corresponsding LVDS_BORDER bit */
                temp |= dev_priv->lvds_border_bits;
@@ -4995,8 +4614,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                 * appropriately here, but we need to look more thoroughly into how
                 * panels behave in the two modes.
                 */
-               /* set the dithering flag on non-PCH LVDS as needed */
-               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+               /* set the dithering flag on LVDS as needed */
+               if (INTEL_INFO(dev)->gen >= 4) {
                        if (dev_priv->lvds_dither)
                                temp |= LVDS_ENABLE_DITHER;
                        else
@@ -5018,66 +4637,567 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                        temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
                        temp |= lvds_sync;
                }
-               I915_WRITE(reg, temp);
+               I915_WRITE(LVDS, temp);
        }
 
-       /* set the dithering flag and clear for anything other than a panel. */
-       if (HAS_PCH_SPLIT(dev)) {
-               pipeconf &= ~PIPECONF_DITHER_EN;
-               pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
-               if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
-                       pipeconf |= PIPECONF_DITHER_EN;
-                       pipeconf |= PIPECONF_DITHER_TYPE_ST1;
-               }
+       if (is_dp) {
+               intel_dp_set_m_n(crtc, mode, adjusted_mode);
        }
 
-       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-               intel_dp_set_m_n(crtc, mode, adjusted_mode);
-       } else if (HAS_PCH_SPLIT(dev)) {
-               /* For non-DP output, clear any trans DP clock recovery setting.*/
+       I915_WRITE(DPLL(pipe), dpll);
+
+       /* Wait for the clocks to stabilize. */
+       POSTING_READ(DPLL(pipe));
+       udelay(150);
+
+       if (INTEL_INFO(dev)->gen >= 4) {
+               temp = 0;
+               if (is_sdvo) {
+                       temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+                       if (temp > 1)
+                               temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+                       else
+                               temp = 0;
+               }
+               I915_WRITE(DPLL_MD(pipe), temp);
+       } else {
+               /* The pixel multiplier can only be updated once the
+                * DPLL is enabled and the clocks are stable.
+                *
+                * So write it again.
+                */
+               I915_WRITE(DPLL(pipe), dpll);
+       }
+
+       intel_crtc->lowfreq_avail = false;
+       if (is_lvds && has_reduced_clock && i915_powersave) {
+               I915_WRITE(FP1(pipe), fp2);
+               intel_crtc->lowfreq_avail = true;
+               if (HAS_PIPE_CXSR(dev)) {
+                       DRM_DEBUG_KMS("enabling CxSR downclocking\n");
+                       pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
+               }
+       } else {
+               I915_WRITE(FP1(pipe), fp);
+               if (HAS_PIPE_CXSR(dev)) {
+                       DRM_DEBUG_KMS("disabling CxSR downclocking\n");
+                       pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+               }
+       }
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+               /* the chip adds 2 halflines automatically */
+               adjusted_mode->crtc_vdisplay -= 1;
+               adjusted_mode->crtc_vtotal -= 1;
+               adjusted_mode->crtc_vblank_start -= 1;
+               adjusted_mode->crtc_vblank_end -= 1;
+               adjusted_mode->crtc_vsync_end -= 1;
+               adjusted_mode->crtc_vsync_start -= 1;
+       } else
+               pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
+
+       I915_WRITE(HTOTAL(pipe),
+                  (adjusted_mode->crtc_hdisplay - 1) |
+                  ((adjusted_mode->crtc_htotal - 1) << 16));
+       I915_WRITE(HBLANK(pipe),
+                  (adjusted_mode->crtc_hblank_start - 1) |
+                  ((adjusted_mode->crtc_hblank_end - 1) << 16));
+       I915_WRITE(HSYNC(pipe),
+                  (adjusted_mode->crtc_hsync_start - 1) |
+                  ((adjusted_mode->crtc_hsync_end - 1) << 16));
+
+       I915_WRITE(VTOTAL(pipe),
+                  (adjusted_mode->crtc_vdisplay - 1) |
+                  ((adjusted_mode->crtc_vtotal - 1) << 16));
+       I915_WRITE(VBLANK(pipe),
+                  (adjusted_mode->crtc_vblank_start - 1) |
+                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
+       I915_WRITE(VSYNC(pipe),
+                  (adjusted_mode->crtc_vsync_start - 1) |
+                  ((adjusted_mode->crtc_vsync_end - 1) << 16));
+
+       /* pipesrc and dspsize control the size that is scaled from,
+        * which should always be the user's requested size.
+        */
+       I915_WRITE(DSPSIZE(plane),
+                  ((mode->vdisplay - 1) << 16) |
+                  (mode->hdisplay - 1));
+       I915_WRITE(DSPPOS(plane), 0);
+       I915_WRITE(PIPESRC(pipe),
+                  ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+
+       I915_WRITE(PIPECONF(pipe), pipeconf);
+       POSTING_READ(PIPECONF(pipe));
+       intel_enable_pipe(dev_priv, pipe, false);
+
+       intel_wait_for_vblank(dev, pipe);
+
+       I915_WRITE(DSPCNTR(plane), dspcntr);
+       POSTING_READ(DSPCNTR(plane));
+
+       ret = intel_pipe_set_base(crtc, x, y, old_fb);
+
+       intel_update_watermarks(dev);
+
+       return ret;
+}
+
+static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode,
+                                 int x, int y,
+                                 struct drm_framebuffer *old_fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int plane = intel_crtc->plane;
+       int refclk, num_connectors = 0;
+       intel_clock_t clock, reduced_clock;
+       u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
+       bool ok, has_reduced_clock = false, is_sdvo = false;
+       bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
+       struct intel_encoder *has_edp_encoder = NULL;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *encoder;
+       const intel_limit_t *limit;
+       int ret;
+       struct fdi_m_n m_n = {0};
+       u32 temp;
+       u32 lvds_sync = 0;
+       int target_clock, pixel_multiplier, lane, link_bw, bpp, factor;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
+                       continue;
+
+               switch (encoder->type) {
+               case INTEL_OUTPUT_LVDS:
+                       is_lvds = true;
+                       break;
+               case INTEL_OUTPUT_SDVO:
+               case INTEL_OUTPUT_HDMI:
+                       is_sdvo = true;
+                       if (encoder->needs_tv_clock)
+                               is_tv = true;
+                       break;
+               case INTEL_OUTPUT_TVOUT:
+                       is_tv = true;
+                       break;
+               case INTEL_OUTPUT_ANALOG:
+                       is_crt = true;
+                       break;
+               case INTEL_OUTPUT_DISPLAYPORT:
+                       is_dp = true;
+                       break;
+               case INTEL_OUTPUT_EDP:
+                       has_edp_encoder = encoder;
+                       break;
+               }
+
+               num_connectors++;
+       }
+
+       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+               refclk = dev_priv->lvds_ssc_freq * 1000;
+               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+                             refclk / 1000);
+       } else {
+               refclk = 96000;
+               if (!has_edp_encoder ||
+                   intel_encoder_is_pch_edp(&has_edp_encoder->base))
+                       refclk = 120000; /* 120Mhz refclk */
+       }
+
+       /*
+        * Returns a set of divisors for the desired target clock with the given
+        * refclk, or FALSE.  The returned values represent the clock equation:
+        * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+        */
+       limit = intel_limit(crtc, refclk);
+       ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+       if (!ok) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return -EINVAL;
+       }
+
+       /* Ensure that the cursor is valid for the new mode before changing... */
+       intel_crtc_update_cursor(crtc, true);
+
+       if (is_lvds && dev_priv->lvds_downclock_avail) {
+               has_reduced_clock = limit->find_pll(limit, crtc,
+                                                   dev_priv->lvds_downclock,
+                                                   refclk,
+                                                   &reduced_clock);
+               if (has_reduced_clock && (clock.p != reduced_clock.p)) {
+                       /*
+                        * If the different P is found, it means that we can't
+                        * switch the display clock by using the FP0/FP1.
+                        * In such case we will disable the LVDS downclock
+                        * feature.
+                        */
+                       DRM_DEBUG_KMS("Different P is found for "
+                                     "LVDS clock/downclock\n");
+                       has_reduced_clock = 0;
+               }
+       }
+       /* SDVO TV has fixed PLL values depend on its clock range,
+          this mirrors vbios setting. */
+       if (is_sdvo && is_tv) {
+               if (adjusted_mode->clock >= 100000
+                   && adjusted_mode->clock < 140500) {
+                       clock.p1 = 2;
+                       clock.p2 = 10;
+                       clock.n = 3;
+                       clock.m1 = 16;
+                       clock.m2 = 8;
+               } else if (adjusted_mode->clock >= 140500
+                          && adjusted_mode->clock <= 200000) {
+                       clock.p1 = 1;
+                       clock.p2 = 10;
+                       clock.n = 6;
+                       clock.m1 = 12;
+                       clock.m2 = 8;
+               }
+       }
+
+       /* FDI link */
+       pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+       lane = 0;
+       /* CPU eDP doesn't require FDI link, so just set DP M/N
+          according to current link config */
+       if (has_edp_encoder &&
+           !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+               target_clock = mode->clock;
+               intel_edp_link_config(has_edp_encoder,
+                                     &lane, &link_bw);
+       } else {
+               /* [e]DP over FDI requires target mode clock
+                  instead of link clock */
+               if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+                       target_clock = mode->clock;
+               else
+                       target_clock = adjusted_mode->clock;
+
+               /* FDI is a binary signal running at ~2.7GHz, encoding
+                * each output octet as 10 bits. The actual frequency
+                * is stored as a divider into a 100MHz clock, and the
+                * mode pixel clock is stored in units of 1KHz.
+                * Hence the bw of each lane in terms of the mode signal
+                * is:
+                */
+               link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
+       }
+
+       /* determine panel color depth */
+       temp = I915_READ(PIPECONF(pipe));
+       temp &= ~PIPE_BPC_MASK;
+       if (is_lvds) {
+               /* the BPC will be 6 if it is 18-bit LVDS panel */
+               if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+                       temp |= PIPE_8BPC;
+               else
+                       temp |= PIPE_6BPC;
+       } else if (has_edp_encoder) {
+               switch (dev_priv->edp.bpp/3) {
+               case 8:
+                       temp |= PIPE_8BPC;
+                       break;
+               case 10:
+                       temp |= PIPE_10BPC;
+                       break;
+               case 6:
+                       temp |= PIPE_6BPC;
+                       break;
+               case 12:
+                       temp |= PIPE_12BPC;
+                       break;
+               }
+       } else
+               temp |= PIPE_8BPC;
+       I915_WRITE(PIPECONF(pipe), temp);
+
+       switch (temp & PIPE_BPC_MASK) {
+       case PIPE_8BPC:
+               bpp = 24;
+               break;
+       case PIPE_10BPC:
+               bpp = 30;
+               break;
+       case PIPE_6BPC:
+               bpp = 18;
+               break;
+       case PIPE_12BPC:
+               bpp = 36;
+               break;
+       default:
+               DRM_ERROR("unknown pipe bpc value\n");
+               bpp = 24;
+       }
+
+       if (!lane) {
+               /*
+                * Account for spread spectrum to avoid
+                * oversubscribing the link. Max center spread
+                * is 2.5%; use 5% for safety's sake.
+                */
+               u32 bps = target_clock * bpp * 21 / 20;
+               lane = bps / (link_bw * 8) + 1;
+       }
+
+       intel_crtc->fdi_lanes = lane;
+
+       if (pixel_multiplier > 1)
+               link_bw *= pixel_multiplier;
+       ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
+
+       /* Ironlake: try to setup display ref clock before DPLL
+        * enabling. This is only under driver's control after
+        * PCH B stepping, previous chipset stepping should be
+        * ignoring this setting.
+        */
+       temp = I915_READ(PCH_DREF_CONTROL);
+       /* Always enable nonspread source */
+       temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+       temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+       temp &= ~DREF_SSC_SOURCE_MASK;
+       temp |= DREF_SSC_SOURCE_ENABLE;
+       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+       POSTING_READ(PCH_DREF_CONTROL);
+       udelay(200);
+
+       if (has_edp_encoder) {
+               if (intel_panel_use_ssc(dev_priv)) {
+                       temp |= DREF_SSC1_ENABLE;
+                       I915_WRITE(PCH_DREF_CONTROL, temp);
+
+                       POSTING_READ(PCH_DREF_CONTROL);
+                       udelay(200);
+               }
+               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+               /* Enable CPU source on CPU attached eDP */
+               if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+                       if (intel_panel_use_ssc(dev_priv))
+                               temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       else
+                               temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+               } else {
+                       /* Enable SSC on PCH eDP if needed */
+                       if (intel_panel_use_ssc(dev_priv)) {
+                               DRM_ERROR("enabling SSC on PCH\n");
+                               temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+                       }
+               }
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+       }
+
+       fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
+       if (has_reduced_clock)
+               fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
+                       reduced_clock.m2;
+
+       /* Enable autotuning of the PLL clock (if permissible) */
+       factor = 21;
+       if (is_lvds) {
+               if ((intel_panel_use_ssc(dev_priv) &&
+                    dev_priv->lvds_ssc_freq == 100) ||
+                   (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
+                       factor = 25;
+       } else if (is_sdvo && is_tv)
+               factor = 20;
+
+       if (clock.m1 < factor * clock.n)
+               fp |= FP_CB_TUNE;
+
+       dpll = 0;
+
+       if (is_lvds)
+               dpll |= DPLLB_MODE_LVDS;
+       else
+               dpll |= DPLLB_MODE_DAC_SERIAL;
+       if (is_sdvo) {
+               int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+               if (pixel_multiplier > 1) {
+                       dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+               }
+               dpll |= DPLL_DVO_HIGH_SPEED;
+       }
+       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+               dpll |= DPLL_DVO_HIGH_SPEED;
+
+       /* compute bitmask from p1 value */
+       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+       /* also FPA1 */
+       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+
+       switch (clock.p2) {
+       case 5:
+               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+               break;
+       case 7:
+               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+               break;
+       case 10:
+               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+               break;
+       case 14:
+               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+               break;
+       }
+
+       if (is_sdvo && is_tv)
+               dpll |= PLL_REF_INPUT_TVCLKINBC;
+       else if (is_tv)
+               /* XXX: just matching BIOS for now */
+               /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
+               dpll |= 3;
+       else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+       else
+               dpll |= PLL_REF_INPUT_DREFCLK;
+
+       /* setup pipeconf */
+       pipeconf = I915_READ(PIPECONF(pipe));
+
+       /* Set up the display plane register */
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+       drm_mode_debug_printmodeline(mode);
+
+       /* PCH eDP needs FDI, but CPU eDP does not */
+       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+               I915_WRITE(PCH_FP0(pipe), fp);
+               I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
+
+               POSTING_READ(PCH_DPLL(pipe));
+               udelay(150);
+       }
+
+       /* enable transcoder DPLL */
+       if (HAS_PCH_CPT(dev)) {
+               temp = I915_READ(PCH_DPLL_SEL);
+               switch (pipe) {
+               case 0:
+                       temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
+                       break;
+               case 1:
+                       temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
+                       break;
+               case 2:
+                       /* FIXME: manage transcoder PLLs? */
+                       temp |= TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL;
+                       break;
+               default:
+                       BUG();
+               }
+               I915_WRITE(PCH_DPLL_SEL, temp);
+
+               POSTING_READ(PCH_DPLL_SEL);
+               udelay(150);
+       }
+
+       /* The LVDS pin pair needs to be on before the DPLLs are enabled.
+        * This is an exception to the general rule that mode_set doesn't turn
+        * things on.
+        */
+       if (is_lvds) {
+               temp = I915_READ(PCH_LVDS);
+               temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+               if (pipe == 1) {
+                       if (HAS_PCH_CPT(dev))
+                               temp |= PORT_TRANS_B_SEL_CPT;
+                       else
+                               temp |= LVDS_PIPEB_SELECT;
+               } else {
+                       if (HAS_PCH_CPT(dev))
+                               temp &= ~PORT_TRANS_SEL_MASK;
+                       else
+                               temp &= ~LVDS_PIPEB_SELECT;
+               }
+               /* set the corresponsding LVDS_BORDER bit */
+               temp |= dev_priv->lvds_border_bits;
+               /* Set the B0-B3 data pairs corresponding to whether we're going to
+                * set the DPLLs for dual-channel mode or not.
+                */
+               if (clock.p2 == 7)
+                       temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+               else
+                       temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+
+               /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
+                * appropriately here, but we need to look more thoroughly into how
+                * panels behave in the two modes.
+                */
+               if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+                       lvds_sync |= LVDS_HSYNC_POLARITY;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+                       lvds_sync |= LVDS_VSYNC_POLARITY;
+               if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY))
+                   != lvds_sync) {
+                       char flags[2] = "-+";
+                       DRM_INFO("Changing LVDS panel from "
+                                "(%chsync, %cvsync) to (%chsync, %cvsync)\n",
+                                flags[!(temp & LVDS_HSYNC_POLARITY)],
+                                flags[!(temp & LVDS_VSYNC_POLARITY)],
+                                flags[!(lvds_sync & LVDS_HSYNC_POLARITY)],
+                                flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]);
+                       temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
+                       temp |= lvds_sync;
+               }
+               I915_WRITE(PCH_LVDS, temp);
+       }
+
+       /* set the dithering flag and clear for anything other than a panel. */
+       pipeconf &= ~PIPECONF_DITHER_EN;
+       pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+       if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
+               pipeconf |= PIPECONF_DITHER_EN;
+               pipeconf |= PIPECONF_DITHER_TYPE_ST1;
+       }
+
+       if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+               intel_dp_set_m_n(crtc, mode, adjusted_mode);
+       } else {
+               /* For non-DP output, clear any trans DP clock recovery setting.*/
                I915_WRITE(TRANSDATA_M1(pipe), 0);
                I915_WRITE(TRANSDATA_N1(pipe), 0);
                I915_WRITE(TRANSDPLINK_M1(pipe), 0);
                I915_WRITE(TRANSDPLINK_N1(pipe), 0);
        }
 
-       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-               I915_WRITE(dpll_reg, dpll);
+       if (!has_edp_encoder ||
+           intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+               I915_WRITE(PCH_DPLL(pipe), dpll);
 
                /* Wait for the clocks to stabilize. */
-               POSTING_READ(dpll_reg);
+               POSTING_READ(PCH_DPLL(pipe));
                udelay(150);
 
-               if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
-                       temp = 0;
-                       if (is_sdvo) {
-                               temp = intel_mode_get_pixel_multiplier(adjusted_mode);
-                               if (temp > 1)
-                                       temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-                               else
-                                       temp = 0;
-                       }
-                       I915_WRITE(DPLL_MD(pipe), temp);
-               } else {
-                       /* The pixel multiplier can only be updated once the
-                        * DPLL is enabled and the clocks are stable.
-                        *
-                        * So write it again.
-                        */
-                       I915_WRITE(dpll_reg, dpll);
-               }
+               /* The pixel multiplier can only be updated once the
+                * DPLL is enabled and the clocks are stable.
+                *
+                * So write it again.
+                */
+               I915_WRITE(PCH_DPLL(pipe), dpll);
        }
 
        intel_crtc->lowfreq_avail = false;
        if (is_lvds && has_reduced_clock && i915_powersave) {
-               I915_WRITE(fp_reg + 4, fp2);
+               I915_WRITE(PCH_FP1(pipe), fp2);
                intel_crtc->lowfreq_avail = true;
                if (HAS_PIPE_CXSR(dev)) {
                        DRM_DEBUG_KMS("enabling CxSR downclocking\n");
                        pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
                }
        } else {
-               I915_WRITE(fp_reg + 4, fp);
+               I915_WRITE(PCH_FP1(pipe), fp);
                if (HAS_PIPE_CXSR(dev)) {
                        DRM_DEBUG_KMS("disabling CxSR downclocking\n");
                        pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -5116,33 +5236,24 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                   (adjusted_mode->crtc_vsync_start - 1) |
                   ((adjusted_mode->crtc_vsync_end - 1) << 16));
 
-       /* pipesrc and dspsize control the size that is scaled from,
-        * which should always be the user's requested size.
+       /* pipesrc controls the size that is scaled from, which should
+        * always be the user's requested size.
         */
-       if (!HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(DSPSIZE(plane),
-                          ((mode->vdisplay - 1) << 16) |
-                          (mode->hdisplay - 1));
-               I915_WRITE(DSPPOS(plane), 0);
-       }
        I915_WRITE(PIPESRC(pipe),
                   ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
-       if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
-               I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
-               I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
-               I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
+       I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+       I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
+       I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
+       I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
 
-               if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                       ironlake_set_pll_edp(crtc, adjusted_mode->clock);
-               }
+       if (has_edp_encoder &&
+           !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+               ironlake_set_pll_edp(crtc, adjusted_mode->clock);
        }
 
        I915_WRITE(PIPECONF(pipe), pipeconf);
        POSTING_READ(PIPECONF(pipe));
-       if (!HAS_PCH_SPLIT(dev))
-               intel_enable_pipe(dev_priv, pipe, false);
 
        intel_wait_for_vblank(dev, pipe);
 
@@ -5161,6 +5272,26 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        intel_update_watermarks(dev);
 
+       return ret;
+}
+
+static int intel_crtc_mode_set(struct drm_crtc *crtc,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode,
+                              int x, int y,
+                              struct drm_framebuffer *old_fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       int ret;
+
+       drm_vblank_pre_modeset(dev, pipe);
+
+       ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
+                                             x, y, old_fb);
+
        drm_vblank_post_modeset(dev, pipe);
 
        return ret;
@@ -5483,43 +5614,140 @@ static struct drm_display_mode load_detect_mode = {
                 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
 };
 
-struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                           struct drm_connector *connector,
-                                           struct drm_display_mode *mode,
-                                           int *dpms_mode)
+static struct drm_framebuffer *
+intel_framebuffer_create(struct drm_device *dev,
+                        struct drm_mode_fb_cmd *mode_cmd,
+                        struct drm_i915_gem_object *obj)
+{
+       struct intel_framebuffer *intel_fb;
+       int ret;
+
+       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+       if (!intel_fb) {
+               drm_gem_object_unreference_unlocked(&obj->base);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(&obj->base);
+               kfree(intel_fb);
+               return ERR_PTR(ret);
+       }
+
+       return &intel_fb->base;
+}
+
+static u32
+intel_framebuffer_pitch_for_width(int width, int bpp)
+{
+       u32 pitch = DIV_ROUND_UP(width * bpp, 8);
+       return ALIGN(pitch, 64);
+}
+
+static u32
+intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp)
+{
+       u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp);
+       return ALIGN(pitch * mode->vdisplay, PAGE_SIZE);
+}
+
+static struct drm_framebuffer *
+intel_framebuffer_create_for_mode(struct drm_device *dev,
+                                 struct drm_display_mode *mode,
+                                 int depth, int bpp)
+{
+       struct drm_i915_gem_object *obj;
+       struct drm_mode_fb_cmd mode_cmd;
+
+       obj = i915_gem_alloc_object(dev,
+                                   intel_framebuffer_size_for_mode(mode, bpp));
+       if (obj == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       mode_cmd.width = mode->hdisplay;
+       mode_cmd.height = mode->vdisplay;
+       mode_cmd.depth = depth;
+       mode_cmd.bpp = bpp;
+       mode_cmd.pitch = intel_framebuffer_pitch_for_width(mode_cmd.width, bpp);
+
+       return intel_framebuffer_create(dev, &mode_cmd, obj);
+}
+
+static struct drm_framebuffer *
+mode_fits_in_fbdev(struct drm_device *dev,
+                  struct drm_display_mode *mode)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_gem_object *obj;
+       struct drm_framebuffer *fb;
+
+       if (dev_priv->fbdev == NULL)
+               return NULL;
+
+       obj = dev_priv->fbdev->ifb.obj;
+       if (obj == NULL)
+               return NULL;
+
+       fb = &dev_priv->fbdev->ifb.base;
+       if (fb->pitch < intel_framebuffer_pitch_for_width(mode->hdisplay,
+                                                         fb->bits_per_pixel))
+               return NULL;
+
+       if (obj->base.size < mode->vdisplay * fb->pitch)
+               return NULL;
+
+       return fb;
+}
+
+bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+                               struct drm_connector *connector,
+                               struct drm_display_mode *mode,
+                               struct intel_load_detect_pipe *old)
 {
        struct intel_crtc *intel_crtc;
        struct drm_crtc *possible_crtc;
-       struct drm_crtc *supported_crtc =NULL;
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = NULL;
        struct drm_device *dev = encoder->dev;
-       struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
-       struct drm_crtc_helper_funcs *crtc_funcs;
+       struct drm_framebuffer *old_fb;
        int i = -1;
 
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector),
+                     encoder->base.id, drm_get_encoder_name(encoder));
+
        /*
         * Algorithm gets a little messy:
+        *
         *   - if the connector already has an assigned crtc, use it (but make
         *     sure it's on first)
+        *
         *   - try to find the first unused crtc that can drive this connector,
         *     and use that if we find one
-        *   - if there are no unused crtcs available, try to use the first
-        *     one we found that supports the connector
         */
 
        /* See if we already have a CRTC for this connector */
        if (encoder->crtc) {
                crtc = encoder->crtc;
-               /* Make sure the crtc and connector are running */
+
                intel_crtc = to_intel_crtc(crtc);
-               *dpms_mode = intel_crtc->dpms_mode;
+               old->dpms_mode = intel_crtc->dpms_mode;
+               old->load_detect_temp = false;
+
+               /* Make sure the crtc and connector are running */
                if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
+                       struct drm_encoder_helper_funcs *encoder_funcs;
+                       struct drm_crtc_helper_funcs *crtc_funcs;
+
                        crtc_funcs = crtc->helper_private;
                        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+
+                       encoder_funcs = encoder->helper_private;
                        encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
                }
-               return crtc;
+
+               return true;
        }
 
        /* Find an unused one (if possible) */
@@ -5531,46 +5759,66 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
                        crtc = possible_crtc;
                        break;
                }
-               if (!supported_crtc)
-                       supported_crtc = possible_crtc;
        }
 
        /*
         * If we didn't find an unused CRTC, don't use any.
         */
        if (!crtc) {
-               return NULL;
+               DRM_DEBUG_KMS("no pipe available for load-detect\n");
+               return false;
        }
 
        encoder->crtc = crtc;
        connector->encoder = encoder;
-       intel_encoder->load_detect_temp = true;
 
        intel_crtc = to_intel_crtc(crtc);
-       *dpms_mode = intel_crtc->dpms_mode;
+       old->dpms_mode = intel_crtc->dpms_mode;
+       old->load_detect_temp = true;
+       old->release_fb = NULL;
 
-       if (!crtc->enabled) {
-               if (!mode)
-                       mode = &load_detect_mode;
-               drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb);
-       } else {
-               if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
-                       crtc_funcs = crtc->helper_private;
-                       crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
-               }
+       if (!mode)
+               mode = &load_detect_mode;
 
-               /* Add this connector to the crtc */
-               encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode);
-               encoder_funcs->commit(encoder);
+       old_fb = crtc->fb;
+
+       /* We need a framebuffer large enough to accommodate all accesses
+        * that the plane may generate whilst we perform load detection.
+        * We can not rely on the fbcon either being present (we get called
+        * during its initialisation to detect all boot displays, or it may
+        * not even exist) or that it is large enough to satisfy the
+        * requested mode.
+        */
+       crtc->fb = mode_fits_in_fbdev(dev, mode);
+       if (crtc->fb == NULL) {
+               DRM_DEBUG_KMS("creating tmp fb for load-detection\n");
+               crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
+               old->release_fb = crtc->fb;
+       } else
+               DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
+       if (IS_ERR(crtc->fb)) {
+               DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
+               crtc->fb = old_fb;
+               return false;
        }
+
+       if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) {
+               DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
+               if (old->release_fb)
+                       old->release_fb->funcs->destroy(old->release_fb);
+               crtc->fb = old_fb;
+               return false;
+       }
+
        /* let the connector get through one full cycle before testing */
        intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-       return crtc;
+       return true;
 }
 
 void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                   struct drm_connector *connector, int dpms_mode)
+                                   struct drm_connector *connector,
+                                   struct intel_load_detect_pipe *old)
 {
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_device *dev = encoder->dev;
@@ -5578,19 +5826,24 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
        struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
 
-       if (intel_encoder->load_detect_temp) {
-               encoder->crtc = NULL;
+       DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+                     connector->base.id, drm_get_connector_name(connector),
+                     encoder->base.id, drm_get_encoder_name(encoder));
+
+       if (old->load_detect_temp) {
                connector->encoder = NULL;
-               intel_encoder->load_detect_temp = false;
-               crtc->enabled = drm_helper_crtc_in_use(crtc);
                drm_helper_disable_unused_functions(dev);
+
+               if (old->release_fb)
+                       old->release_fb->funcs->destroy(old->release_fb);
+
+               return;
        }
 
        /* Switch crtc and encoder back off if necessary */
-       if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) {
-               if (encoder->crtc == crtc)
-                       encoder_funcs->dpms(encoder, dpms_mode);
-               crtc_funcs->dpms(crtc, dpms_mode);
+       if (old->dpms_mode != DRM_MODE_DPMS_ON) {
+               encoder_funcs->dpms(encoder, old->dpms_mode);
+               crtc_funcs->dpms(crtc, old->dpms_mode);
        }
 }
 
@@ -6185,6 +6438,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                break;
 
        case 6:
+       case 7:
                OUT_RING(MI_DISPLAY_FLIP |
                         MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
                OUT_RING(fb->pitch | obj->tiling_mode);
@@ -6504,6 +6758,9 @@ static void intel_setup_outputs(struct drm_device *dev)
        }
 
        intel_panel_setup_backlight(dev);
+
+       /* disable all the possible outputs/crtcs before entering KMS mode */
+       drm_helper_disable_unused_functions(dev);
 }
 
 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
@@ -6571,27 +6828,12 @@ intel_user_framebuffer_create(struct drm_device *dev,
                              struct drm_mode_fb_cmd *mode_cmd)
 {
        struct drm_i915_gem_object *obj;
-       struct intel_framebuffer *intel_fb;
-       int ret;
 
        obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle));
        if (&obj->base == NULL)
                return ERR_PTR(-ENOENT);
 
-       intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
-       if (!intel_fb) {
-               drm_gem_object_unreference_unlocked(&obj->base);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
-       if (ret) {
-               drm_gem_object_unreference_unlocked(&obj->base);
-               kfree(intel_fb);
-               return ERR_PTR(ret);
-       }
-
-       return &intel_fb->base;
+       return intel_framebuffer_create(dev, mode_cmd, obj);
 }
 
 static const struct drm_mode_config_funcs intel_mode_funcs = {
@@ -6605,13 +6847,14 @@ intel_alloc_context_page(struct drm_device *dev)
        struct drm_i915_gem_object *ctx;
        int ret;
 
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
        ctx = i915_gem_alloc_object(dev, 4096);
        if (!ctx) {
                DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
                return NULL;
        }
 
-       mutex_lock(&dev->struct_mutex);
        ret = i915_gem_object_pin(ctx, 4096, true);
        if (ret) {
                DRM_ERROR("failed to pin power context: %d\n", ret);
@@ -6623,7 +6866,6 @@ intel_alloc_context_page(struct drm_device *dev)
                DRM_ERROR("failed to set-domain on power context: %d\n", ret);
                goto err_unpin;
        }
-       mutex_unlock(&dev->struct_mutex);
 
        return ctx;
 
@@ -6758,6 +7000,11 @@ void gen6_disable_rps(struct drm_device *dev)
        I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
        I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
        I915_WRITE(GEN6_PMIER, 0);
+
+       spin_lock_irq(&dev_priv->rps_lock);
+       dev_priv->pm_iir = 0;
+       spin_unlock_irq(&dev_priv->rps_lock);
+
        I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
 }
 
@@ -6851,7 +7098,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
 {
        u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
        u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
-       u32 pcu_mbox;
+       u32 pcu_mbox, rc6_mask = 0;
        int cur_freq, min_freq, max_freq;
        int i;
 
@@ -6862,7 +7109,8 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
         * userspace...
         */
        I915_WRITE(GEN6_RC_STATE, 0);
-       __gen6_gt_force_wake_get(dev_priv);
+       mutex_lock(&dev_priv->dev->struct_mutex);
+       gen6_gt_force_wake_get(dev_priv);
 
        /* disable the counters and set deterministic thresholds */
        I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -6882,9 +7130,12 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
        I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
        I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
 
+       if (i915_enable_rc6)
+               rc6_mask = GEN6_RC_CTL_RC6p_ENABLE |
+                       GEN6_RC_CTL_RC6_ENABLE;
+
        I915_WRITE(GEN6_RC_CONTROL,
-                  GEN6_RC_CTL_RC6p_ENABLE |
-                  GEN6_RC_CTL_RC6_ENABLE |
+                  rc6_mask |
                   GEN6_RC_CTL_EI_MODE(1) |
                   GEN6_RC_CTL_HW_ENABLE);
 
@@ -6956,168 +7207,237 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
                   GEN6_PM_RP_DOWN_THRESHOLD |
                   GEN6_PM_RP_UP_EI_EXPIRED |
                   GEN6_PM_RP_DOWN_EI_EXPIRED);
+       spin_lock_irq(&dev_priv->rps_lock);
+       WARN_ON(dev_priv->pm_iir != 0);
        I915_WRITE(GEN6_PMIMR, 0);
+       spin_unlock_irq(&dev_priv->rps_lock);
        /* enable all PM interrupts */
        I915_WRITE(GEN6_PMINTRMSK, 0);
 
-       __gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv);
+       mutex_unlock(&dev_priv->dev->struct_mutex);
+}
+
+static void ironlake_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+       /* Required for FBC */
+       dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
+               DPFCRUNIT_CLOCK_GATE_DISABLE |
+               DPFDUNIT_CLOCK_GATE_DISABLE;
+       /* Required for CxSR */
+       dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
+
+       I915_WRITE(PCH_3DCGDIS0,
+                  MARIUNIT_CLOCK_GATE_DISABLE |
+                  SVSMUNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(PCH_3DCGDIS1,
+                  VFMUNIT_CLOCK_GATE_DISABLE);
+
+       I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+       /*
+        * According to the spec the following bits should be set in
+        * order to enable memory self-refresh
+        * The bit 22/21 of 0x42004
+        * The bit 5 of 0x42020
+        * The bit 15 of 0x45000
+        */
+       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                  (I915_READ(ILK_DISPLAY_CHICKEN2) |
+                   ILK_DPARB_GATE | ILK_VSDPFD_FULL));
+       I915_WRITE(ILK_DSPCLK_GATE,
+                  (I915_READ(ILK_DSPCLK_GATE) |
+                   ILK_DPARB_CLK_GATE));
+       I915_WRITE(DISP_ARB_CTL,
+                  (I915_READ(DISP_ARB_CTL) |
+                   DISP_FBC_WM_DIS));
+       I915_WRITE(WM3_LP_ILK, 0);
+       I915_WRITE(WM2_LP_ILK, 0);
+       I915_WRITE(WM1_LP_ILK, 0);
+
+       /*
+        * Based on the document from hardware guys the following bits
+        * should be set unconditionally in order to enable FBC.
+        * The bit 22 of 0x42000
+        * The bit 22 of 0x42004
+        * The bit 7,8,9 of 0x42020.
+        */
+       if (IS_IRONLAKE_M(dev)) {
+               I915_WRITE(ILK_DISPLAY_CHICKEN1,
+                          I915_READ(ILK_DISPLAY_CHICKEN1) |
+                          ILK_FBCQ_DIS);
+               I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                          I915_READ(ILK_DISPLAY_CHICKEN2) |
+                          ILK_DPARB_GATE);
+               I915_WRITE(ILK_DSPCLK_GATE,
+                          I915_READ(ILK_DSPCLK_GATE) |
+                          ILK_DPFC_DIS1 |
+                          ILK_DPFC_DIS2 |
+                          ILK_CLK_FBC);
+       }
+
+       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                  I915_READ(ILK_DISPLAY_CHICKEN2) |
+                  ILK_ELPIN_409_SELECT);
+       I915_WRITE(_3D_CHICKEN2,
+                  _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
+                  _3D_CHICKEN2_WM_READ_PIPELINED);
 }
 
-void intel_enable_clock_gating(struct drm_device *dev)
+static void gen6_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
+       uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+       I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                  I915_READ(ILK_DISPLAY_CHICKEN2) |
+                  ILK_ELPIN_409_SELECT);
+
+       I915_WRITE(WM3_LP_ILK, 0);
+       I915_WRITE(WM2_LP_ILK, 0);
+       I915_WRITE(WM1_LP_ILK, 0);
 
        /*
-        * Disable clock gating reported to work incorrectly according to the
-        * specs, but enable as much else as we can.
+        * According to the spec the following bits should be
+        * set in order to enable memory self-refresh and fbc:
+        * The bit21 and bit22 of 0x42000
+        * The bit21 and bit22 of 0x42004
+        * The bit5 and bit7 of 0x42020
+        * The bit14 of 0x70180
+        * The bit14 of 0x71180
         */
-       if (HAS_PCH_SPLIT(dev)) {
-               uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(ILK_DISPLAY_CHICKEN1,
+                  I915_READ(ILK_DISPLAY_CHICKEN1) |
+                  ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
+       I915_WRITE(ILK_DISPLAY_CHICKEN2,
+                  I915_READ(ILK_DISPLAY_CHICKEN2) |
+                  ILK_DPARB_GATE | ILK_VSDPFD_FULL);
+       I915_WRITE(ILK_DSPCLK_GATE,
+                  I915_READ(ILK_DSPCLK_GATE) |
+                  ILK_DPARB_CLK_GATE  |
+                  ILK_DPFD_CLK_GATE);
 
-               if (IS_GEN5(dev)) {
-                       /* Required for FBC */
-                       dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
-                               DPFCRUNIT_CLOCK_GATE_DISABLE |
-                               DPFDUNIT_CLOCK_GATE_DISABLE;
-                       /* Required for CxSR */
-                       dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
-
-                       I915_WRITE(PCH_3DCGDIS0,
-                                  MARIUNIT_CLOCK_GATE_DISABLE |
-                                  SVSMUNIT_CLOCK_GATE_DISABLE);
-                       I915_WRITE(PCH_3DCGDIS1,
-                                  VFMUNIT_CLOCK_GATE_DISABLE);
-               }
+       for_each_pipe(pipe)
+               I915_WRITE(DSPCNTR(pipe),
+                          I915_READ(DSPCNTR(pipe)) |
+                          DISPPLANE_TRICKLE_FEED_DISABLE);
+}
 
-               I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+static void ivybridge_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int pipe;
+       uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
 
-               /*
-                * On Ibex Peak and Cougar Point, we need to disable clock
-                * gating for the panel power sequencer or it will fail to
-                * start up when no ports are active.
-                */
-               I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
 
-               /*
-                * According to the spec the following bits should be set in
-                * order to enable memory self-refresh
-                * The bit 22/21 of 0x42004
-                * The bit 5 of 0x42020
-                * The bit 15 of 0x45000
-                */
-               if (IS_GEN5(dev)) {
-                       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                                       (I915_READ(ILK_DISPLAY_CHICKEN2) |
-                                       ILK_DPARB_GATE | ILK_VSDPFD_FULL));
-                       I915_WRITE(ILK_DSPCLK_GATE,
-                                       (I915_READ(ILK_DSPCLK_GATE) |
-                                               ILK_DPARB_CLK_GATE));
-                       I915_WRITE(DISP_ARB_CTL,
-                                       (I915_READ(DISP_ARB_CTL) |
-                                               DISP_FBC_WM_DIS));
-                       I915_WRITE(WM3_LP_ILK, 0);
-                       I915_WRITE(WM2_LP_ILK, 0);
-                       I915_WRITE(WM1_LP_ILK, 0);
-               }
-               /*
-                * Based on the document from hardware guys the following bits
-                * should be set unconditionally in order to enable FBC.
-                * The bit 22 of 0x42000
-                * The bit 22 of 0x42004
-                * The bit 7,8,9 of 0x42020.
-                */
-               if (IS_IRONLAKE_M(dev)) {
-                       I915_WRITE(ILK_DISPLAY_CHICKEN1,
-                                  I915_READ(ILK_DISPLAY_CHICKEN1) |
-                                  ILK_FBCQ_DIS);
-                       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                                  I915_READ(ILK_DISPLAY_CHICKEN2) |
-                                  ILK_DPARB_GATE);
-                       I915_WRITE(ILK_DSPCLK_GATE,
-                                  I915_READ(ILK_DSPCLK_GATE) |
-                                  ILK_DPFC_DIS1 |
-                                  ILK_DPFC_DIS2 |
-                                  ILK_CLK_FBC);
-               }
+       I915_WRITE(WM3_LP_ILK, 0);
+       I915_WRITE(WM2_LP_ILK, 0);
+       I915_WRITE(WM1_LP_ILK, 0);
 
-               I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                          I915_READ(ILK_DISPLAY_CHICKEN2) |
-                          ILK_ELPIN_409_SELECT);
+       I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
 
-               if (IS_GEN5(dev)) {
-                       I915_WRITE(_3D_CHICKEN2,
-                                  _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
-                                  _3D_CHICKEN2_WM_READ_PIPELINED);
-               }
+       for_each_pipe(pipe)
+               I915_WRITE(DSPCNTR(pipe),
+                          I915_READ(DSPCNTR(pipe)) |
+                          DISPPLANE_TRICKLE_FEED_DISABLE);
+}
+
+static void g4x_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dspclk_gate;
 
-               if (IS_GEN6(dev)) {
-                       I915_WRITE(WM3_LP_ILK, 0);
-                       I915_WRITE(WM2_LP_ILK, 0);
-                       I915_WRITE(WM1_LP_ILK, 0);
+       I915_WRITE(RENCLK_GATE_D1, 0);
+       I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
+                  GS_UNIT_CLOCK_GATE_DISABLE |
+                  CL_UNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(RAMCLK_GATE_D, 0);
+       dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
+               OVRUNIT_CLOCK_GATE_DISABLE |
+               OVCUNIT_CLOCK_GATE_DISABLE;
+       if (IS_GM45(dev))
+               dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
+       I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
+}
 
-                       /*
-                        * According to the spec the following bits should be
-                        * set in order to enable memory self-refresh and fbc:
-                        * The bit21 and bit22 of 0x42000
-                        * The bit21 and bit22 of 0x42004
-                        * The bit5 and bit7 of 0x42020
-                        * The bit14 of 0x70180
-                        * The bit14 of 0x71180
-                        */
-                       I915_WRITE(ILK_DISPLAY_CHICKEN1,
-                                  I915_READ(ILK_DISPLAY_CHICKEN1) |
-                                  ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
-                       I915_WRITE(ILK_DISPLAY_CHICKEN2,
-                                  I915_READ(ILK_DISPLAY_CHICKEN2) |
-                                  ILK_DPARB_GATE | ILK_VSDPFD_FULL);
-                       I915_WRITE(ILK_DSPCLK_GATE,
-                                  I915_READ(ILK_DSPCLK_GATE) |
-                                  ILK_DPARB_CLK_GATE  |
-                                  ILK_DPFD_CLK_GATE);
-
-                       for_each_pipe(pipe)
-                               I915_WRITE(DSPCNTR(pipe),
-                                          I915_READ(DSPCNTR(pipe)) |
-                                          DISPPLANE_TRICKLE_FEED_DISABLE);
-               }
-       } else if (IS_G4X(dev)) {
-               uint32_t dspclk_gate;
-               I915_WRITE(RENCLK_GATE_D1, 0);
-               I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
-                      GS_UNIT_CLOCK_GATE_DISABLE |
-                      CL_UNIT_CLOCK_GATE_DISABLE);
-               I915_WRITE(RAMCLK_GATE_D, 0);
-               dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
-                       OVRUNIT_CLOCK_GATE_DISABLE |
-                       OVCUNIT_CLOCK_GATE_DISABLE;
-               if (IS_GM45(dev))
-                       dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
-               I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
-       } else if (IS_CRESTLINE(dev)) {
-               I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
-               I915_WRITE(RENCLK_GATE_D2, 0);
-               I915_WRITE(DSPCLK_GATE_D, 0);
-               I915_WRITE(RAMCLK_GATE_D, 0);
-               I915_WRITE16(DEUC, 0);
-       } else if (IS_BROADWATER(dev)) {
-               I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
-                      I965_RCC_CLOCK_GATE_DISABLE |
-                      I965_RCPB_CLOCK_GATE_DISABLE |
-                      I965_ISC_CLOCK_GATE_DISABLE |
-                      I965_FBC_CLOCK_GATE_DISABLE);
-               I915_WRITE(RENCLK_GATE_D2, 0);
-       } else if (IS_GEN3(dev)) {
-               u32 dstate = I915_READ(D_STATE);
+static void crestline_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
-               dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
-                       DSTATE_DOT_CLOCK_GATING;
-               I915_WRITE(D_STATE, dstate);
-       } else if (IS_I85X(dev) || IS_I865G(dev)) {
-               I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
-       } else if (IS_I830(dev)) {
-               I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
-       }
+       I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
+       I915_WRITE(RENCLK_GATE_D2, 0);
+       I915_WRITE(DSPCLK_GATE_D, 0);
+       I915_WRITE(RAMCLK_GATE_D, 0);
+       I915_WRITE16(DEUC, 0);
+}
+
+static void broadwater_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
+                  I965_RCC_CLOCK_GATE_DISABLE |
+                  I965_RCPB_CLOCK_GATE_DISABLE |
+                  I965_ISC_CLOCK_GATE_DISABLE |
+                  I965_FBC_CLOCK_GATE_DISABLE);
+       I915_WRITE(RENCLK_GATE_D2, 0);
+}
+
+static void gen3_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 dstate = I915_READ(D_STATE);
+
+       dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
+               DSTATE_DOT_CLOCK_GATING;
+       I915_WRITE(D_STATE, dstate);
+}
+
+static void i85x_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
+}
+
+static void i830_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+}
+
+static void ibx_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /*
+        * On Ibex Peak and Cougar Point, we need to disable clock
+        * gating for the panel power sequencer or it will fail to
+        * start up when no ports are active.
+        */
+       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+}
+
+static void cpt_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /*
+        * On Ibex Peak and Cougar Point, we need to disable clock
+        * gating for the panel power sequencer or it will fail to
+        * start up when no ports are active.
+        */
+       I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
+                  DPLS_EDP_PPS_FIX_DIS);
 }
 
 static void ironlake_teardown_rc6(struct drm_device *dev)
@@ -7187,9 +7507,12 @@ void ironlake_enable_rc6(struct drm_device *dev)
        if (!i915_enable_rc6)
                return;
 
+       mutex_lock(&dev->struct_mutex);
        ret = ironlake_setup_rc6(dev);
-       if (ret)
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
                return;
+       }
 
        /*
         * GPU can automatically power down the render unit if given a page
@@ -7198,6 +7521,7 @@ void ironlake_enable_rc6(struct drm_device *dev)
        ret = BEGIN_LP_RING(6);
        if (ret) {
                ironlake_teardown_rc6(dev);
+               mutex_unlock(&dev->struct_mutex);
                return;
        }
 
@@ -7213,10 +7537,33 @@ void ironlake_enable_rc6(struct drm_device *dev)
        OUT_RING(MI_FLUSH);
        ADVANCE_LP_RING();
 
+       /*
+        * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
+        * does an implicit flush, combined with MI_FLUSH above, it should be
+        * safe to assume that renderctx is valid
+        */
+       ret = intel_wait_ring_idle(LP_RING(dev_priv));
+       if (ret) {
+               DRM_ERROR("failed to enable ironlake power power savings\n");
+               ironlake_teardown_rc6(dev);
+               mutex_unlock(&dev->struct_mutex);
+               return;
+       }
+
        I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
        I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+       mutex_unlock(&dev->struct_mutex);
 }
 
+void intel_init_clock_gating(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->display.init_clock_gating(dev);
+
+       if (dev_priv->display.init_pch_clock_gating)
+               dev_priv->display.init_pch_clock_gating(dev);
+}
 
 /* Set up chip specific display functions */
 static void intel_init_display(struct drm_device *dev)
@@ -7224,10 +7571,13 @@ static void intel_init_display(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        /* We always want a DPMS function */
-       if (HAS_PCH_SPLIT(dev))
+       if (HAS_PCH_SPLIT(dev)) {
                dev_priv->display.dpms = ironlake_crtc_dpms;
-       else
+               dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
+       } else {
                dev_priv->display.dpms = i9xx_crtc_dpms;
+               dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
+       }
 
        if (I915_HAS_FBC(dev)) {
                if (HAS_PCH_SPLIT(dev)) {
@@ -7271,6 +7621,11 @@ static void intel_init_display(struct drm_device *dev)
 
        /* For FIFO watermark updates */
        if (HAS_PCH_SPLIT(dev)) {
+               if (HAS_PCH_IBX(dev))
+                       dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
+               else if (HAS_PCH_CPT(dev))
+                       dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating;
+
                if (IS_GEN5(dev)) {
                        if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
                                dev_priv->display.update_wm = ironlake_update_wm;
@@ -7279,6 +7634,8 @@ static void intel_init_display(struct drm_device *dev)
                                              "Disable CxSR\n");
                                dev_priv->display.update_wm = NULL;
                        }
+                       dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
+                       dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
                } else if (IS_GEN6(dev)) {
                        if (SNB_READ_WM0_LATENCY()) {
                                dev_priv->display.update_wm = sandybridge_update_wm;
@@ -7287,6 +7644,20 @@ static void intel_init_display(struct drm_device *dev)
                                              "Disable CxSR\n");
                                dev_priv->display.update_wm = NULL;
                        }
+                       dev_priv->display.fdi_link_train = gen6_fdi_link_train;
+                       dev_priv->display.init_clock_gating = gen6_init_clock_gating;
+               } else if (IS_IVYBRIDGE(dev)) {
+                       /* FIXME: detect B0+ stepping and use auto training */
+                       dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
+                       if (SNB_READ_WM0_LATENCY()) {
+                               dev_priv->display.update_wm = sandybridge_update_wm;
+                       } else {
+                               DRM_DEBUG_KMS("Failed to read display plane latency. "
+                                             "Disable CxSR\n");
+                               dev_priv->display.update_wm = NULL;
+                       }
+                       dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
+
                } else
                        dev_priv->display.update_wm = NULL;
        } else if (IS_PINEVIEW(dev)) {
@@ -7304,18 +7675,30 @@ static void intel_init_display(struct drm_device *dev)
                        dev_priv->display.update_wm = NULL;
                } else
                        dev_priv->display.update_wm = pineview_update_wm;
-       } else if (IS_G4X(dev))
+       } else if (IS_G4X(dev)) {
                dev_priv->display.update_wm = g4x_update_wm;
-       else if (IS_GEN4(dev))
+               dev_priv->display.init_clock_gating = g4x_init_clock_gating;
+       } else if (IS_GEN4(dev)) {
                dev_priv->display.update_wm = i965_update_wm;
-       else if (IS_GEN3(dev)) {
+               if (IS_CRESTLINE(dev))
+                       dev_priv->display.init_clock_gating = crestline_init_clock_gating;
+               else if (IS_BROADWATER(dev))
+                       dev_priv->display.init_clock_gating = broadwater_init_clock_gating;
+       } else if (IS_GEN3(dev)) {
                dev_priv->display.update_wm = i9xx_update_wm;
                dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
+               dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+       } else if (IS_I865G(dev)) {
+               dev_priv->display.update_wm = i830_update_wm;
+               dev_priv->display.init_clock_gating = i85x_init_clock_gating;
+               dev_priv->display.get_fifo_size = i830_get_fifo_size;
        } else if (IS_I85X(dev)) {
                dev_priv->display.update_wm = i9xx_update_wm;
                dev_priv->display.get_fifo_size = i85x_get_fifo_size;
+               dev_priv->display.init_clock_gating = i85x_init_clock_gating;
        } else {
                dev_priv->display.update_wm = i830_update_wm;
+               dev_priv->display.init_clock_gating = i830_init_clock_gating;
                if (IS_845G(dev))
                        dev_priv->display.get_fifo_size = i845_get_fifo_size;
                else
@@ -7441,12 +7824,11 @@ void intel_modeset_init(struct drm_device *dev)
                intel_crtc_init(dev, i);
        }
 
-       intel_setup_outputs(dev);
-
-       intel_enable_clock_gating(dev);
-
        /* Just disable it once at startup */
        i915_disable_vga(dev);
+       intel_setup_outputs(dev);
+
+       intel_init_clock_gating(dev);
 
        if (IS_IRONLAKE_M(dev)) {
                ironlake_enable_drps(dev);
@@ -7456,12 +7838,15 @@ void intel_modeset_init(struct drm_device *dev)
        if (IS_GEN6(dev))
                gen6_enable_rps(dev_priv);
 
-       if (IS_IRONLAKE_M(dev))
-               ironlake_enable_rc6(dev);
-
        INIT_WORK(&dev_priv->idle_work, intel_idle_update);
        setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
                    (unsigned long)dev);
+}
+
+void intel_modeset_gem_init(struct drm_device *dev)
+{
+       if (IS_IRONLAKE_M(dev))
+               ironlake_enable_rc6(dev);
 
        intel_setup_overlay(dev);
 }
index 1d20712d527f1e5d38a192f59f2aa3c6493e5e53..831d7a4a0d18ce4eb52c86c76cacde8ac804f22e 100644 (file)
@@ -140,7 +140,6 @@ struct intel_fbdev {
 struct intel_encoder {
        struct drm_encoder base;
        int type;
-       bool load_detect_temp;
        bool needs_tv_clock;
        void (*hot_plug)(struct intel_encoder *);
        int crtc_mask;
@@ -291,13 +290,19 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
 extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
-                                                  struct drm_connector *connector,
-                                                  struct drm_display_mode *mode,
-                                                  int *dpms_mode);
+
+struct intel_load_detect_pipe {
+       struct drm_framebuffer *release_fb;
+       bool load_detect_temp;
+       int dpms_mode;
+};
+extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+                                      struct drm_connector *connector,
+                                      struct drm_display_mode *mode,
+                                      struct intel_load_detect_pipe *old);
 extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
                                           struct drm_connector *connector,
-                                          int dpms_mode);
+                                          struct intel_load_detect_pipe *old);
 
 extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
 extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
@@ -339,4 +344,6 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data,
 
 extern void intel_fb_output_poll_changed(struct drm_device *dev);
 extern void intel_fb_restore_mode(struct drm_device *dev);
+
+extern void intel_init_clock_gating(struct drm_device *dev);
 #endif /* __INTEL_DRV_H__ */
index e9e6f71418a43122c3545d712c2ea3268861c2c4..95c4b1429935d562a6ee54f464f0bd52ba3ae6ba 100644 (file)
@@ -236,7 +236,7 @@ init_pipe_control(struct intel_ring_buffer *ring)
                ret = -ENOMEM;
                goto err;
        }
-       obj->agp_type = AGP_USER_CACHED_MEMORY;
+       obj->cache_level = I915_CACHE_LLC;
 
        ret = i915_gem_object_pin(obj, 4096, true);
        if (ret)
@@ -286,7 +286,7 @@ static int init_render_ring(struct intel_ring_buffer *ring)
 
        if (INTEL_INFO(dev)->gen > 3) {
                int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
-               if (IS_GEN6(dev))
+               if (IS_GEN6(dev) || IS_GEN7(dev))
                        mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
                I915_WRITE(MI_MODE, mode);
        }
@@ -551,10 +551,31 @@ render_ring_put_irq(struct intel_ring_buffer *ring)
 
 void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
 {
+       struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = ring->dev->dev_private;
-       u32 mmio = IS_GEN6(ring->dev) ?
-               RING_HWS_PGA_GEN6(ring->mmio_base) :
-               RING_HWS_PGA(ring->mmio_base);
+       u32 mmio = 0;
+
+       /* The ring status page addresses are no longer next to the rest of
+        * the ring registers as of gen7.
+        */
+       if (IS_GEN7(dev)) {
+               switch (ring->id) {
+               case RING_RENDER:
+                       mmio = RENDER_HWS_PGA_GEN7;
+                       break;
+               case RING_BLT:
+                       mmio = BLT_HWS_PGA_GEN7;
+                       break;
+               case RING_BSD:
+                       mmio = BSD_HWS_PGA_GEN7;
+                       break;
+               }
+       } else if (IS_GEN6(ring->dev)) {
+               mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
+       } else {
+               mmio = RING_HWS_PGA(ring->mmio_base);
+       }
+
        I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
        POSTING_READ(mmio);
 }
@@ -600,7 +621,7 @@ ring_add_request(struct intel_ring_buffer *ring,
 }
 
 static bool
-ring_get_irq(struct intel_ring_buffer *ring, u32 flag)
+gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -609,71 +630,67 @@ ring_get_irq(struct intel_ring_buffer *ring, u32 flag)
               return false;
 
        spin_lock(&ring->irq_lock);
-       if (ring->irq_refcount++ == 0)
-               ironlake_enable_irq(dev_priv, flag);
+       if (ring->irq_refcount++ == 0) {
+               ring->irq_mask &= ~rflag;
+               I915_WRITE_IMR(ring, ring->irq_mask);
+               ironlake_enable_irq(dev_priv, gflag);
+       }
        spin_unlock(&ring->irq_lock);
 
        return true;
 }
 
 static void
-ring_put_irq(struct intel_ring_buffer *ring, u32 flag)
+gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        spin_lock(&ring->irq_lock);
-       if (--ring->irq_refcount == 0)
-               ironlake_disable_irq(dev_priv, flag);
+       if (--ring->irq_refcount == 0) {
+               ring->irq_mask |= rflag;
+               I915_WRITE_IMR(ring, ring->irq_mask);
+               ironlake_disable_irq(dev_priv, gflag);
+       }
        spin_unlock(&ring->irq_lock);
 }
 
 static bool
-gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+bsd_ring_get_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        if (!dev->irq_enabled)
-              return false;
+               return false;
 
        spin_lock(&ring->irq_lock);
        if (ring->irq_refcount++ == 0) {
-               ring->irq_mask &= ~rflag;
-               I915_WRITE_IMR(ring, ring->irq_mask);
-               ironlake_enable_irq(dev_priv, gflag);
+               if (IS_G4X(dev))
+                       i915_enable_irq(dev_priv, I915_BSD_USER_INTERRUPT);
+               else
+                       ironlake_enable_irq(dev_priv, GT_BSD_USER_INTERRUPT);
        }
        spin_unlock(&ring->irq_lock);
 
        return true;
 }
-
 static void
-gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+bsd_ring_put_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
        spin_lock(&ring->irq_lock);
        if (--ring->irq_refcount == 0) {
-               ring->irq_mask |= rflag;
-               I915_WRITE_IMR(ring, ring->irq_mask);
-               ironlake_disable_irq(dev_priv, gflag);
+               if (IS_G4X(dev))
+                       i915_disable_irq(dev_priv, I915_BSD_USER_INTERRUPT);
+               else
+                       ironlake_disable_irq(dev_priv, GT_BSD_USER_INTERRUPT);
        }
        spin_unlock(&ring->irq_lock);
 }
 
-static bool
-bsd_ring_get_irq(struct intel_ring_buffer *ring)
-{
-       return ring_get_irq(ring, GT_BSD_USER_INTERRUPT);
-}
-static void
-bsd_ring_put_irq(struct intel_ring_buffer *ring)
-{
-       ring_put_irq(ring, GT_BSD_USER_INTERRUPT);
-}
-
 static int
 ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length)
 {
@@ -759,7 +776,7 @@ static int init_status_page(struct intel_ring_buffer *ring)
                ret = -ENOMEM;
                goto err;
        }
-       obj->agp_type = AGP_USER_CACHED_MEMORY;
+       obj->cache_level = I915_CACHE_LLC;
 
        ret = i915_gem_object_pin(obj, 4096, true);
        if (ret != 0) {
@@ -800,6 +817,7 @@ int intel_init_ring_buffer(struct drm_device *dev,
        INIT_LIST_HEAD(&ring->request_list);
        INIT_LIST_HEAD(&ring->gpu_write_list);
 
+       init_waitqueue_head(&ring->irq_queue);
        spin_lock_init(&ring->irq_lock);
        ring->irq_mask = ~0;
 
@@ -872,7 +890,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
 
        /* Disable the ring buffer. The ring must be idle at this point */
        dev_priv = ring->dev->dev_private;
-       ret = intel_wait_ring_buffer(ring, ring->size - 8);
+       ret = intel_wait_ring_idle(ring);
        if (ret)
                DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
                          ring->name, ret);
@@ -1333,7 +1351,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[VCS];
 
-       if (IS_GEN6(dev))
+       if (IS_GEN6(dev) || IS_GEN7(dev))
                *ring = gen6_bsd_ring;
        else
                *ring = bsd_ring;
index f23cc5f037a6cbf62bec342ec1f237de165d9c72..c0e0ee63fbf4fb012b06beac97238d68f0fa3f4d 100644 (file)
@@ -14,27 +14,24 @@ struct  intel_hw_status_page {
        struct          drm_i915_gem_object *obj;
 };
 
-#define I915_RING_READ(reg) i915_gt_read(dev_priv, reg)
-#define I915_RING_WRITE(reg, val) i915_gt_write(dev_priv, reg, val)
+#define I915_READ_TAIL(ring) I915_READ(RING_TAIL((ring)->mmio_base))
+#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val)
 
-#define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL((ring)->mmio_base))
-#define I915_WRITE_TAIL(ring, val) I915_RING_WRITE(RING_TAIL((ring)->mmio_base), val)
+#define I915_READ_START(ring) I915_READ(RING_START((ring)->mmio_base))
+#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val)
 
-#define I915_READ_START(ring) I915_RING_READ(RING_START((ring)->mmio_base))
-#define I915_WRITE_START(ring, val) I915_RING_WRITE(RING_START((ring)->mmio_base), val)
+#define I915_READ_HEAD(ring)  I915_READ(RING_HEAD((ring)->mmio_base))
+#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val)
 
-#define I915_READ_HEAD(ring)  I915_RING_READ(RING_HEAD((ring)->mmio_base))
-#define I915_WRITE_HEAD(ring, val) I915_RING_WRITE(RING_HEAD((ring)->mmio_base), val)
+#define I915_READ_CTL(ring) I915_READ(RING_CTL((ring)->mmio_base))
+#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val)
 
-#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL((ring)->mmio_base))
-#define I915_WRITE_CTL(ring, val) I915_RING_WRITE(RING_CTL((ring)->mmio_base), val)
+#define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base))
+#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
 
-#define I915_READ_IMR(ring) I915_RING_READ(RING_IMR((ring)->mmio_base))
-#define I915_WRITE_IMR(ring, val) I915_RING_WRITE(RING_IMR((ring)->mmio_base), val)
-
-#define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID((ring)->mmio_base))
-#define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0((ring)->mmio_base))
-#define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1((ring)->mmio_base))
+#define I915_READ_NOPID(ring) I915_READ(RING_NOPID((ring)->mmio_base))
+#define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base))
+#define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base))
 
 struct  intel_ring_buffer {
        const char      *name;
@@ -164,7 +161,13 @@ intel_read_status_page(struct intel_ring_buffer *ring,
 #define I915_BREADCRUMB_INDEX          0x21
 
 void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
+
 int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n);
+static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring)
+{
+       return intel_wait_ring_buffer(ring, ring->space - 8);
+}
+
 int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
 
 static inline void intel_ring_emit(struct intel_ring_buffer *ring,
index 4324f33212d639a357520ced14447264d78233e4..754086f83941148027633e001988ebdbef6ecda1 100644 (file)
@@ -2544,21 +2544,19 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
        if (!intel_sdvo)
                return false;
 
+       intel_sdvo->sdvo_reg = sdvo_reg;
+       intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
+       intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
        if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
                kfree(intel_sdvo);
                return false;
        }
 
-       intel_sdvo->sdvo_reg = sdvo_reg;
-
+       /* encoder type will be decided later */
        intel_encoder = &intel_sdvo->base;
        intel_encoder->type = INTEL_OUTPUT_SDVO;
-       /* encoder type will be decided later */
        drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
 
-       intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
-       intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
-
        /* Read the regs to test if we can talk to the device */
        for (i = 0; i < 0x40; i++) {
                u8 byte;
index 6b22c1dcc015f406bf2fcdbc866511bc92f3d882..113e4e7264cdfdb4ba4c3b26af49c15911c2b679 100644 (file)
@@ -1361,15 +1361,14 @@ intel_tv_detect(struct drm_connector *connector, bool force)
        if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
                type = intel_tv_detect_type(intel_tv, connector);
        } else if (force) {
-               struct drm_crtc *crtc;
-               int dpms_mode;
+               struct intel_load_detect_pipe tmp;
 
-               crtc = intel_get_load_detect_pipe(&intel_tv->base, connector,
-                                                 &mode, &dpms_mode);
-               if (crtc) {
+               if (intel_get_load_detect_pipe(&intel_tv->base, connector,
+                                              &mode, &tmp)) {
                        type = intel_tv_detect_type(intel_tv, connector);
-                       intel_release_load_detect_pipe(&intel_tv->base, connector,
-                                                      dpms_mode);
+                       intel_release_load_detect_pipe(&intel_tv->base,
+                                                      connector,
+                                                      &tmp);
                } else
                        return connector_status_unknown;
        } else
index de70959b9ed51371a42eefccba299b76ab738274..ca1639918f57976b852bdcaab751d18402a882ad 100644 (file)
@@ -11,6 +11,8 @@ config DRM_NOUVEAU
        select FRAMEBUFFER_CONSOLE if !EXPERT
        select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
        select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
+       select ACPI_WMI if ACPI
+       select MXM_WMI if ACPI
        help
          Choose this option for open-source nVidia support.
 
index e12c97fd8db89790299836773533827a8d7af3ee..0583677e4581c2faa476f20a8a7a68acee2398b5 100644 (file)
@@ -20,6 +20,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nv40_graph.o nv50_graph.o nvc0_graph.o \
              nv40_grctx.o nv50_grctx.o nvc0_grctx.o \
              nv84_crypt.o \
+             nva3_copy.o nvc0_copy.o \
+             nv40_mpeg.o nv50_mpeg.o \
              nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
              nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
              nv50_cursor.o nv50_display.o \
index a54238058dc54a5d75cb2bacb5b9467eccb7a8b4..f0d459bb46e4152a2f40c0fa2e0b54311c79a328 100644 (file)
@@ -4,6 +4,8 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/video.h>
+#include <acpi/acpi.h>
+#include <linux/mxm-wmi.h>
 
 #include "drmP.h"
 #include "drm.h"
 
 static struct nouveau_dsm_priv {
        bool dsm_detected;
+       bool optimus_detected;
        acpi_handle dhandle;
        acpi_handle rom_handle;
 } nouveau_dsm_priv;
 
+#define NOUVEAU_DSM_HAS_MUX 0x1
+#define NOUVEAU_DSM_HAS_OPT 0x2
+
 static const char nouveau_dsm_muid[] = {
        0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
        0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
 };
 
+static const char nouveau_op_dsm_muid[] = {
+       0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47,
+       0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0,
+};
+
+static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *obj;
+       int err;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(nouveau_op_dsm_muid);
+       params[0].buffer.pointer = (char *)nouveau_op_dsm_muid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = 0x00000100;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = func;
+       params[3].type = ACPI_TYPE_BUFFER;
+       params[3].buffer.length = 0;
+
+       err = acpi_evaluate_object(handle, "_DSM", &input, &output);
+       if (err) {
+               printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
+               return err;
+       }
+
+       obj = (union acpi_object *)output.pointer;
+
+       if (obj->type == ACPI_TYPE_INTEGER)
+               if (obj->integer.value == 0x80000002) {
+                       return -ENODEV;
+               }
+
+       if (obj->type == ACPI_TYPE_BUFFER) {
+               if (obj->buffer.length == 4 && result) {
+                       *result = 0;
+                       *result |= obj->buffer.pointer[0];
+                       *result |= (obj->buffer.pointer[1] << 8);
+                       *result |= (obj->buffer.pointer[2] << 16);
+                       *result |= (obj->buffer.pointer[3] << 24);
+               }
+       }
+
+       kfree(output.pointer);
+       return 0;
+}
+
 static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
 {
        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -92,6 +150,8 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
 
 static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
 {
+       mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
+       mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
        return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
 }
 
@@ -148,11 +208,11 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = {
        .get_client_id = nouveau_dsm_get_client_id,
 };
 
-static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
+static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
 {
        acpi_handle dhandle, nvidia_handle;
        acpi_status status;
-       int ret;
+       int ret, retval = 0;
        uint32_t result;
 
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
@@ -166,11 +226,17 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
 
        ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
                          NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
-       if (ret < 0)
-               return false;
+       if (ret == 0)
+               retval |= NOUVEAU_DSM_HAS_MUX;
 
-       nouveau_dsm_priv.dhandle = dhandle;
-       return true;
+       ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
+       if (ret == 0)
+               retval |= NOUVEAU_DSM_HAS_OPT;
+
+       if (retval)
+               nouveau_dsm_priv.dhandle = dhandle;
+
+       return retval;
 }
 
 static bool nouveau_dsm_detect(void)
@@ -179,22 +245,42 @@ static bool nouveau_dsm_detect(void)
        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
        struct pci_dev *pdev = NULL;
        int has_dsm = 0;
+       int has_optimus;
        int vga_count = 0;
+       bool guid_valid;
+       int retval;
+       bool ret = false;
+
+       /* lookup the MXM GUID */
+       guid_valid = mxm_wmi_supported();
 
+       if (guid_valid)
+               printk("MXM: GUID detected in BIOS\n");
+
+       /* now do DSM detection */
        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
                vga_count++;
 
-               has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
+               retval = nouveau_dsm_pci_probe(pdev);
+               printk("ret val is %d\n", retval);
+               if (retval & NOUVEAU_DSM_HAS_MUX)
+                       has_dsm |= 1;
+               if (retval & NOUVEAU_DSM_HAS_OPT)
+                       has_optimus = 1;
        }
 
-       if (vga_count == 2 && has_dsm) {
+       if (vga_count == 2 && has_dsm && guid_valid) {
                acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
                printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
                       acpi_method_name);
                nouveau_dsm_priv.dsm_detected = true;
-               return true;
+               ret = true;
        }
-       return false;
+
+       if (has_optimus == 1)
+               nouveau_dsm_priv.optimus_detected = true;
+
+       return ret;
 }
 
 void nouveau_register_dsm_handler(void)
@@ -247,7 +333,7 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
        acpi_status status;
        acpi_handle dhandle, rom_handle;
 
-       if (!nouveau_dsm_priv.dsm_detected)
+       if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected)
                return false;
 
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
index 90aef64b76f277a649cd8e7caf79bfa40851cf3f..729d5fd7c88d246fda09dad22c599efad448623b 100644 (file)
@@ -5049,11 +5049,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
                pll_lim->vco1.max_n = record[11];
                pll_lim->min_p = record[12];
                pll_lim->max_p = record[13];
-               /* where did this go to?? */
-               if ((entry[0] & 0xf0) == 0x80)
-                       pll_lim->refclk = 27000;
-               else
-                       pll_lim->refclk = 100000;
+               pll_lim->refclk = ROM16(entry[9]) * 1000;
        }
 
        /*
@@ -6035,6 +6031,7 @@ parse_dcb_connector_table(struct nvbios *bios)
                case DCB_CONNECTOR_DVI_I:
                case DCB_CONNECTOR_DVI_D:
                case DCB_CONNECTOR_LVDS:
+               case DCB_CONNECTOR_LVDS_SPWG:
                case DCB_CONNECTOR_DP:
                case DCB_CONNECTOR_eDP:
                case DCB_CONNECTOR_HDMI_0:
index 8a54fa7edf5c18d692ecb2bfc94dfa1696800c43..050c314119dff4c0eb37fb36df860031ba61397c 100644 (file)
@@ -82,6 +82,7 @@ enum dcb_connector_type {
        DCB_CONNECTOR_DVI_I = 0x30,
        DCB_CONNECTOR_DVI_D = 0x31,
        DCB_CONNECTOR_LVDS = 0x40,
+       DCB_CONNECTOR_LVDS_SPWG = 0x41,
        DCB_CONNECTOR_DP = 0x46,
        DCB_CONNECTOR_eDP = 0x47,
        DCB_CONNECTOR_HDMI_0 = 0x60,
index 4cea35c57d15a4582ac0dfbd76add6b9934e9317..a7583a8ddb01f13dba3f12a43d1c263630cb261a 100644 (file)
@@ -268,9 +268,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
        unsigned long flags;
+       int i;
 
        /* decrement the refcount, and we're done if there's still refs */
        if (likely(!atomic_dec_and_test(&chan->users))) {
@@ -294,19 +293,12 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
        /* boot it off the hardware */
        pfifo->reassign(dev, false);
 
-       /* We want to give pgraph a chance to idle and get rid of all
-        * potential errors. We need to do this without the context
-        * switch lock held, otherwise the irq handler is unable to
-        * process them.
-        */
-       if (pgraph->channel(dev) == chan)
-               nouveau_wait_for_idle(dev);
-
        /* destroy the engine specific contexts */
        pfifo->destroy_context(chan);
-       pgraph->destroy_context(chan);
-       if (pcrypt->destroy_context)
-               pcrypt->destroy_context(chan);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (chan->engctx[i])
+                       dev_priv->eng[i]->context_del(chan, i);
+       }
 
        pfifo->reassign(dev, true);
 
@@ -414,7 +406,7 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
        struct nouveau_channel *chan;
        int ret;
 
-       if (dev_priv->engine.graph.accel_blocked)
+       if (!dev_priv->eng[NVOBJ_ENGINE_GR])
                return -ENODEV;
 
        if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
index 7ae151109a66f76eb467557f66f055c5ea7cb5c7..1595d0b6e8154544b0149b7053366fbf29baa880 100644 (file)
@@ -442,7 +442,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
                }
 
                /* LVDS always needs gpu scaling */
-               if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS &&
+               if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
                    value == DRM_MODE_SCALE_NONE)
                        return -EINVAL;
 
@@ -650,6 +650,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
                ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
 
        if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
+           nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG ||
            nv_connector->dcb->type == DCB_CONNECTOR_eDP)
                ret += nouveau_connector_scaler_modes_add(connector);
 
@@ -810,6 +811,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
                type = DRM_MODE_CONNECTOR_HDMIA;
                break;
        case DCB_CONNECTOR_LVDS:
+       case DCB_CONNECTOR_LVDS_SPWG:
                type = DRM_MODE_CONNECTOR_LVDS;
                funcs = &nouveau_connector_funcs_lvds;
                break;
@@ -838,7 +840,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
        drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
 
        /* Check if we need dithering enabled */
-       if (dcb->type == DCB_CONNECTOR_LVDS) {
+       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
                bool dummy, is_24bit = false;
 
                ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit);
@@ -883,7 +885,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
                                nv_connector->use_dithering ?
                                DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
 
-               if (dcb->type != DCB_CONNECTOR_LVDS) {
+               if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) {
                        if (dev_priv->card_type >= NV_50)
                                connector->polled = DRM_CONNECTOR_POLL_HPD;
                        else
index 764c15d537bac897d64eebfc791ba3db401fae67..eb514ea29377aee0f79a5073725b990e39800c7c 100644 (file)
@@ -276,7 +276,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        struct nouveau_fence *fence;
        int ret;
 
-       if (dev_priv->engine.graph.accel_blocked)
+       if (!dev_priv->channel)
                return -ENODEV;
 
        s = kzalloc(sizeof(*s), GFP_KERNEL);
index 155ebdcbf06fe2ab1d41f047733a307dd9656389..02c6f37d8bd78b4685ddd07a87c24a3a2ebd4e3c 100644 (file)
@@ -162,11 +162,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_channel *chan;
        struct drm_crtc *crtc;
-       int ret, i;
+       int ret, i, e;
 
        if (pm_state.event == PM_EVENT_PRETHAW)
                return 0;
@@ -206,12 +205,17 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
                        nouveau_channel_idle(chan);
        }
 
-       pgraph->fifo_access(dev, false);
-       nouveau_wait_for_idle(dev);
        pfifo->reassign(dev, false);
        pfifo->disable(dev);
        pfifo->unload_context(dev);
-       pgraph->unload_context(dev);
+
+       for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+               if (dev_priv->eng[e]) {
+                       ret = dev_priv->eng[e]->fini(dev, e);
+                       if (ret)
+                               goto out_abort;
+               }
+       }
 
        ret = pinstmem->suspend(dev);
        if (ret) {
@@ -242,9 +246,12 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
 
 out_abort:
        NV_INFO(dev, "Re-enabling acceleration..\n");
+       for (e = e + 1; e < NVOBJ_ENGINE_NR; e++) {
+               if (dev_priv->eng[e])
+                       dev_priv->eng[e]->init(dev, e);
+       }
        pfifo->enable(dev);
        pfifo->reassign(dev, true);
-       pgraph->fifo_access(dev, true);
        return ret;
 }
 
@@ -299,8 +306,10 @@ nouveau_pci_resume(struct pci_dev *pdev)
        engine->mc.init(dev);
        engine->timer.init(dev);
        engine->fb.init(dev);
-       engine->graph.init(dev);
-       engine->crypt.init(dev);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (dev_priv->eng[i])
+                       dev_priv->eng[i]->init(dev, i);
+       }
        engine->fifo.init(dev);
 
        nouveau_irq_postinstall(dev);
index a76514a209b369880ac8b5ced881bb337a186695..9c56331941e2430cd2dda20ca9c3ab06a6b1c0cf 100644 (file)
@@ -150,13 +150,12 @@ enum nouveau_flags {
 
 #define NVOBJ_ENGINE_SW                0
 #define NVOBJ_ENGINE_GR                1
-#define NVOBJ_ENGINE_PPP       2
-#define NVOBJ_ENGINE_COPY      3
-#define NVOBJ_ENGINE_VP                4
-#define NVOBJ_ENGINE_CRYPT      5
-#define NVOBJ_ENGINE_BSP       6
-#define NVOBJ_ENGINE_DISPLAY   0xcafe0001
-#define NVOBJ_ENGINE_INT       0xdeadbeef
+#define NVOBJ_ENGINE_CRYPT     2
+#define NVOBJ_ENGINE_COPY0     3
+#define NVOBJ_ENGINE_COPY1     4
+#define NVOBJ_ENGINE_MPEG      5
+#define NVOBJ_ENGINE_DISPLAY   15
+#define NVOBJ_ENGINE_NR                16
 
 #define NVOBJ_FLAG_DONT_MAP             (1 << 0)
 #define NVOBJ_FLAG_ZERO_ALLOC          (1 << 1)
@@ -245,11 +244,8 @@ struct nouveau_channel {
        struct nouveau_gpuobj *cache;
        void *fifo_priv;
 
-       /* PGRAPH context */
-       /* XXX may be merge 2 pointers as private data ??? */
-       struct nouveau_gpuobj *ramin_grctx;
-       struct nouveau_gpuobj *crypt_ctx;
-       void *pgraph_ctx;
+       /* Execution engine contexts */
+       void *engctx[NVOBJ_ENGINE_NR];
 
        /* NV50 VM */
        struct nouveau_vm     *vm;
@@ -298,6 +294,18 @@ struct nouveau_channel {
        } debugfs;
 };
 
+struct nouveau_exec_engine {
+       void (*destroy)(struct drm_device *, int engine);
+       int  (*init)(struct drm_device *, int engine);
+       int  (*fini)(struct drm_device *, int engine);
+       int  (*context_new)(struct nouveau_channel *, int engine);
+       void (*context_del)(struct nouveau_channel *, int engine);
+       int  (*object_new)(struct nouveau_channel *, int engine,
+                          u32 handle, u16 class);
+       void (*set_tile_region)(struct drm_device *dev, int i);
+       void (*tlb_flush)(struct drm_device *, int engine);
+};
+
 struct nouveau_instmem_engine {
        void    *priv;
 
@@ -364,30 +372,6 @@ struct nouveau_fifo_engine {
        void (*tlb_flush)(struct drm_device *dev);
 };
 
-struct nouveau_pgraph_engine {
-       bool accel_blocked;
-       bool registered;
-       int grctx_size;
-       void *priv;
-
-       /* NV2x/NV3x context table (0x400780) */
-       struct nouveau_gpuobj *ctx_table;
-
-       int  (*init)(struct drm_device *);
-       void (*takedown)(struct drm_device *);
-
-       void (*fifo_access)(struct drm_device *, bool);
-
-       struct nouveau_channel *(*channel)(struct drm_device *);
-       int  (*create_context)(struct nouveau_channel *);
-       void (*destroy_context)(struct nouveau_channel *);
-       int  (*load_context)(struct nouveau_channel *);
-       int  (*unload_context)(struct drm_device *);
-       void (*tlb_flush)(struct drm_device *dev);
-
-       void (*set_tile_region)(struct drm_device *dev, int i);
-};
-
 struct nouveau_display_engine {
        void *priv;
        int (*early_init)(struct drm_device *);
@@ -426,6 +410,19 @@ struct nouveau_pm_voltage {
        int nr_level;
 };
 
+struct nouveau_pm_memtiming {
+       int id;
+       u32 reg_100220;
+       u32 reg_100224;
+       u32 reg_100228;
+       u32 reg_10022c;
+       u32 reg_100230;
+       u32 reg_100234;
+       u32 reg_100238;
+       u32 reg_10023c;
+       u32 reg_100240;
+};
+
 #define NOUVEAU_PM_MAX_LEVEL 8
 struct nouveau_pm_level {
        struct device_attribute dev_attr;
@@ -436,11 +433,13 @@ struct nouveau_pm_level {
        u32 memory;
        u32 shader;
        u32 unk05;
+       u32 unk0a;
 
        u8 voltage;
        u8 fanspeed;
 
        u16 memscript;
+       struct nouveau_pm_memtiming *timing;
 };
 
 struct nouveau_pm_temp_sensor_constants {
@@ -457,17 +456,6 @@ struct nouveau_pm_threshold_temp {
        s16 fan_boost;
 };
 
-struct nouveau_pm_memtiming {
-       u32 reg_100220;
-       u32 reg_100224;
-       u32 reg_100228;
-       u32 reg_10022c;
-       u32 reg_100230;
-       u32 reg_100234;
-       u32 reg_100238;
-       u32 reg_10023c;
-};
-
 struct nouveau_pm_memtimings {
        bool supported;
        struct nouveau_pm_memtiming *timing;
@@ -499,16 +487,6 @@ struct nouveau_pm_engine {
        int (*temp_get)(struct drm_device *);
 };
 
-struct nouveau_crypt_engine {
-       bool registered;
-
-       int  (*init)(struct drm_device *);
-       void (*takedown)(struct drm_device *);
-       int  (*create_context)(struct nouveau_channel *);
-       void (*destroy_context)(struct nouveau_channel *);
-       void (*tlb_flush)(struct drm_device *dev);
-};
-
 struct nouveau_vram_engine {
        int  (*init)(struct drm_device *);
        int  (*get)(struct drm_device *, u64, u32 align, u32 size_nc,
@@ -523,12 +501,10 @@ struct nouveau_engine {
        struct nouveau_mc_engine      mc;
        struct nouveau_timer_engine   timer;
        struct nouveau_fb_engine      fb;
-       struct nouveau_pgraph_engine  graph;
        struct nouveau_fifo_engine    fifo;
        struct nouveau_display_engine display;
        struct nouveau_gpio_engine    gpio;
        struct nouveau_pm_engine      pm;
-       struct nouveau_crypt_engine   crypt;
        struct nouveau_vram_engine    vram;
 };
 
@@ -637,6 +613,7 @@ struct drm_nouveau_private {
        enum nouveau_card_type card_type;
        /* exact chipset, derived from NV_PMC_BOOT_0 */
        int chipset;
+       int stepping;
        int flags;
 
        void __iomem *mmio;
@@ -647,6 +624,7 @@ struct drm_nouveau_private {
        u32 ramin_base;
        bool ramin_available;
        struct drm_mm ramin_heap;
+       struct nouveau_exec_engine *eng[NVOBJ_ENGINE_NR];
        struct list_head gpuobj_list;
        struct list_head classes;
 
@@ -745,10 +723,6 @@ struct drm_nouveau_private {
        uint32_t crtc_owner;
        uint32_t dac_users[4];
 
-       struct nouveau_suspend_resume {
-               uint32_t *ramin_copy;
-       } susres;
-
        struct backlight_device *backlight;
 
        struct {
@@ -757,8 +731,6 @@ struct drm_nouveau_private {
 
        struct nouveau_fbdev *nfbdev;
        struct apertures_struct *apertures;
-
-       bool powered_down;
 };
 
 static inline struct drm_nouveau_private *
@@ -883,17 +855,27 @@ extern void nouveau_channel_ref(struct nouveau_channel *chan,
 extern void nouveau_channel_idle(struct nouveau_channel *chan);
 
 /* nouveau_object.c */
-#define NVOBJ_CLASS(d,c,e) do {                                                \
+#define NVOBJ_ENGINE_ADD(d, e, p) do {                                         \
+       struct drm_nouveau_private *dev_priv = (d)->dev_private;               \
+       dev_priv->eng[NVOBJ_ENGINE_##e] = (p);                                 \
+} while (0)
+
+#define NVOBJ_ENGINE_DEL(d, e) do {                                            \
+       struct drm_nouveau_private *dev_priv = (d)->dev_private;               \
+       dev_priv->eng[NVOBJ_ENGINE_##e] = NULL;                                \
+} while (0)
+
+#define NVOBJ_CLASS(d, c, e) do {                                              \
        int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e);        \
        if (ret)                                                               \
                return ret;                                                    \
-} while(0)
+} while (0)
 
-#define NVOBJ_MTHD(d,c,m,e) do {                                               \
+#define NVOBJ_MTHD(d, c, m, e) do {                                            \
        int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e));                 \
        if (ret)                                                               \
                return ret;                                                    \
-} while(0)
+} while (0)
 
 extern int  nouveau_gpuobj_early_init(struct drm_device *);
 extern int  nouveau_gpuobj_init(struct drm_device *);
@@ -903,7 +885,7 @@ extern void nouveau_gpuobj_resume(struct drm_device *dev);
 extern int  nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng);
 extern int  nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd,
                                    int (*exec)(struct nouveau_channel *,
-                                               u32 class, u32 mthd, u32 data));
+                                               u32 class, u32 mthd, u32 data));
 extern int  nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32);
 extern int  nouveau_gpuobj_mthd_call2(struct drm_device *, int, u32, u32, u32);
 extern int nouveau_gpuobj_channel_init(struct nouveau_channel *,
@@ -1137,81 +1119,50 @@ extern int  nvc0_fifo_load_context(struct nouveau_channel *);
 extern int  nvc0_fifo_unload_context(struct drm_device *);
 
 /* nv04_graph.c */
-extern int  nv04_graph_init(struct drm_device *);
-extern void nv04_graph_takedown(struct drm_device *);
+extern int  nv04_graph_create(struct drm_device *);
 extern void nv04_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv04_graph_channel(struct drm_device *);
-extern int  nv04_graph_create_context(struct nouveau_channel *);
-extern void nv04_graph_destroy_context(struct nouveau_channel *);
-extern int  nv04_graph_load_context(struct nouveau_channel *);
-extern int  nv04_graph_unload_context(struct drm_device *);
+extern int  nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
 extern int  nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
                                      u32 class, u32 mthd, u32 data);
 extern struct nouveau_bitfield nv04_graph_nsource[];
 
 /* nv10_graph.c */
-extern int  nv10_graph_init(struct drm_device *);
-extern void nv10_graph_takedown(struct drm_device *);
+extern int  nv10_graph_create(struct drm_device *);
 extern struct nouveau_channel *nv10_graph_channel(struct drm_device *);
-extern int  nv10_graph_create_context(struct nouveau_channel *);
-extern void nv10_graph_destroy_context(struct nouveau_channel *);
-extern int  nv10_graph_load_context(struct nouveau_channel *);
-extern int  nv10_graph_unload_context(struct drm_device *);
-extern void nv10_graph_set_tile_region(struct drm_device *dev, int i);
 extern struct nouveau_bitfield nv10_graph_intr[];
 extern struct nouveau_bitfield nv10_graph_nstatus[];
 
 /* nv20_graph.c */
-extern int  nv20_graph_create_context(struct nouveau_channel *);
-extern void nv20_graph_destroy_context(struct nouveau_channel *);
-extern int  nv20_graph_load_context(struct nouveau_channel *);
-extern int  nv20_graph_unload_context(struct drm_device *);
-extern int  nv20_graph_init(struct drm_device *);
-extern void nv20_graph_takedown(struct drm_device *);
-extern int  nv30_graph_init(struct drm_device *);
-extern void nv20_graph_set_tile_region(struct drm_device *dev, int i);
+extern int  nv20_graph_create(struct drm_device *);
 
 /* nv40_graph.c */
-extern int  nv40_graph_init(struct drm_device *);
-extern void nv40_graph_takedown(struct drm_device *);
-extern struct nouveau_channel *nv40_graph_channel(struct drm_device *);
-extern int  nv40_graph_create_context(struct nouveau_channel *);
-extern void nv40_graph_destroy_context(struct nouveau_channel *);
-extern int  nv40_graph_load_context(struct nouveau_channel *);
-extern int  nv40_graph_unload_context(struct drm_device *);
+extern int  nv40_graph_create(struct drm_device *);
 extern void nv40_grctx_init(struct nouveau_grctx *);
-extern void nv40_graph_set_tile_region(struct drm_device *dev, int i);
 
 /* nv50_graph.c */
-extern int  nv50_graph_init(struct drm_device *);
-extern void nv50_graph_takedown(struct drm_device *);
-extern void nv50_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv50_graph_channel(struct drm_device *);
-extern int  nv50_graph_create_context(struct nouveau_channel *);
-extern void nv50_graph_destroy_context(struct nouveau_channel *);
-extern int  nv50_graph_load_context(struct nouveau_channel *);
-extern int  nv50_graph_unload_context(struct drm_device *);
+extern int  nv50_graph_create(struct drm_device *);
 extern int  nv50_grctx_init(struct nouveau_grctx *);
-extern void nv50_graph_tlb_flush(struct drm_device *dev);
-extern void nv84_graph_tlb_flush(struct drm_device *dev);
 extern struct nouveau_enum nv50_data_error_names[];
+extern int  nv50_graph_isr_chid(struct drm_device *dev, u64 inst);
 
 /* nvc0_graph.c */
-extern int  nvc0_graph_init(struct drm_device *);
-extern void nvc0_graph_takedown(struct drm_device *);
-extern void nvc0_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *);
-extern int  nvc0_graph_create_context(struct nouveau_channel *);
-extern void nvc0_graph_destroy_context(struct nouveau_channel *);
-extern int  nvc0_graph_load_context(struct nouveau_channel *);
-extern int  nvc0_graph_unload_context(struct drm_device *);
+extern int  nvc0_graph_create(struct drm_device *);
+extern int  nvc0_graph_isr_chid(struct drm_device *dev, u64 inst);
 
 /* nv84_crypt.c */
-extern int  nv84_crypt_init(struct drm_device *dev);
-extern void nv84_crypt_fini(struct drm_device *dev);
-extern int  nv84_crypt_create_context(struct nouveau_channel *);
-extern void nv84_crypt_destroy_context(struct nouveau_channel *);
-extern void nv84_crypt_tlb_flush(struct drm_device *dev);
+extern int  nv84_crypt_create(struct drm_device *);
+
+/* nva3_copy.c */
+extern int  nva3_copy_create(struct drm_device *dev);
+
+/* nvc0_copy.c */
+extern int  nvc0_copy_create(struct drm_device *dev, int engine);
+
+/* nv40_mpeg.c */
+extern int  nv40_mpeg_create(struct drm_device *dev);
+
+/* nv50_mpeg.c */
+extern int  nv50_mpeg_create(struct drm_device *dev);
 
 /* nv04_instmem.c */
 extern int  nv04_instmem_init(struct drm_device *);
@@ -1402,8 +1353,8 @@ bool nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on);
 /* nv50_calc. */
 int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
                  int *N1, int *M1, int *N2, int *M2, int *P);
-int nv50_calc_pll2(struct drm_device *, struct pll_lims *,
-                  int clk, int *N, int *fN, int *M, int *P);
+int nva3_calc_pll(struct drm_device *, struct pll_lims *,
+                 int clk, int *N, int *fN, int *M, int *P);
 
 #ifndef ioread32_native
 #ifdef __BIG_ENDIAN
@@ -1579,6 +1530,13 @@ nv_match_device(struct drm_device *dev, unsigned device,
                dev->pdev->subsystem_device == sub_device;
 }
 
+static inline void *
+nv_engine(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       return (void *)dev_priv->eng[engine];
+}
+
 /* returns 1 if device is one of the nv4x using the 0x4497 object class,
  * helpful to determine a number of other hardware features
  */
index 4a8ad1307fa49403f53e5768488afd7e4b49f8c9..86c2e374e938e644070f533214bbd6038e72eaf3 100644 (file)
@@ -87,10 +87,10 @@ _cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
        cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
                    (state ? 0 : CP_BRA_IF_CLEAR));
 }
-#define cp_bra(c,f,s,n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
 #ifdef CP_BRA_MOD
-#define cp_cal(c,f,s,n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#define cp_ret(c,f,s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
+#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
 #endif
 
 static inline void
@@ -98,14 +98,14 @@ _cp_wait(struct nouveau_grctx *ctx, int flag, int state)
 {
        cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
 }
-#define cp_wait(c,f,s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
 
 static inline void
 _cp_set(struct nouveau_grctx *ctx, int flag, int state)
 {
        cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
 }
-#define cp_set(c,f,s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
 
 static inline void
 cp_pos(struct nouveau_grctx *ctx, int offset)
index c3e953b089923d552de922e8007c13e1e8eb94e5..2960f583dc389fac112de1d4ad7ee615a0d6ca31 100644 (file)
@@ -51,8 +51,7 @@ nv10_mem_update_tile_region(struct drm_device *dev,
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       int i = tile - dev_priv->tile.reg;
+       int i = tile - dev_priv->tile.reg, j;
        unsigned long save;
 
        nouveau_fence_unref(&tile->fence);
@@ -70,7 +69,10 @@ nv10_mem_update_tile_region(struct drm_device *dev,
        nouveau_wait_for_idle(dev);
 
        pfb->set_tile_region(dev, i);
-       pgraph->set_tile_region(dev, i);
+       for (j = 0; j < NVOBJ_ENGINE_NR; j++) {
+               if (dev_priv->eng[j] && dev_priv->eng[j]->set_tile_region)
+                       dev_priv->eng[j]->set_tile_region(dev, i);
+       }
 
        pfifo->cache_pull(dev, true);
        pfifo->reassign(dev, true);
@@ -595,10 +597,10 @@ nouveau_mem_timing_init(struct drm_device *dev)
        if (!memtimings->timing)
                return;
 
-       /* Get "some number" from the timing reg for NV_40
+       /* Get "some number" from the timing reg for NV_40 and NV_50
         * Used in calculations later */
-       if(dev_priv->card_type == NV_40) {
-               magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24;
+       if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) {
+               magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
        }
 
        entry = mem + mem[1];
@@ -641,51 +643,68 @@ nouveau_mem_timing_init(struct drm_device *dev)
                /* XXX: I don't trust the -1's and +1's... they must come
                 *      from somewhere! */
                timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 |
-                                     tUNK_18 << 16 |
+                                     max(tUNK_18, (u8) 1) << 16 |
                                      (tUNK_1 + tUNK_19 + 1 + magic_number) << 8;
-               if(dev_priv->chipset == 0xa8) {
+               if (dev_priv->chipset == 0xa8) {
                        timing->reg_100224 |= (tUNK_2 - 1);
                } else {
                        timing->reg_100224 |= (tUNK_2 + 2 - magic_number);
                }
 
                timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
-               if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) {
+               if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa)
                        timing->reg_100228 |= (tUNK_19 - 1) << 24;
-               }
+               else
+                       timing->reg_100228 |= magic_number << 24;
 
-               if(dev_priv->card_type == NV_40) {
+               if (dev_priv->card_type == NV_40) {
                        /* NV40: don't know what the rest of the regs are..
                         * And don't need to know either */
-                       timing->reg_100228 |= 0x20200000 | magic_number << 24;
-               } else if(dev_priv->card_type >= NV_50) {
-                       /* XXX: reg_10022c */
-                       timing->reg_10022c = tUNK_2 - 1;
+                       timing->reg_100228 |= 0x20200000;
+               } else if (dev_priv->card_type >= NV_50) {
+                       if (dev_priv->chipset < 0x98 ||
+                           (dev_priv->chipset == 0x98 &&
+                            dev_priv->stepping <= 0xa1)) {
+                               timing->reg_10022c = (0x14 + tUNK_2) << 24 |
+                                                    0x16 << 16 |
+                                                    (tUNK_2 - 1) << 8 |
+                                                    (tUNK_2 - 1);
+                       } else {
+                               /* XXX: reg_10022c for recentish cards */
+                               timing->reg_10022c = tUNK_2 - 1;
+                       }
 
                        timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
                                                  tUNK_13 << 8  | tUNK_13);
 
                        timing->reg_100234 = (tRAS << 24 | tRC);
-                       timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+                       timing->reg_100234 += max(tUNK_10, tUNK_11) << 16;
 
-                       if(dev_priv->chipset < 0xa3) {
+                       if (dev_priv->chipset < 0x98 ||
+                           (dev_priv->chipset == 0x98 &&
+                            dev_priv->stepping <= 0xa1)) {
                                timing->reg_100234 |= (tUNK_2 + 2) << 8;
                        } else {
                                /* XXX: +6? */
                                timing->reg_100234 |= (tUNK_19 + 6) << 8;
                        }
 
-                       /* XXX; reg_100238, reg_10023c
-                        * reg_100238: 0x00??????
-                        * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */
+                       /* XXX; reg_100238
+                        * reg_100238: 0x00?????? */
                        timing->reg_10023c = 0x202;
-                       if(dev_priv->chipset < 0xa3) {
+                       if (dev_priv->chipset < 0x98 ||
+                           (dev_priv->chipset == 0x98 &&
+                            dev_priv->stepping <= 0xa1)) {
                                timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
                        } else {
-                               /* currently unknown
+                               /* XXX: reg_10023c
+                                * currently unknown
                                 * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
                        }
+
+                       /* XXX: reg_100240? */
                }
+               timing->id = i;
 
                NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
                         timing->reg_100220, timing->reg_100224,
@@ -693,10 +712,11 @@ nouveau_mem_timing_init(struct drm_device *dev)
                NV_DEBUG(dev, "         230: %08x %08x %08x %08x\n",
                         timing->reg_100230, timing->reg_100234,
                         timing->reg_100238, timing->reg_10023c);
+               NV_DEBUG(dev, "         240: %08x\n", timing->reg_100240);
        }
 
        memtimings->nr_timing = entries;
-       memtimings->supported = true;
+       memtimings->supported = (dev_priv->chipset <= 0x98);
 }
 
 void
index 67a16e01ffa6db3030fd789d500dafd9b03eaf54..8f97016f5b2648a22fbdb1197f6e26168b1851b2 100644 (file)
@@ -361,20 +361,6 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
        return 0;
 }
 
-
-static uint32_t
-nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       /*XXX: dodgy hack for now */
-       if (dev_priv->card_type >= NV_50)
-               return 24;
-       if (dev_priv->card_type >= NV_40)
-               return 32;
-       return 16;
-}
-
 /*
    DMA objects are used to reference a piece of memory in the
    framebuffer, PCI or AGP address space. Each object is 16 bytes big
@@ -606,11 +592,11 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
    set to 0?
 */
 static int
-nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
-                     struct nouveau_gpuobj **gpuobj_ret)
+nouveau_gpuobj_sw_new(struct nouveau_channel *chan, u32 handle, u16 class)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
        struct nouveau_gpuobj *gpuobj;
+       int ret;
 
        gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
        if (!gpuobj)
@@ -624,8 +610,10 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
        spin_lock(&dev_priv->ramin_lock);
        list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
        spin_unlock(&dev_priv->ramin_lock);
-       *gpuobj_ret = gpuobj;
-       return 0;
+
+       ret = nouveau_ramht_insert(chan, handle, gpuobj);
+       nouveau_gpuobj_ref(NULL, &gpuobj);
+       return ret;
 }
 
 int
@@ -634,101 +622,30 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
        struct drm_device *dev = chan->dev;
        struct nouveau_gpuobj_class *oc;
-       struct nouveau_gpuobj *gpuobj;
        int ret;
 
        NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class);
 
        list_for_each_entry(oc, &dev_priv->classes, head) {
-               if (oc->id == class)
-                       goto found;
-       }
-
-       NV_ERROR(dev, "illegal object class: 0x%x\n", class);
-       return -EINVAL;
+               struct nouveau_exec_engine *eng = dev_priv->eng[oc->engine];
 
-found:
-       switch (oc->engine) {
-       case NVOBJ_ENGINE_SW:
-               if (dev_priv->card_type < NV_C0) {
-                       ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj);
-                       if (ret)
-                               return ret;
-                       goto insert;
-               }
-               break;
-       case NVOBJ_ENGINE_GR:
-               if ((dev_priv->card_type >= NV_20 && !chan->ramin_grctx) ||
-                   (dev_priv->card_type  < NV_20 && !chan->pgraph_ctx)) {
-                       struct nouveau_pgraph_engine *pgraph =
-                               &dev_priv->engine.graph;
+               if (oc->id != class)
+                       continue;
 
-                       ret = pgraph->create_context(chan);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NVOBJ_ENGINE_CRYPT:
-               if (!chan->crypt_ctx) {
-                       struct nouveau_crypt_engine *pcrypt =
-                               &dev_priv->engine.crypt;
+               if (oc->engine == NVOBJ_ENGINE_SW)
+                       return nouveau_gpuobj_sw_new(chan, handle, class);
 
-                       ret = pcrypt->create_context(chan);
+               if (!chan->engctx[oc->engine]) {
+                       ret = eng->context_new(chan, oc->engine);
                        if (ret)
                                return ret;
                }
-               break;
-       }
-
-       /* we're done if this is fermi */
-       if (dev_priv->card_type >= NV_C0)
-               return 0;
-
-       ret = nouveau_gpuobj_new(dev, chan,
-                                nouveau_gpuobj_class_instmem_size(dev, class),
-                                16,
-                                NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
-                                &gpuobj);
-       if (ret) {
-               NV_ERROR(dev, "error creating gpuobj: %d\n", ret);
-               return ret;
-       }
 
-       if (dev_priv->card_type >= NV_50) {
-               nv_wo32(gpuobj,  0, class);
-               nv_wo32(gpuobj, 20, 0x00010000);
-       } else {
-               switch (class) {
-               case NV_CLASS_NULL:
-                       nv_wo32(gpuobj, 0, 0x00001030);
-                       nv_wo32(gpuobj, 4, 0xFFFFFFFF);
-                       break;
-               default:
-                       if (dev_priv->card_type >= NV_40) {
-                               nv_wo32(gpuobj, 0, class);
-#ifdef __BIG_ENDIAN
-                               nv_wo32(gpuobj, 8, 0x01000000);
-#endif
-                       } else {
-#ifdef __BIG_ENDIAN
-                               nv_wo32(gpuobj, 0, class | 0x00080000);
-#else
-                               nv_wo32(gpuobj, 0, class);
-#endif
-                       }
-               }
+               return eng->object_new(chan, oc->engine, handle, class);
        }
-       dev_priv->engine.instmem.flush(dev);
-
-       gpuobj->engine = oc->engine;
-       gpuobj->class  = oc->id;
 
-insert:
-       ret = nouveau_ramht_insert(chan, handle, gpuobj);
-       if (ret)
-               NV_ERROR(dev, "error adding gpuobj to RAMHT: %d\n", ret);
-       nouveau_gpuobj_ref(NULL, &gpuobj);
-       return ret;
+       NV_ERROR(dev, "illegal object class: 0x%x\n", class);
+       return -EINVAL;
 }
 
 static int
@@ -746,9 +663,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
        size = 0x2000;
        base = 0;
 
-       /* PGRAPH context */
-       size += dev_priv->engine.graph.grctx_size;
-
        if (dev_priv->card_type == NV_50) {
                /* Various fixed table thingos */
                size += 0x1400; /* mostly unknown stuff */
index 670e3cb697ec7664921e1fc87f57fa6fa40cd68e..922fb6b664edda718e2e15f929500a2fe3967d21 100644 (file)
@@ -72,6 +72,68 @@ legacy_perf_init(struct drm_device *dev)
        pm->nr_perflvl = 1;
 }
 
+static struct nouveau_pm_memtiming *
+nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
+                   u16 memclk, u8 *entry, u8 recordlen, u8 entries)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nvbios *bios = &dev_priv->vbios;
+       u8 ramcfg;
+       int i;
+
+       /* perf v2 has a separate "timing map" table, we have to match
+        * the target memory clock to a specific entry, *then* use
+        * ramcfg to select the correct subentry
+        */
+       if (P->version == 2) {
+               u8 *tmap = ROMPTR(bios, P->data[4]);
+               if (!tmap) {
+                       NV_DEBUG(dev, "no timing map pointer\n");
+                       return NULL;
+               }
+
+               if (tmap[0] != 0x10) {
+                       NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]);
+                       return NULL;
+               }
+
+               entry = tmap + tmap[1];
+               recordlen = tmap[2] + (tmap[4] * tmap[3]);
+               for (i = 0; i < tmap[5]; i++, entry += recordlen) {
+                       if (memclk >= ROM16(entry[0]) &&
+                           memclk <= ROM16(entry[2]))
+                               break;
+               }
+
+               if (i == tmap[5]) {
+                       NV_WARN(dev, "no match in timing map table\n");
+                       return NULL;
+               }
+
+               entry += tmap[2];
+               recordlen = tmap[3];
+               entries   = tmap[4];
+       }
+
+       ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2;
+       if (bios->ram_restrict_tbl_ptr)
+               ramcfg = bios->data[bios->ram_restrict_tbl_ptr + ramcfg];
+
+       if (ramcfg >= entries) {
+               NV_WARN(dev, "ramcfg strap out of bounds!\n");
+               return NULL;
+       }
+
+       entry += ramcfg * recordlen;
+       if (entry[1] >= pm->memtimings.nr_timing) {
+               NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
+               return NULL;
+       }
+
+       return &pm->memtimings.timing[entry[1]];
+}
+
 void
 nouveau_perf_init(struct drm_device *dev)
 {
@@ -124,6 +186,8 @@ nouveau_perf_init(struct drm_device *dev)
        for (i = 0; i < entries; i++) {
                struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
 
+               perflvl->timing = NULL;
+
                if (entry[0] == 0xff) {
                        entry += recordlen;
                        continue;
@@ -174,9 +238,21 @@ nouveau_perf_init(struct drm_device *dev)
 #define subent(n) entry[perf[2] + ((n) * perf[3])]
                        perflvl->fanspeed = 0; /*XXX*/
                        perflvl->voltage = entry[2];
-                       perflvl->core = (ROM16(subent(0)) & 0xfff) * 1000;
-                       perflvl->shader = (ROM16(subent(1)) & 0xfff) * 1000;
-                       perflvl->memory = (ROM16(subent(2)) & 0xfff) * 1000;
+                       if (dev_priv->card_type == NV_50) {
+                               perflvl->core = ROM16(subent(0)) & 0xfff;
+                               perflvl->shader = ROM16(subent(1)) & 0xfff;
+                               perflvl->memory = ROM16(subent(2)) & 0xfff;
+                       } else {
+                               perflvl->shader = ROM16(subent(3)) & 0xfff;
+                               perflvl->core   = perflvl->shader / 2;
+                               perflvl->unk0a  = ROM16(subent(4)) & 0xfff;
+                               perflvl->memory = ROM16(subent(5)) & 0xfff;
+                       }
+
+                       perflvl->core *= 1000;
+                       perflvl->shader *= 1000;
+                       perflvl->memory *= 1000;
+                       perflvl->unk0a *= 1000;
                        break;
                }
 
@@ -190,6 +266,16 @@ nouveau_perf_init(struct drm_device *dev)
                        }
                }
 
+               /* get the corresponding memory timings */
+               if (version > 0x15) {
+                       /* last 3 args are for < 0x40, ignored for >= 0x40 */
+                       perflvl->timing =
+                               nouveau_perf_timing(dev, &P,
+                                                   perflvl->memory / 1000,
+                                                   entry + perf[3],
+                                                   perf[5], perf[4]);
+               }
+
                snprintf(perflvl->name, sizeof(perflvl->name),
                         "performance_level_%d", i);
                perflvl->id = i;
index 4399e2f34db41068dd1769a06af1547b6603a263..da8d994d5e8a3f2b505a7d9fefa9f764a51112df 100644 (file)
@@ -156,7 +156,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 static void
 nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
 {
-       char c[16], s[16], v[16], f[16];
+       char c[16], s[16], v[16], f[16], t[16];
 
        c[0] = '\0';
        if (perflvl->core)
@@ -174,8 +174,12 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
        if (perflvl->fanspeed)
                snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
 
-       snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000,
-                c, s, v, f);
+       t[0] = '\0';
+       if (perflvl->timing)
+               snprintf(t, sizeof(t), " timing %d", perflvl->timing->id);
+
+       snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000,
+                c, s, v, f, t);
 }
 
 static ssize_t
@@ -449,7 +453,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
 #endif
 }
 
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
 static int
 nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
 {
@@ -476,10 +480,10 @@ nouveau_pm_init(struct drm_device *dev)
        char info[256];
        int ret, i;
 
+       nouveau_mem_timing_init(dev);
        nouveau_volt_init(dev);
        nouveau_perf_init(dev);
        nouveau_temp_init(dev);
-       nouveau_mem_timing_init(dev);
 
        NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
        for (i = 0; i < pm->nr_perflvl; i++) {
@@ -490,6 +494,7 @@ nouveau_pm_init(struct drm_device *dev)
        /* determine current ("boot") performance level */
        ret = nouveau_pm_perflvl_get(dev, &pm->boot);
        if (ret == 0) {
+               strncpy(pm->boot.name, "boot", 4);
                pm->cur = &pm->boot;
 
                nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
@@ -507,7 +512,7 @@ nouveau_pm_init(struct drm_device *dev)
 
        nouveau_sysfs_init(dev);
        nouveau_hwmon_init(dev);
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
        pm->acpi_nb.notifier_call = nouveau_pm_acpi_event;
        register_acpi_notifier(&pm->acpi_nb);
 #endif
@@ -524,12 +529,12 @@ nouveau_pm_fini(struct drm_device *dev)
        if (pm->cur != &pm->boot)
                nouveau_pm_perflvl_set(dev, &pm->boot);
 
-       nouveau_mem_timing_fini(dev);
        nouveau_temp_fini(dev);
        nouveau_perf_fini(dev);
        nouveau_volt_fini(dev);
+       nouveau_mem_timing_fini(dev);
 
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
        unregister_acpi_notifier(&pm->acpi_nb);
 #endif
        nouveau_hwmon_fini(dev);
index 04e8fb7952692ccfde1524439d12e51a7cd88f64..f18cdfc3400fc00894dd8f40c3e3239114e2a2e5 100644 (file)
 #    define NV50_PCONNECTOR_I2C_PORT_4                      0x0000e240
 #    define NV50_PCONNECTOR_I2C_PORT_5                      0x0000e258
 
-#define NV50_AUXCH_DATA_OUT(i,n)             ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
+#define NV50_AUXCH_DATA_OUT(i, n)            ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
 #define NV50_AUXCH_DATA_OUT__SIZE                                             4
-#define NV50_AUXCH_DATA_IN(i,n)              ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
+#define NV50_AUXCH_DATA_IN(i, n)             ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
 #define NV50_AUXCH_DATA_IN__SIZE                                              4
 #define NV50_AUXCH_ADDR(i)                             ((i) * 0x50 + 0x0000e4e0)
 #define NV50_AUXCH_CTRL(i)                             ((i) * 0x50 + 0x0000e4e4)
 #define NV50_PDISPLAY_SOR_BACKLIGHT                                  0x0061c084
 #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE                           0x80000000
 #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL                            0x00000fff
-#define NV50_SOR_DP_CTRL(i,l)            (0x0061c10c + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_CTRL(i, l)           (0x0061c10c + (i) * 0x800 + (l) * 0x80)
 #define NV50_SOR_DP_CTRL_ENABLED                                     0x00000001
 #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED                      0x00004000
 #define NV50_SOR_DP_CTRL_LANE_MASK                                   0x001f0000
 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_DISABLED                   0x00000000
 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_1                          0x01000000
 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2                          0x02000000
-#define NV50_SOR_DP_UNK118(i,l)          (0x0061c118 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK120(i,l)          (0x0061c120 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK128(i,l)          (0x0061c128 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK130(i,l)          (0x0061c130 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK118(i, l)         (0x0061c118 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK120(i, l)         (0x0061c120 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK128(i, l)         (0x0061c128 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK130(i, l)         (0x0061c130 + (i) * 0x800 + (l) * 0x80)
 
 #define NV50_PDISPLAY_USER(i)                        ((i) * 0x1000 + 0x00640000)
 #define NV50_PDISPLAY_USER_PUT(i)                    ((i) * 0x1000 + 0x00640000)
index 915fbce8959517f4c51a9114a8224617ecbe265b..38ea662568c1062a6486426408ef5648265e360a 100644 (file)
@@ -65,14 +65,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv04_fb_init;
                engine->fb.takedown             = nv04_fb_takedown;
-               engine->graph.init              = nv04_graph_init;
-               engine->graph.takedown          = nv04_graph_takedown;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.channel           = nv04_graph_channel;
-               engine->graph.create_context    = nv04_graph_create_context;
-               engine->graph.destroy_context   = nv04_graph_destroy_context;
-               engine->graph.load_context      = nv04_graph_load_context;
-               engine->graph.unload_context    = nv04_graph_unload_context;
                engine->fifo.channels           = 16;
                engine->fifo.init               = nv04_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -98,8 +90,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -123,15 +113,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv10_fb_init_tile_region;
                engine->fb.set_tile_region      = nv10_fb_set_tile_region;
                engine->fb.free_tile_region     = nv10_fb_free_tile_region;
-               engine->graph.init              = nv10_graph_init;
-               engine->graph.takedown          = nv10_graph_takedown;
-               engine->graph.channel           = nv10_graph_channel;
-               engine->graph.create_context    = nv10_graph_create_context;
-               engine->graph.destroy_context   = nv10_graph_destroy_context;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.load_context      = nv10_graph_load_context;
-               engine->graph.unload_context    = nv10_graph_unload_context;
-               engine->graph.set_tile_region   = nv10_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -157,8 +138,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -182,15 +161,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv10_fb_init_tile_region;
                engine->fb.set_tile_region      = nv10_fb_set_tile_region;
                engine->fb.free_tile_region     = nv10_fb_free_tile_region;
-               engine->graph.init              = nv20_graph_init;
-               engine->graph.takedown          = nv20_graph_takedown;
-               engine->graph.channel           = nv10_graph_channel;
-               engine->graph.create_context    = nv20_graph_create_context;
-               engine->graph.destroy_context   = nv20_graph_destroy_context;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.load_context      = nv20_graph_load_context;
-               engine->graph.unload_context    = nv20_graph_unload_context;
-               engine->graph.set_tile_region   = nv20_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -216,8 +186,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -241,15 +209,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv30_fb_init_tile_region;
                engine->fb.set_tile_region      = nv10_fb_set_tile_region;
                engine->fb.free_tile_region     = nv30_fb_free_tile_region;
-               engine->graph.init              = nv30_graph_init;
-               engine->graph.takedown          = nv20_graph_takedown;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.channel           = nv10_graph_channel;
-               engine->graph.create_context    = nv20_graph_create_context;
-               engine->graph.destroy_context   = nv20_graph_destroy_context;
-               engine->graph.load_context      = nv20_graph_load_context;
-               engine->graph.unload_context    = nv20_graph_unload_context;
-               engine->graph.set_tile_region   = nv20_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -277,8 +236,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_set            = nv04_pm_clock_set;
                engine->pm.voltage_get          = nouveau_voltage_gpio_get;
                engine->pm.voltage_set          = nouveau_voltage_gpio_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -303,15 +260,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv30_fb_init_tile_region;
                engine->fb.set_tile_region      = nv40_fb_set_tile_region;
                engine->fb.free_tile_region     = nv30_fb_free_tile_region;
-               engine->graph.init              = nv40_graph_init;
-               engine->graph.takedown          = nv40_graph_takedown;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.channel           = nv40_graph_channel;
-               engine->graph.create_context    = nv40_graph_create_context;
-               engine->graph.destroy_context   = nv40_graph_destroy_context;
-               engine->graph.load_context      = nv40_graph_load_context;
-               engine->graph.unload_context    = nv40_graph_unload_context;
-               engine->graph.set_tile_region   = nv40_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv40_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -340,8 +288,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.voltage_get          = nouveau_voltage_gpio_get;
                engine->pm.voltage_set          = nouveau_voltage_gpio_set;
                engine->pm.temp_get             = nv40_temp_get;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -368,19 +314,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv50_fb_init;
                engine->fb.takedown             = nv50_fb_takedown;
-               engine->graph.init              = nv50_graph_init;
-               engine->graph.takedown          = nv50_graph_takedown;
-               engine->graph.fifo_access       = nv50_graph_fifo_access;
-               engine->graph.channel           = nv50_graph_channel;
-               engine->graph.create_context    = nv50_graph_create_context;
-               engine->graph.destroy_context   = nv50_graph_destroy_context;
-               engine->graph.load_context      = nv50_graph_load_context;
-               engine->graph.unload_context    = nv50_graph_unload_context;
-               if (dev_priv->chipset == 0x50 ||
-                   dev_priv->chipset == 0xac)
-                       engine->graph.tlb_flush = nv50_graph_tlb_flush;
-               else
-                       engine->graph.tlb_flush = nv84_graph_tlb_flush;
                engine->fifo.channels           = 128;
                engine->fifo.init               = nv50_fifo_init;
                engine->fifo.takedown           = nv50_fifo_takedown;
@@ -432,24 +365,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                        engine->pm.temp_get     = nv84_temp_get;
                else
                        engine->pm.temp_get     = nv40_temp_get;
-               switch (dev_priv->chipset) {
-               case 0x84:
-               case 0x86:
-               case 0x92:
-               case 0x94:
-               case 0x96:
-               case 0xa0:
-                       engine->crypt.init      = nv84_crypt_init;
-                       engine->crypt.takedown  = nv84_crypt_fini;
-                       engine->crypt.create_context = nv84_crypt_create_context;
-                       engine->crypt.destroy_context = nv84_crypt_destroy_context;
-                       engine->crypt.tlb_flush = nv84_crypt_tlb_flush;
-                       break;
-               default:
-                       engine->crypt.init      = nouveau_stub_init;
-                       engine->crypt.takedown  = nouveau_stub_takedown;
-                       break;
-               }
                engine->vram.init               = nv50_vram_init;
                engine->vram.get                = nv50_vram_new;
                engine->vram.put                = nv50_vram_del;
@@ -472,14 +387,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nvc0_fb_init;
                engine->fb.takedown             = nvc0_fb_takedown;
-               engine->graph.init              = nvc0_graph_init;
-               engine->graph.takedown          = nvc0_graph_takedown;
-               engine->graph.fifo_access       = nvc0_graph_fifo_access;
-               engine->graph.channel           = nvc0_graph_channel;
-               engine->graph.create_context    = nvc0_graph_create_context;
-               engine->graph.destroy_context   = nvc0_graph_destroy_context;
-               engine->graph.load_context      = nvc0_graph_load_context;
-               engine->graph.unload_context    = nvc0_graph_unload_context;
                engine->fifo.channels           = 128;
                engine->fifo.init               = nvc0_fifo_init;
                engine->fifo.takedown           = nvc0_fifo_takedown;
@@ -503,8 +410,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.irq_register       = nv50_gpio_irq_register;
                engine->gpio.irq_unregister     = nv50_gpio_irq_unregister;
                engine->gpio.irq_enable         = nv50_gpio_irq_enable;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nvc0_vram_init;
                engine->vram.get                = nvc0_vram_new;
                engine->vram.put                = nv50_vram_del;
@@ -593,7 +498,7 @@ nouveau_card_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine;
-       int ret;
+       int ret, e = 0;
 
        vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
        vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
@@ -658,23 +563,80 @@ nouveau_card_init(struct drm_device *dev)
        if (ret)
                goto out_timer;
 
-       if (nouveau_noaccel)
-               engine->graph.accel_blocked = true;
-       else {
-               /* PGRAPH */
-               ret = engine->graph.init(dev);
-               if (ret)
-                       goto out_fb;
+       switch (dev_priv->card_type) {
+       case NV_04:
+               nv04_graph_create(dev);
+               break;
+       case NV_10:
+               nv10_graph_create(dev);
+               break;
+       case NV_20:
+       case NV_30:
+               nv20_graph_create(dev);
+               break;
+       case NV_40:
+               nv40_graph_create(dev);
+               break;
+       case NV_50:
+               nv50_graph_create(dev);
+               break;
+       case NV_C0:
+               nvc0_graph_create(dev);
+               break;
+       default:
+               break;
+       }
 
-               /* PCRYPT */
-               ret = engine->crypt.init(dev);
-               if (ret)
-                       goto out_graph;
+       switch (dev_priv->chipset) {
+       case 0x84:
+       case 0x86:
+       case 0x92:
+       case 0x94:
+       case 0x96:
+       case 0xa0:
+               nv84_crypt_create(dev);
+               break;
+       }
+
+       switch (dev_priv->card_type) {
+       case NV_50:
+               switch (dev_priv->chipset) {
+               case 0xa3:
+               case 0xa5:
+               case 0xa8:
+               case 0xaf:
+                       nva3_copy_create(dev);
+                       break;
+               }
+               break;
+       case NV_C0:
+               nvc0_copy_create(dev, 0);
+               nvc0_copy_create(dev, 1);
+               break;
+       default:
+               break;
+       }
+
+       if (dev_priv->card_type == NV_40)
+               nv40_mpeg_create(dev);
+       else
+       if (dev_priv->card_type == NV_50 &&
+           (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0))
+               nv50_mpeg_create(dev);
+
+       if (!nouveau_noaccel) {
+               for (e = 0; e < NVOBJ_ENGINE_NR; e++) {
+                       if (dev_priv->eng[e]) {
+                               ret = dev_priv->eng[e]->init(dev, e);
+                               if (ret)
+                                       goto out_engine;
+                       }
+               }
 
                /* PFIFO */
                ret = engine->fifo.init(dev);
                if (ret)
-                       goto out_crypt;
+                       goto out_engine;
        }
 
        ret = engine->display.create(dev);
@@ -691,7 +653,7 @@ nouveau_card_init(struct drm_device *dev)
 
        /* what about PVIDEO/PCRTC/PRAMDAC etc? */
 
-       if (!engine->graph.accel_blocked) {
+       if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
                ret = nouveau_fence_init(dev);
                if (ret)
                        goto out_irq;
@@ -715,13 +677,16 @@ out_vblank:
 out_fifo:
        if (!nouveau_noaccel)
                engine->fifo.takedown(dev);
-out_crypt:
-       if (!nouveau_noaccel)
-               engine->crypt.takedown(dev);
-out_graph:
-       if (!nouveau_noaccel)
-               engine->graph.takedown(dev);
-out_fb:
+out_engine:
+       if (!nouveau_noaccel) {
+               for (e = e - 1; e >= 0; e--) {
+                       if (!dev_priv->eng[e])
+                               continue;
+                       dev_priv->eng[e]->fini(dev, e);
+                       dev_priv->eng[e]->destroy(dev,e );
+               }
+       }
+
        engine->fb.takedown(dev);
 out_timer:
        engine->timer.takedown(dev);
@@ -751,16 +716,21 @@ static void nouveau_card_takedown(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
+       int e;
 
-       if (!engine->graph.accel_blocked) {
+       if (dev_priv->channel) {
                nouveau_fence_fini(dev);
                nouveau_channel_put_unlocked(&dev_priv->channel);
        }
 
        if (!nouveau_noaccel) {
                engine->fifo.takedown(dev);
-               engine->crypt.takedown(dev);
-               engine->graph.takedown(dev);
+               for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+                       if (dev_priv->eng[e]) {
+                               dev_priv->eng[e]->fini(dev, e);
+                               dev_priv->eng[e]->destroy(dev,e );
+                       }
+               }
        }
        engine->fb.takedown(dev);
        engine->timer.takedown(dev);
@@ -866,7 +836,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
 #ifdef CONFIG_X86
        primary = dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 #endif
-       
+
        remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb", primary);
        return 0;
 }
@@ -918,11 +888,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
 
        /* Time to determine the card architecture */
        reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
+       dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */
 
        /* We're dealing with >=NV10 */
        if ((reg0 & 0x0f000000) > 0) {
                /* Bit 27-20 contain the architecture in hex */
                dev_priv->chipset = (reg0 & 0xff00000) >> 20;
+               dev_priv->stepping = (reg0 & 0xff);
        /* NV04 or NV05 */
        } else if ((reg0 & 0xff00fff0) == 0x20004000) {
                if (reg0 & 0x00f00000)
index 2e06b55cfdc1844eb4e1a376890fa35912fb10ca..c48a9fc2b47b41eb870f17a7f9fa95c28a4daa20 100644 (file)
@@ -53,8 +53,7 @@ struct nouveau_vm {
        int refcount;
 
        struct list_head pgd_list;
-       atomic_t pgraph_refs;
-       atomic_t pcrypt_refs;
+       atomic_t engref[16];
 
        struct nouveau_vm_pgt *pgt;
        u32 fpde;
index 04fdc00a67d540324bb8a5ef4ee4fcf0d9b1ecfa..75e872741d9218c91aeb49c46dfd7f3f6268cdf2 100644 (file)
@@ -159,8 +159,16 @@ nouveau_volt_init(struct drm_device *dev)
                headerlen = volt[1];
                recordlen = volt[2];
                entries   = volt[3];
-               vidshift  = hweight8(volt[5]);
                vidmask   = volt[4];
+               /* no longer certain what volt[5] is, if it's related to
+                * the vid shift then it's definitely not a function of
+                * how many bits are set.
+                *
+                * after looking at a number of nva3+ vbios images, they
+                * all seem likely to have a static shift of 2.. lets
+                * go with that for now until proven otherwise.
+                */
+               vidshift  = 2;
                break;
        default:
                NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
index 748b9d9c2949df0f24a998e1caf0cfec2f929258..3c78bc81357e0e838ec933e330748d9bd019f661 100644 (file)
@@ -790,8 +790,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
        if (atomic) {
                drm_fb = passed_fb;
                fb = nouveau_framebuffer(passed_fb);
-       }
-       else {
+       } else {
                /* If not atomic, we can go ahead and pin, and unpin the
                 * old fb we were passed.
                 */
@@ -944,14 +943,14 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
        struct drm_gem_object *gem;
        int ret = 0;
 
-       if (width != 64 || height != 64)
-               return -EINVAL;
-
        if (!buffer_handle) {
                nv_crtc->cursor.hide(nv_crtc, true);
                return 0;
        }
 
+       if (width != 64 || height != 64)
+               return -EINVAL;
+
        gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
        if (!gem)
                return -ENOENT;
index af75015068d6bd89477d81f5a5b5aabae41c9a3b..3626ee7db3ba5924cfc5dcd5412b1d618203c5f7 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_hw.h"
 #include "nouveau_util.h"
+#include "nouveau_ramht.h"
 
-static int  nv04_graph_register(struct drm_device *dev);
-static void nv04_graph_isr(struct drm_device *dev);
+struct nv04_graph_engine {
+       struct nouveau_exec_engine base;
+};
 
 static uint32_t nv04_graph_ctx_regs[] = {
        0x0040053c,
@@ -350,7 +352,7 @@ struct graph_state {
        uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
 };
 
-struct nouveau_channel *
+static struct nouveau_channel *
 nv04_graph_channel(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -365,26 +367,6 @@ nv04_graph_channel(struct drm_device *dev)
        return dev_priv->channels.ptr[chid];
 }
 
-static void
-nv04_graph_context_switch(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_channel *chan = NULL;
-       int chid;
-
-       nouveau_wait_for_idle(dev);
-
-       /* If previous context is valid, we need to save it */
-       pgraph->unload_context(dev);
-
-       /* Load context for next channel */
-       chid = dev_priv->engine.fifo.channel_id(dev);
-       chan = dev_priv->channels.ptr[chid];
-       if (chan)
-               nv04_graph_load_context(chan);
-}
-
 static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
 {
        int i;
@@ -397,48 +379,11 @@ static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
        return NULL;
 }
 
-int nv04_graph_create_context(struct nouveau_channel *chan)
-{
-       struct graph_state *pgraph_ctx;
-       NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
-
-       chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
-                                               GFP_KERNEL);
-       if (pgraph_ctx == NULL)
-               return -ENOMEM;
-
-       *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
-
-       return 0;
-}
-
-void nv04_graph_destroy_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
-
-       /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
-
-       /* Free the context resources */
-       kfree(pgraph_ctx);
-       chan->pgraph_ctx = NULL;
-
-       pgraph->fifo_access(dev, true);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-}
-
-int nv04_graph_load_context(struct nouveau_channel *chan)
+static int
+nv04_graph_load_context(struct nouveau_channel *chan)
 {
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
        uint32_t tmp;
        int i;
 
@@ -456,20 +401,19 @@ int nv04_graph_load_context(struct nouveau_channel *chan)
        return 0;
 }
 
-int
+static int
 nv04_graph_unload_context(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_channel *chan = NULL;
        struct graph_state *ctx;
        uint32_t tmp;
        int i;
 
-       chan = pgraph->channel(dev);
+       chan = nv04_graph_channel(dev);
        if (!chan)
                return 0;
-       ctx = chan->pgraph_ctx;
+       ctx = chan->engctx[NVOBJ_ENGINE_GR];
 
        for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
                ctx->nv04[i] = nv_rd32(dev, nv04_graph_ctx_regs[i]);
@@ -481,23 +425,85 @@ nv04_graph_unload_context(struct drm_device *dev)
        return 0;
 }
 
-int nv04_graph_init(struct drm_device *dev)
+static int
+nv04_graph_context_new(struct nouveau_channel *chan, int engine)
 {
+       struct graph_state *pgraph_ctx;
+       NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
+
+       pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
+       if (pgraph_ctx == NULL)
+               return -ENOMEM;
+
+       *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
+
+       chan->engctx[engine] = pgraph_ctx;
+       return 0;
+}
+
+static void
+nv04_graph_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t tmp;
+       struct graph_state *pgraph_ctx = chan->engctx[engine];
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv04_graph_fifo_access(dev, false);
+
+       /* Unload the context if it's the currently active one */
+       if (nv04_graph_channel(dev) == chan)
+               nv04_graph_unload_context(dev);
+
+       nv04_graph_fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       /* Free the context resources */
+       kfree(pgraph_ctx);
+       chan->engctx[engine] = NULL;
+}
+
+int
+nv04_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct nouveau_gpuobj *obj = NULL;
        int ret;
 
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 1;
+       obj->class  = class;
+
+#ifdef __BIG_ENDIAN
+       nv_wo32(obj, 0x00, 0x00080000 | class);
+#else
+       nv_wo32(obj, 0x00, class);
+#endif
+       nv_wo32(obj, 0x04, 0x00000000);
+       nv_wo32(obj, 0x08, 0x00000000);
+       nv_wo32(obj, 0x0c, 0x00000000);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
+}
+
+static int
+nv04_graph_init(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t tmp;
+
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
                        ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
                         NV_PMC_ENABLE_PGRAPH);
 
-       ret = nv04_graph_register(dev);
-       if (ret)
-               return ret;
-
        /* Enable PGRAPH interrupts */
-       nouveau_irq_register(dev, 12, nv04_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -507,7 +513,7 @@ int nv04_graph_init(struct drm_device *dev)
        nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
        nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x1231c000);
        /*1231C000 blob, 001 haiku*/
-       //*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+       /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
        nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x72111100);
        /*0x72111100 blob , 01 haiku*/
        /*nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
@@ -531,10 +537,12 @@ int nv04_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void nv04_graph_takedown(struct drm_device *dev)
+static int
+nv04_graph_fini(struct drm_device *dev, int engine)
 {
+       nv04_graph_unload_context(dev);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
+       return 0;
 }
 
 void
@@ -969,13 +977,138 @@ nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan,
        return 1;
 }
 
-static int
-nv04_graph_register(struct drm_device *dev)
+static struct nouveau_bitfield nv04_graph_intr[] = {
+       { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+       {}
+};
+
+static struct nouveau_bitfield nv04_graph_nstatus[] = {
+       { NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
+       { NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
+       { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
+       { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
+       {}
+};
+
+struct nouveau_bitfield nv04_graph_nsource[] = {
+       { NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
+       { NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
+       { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
+       { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
+       { NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
+       { NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
+       { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
+       { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
+       { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
+       { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
+       { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
+       { NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
+       { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
+       { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
+       { NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
+       { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
+       { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
+       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
+       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
+       {}
+};
+
+static void
+nv04_graph_context_switch(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_channel *chan = NULL;
+       int chid;
 
-       if (dev_priv->engine.graph.registered)
-               return 0;
+       nouveau_wait_for_idle(dev);
+
+       /* If previous context is valid, we need to save it */
+       nv04_graph_unload_context(dev);
+
+       /* Load context for next channel */
+       chid = dev_priv->engine.fifo.channel_id(dev);
+       chan = dev_priv->channels.ptr[chid];
+       if (chan)
+               nv04_graph_load_context(chan);
+}
+
+static void
+nv04_graph_isr(struct drm_device *dev)
+{
+       u32 stat;
+
+       while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+               u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+               u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
+               u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+               u32 chid = (addr & 0x0f000000) >> 24;
+               u32 subc = (addr & 0x0000e000) >> 13;
+               u32 mthd = (addr & 0x00001ffc);
+               u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+               u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
+               u32 show = stat;
+
+               if (stat & NV_PGRAPH_INTR_NOTIFY) {
+                       if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+                               if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
+                                       show &= ~NV_PGRAPH_INTR_NOTIFY;
+                       }
+               }
+
+               if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+                       nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+                       stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+                       show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+                       nv04_graph_context_switch(dev);
+               }
+
+               nv_wr32(dev, NV03_PGRAPH_INTR, stat);
+               nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
+
+               if (show && nouveau_ratelimit()) {
+                       NV_INFO(dev, "PGRAPH -");
+                       nouveau_bitfield_print(nv04_graph_intr, show);
+                       printk(" nsource:");
+                       nouveau_bitfield_print(nv04_graph_nsource, nsource);
+                       printk(" nstatus:");
+                       nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
+                       printk("\n");
+                       NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
+                                    "mthd 0x%04x data 0x%08x\n",
+                               chid, subc, class, mthd, data);
+               }
+       }
+}
+
+static void
+nv04_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv04_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(pgraph);
+}
+
+int
+nv04_graph_create(struct drm_device *dev)
+{
+       struct nv04_graph_engine *pgraph;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv04_graph_destroy;
+       pgraph->base.init = nv04_graph_init;
+       pgraph->base.fini = nv04_graph_fini;
+       pgraph->base.context_new = nv04_graph_context_new;
+       pgraph->base.context_del = nv04_graph_context_del;
+       pgraph->base.object_new = nv04_graph_object_new;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv04_graph_isr);
 
        /* dvd subpicture */
        NVOBJ_CLASS(dev, 0x0038, GR);
@@ -1222,93 +1355,5 @@ nv04_graph_register(struct drm_device *dev)
        NVOBJ_CLASS(dev, 0x506e, SW);
        NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref);
        NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
        return 0;
-};
-
-static struct nouveau_bitfield nv04_graph_intr[] = {
-       { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
-       {}
-};
-
-static struct nouveau_bitfield nv04_graph_nstatus[] =
-{
-       { NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
-       { NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
-       { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
-       { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
-       {}
-};
-
-struct nouveau_bitfield nv04_graph_nsource[] =
-{
-       { NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
-       { NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
-       { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
-       { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
-       { NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
-       { NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
-       { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
-       { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
-       { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
-       { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
-       { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
-       { NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
-       { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
-       { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
-       { NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
-       { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
-       { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
-       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
-       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
-       {}
-};
-
-static void
-nv04_graph_isr(struct drm_device *dev)
-{
-       u32 stat;
-
-       while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-               u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-               u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-               u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-               u32 chid = (addr & 0x0f000000) >> 24;
-               u32 subc = (addr & 0x0000e000) >> 13;
-               u32 mthd = (addr & 0x00001ffc);
-               u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-               u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
-               u32 show = stat;
-
-               if (stat & NV_PGRAPH_INTR_NOTIFY) {
-                       if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-                               if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-                                       show &= ~NV_PGRAPH_INTR_NOTIFY;
-                       }
-               }
-
-               if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-                       nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-                       stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-                       show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-                       nv04_graph_context_switch(dev);
-               }
-
-               nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-               nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-               if (show && nouveau_ratelimit()) {
-                       NV_INFO(dev, "PGRAPH -");
-                       nouveau_bitfield_print(nv04_graph_intr, show);
-                       printk(" nsource:");
-                       nouveau_bitfield_print(nv04_graph_nsource, nsource);
-                       printk(" nstatus:");
-                       nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
-                       printk("\n");
-                       NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-                                    "mthd 0x%04x data 0x%08x\n",
-                               chid, subc, class, mthd, data);
-               }
-       }
 }
index b8e3edb5c063f2bb2f704485e6336779848c29ac..b8611b9553131b1df7669f394586dc8e4e80abff 100644 (file)
@@ -95,6 +95,9 @@ nv04_instmem_takedown(struct drm_device *dev)
        nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
        nouveau_gpuobj_ref(NULL, &dev_priv->ramro);
        nouveau_gpuobj_ref(NULL, &dev_priv->ramfc);
+
+       if (drm_mm_initialized(&dev_priv->ramin_heap))
+               drm_mm_takedown(&dev_priv->ramin_heap);
 }
 
 int
index 8c92edb7bbcd1833dcc2c823f230793b243e86e1..0930c6cb88e079cb6b6d2f4aaca45a55b1c0ca7d 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_util.h"
 
-static int  nv10_graph_register(struct drm_device *);
-static void nv10_graph_isr(struct drm_device *);
-
-#define NV10_FIFO_NUMBER 32
+struct nv10_graph_engine {
+       struct nouveau_exec_engine base;
+};
 
 struct pipe_state {
        uint32_t pipe_0x0000[0x040/4];
@@ -414,9 +413,9 @@ struct graph_state {
 
 static void nv10_graph_save_pipe(struct nouveau_channel *chan)
 {
-       struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+       struct drm_device *dev = chan->dev;
 
        PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
        PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
@@ -432,9 +431,9 @@ static void nv10_graph_save_pipe(struct nouveau_channel *chan)
 
 static void nv10_graph_load_pipe(struct nouveau_channel *chan)
 {
-       struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+       struct drm_device *dev = chan->dev;
        uint32_t xfmode0, xfmode1;
        int i;
 
@@ -482,9 +481,9 @@ static void nv10_graph_load_pipe(struct nouveau_channel *chan)
 
 static void nv10_graph_create_pipe(struct nouveau_channel *chan)
 {
-       struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
+       struct drm_device *dev = chan->dev;
        uint32_t *fifo_pipe_state_addr;
        int i;
 #define PIPE_INIT(addr) \
@@ -661,8 +660,6 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
                                       uint32_t inst)
 {
        struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
        uint32_t ctx_user, ctx_switch[5];
        int i, subchan = -1;
@@ -711,8 +708,8 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
                0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
        nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
        nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
-       pgraph->fifo_access(dev, true);
-       pgraph->fifo_access(dev, false);
+       nv04_graph_fifo_access(dev, true);
+       nv04_graph_fifo_access(dev, false);
 
        /* Restore the FIFO state */
        for (i = 0; i < ARRAY_SIZE(fifo); i++)
@@ -729,11 +726,12 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
        nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
 }
 
-int nv10_graph_load_context(struct nouveau_channel *chan)
+static int
+nv10_graph_load_context(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        uint32_t tmp;
        int i;
 
@@ -757,21 +755,20 @@ int nv10_graph_load_context(struct nouveau_channel *chan)
        return 0;
 }
 
-int
+static int
 nv10_graph_unload_context(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_channel *chan;
        struct graph_state *ctx;
        uint32_t tmp;
        int i;
 
-       chan = pgraph->channel(dev);
+       chan = nv10_graph_channel(dev);
        if (!chan)
                return 0;
-       ctx = chan->pgraph_ctx;
+       ctx = chan->engctx[NVOBJ_ENGINE_GR];
 
        for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
                ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]);
@@ -805,7 +802,7 @@ nv10_graph_context_switch(struct drm_device *dev)
        /* Load context for next channel */
        chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
        chan = dev_priv->channels.ptr[chid];
-       if (chan && chan->pgraph_ctx)
+       if (chan && chan->engctx[NVOBJ_ENGINE_GR])
                nv10_graph_load_context(chan);
 }
 
@@ -836,7 +833,8 @@ nv10_graph_channel(struct drm_device *dev)
        return dev_priv->channels.ptr[chid];
 }
 
-int nv10_graph_create_context(struct nouveau_channel *chan)
+static int
+nv10_graph_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -844,11 +842,10 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
 
        NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id);
 
-       chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
-                                               GFP_KERNEL);
+       pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
        if (pgraph_ctx == NULL)
                return -ENOMEM;
-
+       chan->engctx[engine] = pgraph_ctx;
 
        NV_WRITE_CTX(0x00400e88, 0x08000000);
        NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
@@ -873,30 +870,30 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
        return 0;
 }
 
-void nv10_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv10_graph_context_del(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[engine];
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
+       nv04_graph_fifo_access(dev, false);
 
        /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
+       if (nv10_graph_channel(dev) == chan)
+               nv10_graph_unload_context(dev);
+
+       nv04_graph_fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        /* Free the context resources */
+       chan->engctx[engine] = NULL;
        kfree(pgraph_ctx);
-       chan->pgraph_ctx = NULL;
-
-       pgraph->fifo_access(dev, true);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 }
 
-void
+static void
 nv10_graph_set_tile_region(struct drm_device *dev, int i)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -907,22 +904,18 @@ nv10_graph_set_tile_region(struct drm_device *dev, int i)
        nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr);
 }
 
-int nv10_graph_init(struct drm_device *dev)
+static int
+nv10_graph_init(struct drm_device *dev, int engine)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t tmp;
-       int ret, i;
+       u32 tmp;
+       int i;
 
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
                        ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
                         NV_PMC_ENABLE_PGRAPH);
 
-       ret = nv10_graph_register(dev);
-       if (ret)
-               return ret;
-
-       nouveau_irq_register(dev, 12, nv10_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -963,18 +956,20 @@ int nv10_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void nv10_graph_takedown(struct drm_device *dev)
+static int
+nv10_graph_fini(struct drm_device *dev, int engine)
 {
+       nv10_graph_unload_context(dev);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
+       return 0;
 }
 
 static int
 nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
                           u32 class, u32 mthd, u32 data)
 {
+       struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
-       struct graph_state *ctx = chan->pgraph_ctx;
        struct pipe_state *pipe = &ctx->pipe_state;
        uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
        uint32_t xfmode0, xfmode1;
@@ -1061,64 +1056,13 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
        return 0;
 }
 
-static int
-nv10_graph_register(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
-       NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
-       NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
-       NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
-
-       /* celcius */
-       if (dev_priv->chipset <= 0x10) {
-               NVOBJ_CLASS(dev, 0x0056, GR);
-       } else
-       if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
-               NVOBJ_CLASS(dev, 0x0096, GR);
-       } else {
-               NVOBJ_CLASS(dev, 0x0099, GR);
-               NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
-       }
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
-       return 0;
-}
-
 struct nouveau_bitfield nv10_graph_intr[] = {
        { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
        { NV_PGRAPH_INTR_ERROR,  "ERROR"  },
        {}
 };
 
-struct nouveau_bitfield nv10_graph_nstatus[] =
-{
+struct nouveau_bitfield nv10_graph_nstatus[] = {
        { NV10_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
        { NV10_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
        { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
@@ -1173,3 +1117,73 @@ nv10_graph_isr(struct drm_device *dev)
                }
        }
 }
+
+static void
+nv10_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv10_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+       kfree(pgraph);
+}
+
+int
+nv10_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv10_graph_engine *pgraph;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv10_graph_destroy;
+       pgraph->base.init = nv10_graph_init;
+       pgraph->base.fini = nv10_graph_fini;
+       pgraph->base.context_new = nv10_graph_context_new;
+       pgraph->base.context_del = nv10_graph_context_del;
+       pgraph->base.object_new = nv04_graph_object_new;
+       pgraph->base.set_tile_region = nv10_graph_set_tile_region;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv10_graph_isr);
+
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+       NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
+       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+       NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
+       NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
+       NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
+       NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
+
+       /* celcius */
+       if (dev_priv->chipset <= 0x10) {
+               NVOBJ_CLASS(dev, 0x0056, GR);
+       } else
+       if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
+               NVOBJ_CLASS(dev, 0x0096, GR);
+       } else {
+               NVOBJ_CLASS(dev, 0x0099, GR);
+               NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
+       }
+
+       return 0;
+}
index 8464b76798d5e4746af344ef260526a4b97fdee9..affc7d7dd0291d1707a6e714eb5e57294fbcc807 100644 (file)
  *
  */
 
+struct nv20_graph_engine {
+       struct nouveau_exec_engine base;
+       struct nouveau_gpuobj *ctxtab;
+       void (*grctx_init)(struct nouveau_gpuobj *);
+       u32 grctx_size;
+       u32 grctx_user;
+};
+
 #define NV20_GRCTX_SIZE (3580*4)
 #define NV25_GRCTX_SIZE (3529*4)
 #define NV2A_GRCTX_SIZE (3500*4)
 #define NV34_GRCTX_SIZE    (18140)
 #define NV35_36_GRCTX_SIZE (22396)
 
-static int nv20_graph_register(struct drm_device *);
-static int nv30_graph_register(struct drm_device *);
-static void nv20_graph_isr(struct drm_device *);
+int
+nv20_graph_unload_context(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+       struct nouveau_channel *chan;
+       struct nouveau_gpuobj *grctx;
+       u32 tmp;
+
+       chan = nv10_graph_channel(dev);
+       if (!chan)
+               return 0;
+       grctx = chan->engctx[NVOBJ_ENGINE_GR];
+
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, grctx->pinst >> 4);
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
+                    NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
+
+       nouveau_wait_for_idle(dev);
+
+       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+       tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
+       tmp |= (pfifo->channels - 1) << 24;
+       nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
+       return 0;
+}
+
+static void
+nv20_graph_rdi(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       int i, writecount = 32;
+       uint32_t rdi_index = 0x2c80000;
+
+       if (dev_priv->chipset == 0x20) {
+               rdi_index = 0x3d0000;
+               writecount = 15;
+       }
+
+       nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
+       for (i = 0; i < writecount; i++)
+               nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
+
+       nouveau_wait_for_idle(dev);
+}
 
 static void
-nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv20_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -87,7 +137,7 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv25_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -146,7 +196,7 @@ nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv2a_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -196,7 +246,7 @@ nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv30_31_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -254,7 +304,7 @@ nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv34_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -312,7 +362,7 @@ nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv35_36_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -370,148 +420,57 @@ nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 int
-nv20_graph_create_context(struct nouveau_channel *chan)
+nv20_graph_context_new(struct nouveau_channel *chan, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+       struct nouveau_gpuobj *grctx = NULL;
        struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
-       unsigned int idoffs = 0x28;
        int ret;
 
-       switch (dev_priv->chipset) {
-       case 0x20:
-               ctx_init = nv20_graph_context_init;
-               idoffs = 0;
-               break;
-       case 0x25:
-       case 0x28:
-               ctx_init = nv25_graph_context_init;
-               break;
-       case 0x2a:
-               ctx_init = nv2a_graph_context_init;
-               idoffs = 0;
-               break;
-       case 0x30:
-       case 0x31:
-               ctx_init = nv30_31_graph_context_init;
-               break;
-       case 0x34:
-               ctx_init = nv34_graph_context_init;
-               break;
-       case 0x35:
-       case 0x36:
-               ctx_init = nv35_36_graph_context_init;
-               break;
-       default:
-               BUG_ON(1);
-       }
-
-       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
-                                NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
+       ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+                                NVOBJ_FLAG_ZERO_ALLOC, &grctx);
        if (ret)
                return ret;
 
        /* Initialise default context values */
-       ctx_init(dev, chan->ramin_grctx);
+       pgraph->grctx_init(grctx);
 
        /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
-       nv_wo32(chan->ramin_grctx, idoffs,
-               (chan->id << 24) | 0x1); /* CTX_USER */
+       /* CTX_USER */
+       nv_wo32(grctx, pgraph->grctx_user, (chan->id << 24) | 0x1);
 
-       nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4);
+       nv_wo32(pgraph->ctxtab, chan->id * 4, grctx->pinst >> 4);
+       chan->engctx[engine] = grctx;
        return 0;
 }
 
 void
-nv20_graph_destroy_context(struct nouveau_channel *chan)
+nv20_graph_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+       struct nouveau_gpuobj *grctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
+       nv04_graph_fifo_access(dev, false);
 
        /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
+       if (nv10_graph_channel(dev) == chan)
+               nv20_graph_unload_context(dev);
 
-       pgraph->fifo_access(dev, true);
+       nv04_graph_fifo_access(dev, true);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        /* Free the context resources */
-       nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
-       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
-int
-nv20_graph_load_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       uint32_t inst;
+       nv_wo32(pgraph->ctxtab, chan->id * 4, 0);
 
-       if (!chan->ramin_grctx)
-               return -EINVAL;
-       inst = chan->ramin_grctx->pinst >> 4;
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
-                    NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD);
-       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-
-       nouveau_wait_for_idle(dev);
-       return 0;
-}
-
-int
-nv20_graph_unload_context(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_channel *chan;
-       uint32_t inst, tmp;
-
-       chan = pgraph->channel(dev);
-       if (!chan)
-               return 0;
-       inst = chan->ramin_grctx->pinst >> 4;
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
-                    NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
-
-       nouveau_wait_for_idle(dev);
-
-       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
-       tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-       tmp |= (pfifo->channels - 1) << 24;
-       nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
-       return 0;
+       nouveau_gpuobj_ref(NULL, &grctx);
+       chan->engctx[engine] = NULL;
 }
 
 static void
-nv20_graph_rdi(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int i, writecount = 32;
-       uint32_t rdi_index = 0x2c80000;
-
-       if (dev_priv->chipset == 0x20) {
-               rdi_index = 0x3d0000;
-               writecount = 15;
-       }
-
-       nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
-       for (i = 0; i < writecount; i++)
-               nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
-
-       nouveau_wait_for_idle(dev);
-}
-
-void
 nv20_graph_set_tile_region(struct drm_device *dev, int i)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -536,56 +495,22 @@ nv20_graph_set_tile_region(struct drm_device *dev, int i)
 }
 
 int
-nv20_graph_init(struct drm_device *dev)
+nv20_graph_init(struct drm_device *dev, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        uint32_t tmp, vramsz;
-       int ret, i;
-
-       switch (dev_priv->chipset) {
-       case 0x20:
-               pgraph->grctx_size = NV20_GRCTX_SIZE;
-               break;
-       case 0x25:
-       case 0x28:
-               pgraph->grctx_size = NV25_GRCTX_SIZE;
-               break;
-       case 0x2a:
-               pgraph->grctx_size = NV2A_GRCTX_SIZE;
-               break;
-       default:
-               NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
-               pgraph->accel_blocked = true;
-               return 0;
-       }
+       int i;
 
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
 
-       if (!pgraph->ctx_table) {
-               /* Create Context Pointer Table */
-               ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
-                                        NVOBJ_FLAG_ZERO_ALLOC,
-                                        &pgraph->ctx_table);
-               if (ret)
-                       return ret;
-       }
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-                    pgraph->ctx_table->pinst >> 4);
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
 
        nv20_graph_rdi(dev);
 
-       ret = nv20_graph_register(dev);
-       if (ret) {
-               nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-               return ret;
-       }
-
-       nouveau_irq_register(dev, 12, nv20_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -657,67 +582,20 @@ nv20_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void
-nv20_graph_takedown(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-
-       nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
-
-       nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-}
-
 int
-nv30_graph_init(struct drm_device *dev)
+nv30_graph_init(struct drm_device *dev, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       int ret, i;
-
-       switch (dev_priv->chipset) {
-       case 0x30:
-       case 0x31:
-               pgraph->grctx_size = NV30_31_GRCTX_SIZE;
-               break;
-       case 0x34:
-               pgraph->grctx_size = NV34_GRCTX_SIZE;
-               break;
-       case 0x35:
-       case 0x36:
-               pgraph->grctx_size = NV35_36_GRCTX_SIZE;
-               break;
-       default:
-               NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
-               pgraph->accel_blocked = true;
-               return 0;
-       }
+       int i;
 
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
 
-       if (!pgraph->ctx_table) {
-               /* Create Context Pointer Table */
-               ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
-                                        NVOBJ_FLAG_ZERO_ALLOC,
-                                        &pgraph->ctx_table);
-               if (ret)
-                       return ret;
-       }
-
-       ret = nv30_graph_register(dev);
-       if (ret) {
-               nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-               return ret;
-       }
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
 
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-                    pgraph->ctx_table->pinst >> 4);
-
-       nouveau_irq_register(dev, 12, nv20_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -775,85 +653,11 @@ nv30_graph_init(struct drm_device *dev)
        return 0;
 }
 
-static int
-nv20_graph_register(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
-       NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
-
-       /* kelvin */
-       if (dev_priv->chipset < 0x25)
-               NVOBJ_CLASS(dev, 0x0097, GR);
-       else
-               NVOBJ_CLASS(dev, 0x0597, GR);
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
-       return 0;
-}
-
-static int
-nv30_graph_register(struct drm_device *dev)
+int
+nv20_graph_fini(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
-
-       /* rankine */
-       if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
-               NVOBJ_CLASS(dev, 0x0397, GR);
-       else
-       if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
-               NVOBJ_CLASS(dev, 0x0697, GR);
-       else
-       if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
-               NVOBJ_CLASS(dev, 0x0497, GR);
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
+       nv20_graph_unload_context(dev);
+       nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
        return 0;
 }
 
@@ -897,3 +701,135 @@ nv20_graph_isr(struct drm_device *dev)
                }
        }
 }
+
+static void
+nv20_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+       nouveau_gpuobj_ref(NULL, &pgraph->ctxtab);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(pgraph);
+}
+
+int
+nv20_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv20_graph_engine *pgraph;
+       int ret;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv20_graph_destroy;
+       pgraph->base.fini = nv20_graph_fini;
+       pgraph->base.context_new = nv20_graph_context_new;
+       pgraph->base.context_del = nv20_graph_context_del;
+       pgraph->base.object_new = nv04_graph_object_new;
+       pgraph->base.set_tile_region = nv20_graph_set_tile_region;
+
+       pgraph->grctx_user = 0x0028;
+       if (dev_priv->card_type == NV_20) {
+               pgraph->base.init = nv20_graph_init;
+               switch (dev_priv->chipset) {
+               case 0x20:
+                       pgraph->grctx_init = nv20_graph_context_init;
+                       pgraph->grctx_size = NV20_GRCTX_SIZE;
+                       pgraph->grctx_user = 0x0000;
+                       break;
+               case 0x25:
+               case 0x28:
+                       pgraph->grctx_init = nv25_graph_context_init;
+                       pgraph->grctx_size = NV25_GRCTX_SIZE;
+                       break;
+               case 0x2a:
+                       pgraph->grctx_init = nv2a_graph_context_init;
+                       pgraph->grctx_size = NV2A_GRCTX_SIZE;
+                       pgraph->grctx_user = 0x0000;
+                       break;
+               default:
+                       NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+                       return 0;
+               }
+       } else {
+               pgraph->base.init = nv30_graph_init;
+               switch (dev_priv->chipset) {
+               case 0x30:
+               case 0x31:
+                       pgraph->grctx_init = nv30_31_graph_context_init;
+                       pgraph->grctx_size = NV30_31_GRCTX_SIZE;
+                       break;
+               case 0x34:
+                       pgraph->grctx_init = nv34_graph_context_init;
+                       pgraph->grctx_size = NV34_GRCTX_SIZE;
+                       break;
+               case 0x35:
+               case 0x36:
+                       pgraph->grctx_init = nv35_36_graph_context_init;
+                       pgraph->grctx_size = NV35_36_GRCTX_SIZE;
+                       break;
+               default:
+                       NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+                       return 0;
+               }
+       }
+
+       /* Create Context Pointer Table */
+       ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC,
+                                &pgraph->ctxtab);
+       if (ret) {
+               kfree(pgraph);
+               return ret;
+       }
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv20_graph_isr);
+
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+       if (dev_priv->card_type == NV_20) {
+               NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
+               NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
+
+               /* kelvin */
+               if (dev_priv->chipset < 0x25)
+                       NVOBJ_CLASS(dev, 0x0097, GR);
+               else
+                       NVOBJ_CLASS(dev, 0x0597, GR);
+       } else {
+               NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
+               NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
+               NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
+               NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
+
+               /* rankine */
+               if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
+                       NVOBJ_CLASS(dev, 0x0397, GR);
+               else
+               if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
+                       NVOBJ_CLASS(dev, 0x0697, GR);
+               else
+               if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
+                       NVOBJ_CLASS(dev, 0x0497, GR);
+       }
+
+       return 0;
+}
index 49b9a35a9cd6c79857fab54e69590f3e046cac53..68cb2d991c88c5c865062ed9bc5d88f14c242357 100644 (file)
@@ -115,6 +115,7 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
        nv_wr32(dev, 0x32e8, nv_ri32(dev, fc + 68));
        nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
        nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
+       nv_wr32(dev, 0x330c, nv_ri32(dev, fc + 84));
 
        nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
        nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
@@ -186,6 +187,7 @@ nv40_fifo_unload_context(struct drm_device *dev)
        tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
        nv_wi32(dev, fc + 72, tmp);
 #endif
+       nv_wi32(dev, fc + 84, nv_rd32(dev, 0x330c));
 
        nv40_fifo_do_load_context(dev, pfifo->channels - 1);
        nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
index fceb44c0ec748d2f1499dc6255983339c675c830..5beb01b8ace1387bd04639a7b49be90d28bd4d9f 100644 (file)
 #include "drm.h"
 #include "nouveau_drv.h"
 #include "nouveau_grctx.h"
+#include "nouveau_ramht.h"
 
-static int nv40_graph_register(struct drm_device *);
-static void nv40_graph_isr(struct drm_device *);
+struct nv40_graph_engine {
+       struct nouveau_exec_engine base;
+       u32 grctx_size;
+};
 
-struct nouveau_channel *
+static struct nouveau_channel *
 nv40_graph_channel(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *grctx;
        uint32_t inst;
        int i;
 
@@ -45,74 +49,17 @@ nv40_graph_channel(struct drm_device *dev)
        inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
 
        for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+               if (!dev_priv->channels.ptr[i])
+                       continue;
 
-               if (chan && chan->ramin_grctx &&
-                   chan->ramin_grctx->pinst == inst)
-                       return chan;
+               grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
+               if (grctx && grctx->pinst == inst)
+                       return dev_priv->channels.ptr[i];
        }
 
        return NULL;
 }
 
-int
-nv40_graph_create_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_grctx ctx = {};
-       unsigned long flags;
-       int ret;
-
-       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
-                                NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
-       if (ret)
-               return ret;
-
-       /* Initialise default context values */
-       ctx.dev = chan->dev;
-       ctx.mode = NOUVEAU_GRCTX_VALS;
-       ctx.data = chan->ramin_grctx;
-       nv40_grctx_init(&ctx);
-
-       nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
-
-       /* init grctx pointer in ramfc, and on PFIFO if channel is
-        * already active there
-        */
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       nv_wo32(chan->ramfc, 0x38, chan->ramin_grctx->pinst >> 4);
-       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
-       if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
-               nv_wr32(dev, 0x0032e0, chan->ramin_grctx->pinst >> 4);
-       nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-       return 0;
-}
-
-void
-nv40_graph_destroy_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
-
-       /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
-
-       pgraph->fifo_access(dev, true);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-       /* Free the context resources */
-       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
 static int
 nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
 {
@@ -154,57 +101,115 @@ nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
        return 0;
 }
 
-/* Restore the context for a specific channel into PGRAPH */
-int
-nv40_graph_load_context(struct nouveau_channel *chan)
+static int
+nv40_graph_unload_context(struct drm_device *dev)
 {
-       struct drm_device *dev = chan->dev;
        uint32_t inst;
        int ret;
 
-       if (!chan->ramin_grctx)
-               return -EINVAL;
-       inst = chan->ramin_grctx->pinst >> 4;
+       inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
+       if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
+               return 0;
+       inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+       ret = nv40_graph_transfer_context(dev, inst, 1);
+
+       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+       return ret;
+}
+
+static int
+nv40_graph_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine);
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *grctx = NULL;
+       struct nouveau_grctx ctx = {};
+       unsigned long flags;
+       int ret;
 
-       ret = nv40_graph_transfer_context(dev, inst, 0);
+       ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+                                NVOBJ_FLAG_ZERO_ALLOC, &grctx);
        if (ret)
                return ret;
 
-       /* 0x40032C, no idea of it's exact function.  Could simply be a
-        * record of the currently active PGRAPH context.  It's currently
-        * unknown as to what bit 24 does.  The nv ddx has it set, so we will
-        * set it here too.
-        */
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR,
-                (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) |
-                 NV40_PGRAPH_CTXCTL_CUR_LOADED);
-       /* 0x32E0 records the instance address of the active FIFO's PGRAPH
-        * context.  If at any time this doesn't match 0x40032C, you will
-        * receive PGRAPH_INTR_CONTEXT_SWITCH
+       /* Initialise default context values */
+       ctx.dev = chan->dev;
+       ctx.mode = NOUVEAU_GRCTX_VALS;
+       ctx.data = grctx;
+       nv40_grctx_init(&ctx);
+
+       nv_wo32(grctx, 0, grctx->vinst);
+
+       /* init grctx pointer in ramfc, and on PFIFO if channel is
+        * already active there
         */
-       nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, inst);
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_wo32(chan->ramfc, 0x38, grctx->vinst >> 4);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+       if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
+               nv_wr32(dev, 0x0032e0, grctx->vinst >> 4);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       chan->engctx[engine] = grctx;
        return 0;
 }
 
-int
-nv40_graph_unload_context(struct drm_device *dev)
+static void
+nv40_graph_context_del(struct nouveau_channel *chan, int engine)
 {
-       uint32_t inst;
-       int ret;
+       struct nouveau_gpuobj *grctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       unsigned long flags;
 
-       inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
-               return 0;
-       inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv04_graph_fifo_access(dev, false);
 
-       ret = nv40_graph_transfer_context(dev, inst, 1);
+       /* Unload the context if it's the currently active one */
+       if (nv40_graph_channel(dev) == chan)
+               nv40_graph_unload_context(dev);
 
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+       nv04_graph_fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       /* Free the context resources */
+       nouveau_gpuobj_ref(NULL, &grctx);
+       chan->engctx[engine] = NULL;
+}
+
+int
+nv40_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 1;
+       obj->class  = class;
+
+       nv_wo32(obj, 0x00, class);
+       nv_wo32(obj, 0x04, 0x00000000);
+#ifndef __BIG_ENDIAN
+       nv_wo32(obj, 0x08, 0x00000000);
+#else
+       nv_wo32(obj, 0x08, 0x01000000);
+#endif
+       nv_wo32(obj, 0x0c, 0x00000000);
+       nv_wo32(obj, 0x10, 0x00000000);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
        return ret;
 }
 
-void
+static void
 nv40_graph_set_tile_region(struct drm_device *dev, int i)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -257,14 +262,14 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
  * C51         0x4e
  */
 int
-nv40_graph_init(struct drm_device *dev)
+nv40_graph_init(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv =
-               (struct drm_nouveau_private *)dev->dev_private;
+       struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
        struct nouveau_grctx ctx = {};
        uint32_t vramsz, *cp;
-       int ret, i, j;
+       int i, j;
 
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
                        ~NV_PMC_ENABLE_PGRAPH);
@@ -280,7 +285,7 @@ nv40_graph_init(struct drm_device *dev)
        ctx.data = cp;
        ctx.ctxprog_max = 256;
        nv40_grctx_init(&ctx);
-       dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+       pgraph->grctx_size = ctx.ctxvals_pos * 4;
 
        nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
        for (i = 0; i < ctx.ctxprog_len; i++)
@@ -288,14 +293,9 @@ nv40_graph_init(struct drm_device *dev)
 
        kfree(cp);
 
-       ret = nv40_graph_register(dev);
-       if (ret)
-               return ret;
-
        /* No context present currently */
        nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
 
-       nouveau_irq_register(dev, 12, nv40_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -428,47 +428,10 @@ nv40_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void nv40_graph_takedown(struct drm_device *dev)
-{
-       nouveau_irq_unregister(dev, 12);
-}
-
 static int
-nv40_graph_register(struct drm_device *dev)
+nv40_graph_fini(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
-
-       /* curie */
-       if (nv44_graph_class(dev))
-               NVOBJ_CLASS(dev, 0x4497, GR);
-       else
-               NVOBJ_CLASS(dev, 0x4097, GR);
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
+       nv40_graph_unload_context(dev);
        return 0;
 }
 
@@ -476,17 +439,17 @@ static int
 nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_channel *chan;
+       struct nouveau_gpuobj *grctx;
        unsigned long flags;
        int i;
 
        spin_lock_irqsave(&dev_priv->channels.lock, flags);
        for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               chan = dev_priv->channels.ptr[i];
-               if (!chan || !chan->ramin_grctx)
+               if (!dev_priv->channels.ptr[i])
                        continue;
+               grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
 
-               if (inst == chan->ramin_grctx->pinst)
+               if (grctx && grctx->pinst == inst)
                        break;
        }
        spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
@@ -537,3 +500,63 @@ nv40_graph_isr(struct drm_device *dev)
                }
        }
 }
+
+static void
+nv40_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(pgraph);
+}
+
+int
+nv40_graph_create(struct drm_device *dev)
+{
+       struct nv40_graph_engine *pgraph;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv40_graph_destroy;
+       pgraph->base.init = nv40_graph_init;
+       pgraph->base.fini = nv40_graph_fini;
+       pgraph->base.context_new = nv40_graph_context_new;
+       pgraph->base.context_del = nv40_graph_context_del;
+       pgraph->base.object_new = nv40_graph_object_new;
+       pgraph->base.set_tile_region = nv40_graph_set_tile_region;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv40_graph_isr);
+
+       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+       NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
+       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+       NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
+       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+       NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
+
+       /* curie */
+       if (nv44_graph_class(dev))
+               NVOBJ_CLASS(dev, 0x4497, GR);
+       else
+               NVOBJ_CLASS(dev, 0x4097, GR);
+
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c
new file mode 100644 (file)
index 0000000..6d2af29
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv40_mpeg_engine {
+       struct nouveau_exec_engine base;
+};
+
+static int
+nv40_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ctx = NULL;
+       unsigned long flags;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ctx, 0x78, 0x02001ec1);
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+       if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id)
+               nv_wr32(dev, 0x00330c, ctx->pinst >> 4);
+       nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static void
+nv40_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       unsigned long flags;
+       u32 inst = 0x80000000 | (ctx->pinst >> 4);
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       if (nv_rd32(dev, 0x00b318) == inst)
+               nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       nouveau_gpuobj_ref(NULL, &ctx);
+       chan->engctx[engine] = NULL;
+}
+
+static int
+nv40_mpeg_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 2;
+       obj->class  = class;
+
+       nv_wo32(obj, 0x00, class);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
+}
+
+static int
+nv40_mpeg_init(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+       int i;
+
+       /* VPE init */
+       nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
+       nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+       nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+
+       for (i = 0; i < dev_priv->engine.fb.num_tiles; i++)
+               pmpeg->base.set_tile_region(dev, i);
+
+       /* PMPEG init */
+       nv_wr32(dev, 0x00b32c, 0x00000000);
+       nv_wr32(dev, 0x00b314, 0x00000100);
+       nv_wr32(dev, 0x00b220, 0x00000044);
+       nv_wr32(dev, 0x00b300, 0x02001ec1);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+       nv_wr32(dev, 0x00b100, 0xffffffff);
+       nv_wr32(dev, 0x00b140, 0xffffffff);
+
+       if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int
+nv40_mpeg_fini(struct drm_device *dev, int engine)
+{
+       /*XXX: context save? */
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       nv_wr32(dev, 0x00b140, 0x00000000);
+       return 0;
+}
+
+static int
+nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+       struct drm_device *dev = chan->dev;
+       u32 inst = data << 4;
+       u32 dma0 = nv_ri32(dev, inst + 0);
+       u32 dma1 = nv_ri32(dev, inst + 4);
+       u32 dma2 = nv_ri32(dev, inst + 8);
+       u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+       u32 size = dma1 + 1;
+
+       /* only allow linear DMA objects */
+       if (!(dma0 & 0x00002000))
+               return -EINVAL;
+
+       if (mthd == 0x0190) {
+               /* DMA_CMD */
+               nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+               nv_wr32(dev, 0x00b334, base);
+               nv_wr32(dev, 0x00b324, size);
+       } else
+       if (mthd == 0x01a0) {
+               /* DMA_DATA */
+               nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+               nv_wr32(dev, 0x00b360, base);
+               nv_wr32(dev, 0x00b364, size);
+       } else {
+               /* DMA_IMAGE, VRAM only */
+               if (dma0 & 0x000c0000)
+                       return -EINVAL;
+
+               nv_wr32(dev, 0x00b370, base);
+               nv_wr32(dev, 0x00b374, size);
+       }
+
+       return 0;
+}
+
+static int
+nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ctx;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&dev_priv->channels.lock, flags);
+       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+               if (!dev_priv->channels.ptr[i])
+                       continue;
+
+               ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG];
+               if (ctx && ctx->pinst == inst)
+                       break;
+       }
+       spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+       return i;
+}
+
+static void
+nv40_vpe_set_tile_region(struct drm_device *dev, int i)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+       nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch);
+       nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit);
+       nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr);
+}
+
+static void
+nv40_mpeg_isr(struct drm_device *dev)
+{
+       u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4;
+       u32 chid = nv40_mpeg_isr_chid(dev, inst);
+       u32 stat = nv_rd32(dev, 0x00b100);
+       u32 type = nv_rd32(dev, 0x00b230);
+       u32 mthd = nv_rd32(dev, 0x00b234);
+       u32 data = nv_rd32(dev, 0x00b238);
+       u32 show = stat;
+
+       if (stat & 0x01000000) {
+               /* happens on initial binding of the object */
+               if (type == 0x00000020 && mthd == 0x0000) {
+                       nv_mask(dev, 0x00b308, 0x00000000, 0x00000000);
+                       show &= ~0x01000000;
+               }
+
+               if (type == 0x00000010) {
+                       if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data))
+                               show &= ~0x01000000;
+               }
+       }
+
+       nv_wr32(dev, 0x00b100, stat);
+       nv_wr32(dev, 0x00b230, 0x00000001);
+
+       if (show && nouveau_ratelimit()) {
+               NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                       chid, inst, stat, type, mthd, data);
+       }
+}
+
+static void
+nv40_vpe_isr(struct drm_device *dev)
+{
+       if (nv_rd32(dev, 0x00b100))
+               nv40_mpeg_isr(dev);
+
+       if (nv_rd32(dev, 0x00b800)) {
+               u32 stat = nv_rd32(dev, 0x00b800);
+               NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+               nv_wr32(dev, 0xb800, stat);
+       }
+}
+
+static void
+nv40_mpeg_destroy(struct drm_device *dev, int engine)
+{
+       struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 0);
+
+       NVOBJ_ENGINE_DEL(dev, MPEG);
+       kfree(pmpeg);
+}
+
+int
+nv40_mpeg_create(struct drm_device *dev)
+{
+       struct nv40_mpeg_engine *pmpeg;
+
+       pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+       if (!pmpeg)
+               return -ENOMEM;
+
+       pmpeg->base.destroy = nv40_mpeg_destroy;
+       pmpeg->base.init = nv40_mpeg_init;
+       pmpeg->base.fini = nv40_mpeg_fini;
+       pmpeg->base.context_new = nv40_mpeg_context_new;
+       pmpeg->base.context_del = nv40_mpeg_context_del;
+       pmpeg->base.object_new = nv40_mpeg_object_new;
+
+       /* ISR vector, PMC_ENABLE bit,  and TILE regs are shared between
+        * all VPE engines, for this driver's purposes the PMPEG engine
+        * will be treated as the "master" and handle the global VPE
+        * bits too
+        */
+       pmpeg->base.set_tile_region = nv40_vpe_set_tile_region;
+       nouveau_irq_register(dev, 0, nv40_vpe_isr);
+
+       NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+       NVOBJ_CLASS(dev, 0x3174, MPEG);
+       NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma);
+       NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma);
+       NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma);
+
+#if 0
+       NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+       NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+       return 0;
+
+}
index de81151648f831c5a7c97b9491d3670c356276f5..8cf63a8b30cdb96198e8b8be469e48e2c42604a4 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include "drmP.h"
-#include "drm_fixed.h"
 #include "nouveau_drv.h"
 #include "nouveau_hw.h"
 
@@ -47,45 +46,52 @@ nv50_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
 }
 
 int
-nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
-              int *N, int *fN, int *M, int *P)
+nva3_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
+             int *pN, int *pfN, int *pM, int *P)
 {
-       fixed20_12 fb_div, a, b;
-       u32 refclk = pll->refclk / 10;
-       u32 max_vco_freq = pll->vco1.maxfreq / 10;
-       u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
-       clk /= 10;
+       u32 best_err = ~0, err;
+       int M, lM, hM, N, fN;
 
-       *P = max_vco_freq / clk;
+       *P = pll->vco1.maxfreq / clk;
        if (*P > pll->max_p)
                *P = pll->max_p;
        if (*P < pll->min_p)
                *P = pll->min_p;
 
-       /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
-       a.full = dfixed_const(refclk + max_vco_inputfreq);
-       b.full = dfixed_const(max_vco_inputfreq);
-       a.full = dfixed_div(a, b);
-       a.full = dfixed_floor(a);
-       *M = dfixed_trunc(a);
+       lM = (pll->refclk + pll->vco1.max_inputfreq) / pll->vco1.max_inputfreq;
+       lM = max(lM, (int)pll->vco1.min_m);
+       hM = (pll->refclk + pll->vco1.min_inputfreq) / pll->vco1.min_inputfreq;
+       hM = min(hM, (int)pll->vco1.max_m);
 
-       /* fb_div = (vco * *M) / refclk; */
-       fb_div.full = dfixed_const(clk * *P);
-       fb_div.full = dfixed_mul(fb_div, a);
-       a.full = dfixed_const(refclk);
-       fb_div.full = dfixed_div(fb_div, a);
+       for (M = lM; M <= hM; M++) {
+               u32 tmp = clk * *P * M;
+               N  = tmp / pll->refclk;
+               fN = tmp % pll->refclk;
+               if (!pfN && fN >= pll->refclk / 2)
+                       N++;
 
-       /* *N = floor(fb_div); */
-       a.full = dfixed_floor(fb_div);
-       *N = dfixed_trunc(fb_div);
+               if (N < pll->vco1.min_n)
+                       continue;
+               if (N > pll->vco1.max_n)
+                       break;
 
-       /* *fN = (fmod(fb_div, 1.0) * 8192) - 4096; */
-       b.full = dfixed_const(8192);
-       a.full = dfixed_mul(a, b);
-       fb_div.full = dfixed_mul(fb_div, b);
-       fb_div.full = fb_div.full - a.full;
-       *fN = dfixed_trunc(fb_div) - 4096;
-       *fN &= 0xffff;
+               err = abs(clk - (pll->refclk * N / M / *P));
+               if (err < best_err) {
+                       best_err = err;
+                       *pN = N;
+                       *pM = M;
+               }
 
-       return clk;
+               if (pfN) {
+                       *pfN = (((fN << 13) / pll->refclk) - 4096) & 0xffff;
+                       return clk;
+               }
+       }
+
+       if (unlikely(best_err == ~0)) {
+               NV_ERROR(dev, "unable to find matching pll values\n");
+               return -EINVAL;
+       }
+
+       return pll->refclk * *pN / *pM / *P;
 }
index a19ccaa025b389508f604f72a10a060d338a32ee..ebabacf38da9ff02ae5f2f0f2503e1ffb3fd0ce5 100644 (file)
@@ -286,7 +286,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
        } else
        if (dev_priv->chipset < NV_C0) {
-               ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+               ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
                if (ret <= 0)
                        return 0;
 
@@ -298,7 +298,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
                nv_wr32(dev, pll.reg + 8, N2);
        } else {
-               ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+               ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
                if (ret <= 0)
                        return 0;
 
@@ -349,14 +349,14 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
        struct drm_gem_object *gem;
        int ret = 0, i;
 
-       if (width != 64 || height != 64)
-               return -EINVAL;
-
        if (!buffer_handle) {
                nv_crtc->cursor.hide(nv_crtc, true);
                return 0;
        }
 
+       if (width != 64 || height != 64)
+               return -EINVAL;
+
        gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
        if (!gem)
                return -ENOENT;
@@ -532,8 +532,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
        if (atomic) {
                drm_fb = passed_fb;
                fb = nouveau_framebuffer(passed_fb);
-       }
-       else {
+       } else {
                /* If not atomic, we can go ahead and pin, and unpin the
                 * old fb we were passed.
                 */
index 75a376cc342a54e4201c978bf8d7a08de21ccd0d..74a3f687270124cdfb32ddd55ce78f9ae70a6157 100644 (file)
@@ -517,13 +517,25 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
                        if (bios->fp.if_is_24bit)
                                script |= 0x0200;
                } else {
+                       /* determine number of lvds links */
+                       if (nv_connector && nv_connector->edid &&
+                           nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
+                               /* http://www.spwg.org */
+                               if (((u8 *)nv_connector->edid)[121] == 2)
+                                       script |= 0x0100;
+                       } else
                        if (pxclk >= bios->fp.duallink_transition_clk) {
                                script |= 0x0100;
+                       }
+
+                       /* determine panel depth */
+                       if (script & 0x0100) {
                                if (bios->fp.strapless_is_24bit & 2)
                                        script |= 0x0200;
-                       } else
-                       if (bios->fp.strapless_is_24bit & 1)
-                               script |= 0x0200;
+                       } else {
+                               if (bios->fp.strapless_is_24bit & 1)
+                                       script |= 0x0200;
+                       }
 
                        if (nv_connector && nv_connector->edid &&
                            (nv_connector->edid->revision >= 4) &&
index b02a5b1e7d379fb1928467a668b905ddb4fa30b9..e25cbb46789a6780b5cf9611680468a835a09cff 100644 (file)
 #include "nouveau_grctx.h"
 #include "nouveau_dma.h"
 #include "nouveau_vm.h"
+#include "nouveau_ramht.h"
 #include "nv50_evo.h"
 
-static int  nv50_graph_register(struct drm_device *);
-static void nv50_graph_isr(struct drm_device *);
+struct nv50_graph_engine {
+       struct nouveau_exec_engine base;
+       u32 ctxprog[512];
+       u32 ctxprog_size;
+       u32 grctx_size;
+};
+
+static void
+nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
+{
+       const uint32_t mask = 0x00010001;
+
+       if (enabled)
+               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
+       else
+               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
+}
+
+static struct nouveau_channel *
+nv50_graph_channel(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t inst;
+       int i;
+
+       /* Be sure we're not in the middle of a context switch or bad things
+        * will happen, such as unloading the wrong pgraph context.
+        */
+       if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
+               NV_ERROR(dev, "Ctxprog is still running\n");
+
+       inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+               return NULL;
+       inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
+
+       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+
+               if (chan && chan->ramin && chan->ramin->vinst == inst)
+                       return chan;
+       }
+
+       return NULL;
+}
+
+static int
+nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
+{
+       uint32_t fifo = nv_rd32(dev, 0x400500);
+
+       nv_wr32(dev, 0x400500, fifo & ~1);
+       nv_wr32(dev, 0x400784, inst);
+       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
+       nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
+       nv_wr32(dev, 0x400040, 0xffffffff);
+       (void)nv_rd32(dev, 0x400040);
+       nv_wr32(dev, 0x400040, 0x00000000);
+       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
+
+       if (nouveau_wait_for_idle(dev))
+               nv_wr32(dev, 0x40032c, inst | (1<<31));
+       nv_wr32(dev, 0x400500, fifo);
+
+       return 0;
+}
+
+static int
+nv50_graph_unload_context(struct drm_device *dev)
+{
+       uint32_t inst;
+
+       inst  = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+               return 0;
+       inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+       nouveau_wait_for_idle(dev);
+       nv_wr32(dev, 0x400784, inst);
+       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
+       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
+       nouveau_wait_for_idle(dev);
+
+       nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
+       return 0;
+}
 
 static void
 nv50_graph_init_reset(struct drm_device *dev)
@@ -52,7 +137,6 @@ nv50_graph_init_intr(struct drm_device *dev)
 {
        NV_DEBUG(dev, "\n");
 
-       nouveau_irq_register(dev, 12, nv50_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff);
        nv_wr32(dev, 0x400138, 0xffffffff);
        nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff);
@@ -135,34 +219,14 @@ nv50_graph_init_zcull(struct drm_device *dev)
 static int
 nv50_graph_init_ctxctl(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_grctx ctx = {};
-       uint32_t *cp;
+       struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR);
        int i;
 
        NV_DEBUG(dev, "\n");
 
-       cp = kmalloc(512 * 4, GFP_KERNEL);
-       if (!cp) {
-               NV_ERROR(dev, "failed to allocate ctxprog\n");
-               dev_priv->engine.graph.accel_blocked = true;
-               return 0;
-       }
-
-       ctx.dev = dev;
-       ctx.mode = NOUVEAU_GRCTX_PROG;
-       ctx.data = cp;
-       ctx.ctxprog_max = 512;
-       if (!nv50_grctx_init(&ctx)) {
-               dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
-
-               nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
-               for (i = 0; i < ctx.ctxprog_len; i++)
-                       nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
-       } else {
-               dev_priv->engine.graph.accel_blocked = true;
-       }
-       kfree(cp);
+       nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+       for (i = 0; i < pgraph->ctxprog_size; i++)
+               nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]);
 
        nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
        nv_wr32(dev, 0x400320, 4);
@@ -171,8 +235,8 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
        return 0;
 }
 
-int
-nv50_graph_init(struct drm_device *dev)
+static int
+nv50_graph_init(struct drm_device *dev, int engine)
 {
        int ret;
 
@@ -186,105 +250,66 @@ nv50_graph_init(struct drm_device *dev)
        if (ret)
                return ret;
 
-       ret = nv50_graph_register(dev);
-       if (ret)
-               return ret;
        nv50_graph_init_intr(dev);
        return 0;
 }
 
-void
-nv50_graph_takedown(struct drm_device *dev)
+static int
+nv50_graph_fini(struct drm_device *dev, int engine)
 {
        NV_DEBUG(dev, "\n");
+       nv50_graph_unload_context(dev);
        nv_wr32(dev, 0x40013c, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
-}
-
-void
-nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
-{
-       const uint32_t mask = 0x00010001;
-
-       if (enabled)
-               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
-       else
-               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
-}
-
-struct nouveau_channel *
-nv50_graph_channel(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t inst;
-       int i;
-
-       /* Be sure we're not in the middle of a context switch or bad things
-        * will happen, such as unloading the wrong pgraph context.
-        */
-       if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
-               NV_ERROR(dev, "Ctxprog is still running\n");
-
-       inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
-               return NULL;
-       inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
-
-       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-
-               if (chan && chan->ramin && chan->ramin->vinst == inst)
-                       return chan;
-       }
-
-       return NULL;
+       return 0;
 }
 
-int
-nv50_graph_create_context(struct nouveau_channel *chan)
+static int
+nv50_graph_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *ramin = chan->ramin;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       struct nouveau_gpuobj *grctx = NULL;
+       struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
        struct nouveau_grctx ctx = {};
        int hdr, ret;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0,
+       ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0,
                                 NVOBJ_FLAG_ZERO_ALLOC |
-                                NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
+                                NVOBJ_FLAG_ZERO_FREE, &grctx);
        if (ret)
                return ret;
 
        hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
        nv_wo32(ramin, hdr + 0x00, 0x00190002);
-       nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst +
-                                  pgraph->grctx_size - 1);
-       nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst);
+       nv_wo32(ramin, hdr + 0x04, grctx->vinst + grctx->size - 1);
+       nv_wo32(ramin, hdr + 0x08, grctx->vinst);
        nv_wo32(ramin, hdr + 0x0c, 0);
        nv_wo32(ramin, hdr + 0x10, 0);
        nv_wo32(ramin, hdr + 0x14, 0x00010000);
 
        ctx.dev = chan->dev;
        ctx.mode = NOUVEAU_GRCTX_VALS;
-       ctx.data = chan->ramin_grctx;
+       ctx.data = grctx;
        nv50_grctx_init(&ctx);
 
-       nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
+       nv_wo32(grctx, 0x00000, chan->ramin->vinst >> 12);
 
        dev_priv->engine.instmem.flush(dev);
-       atomic_inc(&chan->vm->pgraph_refs);
+
+       atomic_inc(&chan->vm->engref[NVOBJ_ENGINE_GR]);
+       chan->engctx[NVOBJ_ENGINE_GR] = grctx;
        return 0;
 }
 
-void
-nv50_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv50_graph_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nouveau_gpuobj *grctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
        unsigned long flags;
@@ -296,72 +321,49 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
        pfifo->reassign(dev, false);
-       pgraph->fifo_access(dev, false);
+       nv50_graph_fifo_access(dev, false);
 
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
+       if (nv50_graph_channel(dev) == chan)
+               nv50_graph_unload_context(dev);
 
        for (i = hdr; i < hdr + 24; i += 4)
                nv_wo32(chan->ramin, i, 0);
        dev_priv->engine.instmem.flush(dev);
 
-       pgraph->fifo_access(dev, true);
+       nv50_graph_fifo_access(dev, true);
        pfifo->reassign(dev, true);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
-       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+       nouveau_gpuobj_ref(NULL, &grctx);
 
-       atomic_dec(&chan->vm->pgraph_refs);
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = NULL;
 }
 
 static int
-nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
-{
-       uint32_t fifo = nv_rd32(dev, 0x400500);
-
-       nv_wr32(dev, 0x400500, fifo & ~1);
-       nv_wr32(dev, 0x400784, inst);
-       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
-       nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
-       nv_wr32(dev, 0x400040, 0xffffffff);
-       (void)nv_rd32(dev, 0x400040);
-       nv_wr32(dev, 0x400040, 0x00000000);
-       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
-
-       if (nouveau_wait_for_idle(dev))
-               nv_wr32(dev, 0x40032c, inst | (1<<31));
-       nv_wr32(dev, 0x400500, fifo);
-
-       return 0;
-}
-
-int
-nv50_graph_load_context(struct nouveau_channel *chan)
-{
-       uint32_t inst = chan->ramin->vinst >> 12;
-
-       NV_DEBUG(chan->dev, "ch%d\n", chan->id);
-       return nv50_graph_do_load_context(chan->dev, inst);
-}
-
-int
-nv50_graph_unload_context(struct drm_device *dev)
+nv50_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
-       uint32_t inst;
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
 
-       inst  = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
-               return 0;
-       inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 1;
+       obj->class  = class;
 
-       nouveau_wait_for_idle(dev);
-       nv_wr32(dev, 0x400784, inst);
-       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
-       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
-       nouveau_wait_for_idle(dev);
+       nv_wo32(obj, 0x00, class);
+       nv_wo32(obj, 0x04, 0x00000000);
+       nv_wo32(obj, 0x08, 0x00000000);
+       nv_wo32(obj, 0x0c, 0x00000000);
+       dev_priv->engine.instmem.flush(dev);
 
-       nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
-       return 0;
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
 }
 
 static void
@@ -442,68 +444,15 @@ nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
        return 0;
 }
 
-static int
-nv50_graph_register(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
-       NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
-       NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
-       NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
-
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
-
-       /* tesla */
-       if (dev_priv->chipset == 0x50)
-               NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
-       else
-       if (dev_priv->chipset < 0xa0)
-               NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
-       else {
-               switch (dev_priv->chipset) {
-               case 0xa0:
-               case 0xaa:
-               case 0xac:
-                       NVOBJ_CLASS(dev, 0x8397, GR);
-                       break;
-               case 0xa3:
-               case 0xa5:
-               case 0xa8:
-                       NVOBJ_CLASS(dev, 0x8597, GR);
-                       break;
-               case 0xaf:
-                       NVOBJ_CLASS(dev, 0x8697, GR);
-                       break;
-               }
-       }
-
-       /* compute */
-       NVOBJ_CLASS(dev, 0x50c0, GR);
-       if (dev_priv->chipset  > 0xa0 &&
-           dev_priv->chipset != 0xaa &&
-           dev_priv->chipset != 0xac)
-               NVOBJ_CLASS(dev, 0x85c0, GR);
-
-       dev_priv->engine.graph.registered = true;
-       return 0;
-}
 
-void
-nv50_graph_tlb_flush(struct drm_device *dev)
+static void
+nv50_graph_tlb_flush(struct drm_device *dev, int engine)
 {
        nv50_vm_flush_engine(dev, 0);
 }
 
-void
-nv84_graph_tlb_flush(struct drm_device *dev)
+static void
+nv84_graph_tlb_flush(struct drm_device *dev, int engine)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
@@ -548,8 +497,7 @@ nv84_graph_tlb_flush(struct drm_device *dev)
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 }
 
-static struct nouveau_enum nv50_mp_exec_error_names[] =
-{
+static struct nouveau_enum nv50_mp_exec_error_names[] = {
        { 3, "STACK_UNDERFLOW", NULL },
        { 4, "QUADON_ACTIVE", NULL },
        { 8, "TIMEOUT", NULL },
@@ -663,7 +611,7 @@ nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
                        nv_rd32(dev, addr + 0x20);
                        pc = nv_rd32(dev, addr + 0x24);
                        oplow = nv_rd32(dev, addr + 0x70);
-                       ophigh= nv_rd32(dev, addr + 0x74);
+                       ophigh = nv_rd32(dev, addr + 0x74);
                        NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
                                        "TP %d MP %d: ", tpid, i);
                        nouveau_enum_print(nv50_mp_exec_error_names, status);
@@ -991,7 +939,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid
        return 1;
 }
 
-static int
+int
 nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1073,3 +1021,101 @@ nv50_graph_isr(struct drm_device *dev)
        if (nv_rd32(dev, 0x400824) & (1 << 31))
                nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
 }
+
+static void
+nv50_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+
+       nouveau_irq_unregister(dev, 12);
+       kfree(pgraph);
+}
+
+int
+nv50_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv50_graph_engine *pgraph;
+       struct nouveau_grctx ctx = {};
+       int ret;
+
+       pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       ctx.dev = dev;
+       ctx.mode = NOUVEAU_GRCTX_PROG;
+       ctx.data = pgraph->ctxprog;
+       ctx.ctxprog_max = ARRAY_SIZE(pgraph->ctxprog);
+
+       ret = nv50_grctx_init(&ctx);
+       if (ret) {
+               NV_ERROR(dev, "PGRAPH: ctxprog build failed\n");
+               kfree(pgraph);
+               return 0;
+       }
+
+       pgraph->grctx_size = ctx.ctxvals_pos * 4;
+       pgraph->ctxprog_size = ctx.ctxprog_len;
+
+       pgraph->base.destroy = nv50_graph_destroy;
+       pgraph->base.init = nv50_graph_init;
+       pgraph->base.fini = nv50_graph_fini;
+       pgraph->base.context_new = nv50_graph_context_new;
+       pgraph->base.context_del = nv50_graph_context_del;
+       pgraph->base.object_new = nv50_graph_object_new;
+       if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac)
+               pgraph->base.tlb_flush = nv50_graph_tlb_flush;
+       else
+               pgraph->base.tlb_flush = nv84_graph_tlb_flush;
+
+       nouveau_irq_register(dev, 12, nv50_graph_isr);
+
+       /* NVSW really doesn't live here... */
+       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+       NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
+       NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
+       NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
+       NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
+
+       /* tesla */
+       if (dev_priv->chipset == 0x50)
+               NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
+       else
+       if (dev_priv->chipset < 0xa0)
+               NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
+       else {
+               switch (dev_priv->chipset) {
+               case 0xa0:
+               case 0xaa:
+               case 0xac:
+                       NVOBJ_CLASS(dev, 0x8397, GR);
+                       break;
+               case 0xa3:
+               case 0xa5:
+               case 0xa8:
+                       NVOBJ_CLASS(dev, 0x8597, GR);
+                       break;
+               case 0xaf:
+                       NVOBJ_CLASS(dev, 0x8697, GR);
+                       break;
+               }
+       }
+
+       /* compute */
+       NVOBJ_CLASS(dev, 0x50c0, GR);
+       if (dev_priv->chipset  > 0xa0 &&
+           dev_priv->chipset != 0xaa &&
+           dev_priv->chipset != 0xac)
+               NVOBJ_CLASS(dev, 0x85c0, GR);
+
+       return 0;
+}
index 336aab2a24a66ff030b7af629db43f53aaa9ef8e..de9abff12b909122faf612f16a2dfd0ab17d0052 100644 (file)
@@ -747,7 +747,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                                gr_def(ctx, offset + 0x64, 0x0000001f);
                                gr_def(ctx, offset + 0x68, 0x0000000f);
                                gr_def(ctx, offset + 0x6c, 0x0000000f);
-                       } else if(dev_priv->chipset < 0xa0) {
+                       } else if (dev_priv->chipset < 0xa0) {
                                cp_ctx(ctx, offset + 0x50, 1);
                                cp_ctx(ctx, offset + 0x70, 1);
                        } else {
@@ -924,7 +924,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
                dd_emit(ctx, 1, 0);     /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
        } else {
                dd_emit(ctx, 1, 0);     /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
-       } 
+       }
        dd_emit(ctx, 1, 0xc);           /* 000000ff SEMANTIC_COLOR.BFC0_ID */
        if (dev_priv->chipset != 0x50)
                dd_emit(ctx, 1, 0);     /* 00000001 SEMANTIC_COLOR.CLMP_EN */
@@ -1803,9 +1803,7 @@ nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
                xf_emit(ctx, 1, 0);     /* 1ff */
                xf_emit(ctx, 8, 0);     /* 0? */
                xf_emit(ctx, 9, 0);     /* ffffffff, 7ff */
-       }
-       else
-       {
+       } else {
                xf_emit(ctx, 0xc, 0);   /* RO */
                /* SEEK */
                xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
@@ -2836,7 +2834,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
        xf_emit(ctx, 1, 1);             /* 00000001 DST_LINEAR */
        if (IS_NVA3F(dev_priv->chipset))
                xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
-       if(dev_priv->chipset == 0x50)
+       if (dev_priv->chipset == 0x50)
                xf_emit(ctx, 1, 0);     /* ff */
        else
                xf_emit(ctx, 3, 0);     /* 1, 7, 3ff */
diff --git a/drivers/gpu/drm/nouveau/nv50_mpeg.c b/drivers/gpu/drm/nouveau/nv50_mpeg.c
new file mode 100644 (file)
index 0000000..1dc5913
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv50_mpeg_engine {
+       struct nouveau_exec_engine base;
+};
+
+static inline u32
+CTX_PTR(struct drm_device *dev, u32 offset)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->chipset == 0x50)
+               offset += 0x0260;
+       else
+               offset += 0x0060;
+
+       return offset;
+}
+
+static int
+nv50_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx = NULL;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, chan, 128 * 4, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, CTX_PTR(dev, 0x00), 0x80190002);
+       nv_wo32(ramin, CTX_PTR(dev, 0x04), ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, CTX_PTR(dev, 0x08), ctx->vinst);
+       nv_wo32(ramin, CTX_PTR(dev, 0x0c), 0);
+       nv_wo32(ramin, CTX_PTR(dev, 0x10), 0);
+       nv_wo32(ramin, CTX_PTR(dev, 0x14), 0x00010000);
+
+       nv_wo32(ctx, 0x70, 0x00801ec1);
+       nv_wo32(ctx, 0x7c, 0x0000037c);
+       dev_priv->engine.instmem.flush(dev);
+
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static void
+nv50_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       unsigned long flags;
+       u32 inst, i;
+
+       if (!chan->ramin)
+               return;
+
+       inst  = chan->ramin->vinst >> 12;
+       inst |= 0x80000000;
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       if (nv_rd32(dev, 0x00b318) == inst)
+               nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       for (i = 0x00; i <= 0x14; i += 4)
+               nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000);
+       nouveau_gpuobj_ref(NULL, &ctx);
+       chan->engctx[engine] = NULL;
+}
+
+static int
+nv50_mpeg_object_new(struct nouveau_channel *chan, int engine,
+                    u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 2;
+       obj->class  = class;
+
+       nv_wo32(obj, 0x00, class);
+       nv_wo32(obj, 0x04, 0x00000000);
+       nv_wo32(obj, 0x08, 0x00000000);
+       nv_wo32(obj, 0x0c, 0x00000000);
+       dev_priv->engine.instmem.flush(dev);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
+}
+
+static void
+nv50_mpeg_tlb_flush(struct drm_device *dev, int engine)
+{
+       nv50_vm_flush_engine(dev, 0x08);
+}
+
+static int
+nv50_mpeg_init(struct drm_device *dev, int engine)
+{
+       nv_wr32(dev, 0x00b32c, 0x00000000);
+       nv_wr32(dev, 0x00b314, 0x00000100);
+       nv_wr32(dev, 0x00b0e0, 0x0000001a);
+
+       nv_wr32(dev, 0x00b220, 0x00000044);
+       nv_wr32(dev, 0x00b300, 0x00801ec1);
+       nv_wr32(dev, 0x00b390, 0x00000000);
+       nv_wr32(dev, 0x00b394, 0x00000000);
+       nv_wr32(dev, 0x00b398, 0x00000000);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+       nv_wr32(dev, 0x00b100, 0xffffffff);
+       nv_wr32(dev, 0x00b140, 0xffffffff);
+
+       if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int
+nv50_mpeg_fini(struct drm_device *dev, int engine)
+{
+       /*XXX: context save for s/r */
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       nv_wr32(dev, 0x00b140, 0x00000000);
+       return 0;
+}
+
+static void
+nv50_mpeg_isr(struct drm_device *dev)
+{
+       u32 stat = nv_rd32(dev, 0x00b100);
+       u32 type = nv_rd32(dev, 0x00b230);
+       u32 mthd = nv_rd32(dev, 0x00b234);
+       u32 data = nv_rd32(dev, 0x00b238);
+       u32 show = stat;
+
+       if (stat & 0x01000000) {
+               /* happens on initial binding of the object */
+               if (type == 0x00000020 && mthd == 0x0000) {
+                       nv_wr32(dev, 0x00b308, 0x00000100);
+                       show &= ~0x01000000;
+               }
+       }
+
+       if (show && nouveau_ratelimit()) {
+               NV_INFO(dev, "PMPEG - 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                       stat, type, mthd, data);
+       }
+
+       nv_wr32(dev, 0x00b100, stat);
+       nv_wr32(dev, 0x00b230, 0x00000001);
+       nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nv50_vpe_isr(struct drm_device *dev)
+{
+       if (nv_rd32(dev, 0x00b100))
+               nv50_mpeg_isr(dev);
+
+       if (nv_rd32(dev, 0x00b800)) {
+               u32 stat = nv_rd32(dev, 0x00b800);
+               NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+               nv_wr32(dev, 0xb800, stat);
+       }
+}
+
+static void
+nv50_mpeg_destroy(struct drm_device *dev, int engine)
+{
+       struct nv50_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 0);
+
+       NVOBJ_ENGINE_DEL(dev, MPEG);
+       kfree(pmpeg);
+}
+
+int
+nv50_mpeg_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv50_mpeg_engine *pmpeg;
+
+       pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+       if (!pmpeg)
+               return -ENOMEM;
+
+       pmpeg->base.destroy = nv50_mpeg_destroy;
+       pmpeg->base.init = nv50_mpeg_init;
+       pmpeg->base.fini = nv50_mpeg_fini;
+       pmpeg->base.context_new = nv50_mpeg_context_new;
+       pmpeg->base.context_del = nv50_mpeg_context_del;
+       pmpeg->base.object_new = nv50_mpeg_object_new;
+       pmpeg->base.tlb_flush = nv50_mpeg_tlb_flush;
+
+       if (dev_priv->chipset == 0x50) {
+               nouveau_irq_register(dev, 0, nv50_vpe_isr);
+               NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+               NVOBJ_CLASS(dev, 0x3174, MPEG);
+#if 0
+               NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+               NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+       } else {
+               nouveau_irq_register(dev, 0, nv50_mpeg_isr);
+               NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+               NVOBJ_CLASS(dev, 0x8274, MPEG);
+       }
+
+       return 0;
+
+}
index 7dbb305d7e63598056678c8e3e20b594c8c25a18..8a2810011bda5e9cd1861d03ecf3482229be20da 100644 (file)
@@ -47,6 +47,21 @@ nv50_pm_clock_get(struct drm_device *dev, u32 id)
 
        reg0 = nv_rd32(dev, pll.reg + 0);
        reg1 = nv_rd32(dev, pll.reg + 4);
+
+       if ((reg0 & 0x80000000) == 0) {
+               if (id == PLL_SHADER) {
+                       NV_DEBUG(dev, "Shader PLL is disabled. "
+                               "Shader clock is twice the core\n");
+                       ret = nv50_pm_clock_get(dev, PLL_CORE);
+                       if (ret > 0)
+                               return ret << 1;
+               } else if (id == PLL_MEMORY) {
+                       NV_DEBUG(dev, "Memory PLL is disabled. "
+                               "Memory clock is equal to the ref_clk\n");
+                       return pll.refclk;
+               }
+       }
+
        P = (reg0 & 0x00070000) >> 16;
        N = (reg1 & 0x0000ff00) >> 8;
        M = (reg1 & 0x000000ff);
index 6c26944907418b0d090d35758b8e22d7ce9de06c..1a0dd491a0e44257dc1eb4dc87005b4b3d18f1dc 100644 (file)
@@ -151,8 +151,7 @@ nv50_vm_flush(struct nouveau_vm *vm)
        struct drm_nouveau_private *dev_priv = vm->dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
+       int i;
 
        pinstmem->flush(vm->dev);
 
@@ -163,11 +162,10 @@ nv50_vm_flush(struct nouveau_vm *vm)
        }
 
        pfifo->tlb_flush(vm->dev);
-
-       if (atomic_read(&vm->pgraph_refs))
-               pgraph->tlb_flush(vm->dev);
-       if (atomic_read(&vm->pcrypt_refs))
-               pcrypt->tlb_flush(vm->dev);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (atomic_read(&vm->engref[i]))
+                       dev_priv->eng[i]->tlb_flush(vm->dev, i);
+       }
 }
 
 void
index fabc7fd30b1d9150e7f532f7cf58de8e5f9f247f..75b809a51748e09eaa78cd8e07d5a7b754b3e408 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_util.h"
 #include "nouveau_vm.h"
+#include "nouveau_ramht.h"
 
-static void nv84_crypt_isr(struct drm_device *);
+struct nv84_crypt_engine {
+       struct nouveau_exec_engine base;
+};
 
-int
-nv84_crypt_create_context(struct nouveau_channel *chan)
+static int
+nv84_crypt_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx;
        int ret;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       ret = nouveau_gpuobj_new(dev, chan, 256, 0,
-                                NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
-                                &chan->crypt_ctx);
+       ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
        if (ret)
                return ret;
 
        nv_wo32(ramin, 0xa0, 0x00190000);
-       nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff);
-       nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst);
+       nv_wo32(ramin, 0xa4, ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, 0xa8, ctx->vinst);
        nv_wo32(ramin, 0xac, 0);
        nv_wo32(ramin, 0xb0, 0);
        nv_wo32(ramin, 0xb4, 0);
-
        dev_priv->engine.instmem.flush(dev);
-       atomic_inc(&chan->vm->pcrypt_refs);
+
+       atomic_inc(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
        return 0;
 }
 
-void
-nv84_crypt_destroy_context(struct nouveau_channel *chan)
+static void
+nv84_crypt_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        u32 inst;
 
-       if (!chan->crypt_ctx)
-               return;
-
        inst  = (chan->ramin->vinst >> 12);
        inst |= 0x80000000;
 
@@ -80,43 +82,39 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan)
                nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
        nv_wr32(dev, 0x10200c, 0x00000010);
 
-       nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
-       atomic_dec(&chan->vm->pcrypt_refs);
-}
+       nouveau_gpuobj_ref(NULL, &ctx);
 
-void
-nv84_crypt_tlb_flush(struct drm_device *dev)
-{
-       nv50_vm_flush_engine(dev, 0x0a);
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = NULL;
 }
 
-int
-nv84_crypt_init(struct drm_device *dev)
+static int
+nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
+       struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
-
-       if (!pcrypt->registered) {
-               NVOBJ_CLASS(dev, 0x74c1, CRYPT);
-               pcrypt->registered = true;
-       }
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
 
-       nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
-       nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 5;
+       obj->class  = class;
 
-       nouveau_irq_register(dev, 14, nv84_crypt_isr);
-       nv_wr32(dev, 0x102130, 0xffffffff);
-       nv_wr32(dev, 0x102140, 0xffffffbf);
+       nv_wo32(obj, 0x00, class);
+       dev_priv->engine.instmem.flush(dev);
 
-       nv_wr32(dev, 0x10200c, 0x00000010);
-       return 0;
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
 }
 
-void
-nv84_crypt_fini(struct drm_device *dev)
+static void
+nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
 {
-       nv_wr32(dev, 0x102140, 0x00000000);
-       nouveau_irq_unregister(dev, 14);
+       nv50_vm_flush_engine(dev, 0x0a);
 }
 
 static void
@@ -138,3 +136,58 @@ nv84_crypt_isr(struct drm_device *dev)
 
        nv50_fb_vm_trap(dev, show);
 }
+
+static int
+nv84_crypt_fini(struct drm_device *dev, int engine)
+{
+       nv_wr32(dev, 0x102140, 0x00000000);
+       return 0;
+}
+
+static int
+nv84_crypt_init(struct drm_device *dev, int engine)
+{
+       nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+
+       nv_wr32(dev, 0x102130, 0xffffffff);
+       nv_wr32(dev, 0x102140, 0xffffffbf);
+
+       nv_wr32(dev, 0x10200c, 0x00000010);
+       return 0;
+}
+
+static void
+nv84_crypt_destroy(struct drm_device *dev, int engine)
+{
+       struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
+
+       NVOBJ_ENGINE_DEL(dev, CRYPT);
+
+       nouveau_irq_unregister(dev, 14);
+       kfree(pcrypt);
+}
+
+int
+nv84_crypt_create(struct drm_device *dev)
+{
+       struct nv84_crypt_engine *pcrypt;
+
+       pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
+       if (!pcrypt)
+               return -ENOMEM;
+
+       pcrypt->base.destroy = nv84_crypt_destroy;
+       pcrypt->base.init = nv84_crypt_init;
+       pcrypt->base.fini = nv84_crypt_fini;
+       pcrypt->base.context_new = nv84_crypt_context_new;
+       pcrypt->base.context_del = nv84_crypt_context_del;
+       pcrypt->base.object_new = nv84_crypt_object_new;
+       pcrypt->base.tlb_flush = nv84_crypt_tlb_flush;
+
+       nouveau_irq_register(dev, 14, nv84_crypt_isr);
+
+       NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
+       NVOBJ_CLASS (dev, 0x74c1, CRYPT);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.c b/drivers/gpu/drm/nouveau/nva3_copy.c
new file mode 100644 (file)
index 0000000..b86820a
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nva3_copy.fuc.h"
+
+struct nva3_copy_engine {
+       struct nouveau_exec_engine base;
+};
+
+static int
+nva3_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx = NULL;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, 0xc0, 0x00190000);
+       nv_wo32(ramin, 0xc4, ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, 0xc8, ctx->vinst);
+       nv_wo32(ramin, 0xcc, 0x00000000);
+       nv_wo32(ramin, 0xd0, 0x00000000);
+       nv_wo32(ramin, 0xd4, 0x00000000);
+       dev_priv->engine.instmem.flush(dev);
+
+       atomic_inc(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static int
+nva3_copy_object_new(struct nouveau_channel *chan, int engine,
+                    u32 handle, u16 class)
+{
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+
+       /* fuc engine doesn't need an object, our ramht code does.. */
+       ctx->engine = 3;
+       ctx->class  = class;
+       return nouveau_ramht_insert(chan, handle, ctx);
+}
+
+static void
+nva3_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       u32 inst;
+
+       inst  = (chan->ramin->vinst >> 12);
+       inst |= 0x40000000;
+
+       /* disable fifo access */
+       nv_wr32(dev, 0x104048, 0x00000000);
+       /* mark channel as unloaded if it's currently active */
+       if (nv_rd32(dev, 0x104050) == inst)
+               nv_mask(dev, 0x104050, 0x40000000, 0x00000000);
+       /* mark next channel as invalid if it's about to be loaded */
+       if (nv_rd32(dev, 0x104054) == inst)
+               nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+       /* restore fifo access */
+       nv_wr32(dev, 0x104048, 0x00000003);
+
+       for (inst = 0xc0; inst <= 0xd4; inst += 4)
+               nv_wo32(chan->ramin, inst, 0x00000000);
+
+       nouveau_gpuobj_ref(NULL, &ctx);
+
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
+}
+
+static void
+nva3_copy_tlb_flush(struct drm_device *dev, int engine)
+{
+       nv50_vm_flush_engine(dev, 0x0d);
+}
+
+static int
+nva3_copy_init(struct drm_device *dev, int engine)
+{
+       int i;
+
+       nv_mask(dev, 0x000200, 0x00002000, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00002000, 0x00002000);
+       nv_wr32(dev, 0x104014, 0xffffffff); /* disable all interrupts */
+
+       /* upload ucode */
+       nv_wr32(dev, 0x1041c0, 0x01000000);
+       for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
+               nv_wr32(dev, 0x1041c4, nva3_pcopy_data[i]);
+
+       nv_wr32(dev, 0x104180, 0x01000000);
+       for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
+               if ((i & 0x3f) == 0)
+                       nv_wr32(dev, 0x104188, i >> 6);
+               nv_wr32(dev, 0x104184, nva3_pcopy_code[i]);
+       }
+
+       /* start it running */
+       nv_wr32(dev, 0x10410c, 0x00000000);
+       nv_wr32(dev, 0x104104, 0x00000000); /* ENTRY */
+       nv_wr32(dev, 0x104100, 0x00000002); /* TRIGGER */
+       return 0;
+}
+
+static int
+nva3_copy_fini(struct drm_device *dev, int engine)
+{
+       nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
+
+       /* trigger fuc context unload */
+       nv_wait(dev, 0x104008, 0x0000000c, 0x00000000);
+       nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+       nv_wr32(dev, 0x104000, 0x00000008);
+       nv_wait(dev, 0x104008, 0x00000008, 0x00000000);
+
+       nv_wr32(dev, 0x104014, 0xffffffff);
+       return 0;
+}
+
+static struct nouveau_enum nva3_copy_isr_error_name[] = {
+       { 0x0001, "ILLEGAL_MTHD" },
+       { 0x0002, "INVALID_ENUM" },
+       { 0x0003, "INVALID_BITFIELD" },
+       {}
+};
+
+static void
+nva3_copy_isr(struct drm_device *dev)
+{
+       u32 dispatch = nv_rd32(dev, 0x10401c);
+       u32 stat = nv_rd32(dev, 0x104008) & dispatch & ~(dispatch >> 16);
+       u32 inst = nv_rd32(dev, 0x104050) & 0x3fffffff;
+       u32 ssta = nv_rd32(dev, 0x104040) & 0x0000ffff;
+       u32 addr = nv_rd32(dev, 0x104040) >> 16;
+       u32 mthd = (addr & 0x07ff) << 2;
+       u32 subc = (addr & 0x3800) >> 11;
+       u32 data = nv_rd32(dev, 0x104044);
+       int chid = nv50_graph_isr_chid(dev, inst);
+
+       if (stat & 0x00000040) {
+               NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+               nouveau_enum_print(nva3_copy_isr_error_name, ssta);
+               printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
+                       chid, inst, subc, mthd, data);
+               nv_wr32(dev, 0x104004, 0x00000040);
+               stat &= ~0x00000040;
+       }
+
+       if (stat) {
+               NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+               nv_wr32(dev, 0x104004, stat);
+       }
+       nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nva3_copy_destroy(struct drm_device *dev, int engine)
+{
+       struct nva3_copy_engine *pcopy = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 22);
+
+       NVOBJ_ENGINE_DEL(dev, COPY0);
+       kfree(pcopy);
+}
+
+int
+nva3_copy_create(struct drm_device *dev)
+{
+       struct nva3_copy_engine *pcopy;
+
+       pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+       if (!pcopy)
+               return -ENOMEM;
+
+       pcopy->base.destroy = nva3_copy_destroy;
+       pcopy->base.init = nva3_copy_init;
+       pcopy->base.fini = nva3_copy_fini;
+       pcopy->base.context_new = nva3_copy_context_new;
+       pcopy->base.context_del = nva3_copy_context_del;
+       pcopy->base.object_new = nva3_copy_object_new;
+       pcopy->base.tlb_flush = nva3_copy_tlb_flush;
+
+       nouveau_irq_register(dev, 22, nva3_copy_isr);
+
+       NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+       NVOBJ_CLASS(dev, 0x85b5, COPY0);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc b/drivers/gpu/drm/nouveau/nva3_copy.fuc
new file mode 100644 (file)
index 0000000..eaf35f8
--- /dev/null
@@ -0,0 +1,870 @@
+/* fuc microcode for copy engine on nva3- chipsets
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* To build for nva3:nvc0
+ *    m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h
+ *
+ * To build for nvc0-
+ *    m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h
+ */
+
+ifdef(`NVA3',
+.section nva3_pcopy_data,
+.section nvc0_pcopy_data
+)
+
+ctx_object:                   .b32 0
+ifdef(`NVA3',
+ctx_dma:
+ctx_dma_query:                .b32 0
+ctx_dma_src:                  .b32 0
+ctx_dma_dst:                  .b32 0
+,)
+.equ ctx_dma_count 3
+ctx_query_address_high:       .b32 0
+ctx_query_address_low:        .b32 0
+ctx_query_counter:            .b32 0
+ctx_src_address_high:         .b32 0
+ctx_src_address_low:          .b32 0
+ctx_src_pitch:                .b32 0
+ctx_src_tile_mode:            .b32 0
+ctx_src_xsize:                .b32 0
+ctx_src_ysize:                .b32 0
+ctx_src_zsize:                .b32 0
+ctx_src_zoff:                 .b32 0
+ctx_src_xoff:                 .b32 0
+ctx_src_yoff:                 .b32 0
+ctx_src_cpp:                  .b32 0
+ctx_dst_address_high:         .b32 0
+ctx_dst_address_low:          .b32 0
+ctx_dst_pitch:                .b32 0
+ctx_dst_tile_mode:            .b32 0
+ctx_dst_xsize:                .b32 0
+ctx_dst_ysize:                .b32 0
+ctx_dst_zsize:                .b32 0
+ctx_dst_zoff:                 .b32 0
+ctx_dst_xoff:                 .b32 0
+ctx_dst_yoff:                 .b32 0
+ctx_dst_cpp:                  .b32 0
+ctx_format:                   .b32 0
+ctx_swz_const0:               .b32 0
+ctx_swz_const1:               .b32 0
+ctx_xcnt:                     .b32 0
+ctx_ycnt:                     .b32 0
+.align 256
+
+dispatch_table:
+// mthd 0x0000, NAME
+.b16 0x000 1
+.b32 ctx_object                     ~0xffffffff
+// mthd 0x0100, NOP
+.b16 0x040 1
+.b32 0x00010000 + cmd_nop           ~0xffffffff
+// mthd 0x0140, PM_TRIGGER
+.b16 0x050 1
+.b32 0x00010000 + cmd_pm_trigger    ~0xffffffff
+ifdef(`NVA3', `
+// mthd 0x0180-0x018c, DMA_
+.b16 0x060 ctx_dma_count
+dispatch_dma:
+.b32 0x00010000 + cmd_dma           ~0xffffffff
+.b32 0x00010000 + cmd_dma           ~0xffffffff
+.b32 0x00010000 + cmd_dma           ~0xffffffff
+',)
+// mthd 0x0200-0x0218, SRC_TILE
+.b16 0x80 7
+.b32 ctx_src_tile_mode              ~0x00000fff
+.b32 ctx_src_xsize                  ~0x0007ffff
+.b32 ctx_src_ysize                  ~0x00001fff
+.b32 ctx_src_zsize                  ~0x000007ff
+.b32 ctx_src_zoff                   ~0x00000fff
+.b32 ctx_src_xoff                   ~0x0007ffff
+.b32 ctx_src_yoff                   ~0x00001fff
+// mthd 0x0220-0x0238, DST_TILE
+.b16 0x88 7
+.b32 ctx_dst_tile_mode              ~0x00000fff
+.b32 ctx_dst_xsize                  ~0x0007ffff
+.b32 ctx_dst_ysize                  ~0x00001fff
+.b32 ctx_dst_zsize                  ~0x000007ff
+.b32 ctx_dst_zoff                   ~0x00000fff
+.b32 ctx_dst_xoff                   ~0x0007ffff
+.b32 ctx_dst_yoff                   ~0x00001fff
+// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
+.b16 0xc0 2
+.b32 0x00010000 + cmd_exec          ~0xffffffff
+.b32 0x00010000 + cmd_wrcache_flush ~0xffffffff
+// mthd 0x030c-0x0340, various stuff
+.b16 0xc3 14
+.b32 ctx_src_address_high           ~0x000000ff
+.b32 ctx_src_address_low            ~0xfffffff0
+.b32 ctx_dst_address_high           ~0x000000ff
+.b32 ctx_dst_address_low            ~0xfffffff0
+.b32 ctx_src_pitch                  ~0x0007ffff
+.b32 ctx_dst_pitch                  ~0x0007ffff
+.b32 ctx_xcnt                       ~0x0000ffff
+.b32 ctx_ycnt                       ~0x00001fff
+.b32 ctx_format                     ~0x0333ffff
+.b32 ctx_swz_const0                 ~0xffffffff
+.b32 ctx_swz_const1                 ~0xffffffff
+.b32 ctx_query_address_high         ~0x000000ff
+.b32 ctx_query_address_low          ~0xffffffff
+.b32 ctx_query_counter              ~0xffffffff
+.b16 0x800 0
+
+ifdef(`NVA3',
+.section nva3_pcopy_code,
+.section nvc0_pcopy_code
+)
+
+main:
+   clear b32 $r0
+   mov $sp $r0
+
+   // setup i0 handler and route fifo and ctxswitch to it
+   mov $r1 ih
+   mov $iv0 $r1
+   mov $r1 0x400
+   movw $r2 0xfff3
+   sethi $r2 0
+   iowr I[$r2 + 0x300] $r2
+
+   // enable interrupts
+   or $r2 0xc
+   iowr I[$r1] $r2
+   bset $flags ie0
+
+   // enable fifo access and context switching
+   mov $r1 0x1200
+   mov $r2 3
+   iowr I[$r1] $r2
+
+   // sleep forever, waking for interrupts
+   bset $flags $p0
+   spin:
+      sleep $p0
+      bra spin
+
+// i0 handler
+ih:
+   iord $r1 I[$r0 + 0x200]
+
+   and $r2 $r1 0x00000008
+   bra e ih_no_chsw
+      call chsw
+   ih_no_chsw:
+   and $r2 $r1 0x00000004
+   bra e ih_no_cmd
+      call dispatch
+
+   ih_no_cmd:
+   and $r1 $r1 0x0000000c
+   iowr I[$r0 + 0x100] $r1
+   iret
+
+// $p1 direction (0 = unload, 1 = load)
+// $r3 channel
+swctx:
+   mov $r4 0x7700
+   mov $xtargets $r4
+ifdef(`NVA3', `
+   // target 7 hardcoded to ctx dma object
+   mov $xdbase $r0
+', ` // NVC0
+   // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
+   mov $r4 0x2100
+   iord $r4 I[$r4 + 0]
+   and $r4 1
+   shl b32 $r4 4
+   add b32 $r4 0x30
+
+   // channel is in vram
+   mov $r15 0x61c
+   shl b32 $r15 6
+   mov $r5 0x114
+   iowrs I[$r15] $r5
+
+   // read 16-byte PCOPYn info, containing context pointer, from channel
+   shl b32 $r5 $r3 4
+   add b32 $r5 2
+   mov $xdbase $r5
+   mov $r5 $sp
+   // get a chunk of stack space, aligned to 256 byte boundary
+   sub b32 $r5 0x100
+   mov $r6 0xff
+   not b32 $r6
+   and $r5 $r6
+   sethi $r5 0x00020000
+   xdld $r4 $r5
+   xdwait
+   sethi $r5 0
+
+   // set context pointer, from within channel VM
+   mov $r14 0
+   iowrs I[$r15] $r14
+   ld b32 $r4 D[$r5 + 0]
+   shr b32 $r4 8
+   ld b32 $r6 D[$r5 + 4]
+   shl b32 $r6 24
+   or $r4 $r6
+   mov $xdbase $r4
+')
+   // 256-byte context, at start of data segment
+   mov b32 $r4 $r0
+   sethi $r4 0x60000
+
+   // swap!
+   bra $p1 swctx_load
+      xdst $r0 $r4
+      bra swctx_done
+   swctx_load:
+      xdld $r0 $r4
+   swctx_done:
+   xdwait
+   ret
+
+chsw:
+   // read current channel
+   mov $r2 0x1400
+   iord $r3 I[$r2]
+
+   // if it's active, unload it and return
+   xbit $r15 $r3 0x1e
+   bra e chsw_no_unload
+      bclr $flags $p1
+      call swctx
+      bclr $r3 0x1e
+      iowr I[$r2] $r3
+      mov $r4 1
+      iowr I[$r2 + 0x200] $r4
+      ret
+
+   // read next channel
+   chsw_no_unload:
+   iord $r3 I[$r2 + 0x100]
+
+   // is there a channel waiting to be loaded?
+   xbit $r13 $r3 0x1e
+   bra e chsw_finish_load
+      bset $flags $p1
+      call swctx
+ifdef(`NVA3',
+      // load dma objects back into TARGET regs
+      mov $r5 ctx_dma
+      mov $r6 ctx_dma_count
+      chsw_load_ctx_dma:
+         ld b32 $r7 D[$r5 + $r6 * 4]
+         add b32 $r8 $r6 0x180
+         shl b32 $r8 8
+         iowr I[$r8] $r7
+         sub b32 $r6 1
+         bra nc chsw_load_ctx_dma
+,)
+
+   chsw_finish_load:
+   mov $r3 2
+   iowr I[$r2 + 0x200] $r3
+   ret
+
+dispatch:
+   // read incoming fifo command
+   mov $r3 0x1900
+   iord $r2 I[$r3 + 0x100]
+   iord $r3 I[$r3 + 0x000]
+   and $r4 $r2 0x7ff
+   // $r2 will be used to store exception data
+   shl b32 $r2 0x10
+
+   // lookup method in the dispatch table, ILLEGAL_MTHD if not found
+   mov $r5 dispatch_table
+   clear b32 $r6
+   clear b32 $r7
+   dispatch_loop:
+      ld b16 $r6 D[$r5 + 0]
+      ld b16 $r7 D[$r5 + 2]
+      add b32 $r5 4
+      cmpu b32 $r4 $r6
+      bra c dispatch_illegal_mthd
+      add b32 $r7 $r6
+      cmpu b32 $r4 $r7
+      bra c dispatch_valid_mthd
+      sub b32 $r7 $r6
+      shl b32 $r7 3
+      add b32 $r5 $r7
+      bra dispatch_loop
+
+   // ensure no bits set in reserved fields, INVALID_BITFIELD
+   dispatch_valid_mthd:
+   sub b32 $r4 $r6
+   shl b32 $r4 3
+   add b32 $r4 $r5
+   ld b32 $r5 D[$r4 + 4]
+   and $r5 $r3
+   cmpu b32 $r5 0
+   bra ne dispatch_invalid_bitfield
+
+   // depending on dispatch flags: execute method, or save data as state
+   ld b16 $r5 D[$r4 + 0]
+   ld b16 $r6 D[$r4 + 2]
+   cmpu b32 $r6 0
+   bra ne dispatch_cmd
+      st b32 D[$r5] $r3
+      bra dispatch_done
+   dispatch_cmd:
+      bclr $flags $p1
+      call $r5
+      bra $p1 dispatch_error
+      bra dispatch_done
+
+   dispatch_invalid_bitfield:
+   or $r2 2
+   dispatch_illegal_mthd:
+   or $r2 1
+
+   // store exception data in SCRATCH0/SCRATCH1, signal hostirq
+   dispatch_error:
+   mov $r4 0x1000
+   iowr I[$r4 + 0x000] $r2
+   iowr I[$r4 + 0x100] $r3
+   mov $r2 0x40
+   iowr I[$r0] $r2
+   hostirq_wait:
+      iord $r2 I[$r0 + 0x200]
+      and $r2 0x40
+      cmpu b32 $r2 0
+      bra ne hostirq_wait
+
+   dispatch_done:
+   mov $r2 0x1d00
+   mov $r3 1
+   iowr I[$r2] $r3
+   ret
+
+// No-operation
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_nop:
+   ret
+
+// PM_TRIGGER
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_pm_trigger:
+   mov $r2 0x2200
+   clear b32 $r3
+   sethi $r3 0x20000
+   iowr I[$r2] $r3
+   ret
+
+ifdef(`NVA3',
+// SET_DMA_* method handler
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_dma:
+   sub b32 $r4 dispatch_dma
+   shr b32 $r4 1
+   bset $r3 0x1e
+   st b32 D[$r4 + ctx_dma] $r3
+   add b32 $r4 0x600
+   shl b32 $r4 6
+   iowr I[$r4] $r3
+   ret
+,)
+
+// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
+//
+cmd_exec_set_format:
+   // zero out a chunk of the stack to store the swizzle into
+   add $sp -0x10
+   st b32 D[$sp + 0x00] $r0
+   st b32 D[$sp + 0x04] $r0
+   st b32 D[$sp + 0x08] $r0
+   st b32 D[$sp + 0x0c] $r0
+
+   // extract cpp, src_ncomp and dst_ncomp from FORMAT
+   ld b32 $r4 D[$r0 + ctx_format]
+   extr $r5 $r4 16:17
+   add b32 $r5 1
+   extr $r6 $r4 20:21
+   add b32 $r6 1
+   extr $r7 $r4 24:25
+   add b32 $r7 1
+
+   // convert FORMAT swizzle mask to hw swizzle mask
+   bclr $flags $p2
+   clear b32 $r8
+   clear b32 $r9
+   ncomp_loop:
+      and $r10 $r4 0xf
+      shr b32 $r4 4
+      clear b32 $r11
+      bpc_loop:
+         cmpu b8 $r10 4
+         bra nc cmp_c0
+            mulu $r12 $r10 $r5
+            add b32 $r12 $r11
+            bset $flags $p2
+            bra bpc_next
+         cmp_c0:
+         bra ne cmp_c1
+            mov $r12 0x10
+            add b32 $r12 $r11
+            bra bpc_next
+         cmp_c1:
+         cmpu b8 $r10 6
+         bra nc cmp_zero
+            mov $r12 0x14
+            add b32 $r12 $r11
+            bra bpc_next
+         cmp_zero:
+            mov $r12 0x80
+         bpc_next:
+         st b8 D[$sp + $r8] $r12
+         add b32 $r8 1
+         add b32 $r11 1
+         cmpu b32 $r11 $r5
+         bra c bpc_loop
+      add b32 $r9 1
+      cmpu b32 $r9 $r7
+      bra c ncomp_loop
+
+   // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
+   mulu $r6 $r5
+   st b32 D[$r0 + ctx_src_cpp] $r6
+   ld b32 $r8 D[$r0 + ctx_xcnt]
+   mulu $r6 $r8
+   bra $p2 dst_xcnt
+   clear b32 $r6
+
+   dst_xcnt:
+   mulu $r7 $r5
+   st b32 D[$r0 + ctx_dst_cpp] $r7
+   mulu $r7 $r8
+
+   mov $r5 0x810
+   shl b32 $r5 6
+   iowr I[$r5 + 0x000] $r6
+   iowr I[$r5 + 0x100] $r7
+   add b32 $r5 0x800
+   ld b32 $r6 D[$r0 + ctx_dst_cpp]
+   sub b32 $r6 1
+   shl b32 $r6 8
+   ld b32 $r7 D[$r0 + ctx_src_cpp]
+   sub b32 $r7 1
+   or $r6 $r7
+   iowr I[$r5 + 0x000] $r6
+   add b32 $r5 0x100
+   ld b32 $r6 D[$sp + 0x00]
+   iowr I[$r5 + 0x000] $r6
+   ld b32 $r6 D[$sp + 0x04]
+   iowr I[$r5 + 0x100] $r6
+   ld b32 $r6 D[$sp + 0x08]
+   iowr I[$r5 + 0x200] $r6
+   ld b32 $r6 D[$sp + 0x0c]
+   iowr I[$r5 + 0x300] $r6
+   add b32 $r5 0x400
+   ld b32 $r6 D[$r0 + ctx_swz_const0]
+   iowr I[$r5 + 0x000] $r6
+   ld b32 $r6 D[$r0 + ctx_swz_const1]
+   iowr I[$r5 + 0x100] $r6
+   add $sp 0x10
+   ret
+
+// Setup to handle a tiled surface
+//
+// Calculates a number of parameters the hardware requires in order
+// to correctly handle tiling.
+//
+// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
+//    nTx = round_up(w * cpp, 1 << Tp) >> Tp
+//    nTy = round_up(h, 1 << Th) >> Th
+//    Txo = (x * cpp) & ((1 << Tp) - 1)
+//     Tx = (x * cpp) >> Tp
+//    Tyo = y & ((1 << Th) - 1)
+//     Ty = y >> Th
+//    Tzo = z & ((1 << Td) - 1)
+//     Tz = z >> Td
+//
+//    off  = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
+//    off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
+//
+// Inputs:
+//    $r4: hw command (0x104800)
+//    $r5: ctx offset adjustment for src/dst selection
+//    $p2: set if dst surface
+//
+cmd_exec_set_surface_tiled:
+   // translate TILE_MODE into Tp, Th, Td shift values
+   ld b32 $r7 D[$r5 + ctx_src_tile_mode]
+   extr $r9 $r7 8:11
+   extr $r8 $r7 4:7
+ifdef(`NVA3',
+   add b32 $r8 2
+,
+   add b32 $r8 3
+)
+   extr $r7 $r7 0:3
+   cmp b32 $r7 0xe
+   bra ne xtile64
+   mov $r7 4
+   bra xtileok
+   xtile64:
+   xbit $r7 $flags $p2
+   add b32 $r7 17
+   bset $r4 $r7
+   mov $r7 6
+   xtileok:
+
+   // Op = (x * cpp) & ((1 << Tp) - 1)
+   // Tx = (x * cpp) >> Tp
+   ld b32 $r10 D[$r5 + ctx_src_xoff]
+   ld b32 $r11 D[$r5 + ctx_src_cpp]
+   mulu $r10 $r11
+   mov $r11 1
+   shl b32 $r11 $r7
+   sub b32 $r11 1
+   and $r12 $r10 $r11
+   shr b32 $r10 $r7
+
+   // Tyo = y & ((1 << Th) - 1)
+   // Ty  = y >> Th
+   ld b32 $r13 D[$r5 + ctx_src_yoff]
+   mov $r14 1
+   shl b32 $r14 $r8
+   sub b32 $r14 1
+   and $r11 $r13 $r14
+   shr b32 $r13 $r8
+
+   // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
+   add b32 $r14 1
+   shl b32 $r15 $r14 12
+   sub b32 $r14 $r11
+   or $r15 $r14
+   xbit $r6 $flags $p2
+   add b32 $r6 0x208
+   shl b32 $r6 8
+   iowr I[$r6 + 0x000] $r15
+
+   // Op += Tyo << Tp
+   shl b32 $r11 $r7
+   add b32 $r12 $r11
+
+   // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
+   ld b32 $r15 D[$r5 + ctx_src_xsize]
+   ld b32 $r11 D[$r5 + ctx_src_cpp]
+   mulu $r15 $r11
+   mov $r11 1
+   shl b32 $r11 $r7
+   sub b32 $r11 1
+   add b32 $r15 $r11
+   shr b32 $r15 $r7
+   push $r15
+
+   // nTy = (h + ((1 << Th) - 1)) >> Th
+   ld b32 $r15 D[$r5 + ctx_src_ysize]
+   mov $r11 1
+   shl b32 $r11 $r8
+   sub b32 $r11 1
+   add b32 $r15 $r11
+   shr b32 $r15 $r8
+   push $r15
+
+   // Tys = Tp + Th
+   // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
+   add b32 $r7 $r8
+   sub b32 $r8 2
+   mov $r11 1
+   shl b32 $r11 $r8
+   shl b32 $r11 $r9
+
+   // Tzo = z & ((1 << Td) - 1)
+   // Tz  = z >> Td
+   // Op += Tzo << Tys
+   // Ts  = Tys + Td
+   ld b32 $r8 D[$r5 + ctx_src_zoff]
+   mov $r14 1
+   shl b32 $r14 $r9
+   sub b32 $r14 1
+   and $r15 $r8 $r14
+   shl b32 $r15 $r7
+   add b32 $r12 $r15
+   add b32 $r7 $r9
+   shr b32 $r8 $r9
+
+   // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
+   pop $r15
+   pop $r9
+   mulu $r13 $r9
+   add b32 $r10 $r13
+   mulu $r8 $r9
+   mulu $r8 $r15
+   add b32 $r10 $r8
+   shl b32 $r10 $r7
+
+   // PITCH = (nTx - 1) << Ts
+   sub b32 $r9 1
+   shl b32 $r9 $r7
+   iowr I[$r6 + 0x200] $r9
+
+   // SRC_ADDRESS_LOW   = (Ot + Op) & 0xffffffff
+   // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
+   ld b32 $r7 D[$r5 + ctx_src_address_low]
+   ld b32 $r8 D[$r5 + ctx_src_address_high]
+   add b32 $r10 $r12
+   add b32 $r7 $r10
+   adc b32 $r8 0
+   shl b32 $r8 16
+   or $r8 $r11
+   sub b32 $r6 0x600
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   iowr I[$r6 + 0x000] $r8
+   ret
+
+// Setup to handle a linear surface
+//
+// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
+//
+cmd_exec_set_surface_linear:
+   xbit $r6 $flags $p2
+   add b32 $r6 0x202
+   shl b32 $r6 8
+   ld b32 $r7 D[$r5 + ctx_src_address_low]
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   ld b32 $r7 D[$r5 + ctx_src_address_high]
+   shl b32 $r7 16
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   ld b32 $r7 D[$r5 + ctx_src_pitch]
+   iowr I[$r6 + 0x000] $r7
+   ret
+
+// wait for regs to be available for use
+cmd_exec_wait:
+   push $r0
+   push $r1
+   mov $r0 0x800
+   shl b32 $r0 6
+   loop:
+      iord $r1 I[$r0]
+      and $r1 1
+      bra ne loop
+   pop $r1
+   pop $r0
+   ret
+
+cmd_exec_query:
+   // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
+   xbit $r4 $r3 13
+   bra ne query_counter
+      call cmd_exec_wait
+      mov $r4 0x80c
+      shl b32 $r4 6
+      ld b32 $r5 D[$r0 + ctx_query_address_low]
+      add b32 $r5 4
+      iowr I[$r4 + 0x000] $r5
+      iowr I[$r4 + 0x100] $r0
+      mov $r5 0xc
+      iowr I[$r4 + 0x200] $r5
+      add b32 $r4 0x400
+      ld b32 $r5 D[$r0 + ctx_query_address_high]
+      shl b32 $r5 16
+      iowr I[$r4 + 0x000] $r5
+      add b32 $r4 0x500
+      mov $r5 0x00000b00
+      sethi $r5 0x00010000
+      iowr I[$r4 + 0x000] $r5
+      mov $r5 0x00004040
+      shl b32 $r5 1
+      sethi $r5 0x80800000
+      iowr I[$r4 + 0x100] $r5
+      mov $r5 0x00001110
+      sethi $r5 0x13120000
+      iowr I[$r4 + 0x200] $r5
+      mov $r5 0x00001514
+      sethi $r5 0x17160000
+      iowr I[$r4 + 0x300] $r5
+      mov $r5 0x00002601
+      sethi $r5 0x00010000
+      mov $r4 0x800
+      shl b32 $r4 6
+      iowr I[$r4 + 0x000] $r5
+
+   // write COUNTER
+   query_counter:
+   call cmd_exec_wait
+   mov $r4 0x80c
+   shl b32 $r4 6
+   ld b32 $r5 D[$r0 + ctx_query_address_low]
+   iowr I[$r4 + 0x000] $r5
+   iowr I[$r4 + 0x100] $r0
+   mov $r5 0x4
+   iowr I[$r4 + 0x200] $r5
+   add b32 $r4 0x400
+   ld b32 $r5 D[$r0 + ctx_query_address_high]
+   shl b32 $r5 16
+   iowr I[$r4 + 0x000] $r5
+   add b32 $r4 0x500
+   mov $r5 0x00000300
+   iowr I[$r4 + 0x000] $r5
+   mov $r5 0x00001110
+   sethi $r5 0x13120000
+   iowr I[$r4 + 0x100] $r5
+   ld b32 $r5 D[$r0 + ctx_query_counter]
+   add b32 $r4 0x500
+   iowr I[$r4 + 0x000] $r5
+   mov $r5 0x00002601
+   sethi $r5 0x00010000
+   mov $r4 0x800
+   shl b32 $r4 6
+   iowr I[$r4 + 0x000] $r5
+   ret
+
+// Execute a copy operation
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//       000002000 QUERY_SHORT
+//       000001000 QUERY
+//       000000100 DST_LINEAR
+//       000000010 SRC_LINEAR
+//       000000001 FORMAT
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_exec:
+   call cmd_exec_wait
+
+   // if format requested, call function to calculate it, otherwise
+   // fill in cpp/xcnt for both surfaces as if (cpp == 1)
+   xbit $r15 $r3 0
+   bra e cmd_exec_no_format
+      call cmd_exec_set_format
+      mov $r4 0x200
+      bra cmd_exec_init_src_surface
+   cmd_exec_no_format:
+      mov $r6 0x810
+      shl b32 $r6 6
+      mov $r7 1
+      st b32 D[$r0 + ctx_src_cpp] $r7
+      st b32 D[$r0 + ctx_dst_cpp] $r7
+      ld b32 $r7 D[$r0 + ctx_xcnt]
+      iowr I[$r6 + 0x000] $r7
+      iowr I[$r6 + 0x100] $r7
+      clear b32 $r4
+
+   cmd_exec_init_src_surface:
+   bclr $flags $p2
+   clear b32 $r5
+   xbit $r15 $r3 4
+   bra e src_tiled
+      call cmd_exec_set_surface_linear
+      bra cmd_exec_init_dst_surface
+   src_tiled:
+      call cmd_exec_set_surface_tiled
+      bset $r4 7
+
+   cmd_exec_init_dst_surface:
+   bset $flags $p2
+   mov $r5 ctx_dst_address_high - ctx_src_address_high
+   xbit $r15 $r3 8
+   bra e dst_tiled
+      call cmd_exec_set_surface_linear
+      bra cmd_exec_kick
+   dst_tiled:
+      call cmd_exec_set_surface_tiled
+      bset $r4 8
+
+   cmd_exec_kick:
+   mov $r5 0x800
+   shl b32 $r5 6
+   ld b32 $r6 D[$r0 + ctx_ycnt]
+   iowr I[$r5 + 0x100] $r6
+   mov $r6 0x0041
+   // SRC_TARGET = 1, DST_TARGET = 2
+   sethi $r6 0x44000000
+   or $r4 $r6
+   iowr I[$r5] $r4
+
+   // if requested, queue up a QUERY write after the copy has completed
+   xbit $r15 $r3 12
+   bra e cmd_exec_done
+      call cmd_exec_query
+
+   cmd_exec_done:
+   ret
+
+// Flush write cache
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_wrcache_flush:
+   mov $r2 0x2200
+   clear b32 $r3
+   sethi $r3 0x10000
+   iowr I[$r2] $r3
+   ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc.h b/drivers/gpu/drm/nouveau/nva3_copy.fuc.h
new file mode 100644 (file)
index 0000000..2731de2
--- /dev/null
@@ -0,0 +1,534 @@
+uint32_t nva3_pcopy_data[] = {
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00010000,
+       0x00000000,
+       0x00000000,
+       0x00010040,
+       0x00010160,
+       0x00000000,
+       0x00010050,
+       0x00010162,
+       0x00000000,
+       0x00030060,
+       0x00010170,
+       0x00000000,
+       0x00010170,
+       0x00000000,
+       0x00010170,
+       0x00000000,
+       0x00070080,
+       0x00000028,
+       0xfffff000,
+       0x0000002c,
+       0xfff80000,
+       0x00000030,
+       0xffffe000,
+       0x00000034,
+       0xfffff800,
+       0x00000038,
+       0xfffff000,
+       0x0000003c,
+       0xfff80000,
+       0x00000040,
+       0xffffe000,
+       0x00070088,
+       0x00000054,
+       0xfffff000,
+       0x00000058,
+       0xfff80000,
+       0x0000005c,
+       0xffffe000,
+       0x00000060,
+       0xfffff800,
+       0x00000064,
+       0xfffff000,
+       0x00000068,
+       0xfff80000,
+       0x0000006c,
+       0xffffe000,
+       0x000200c0,
+       0x00010492,
+       0x00000000,
+       0x0001051b,
+       0x00000000,
+       0x000e00c3,
+       0x0000001c,
+       0xffffff00,
+       0x00000020,
+       0x0000000f,
+       0x00000048,
+       0xffffff00,
+       0x0000004c,
+       0x0000000f,
+       0x00000024,
+       0xfff80000,
+       0x00000050,
+       0xfff80000,
+       0x00000080,
+       0xffff0000,
+       0x00000084,
+       0xffffe000,
+       0x00000074,
+       0xfccc0000,
+       0x00000078,
+       0x00000000,
+       0x0000007c,
+       0x00000000,
+       0x00000010,
+       0xffffff00,
+       0x00000014,
+       0x00000000,
+       0x00000018,
+       0x00000000,
+       0x00000800,
+};
+
+uint32_t nva3_pcopy_code[] = {
+       0x04fe04bd,
+       0x3517f000,
+       0xf10010fe,
+       0xf1040017,
+       0xf0fff327,
+       0x22d00023,
+       0x0c25f0c0,
+       0xf40012d0,
+       0x17f11031,
+       0x27f01200,
+       0x0012d003,
+       0xf40031f4,
+       0x0ef40028,
+       0x8001cffd,
+       0xf40812c4,
+       0x21f4060b,
+       0x0412c472,
+       0xf4060bf4,
+       0x11c4c321,
+       0x4001d00c,
+       0x47f101f8,
+       0x4bfe7700,
+       0x0007fe00,
+       0xf00204b9,
+       0x01f40643,
+       0x0604fa09,
+       0xfa060ef4,
+       0x03f80504,
+       0x27f100f8,
+       0x23cf1400,
+       0x1e3fc800,
+       0xf4170bf4,
+       0x21f40132,
+       0x1e3af052,
+       0xf00023d0,
+       0x24d00147,
+       0xcf00f880,
+       0x3dc84023,
+       0x220bf41e,
+       0xf40131f4,
+       0x57f05221,
+       0x0367f004,
+       0xa07856bc,
+       0xb6018068,
+       0x87d00884,
+       0x0162b600,
+       0xf0f018f4,
+       0x23d00237,
+       0xf100f880,
+       0xcf190037,
+       0x33cf4032,
+       0xff24e400,
+       0x1024b607,
+       0x010057f1,
+       0x74bd64bd,
+       0x58005658,
+       0x50b60157,
+       0x0446b804,
+       0xbb4d08f4,
+       0x47b80076,
+       0x0f08f404,
+       0xb60276bb,
+       0x57bb0374,
+       0xdf0ef400,
+       0xb60246bb,
+       0x45bb0344,
+       0x01459800,
+       0xb00453fd,
+       0x1bf40054,
+       0x00455820,
+       0xb0014658,
+       0x1bf40064,
+       0x00538009,
+       0xf4300ef4,
+       0x55f90132,
+       0xf40c01f4,
+       0x25f0250e,
+       0x0125f002,
+       0x100047f1,
+       0xd00042d0,
+       0x27f04043,
+       0x0002d040,
+       0xf08002cf,
+       0x24b04024,
+       0xf71bf400,
+       0x1d0027f1,
+       0xd00137f0,
+       0x00f80023,
+       0x27f100f8,
+       0x34bd2200,
+       0xd00233f0,
+       0x00f80023,
+       0x012842b7,
+       0xf00145b6,
+       0x43801e39,
+       0x0040b701,
+       0x0644b606,
+       0xf80043d0,
+       0xf030f400,
+       0xb00001b0,
+       0x01b00101,
+       0x0301b002,
+       0xc71d0498,
+       0x50b63045,
+       0x3446c701,
+       0xc70160b6,
+       0x70b63847,
+       0x0232f401,
+       0x94bd84bd,
+       0xb60f4ac4,
+       0xb4bd0445,
+       0xf404a430,
+       0xa5ff0f18,
+       0x00cbbbc0,
+       0xf40231f4,
+       0x1bf4220e,
+       0x10c7f00c,
+       0xf400cbbb,
+       0xa430160e,
+       0x0c18f406,
+       0xbb14c7f0,
+       0x0ef400cb,
+       0x80c7f107,
+       0x01c83800,
+       0xb60180b6,
+       0xb5b801b0,
+       0xc308f404,
+       0xb80190b6,
+       0x08f40497,
+       0x0065fdb2,
+       0x98110680,
+       0x68fd2008,
+       0x0502f400,
+       0x75fd64bd,
+       0x1c078000,
+       0xf10078fd,
+       0xb6081057,
+       0x56d00654,
+       0x4057d000,
+       0x080050b7,
+       0xb61c0698,
+       0x64b60162,
+       0x11079808,
+       0xfd0172b6,
+       0x56d00567,
+       0x0050b700,
+       0x0060b401,
+       0xb40056d0,
+       0x56d00160,
+       0x0260b440,
+       0xb48056d0,
+       0x56d00360,
+       0x0050b7c0,
+       0x1e069804,
+       0x980056d0,
+       0x56d01f06,
+       0x1030f440,
+       0x579800f8,
+       0x6879c70a,
+       0xb66478c7,
+       0x77c70280,
+       0x0e76b060,
+       0xf0091bf4,
+       0x0ef40477,
+       0x027cf00f,
+       0xfd1170b6,
+       0x77f00947,
+       0x0f5a9806,
+       0xfd115b98,
+       0xb7f000ab,
+       0x04b7bb01,
+       0xff01b2b6,
+       0xa7bbc4ab,
+       0x105d9805,
+       0xbb01e7f0,
+       0xe2b604e8,
+       0xb4deff01,
+       0xb605d8bb,
+       0xef9401e0,
+       0x02ebbb0c,
+       0xf005fefd,
+       0x60b7026c,
+       0x64b60208,
+       0x006fd008,
+       0xbb04b7bb,
+       0x5f9800cb,
+       0x115b980b,
+       0xf000fbfd,
+       0xb7bb01b7,
+       0x01b2b604,
+       0xbb00fbbb,
+       0xf0f905f7,
+       0xf00c5f98,
+       0xb8bb01b7,
+       0x01b2b604,
+       0xbb00fbbb,
+       0xf0f905f8,
+       0xb60078bb,
+       0xb7f00282,
+       0x04b8bb01,
+       0x9804b9bb,
+       0xe7f00e58,
+       0x04e9bb01,
+       0xff01e2b6,
+       0xf7bbf48e,
+       0x00cfbb04,
+       0xbb0079bb,
+       0xf0fc0589,
+       0xd9fd90fc,
+       0x00adbb00,
+       0xfd0089fd,
+       0xa8bb008f,
+       0x04a7bb00,
+       0xbb0192b6,
+       0x69d00497,
+       0x08579880,
+       0xbb075898,
+       0x7abb00ac,
+       0x0081b600,
+       0xfd1084b6,
+       0x62b7058b,
+       0x67d00600,
+       0x0060b700,
+       0x0068d004,
+       0x6cf000f8,
+       0x0260b702,
+       0x0864b602,
+       0xd0085798,
+       0x60b70067,
+       0x57980400,
+       0x1074b607,
+       0xb70067d0,
+       0x98040060,
+       0x67d00957,
+       0xf900f800,
+       0xf110f900,
+       0xb6080007,
+       0x01cf0604,
+       0x0114f000,
+       0xfcfa1bf4,
+       0xf800fc10,
+       0x0d34c800,
+       0xf5701bf4,
+       0xf103ab21,
+       0xb6080c47,
+       0x05980644,
+       0x0450b605,
+       0xd00045d0,
+       0x57f04040,
+       0x8045d00c,
+       0x040040b7,
+       0xb6040598,
+       0x45d01054,
+       0x0040b700,
+       0x0057f105,
+       0x0153f00b,
+       0xf10045d0,
+       0xb6404057,
+       0x53f10154,
+       0x45d08080,
+       0x1057f140,
+       0x1253f111,
+       0x8045d013,
+       0x151457f1,
+       0x171653f1,
+       0xf1c045d0,
+       0xf0260157,
+       0x47f10153,
+       0x44b60800,
+       0x0045d006,
+       0x03ab21f5,
+       0x080c47f1,
+       0x980644b6,
+       0x45d00505,
+       0x4040d000,
+       0xd00457f0,
+       0x40b78045,
+       0x05980400,
+       0x1054b604,
+       0xb70045d0,
+       0xf1050040,
+       0xd0030057,
+       0x57f10045,
+       0x53f11110,
+       0x45d01312,
+       0x06059840,
+       0x050040b7,
+       0xf10045d0,
+       0xf0260157,
+       0x47f10153,
+       0x44b60800,
+       0x0045d006,
+       0x21f500f8,
+       0x3fc803ab,
+       0x0e0bf400,
+       0x018921f5,
+       0x020047f1,
+       0xf11e0ef4,
+       0xb6081067,
+       0x77f00664,
+       0x11078001,
+       0x981c0780,
+       0x67d02007,
+       0x4067d000,
+       0x32f444bd,
+       0xc854bd02,
+       0x0bf4043f,
+       0x8221f50a,
+       0x0a0ef403,
+       0x027621f5,
+       0xf40749f0,
+       0x57f00231,
+       0x083fc82c,
+       0xf50a0bf4,
+       0xf4038221,
+       0x21f50a0e,
+       0x49f00276,
+       0x0057f108,
+       0x0654b608,
+       0xd0210698,
+       0x67f04056,
+       0x0063f141,
+       0x0546fd44,
+       0xc80054d0,
+       0x0bf40c3f,
+       0xc521f507,
+       0xf100f803,
+       0xbd220027,
+       0x0133f034,
+       0xf80023d0,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
index dbbafed36406d6609502a0e6ccbeabf0c33dcc66..e4b2b9e934b2733e910ee7f2cab77c6548680857 100644 (file)
 #include "nouveau_bios.h"
 #include "nouveau_pm.h"
 
-/*XXX: boards using limits 0x40 need fixing, the register layout
- *     is correct here, but, there's some other funny magic
- *     that modifies things, so it's not likely we'll set/read
- *     the correct timings yet..  working on it...
+/* This is actually a lot more complex than it appears here, but hopefully
+ * this should be able to deal with what the VBIOS leaves for us..
+ *
+ * If not, well, I'll jump off that bridge when I come to it.
  */
 
 struct nva3_pm_state {
-       struct pll_lims pll;
-       int N, M, P;
+       enum pll_types type;
+       u32 src0;
+       u32 src1;
+       u32 ctrl;
+       u32 coef;
+       u32 old_pnm;
+       u32 new_pnm;
+       u32 new_div;
 };
 
+static int
+nva3_pm_pll_offset(u32 id)
+{
+       static const u32 pll_map[] = {
+               0x00, PLL_CORE,
+               0x01, PLL_SHADER,
+               0x02, PLL_MEMORY,
+               0x00, 0x00
+       };
+       const u32 *map = pll_map;
+
+       while (map[1]) {
+               if (id == map[1])
+                       return map[0];
+               map += 2;
+       }
+
+       return -ENOENT;
+}
+
 int
 nva3_pm_clock_get(struct drm_device *dev, u32 id)
 {
+       u32 src0, src1, ctrl, coef;
        struct pll_lims pll;
-       int P, N, M, ret;
-       u32 reg;
+       int ret, off;
+       int P, N, M;
 
        ret = get_pll_limits(dev, id, &pll);
        if (ret)
                return ret;
 
-       reg = nv_rd32(dev, pll.reg + 4);
-       P = (reg & 0x003f0000) >> 16;
-       N = (reg & 0x0000ff00) >> 8;
-       M = (reg & 0x000000ff);
+       off = nva3_pm_pll_offset(id);
+       if (off < 0)
+               return off;
+
+       src0 = nv_rd32(dev, 0x4120 + (off * 4));
+       src1 = nv_rd32(dev, 0x4160 + (off * 4));
+       ctrl = nv_rd32(dev, pll.reg + 0);
+       coef = nv_rd32(dev, pll.reg + 4);
+       NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                     id, src0, src1, ctrl, coef);
+
+       if (ctrl & 0x00000008) {
+               u32 div = ((src1 & 0x003c0000) >> 18) + 1;
+               return (pll.refclk * 2) / div;
+       }
+
+       P = (coef & 0x003f0000) >> 16;
+       N = (coef & 0x0000ff00) >> 8;
+       M = (coef & 0x000000ff);
        return pll.refclk * N / M / P;
 }
 
@@ -60,36 +102,103 @@ void *
 nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
                  u32 id, int khz)
 {
-       struct nva3_pm_state *state;
-       int dummy, ret;
+       struct nva3_pm_state *pll;
+       struct pll_lims limits;
+       int N, M, P, diff;
+       int ret, off;
+
+       ret = get_pll_limits(dev, id, &limits);
+       if (ret < 0)
+               return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+
+       off = nva3_pm_pll_offset(id);
+       if (id < 0)
+               return ERR_PTR(-EINVAL);
 
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (!state)
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (!pll)
                return ERR_PTR(-ENOMEM);
+       pll->type = id;
+       pll->src0 = 0x004120 + (off * 4);
+       pll->src1 = 0x004160 + (off * 4);
+       pll->ctrl = limits.reg + 0;
+       pll->coef = limits.reg + 4;
 
-       ret = get_pll_limits(dev, id, &state->pll);
-       if (ret < 0) {
-               kfree(state);
-               return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+       /* If target clock is within [-2, 3) MHz of a divisor, we'll
+        * use that instead of calculating MNP values
+        */
+       pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16);
+       if (pll->new_div) {
+               diff = khz - ((limits.refclk * 2) / pll->new_div);
+               if (diff < -2000 || diff >= 3000)
+                       pll->new_div = 0;
        }
 
-       ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
-                            &state->M, &state->P);
-       if (ret < 0) {
-               kfree(state);
-               return ERR_PTR(ret);
+       if (!pll->new_div) {
+               ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
+               if (ret < 0)
+                       return ERR_PTR(ret);
+
+               pll->new_pnm = (P << 16) | (N << 8) | M;
+               pll->new_div = 2 - 1;
+       } else {
+               pll->new_pnm = 0;
+               pll->new_div--;
        }
 
-       return state;
+       if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101)
+               pll->old_pnm = nv_rd32(dev, pll->coef);
+       return pll;
 }
 
 void
 nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
 {
-       struct nva3_pm_state *state = pre_state;
-       u32 reg = state->pll.reg;
+       struct nva3_pm_state *pll = pre_state;
+       u32 ctrl = 0;
+
+       /* For the memory clock, NVIDIA will build a "script" describing
+        * the reclocking process and ask PDAEMON to execute it.
+        */
+       if (pll->type == PLL_MEMORY) {
+               nv_wr32(dev, 0x100210, 0);
+               nv_wr32(dev, 0x1002dc, 1);
+               nv_wr32(dev, 0x004018, 0x00001000);
+               ctrl = 0x18000100;
+       }
+
+       if (pll->old_pnm || !pll->new_pnm) {
+               nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 |
+                                                   (pll->new_div << 18));
+               nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+               nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+       }
+
+       if (pll->new_pnm) {
+               nv_mask(dev, pll->src0, 0x00000101, 0x00000101);
+               nv_wr32(dev, pll->coef, pll->new_pnm);
+               nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+               nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000);
+               nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010);
+               nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl);
+               nv_mask(dev, pll->src1, 0x00000100, 0x00000000);
+               nv_mask(dev, pll->src1, 0x00000001, 0x00000000);
+               if (pll->type == PLL_MEMORY)
+                       nv_wr32(dev, 0x4018, 0x10005000);
+       } else {
+               nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+               nv_mask(dev, pll->src0, 0x00000100, 0x00000000);
+               nv_mask(dev, pll->src0, 0x00000001, 0x00000000);
+               if (pll->type == PLL_MEMORY)
+                       nv_wr32(dev, 0x4018, 0x1000d000);
+       }
+
+       if (pll->type == PLL_MEMORY) {
+               nv_wr32(dev, 0x1002dc, 0);
+               nv_wr32(dev, 0x100210, 0x80000000);
+       }
 
-       nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
-       kfree(state);
+       kfree(pll);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.c b/drivers/gpu/drm/nouveau/nvc0_copy.c
new file mode 100644 (file)
index 0000000..208fa7a
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nvc0_copy.fuc.h"
+
+struct nvc0_copy_engine {
+       struct nouveau_exec_engine base;
+       u32 irq;
+       u32 pmc;
+       u32 fuc;
+       u32 ctx;
+};
+
+static int
+nvc0_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, NULL, 256, 256,
+                                NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER |
+                                NVOBJ_FLAG_ZERO_ALLOC, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(ctx->vinst));
+       nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(ctx->vinst));
+       dev_priv->engine.instmem.flush(dev);
+
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static int
+nvc0_copy_object_new(struct nouveau_channel *chan, int engine,
+                    u32 handle, u16 class)
+{
+       return 0;
+}
+
+static void
+nvc0_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       u32 inst;
+
+       inst  = (chan->ramin->vinst >> 12);
+       inst |= 0x40000000;
+
+       /* disable fifo access */
+       nv_wr32(dev, pcopy->fuc + 0x048, 0x00000000);
+       /* mark channel as unloaded if it's currently active */
+       if (nv_rd32(dev, pcopy->fuc + 0x050) == inst)
+               nv_mask(dev, pcopy->fuc + 0x050, 0x40000000, 0x00000000);
+       /* mark next channel as invalid if it's about to be loaded */
+       if (nv_rd32(dev, pcopy->fuc + 0x054) == inst)
+               nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+       /* restore fifo access */
+       nv_wr32(dev, pcopy->fuc + 0x048, 0x00000003);
+
+       nv_wo32(chan->ramin, pcopy->ctx + 0, 0x00000000);
+       nv_wo32(chan->ramin, pcopy->ctx + 4, 0x00000000);
+       nouveau_gpuobj_ref(NULL, &ctx);
+
+       chan->engctx[engine] = ctx;
+}
+
+static int
+nvc0_copy_init(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+       int i;
+
+       nv_mask(dev, 0x000200, pcopy->pmc, 0x00000000);
+       nv_mask(dev, 0x000200, pcopy->pmc, pcopy->pmc);
+       nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+
+       nv_wr32(dev, pcopy->fuc + 0x1c0, 0x01000000);
+       for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
+               nv_wr32(dev, pcopy->fuc + 0x1c4, nvc0_pcopy_data[i]);
+
+       nv_wr32(dev, pcopy->fuc + 0x180, 0x01000000);
+       for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
+               if ((i & 0x3f) == 0)
+                       nv_wr32(dev, pcopy->fuc + 0x188, i >> 6);
+               nv_wr32(dev, pcopy->fuc + 0x184, nvc0_pcopy_code[i]);
+       }
+
+       nv_wr32(dev, pcopy->fuc + 0x084, engine - NVOBJ_ENGINE_COPY0);
+       nv_wr32(dev, pcopy->fuc + 0x10c, 0x00000000);
+       nv_wr32(dev, pcopy->fuc + 0x104, 0x00000000); /* ENTRY */
+       nv_wr32(dev, pcopy->fuc + 0x100, 0x00000002); /* TRIGGER */
+       return 0;
+}
+
+static int
+nvc0_copy_fini(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+       nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000);
+
+       /* trigger fuc context unload */
+       nv_wait(dev, pcopy->fuc + 0x008, 0x0000000c, 0x00000000);
+       nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+       nv_wr32(dev, pcopy->fuc + 0x000, 0x00000008);
+       nv_wait(dev, pcopy->fuc + 0x008, 0x00000008, 0x00000000);
+
+       nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+       return 0;
+}
+
+static struct nouveau_enum nvc0_copy_isr_error_name[] = {
+       { 0x0001, "ILLEGAL_MTHD" },
+       { 0x0002, "INVALID_ENUM" },
+       { 0x0003, "INVALID_BITFIELD" },
+       {}
+};
+
+static void
+nvc0_copy_isr(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+       u32 disp = nv_rd32(dev, pcopy->fuc + 0x01c);
+       u32 stat = nv_rd32(dev, pcopy->fuc + 0x008) & disp & ~(disp >> 16);
+       u64 inst = (u64)(nv_rd32(dev, pcopy->fuc + 0x050) & 0x0fffffff) << 12;
+       u32 chid = nvc0_graph_isr_chid(dev, inst);
+       u32 ssta = nv_rd32(dev, pcopy->fuc + 0x040) & 0x0000ffff;
+       u32 addr = nv_rd32(dev, pcopy->fuc + 0x040) >> 16;
+       u32 mthd = (addr & 0x07ff) << 2;
+       u32 subc = (addr & 0x3800) >> 11;
+       u32 data = nv_rd32(dev, pcopy->fuc + 0x044);
+
+       if (stat & 0x00000040) {
+               NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+               nouveau_enum_print(nvc0_copy_isr_error_name, ssta);
+               printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
+                       chid, inst, subc, mthd, data);
+               nv_wr32(dev, pcopy->fuc + 0x004, 0x00000040);
+               stat &= ~0x00000040;
+       }
+
+       if (stat) {
+               NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+               nv_wr32(dev, pcopy->fuc + 0x004, stat);
+       }
+}
+
+static void
+nvc0_copy_isr_0(struct drm_device *dev)
+{
+       nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY0);
+}
+
+static void
+nvc0_copy_isr_1(struct drm_device *dev)
+{
+       nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY1);
+}
+
+static void
+nvc0_copy_destroy(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, pcopy->irq);
+
+       if (engine == NVOBJ_ENGINE_COPY0)
+               NVOBJ_ENGINE_DEL(dev, COPY0);
+       else
+               NVOBJ_ENGINE_DEL(dev, COPY1);
+       kfree(pcopy);
+}
+
+int
+nvc0_copy_create(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy;
+
+       pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+       if (!pcopy)
+               return -ENOMEM;
+
+       pcopy->base.destroy = nvc0_copy_destroy;
+       pcopy->base.init = nvc0_copy_init;
+       pcopy->base.fini = nvc0_copy_fini;
+       pcopy->base.context_new = nvc0_copy_context_new;
+       pcopy->base.context_del = nvc0_copy_context_del;
+       pcopy->base.object_new = nvc0_copy_object_new;
+
+       if (engine == 0) {
+               pcopy->irq = 5;
+               pcopy->pmc = 0x00000040;
+               pcopy->fuc = 0x104000;
+               pcopy->ctx = 0x0230;
+               nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_0);
+               NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+               NVOBJ_CLASS(dev, 0x90b5, COPY0);
+       } else {
+               pcopy->irq = 6;
+               pcopy->pmc = 0x00000080;
+               pcopy->fuc = 0x105000;
+               pcopy->ctx = 0x0240;
+               nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_1);
+               NVOBJ_ENGINE_ADD(dev, COPY1, &pcopy->base);
+               NVOBJ_CLASS(dev, 0x90b8, COPY1);
+       }
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h b/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h
new file mode 100644 (file)
index 0000000..4199038
--- /dev/null
@@ -0,0 +1,527 @@
+uint32_t nvc0_pcopy_data[] = {
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00010000,
+       0x00000000,
+       0x00000000,
+       0x00010040,
+       0x0001019f,
+       0x00000000,
+       0x00010050,
+       0x000101a1,
+       0x00000000,
+       0x00070080,
+       0x0000001c,
+       0xfffff000,
+       0x00000020,
+       0xfff80000,
+       0x00000024,
+       0xffffe000,
+       0x00000028,
+       0xfffff800,
+       0x0000002c,
+       0xfffff000,
+       0x00000030,
+       0xfff80000,
+       0x00000034,
+       0xffffe000,
+       0x00070088,
+       0x00000048,
+       0xfffff000,
+       0x0000004c,
+       0xfff80000,
+       0x00000050,
+       0xffffe000,
+       0x00000054,
+       0xfffff800,
+       0x00000058,
+       0xfffff000,
+       0x0000005c,
+       0xfff80000,
+       0x00000060,
+       0xffffe000,
+       0x000200c0,
+       0x000104b8,
+       0x00000000,
+       0x00010541,
+       0x00000000,
+       0x000e00c3,
+       0x00000010,
+       0xffffff00,
+       0x00000014,
+       0x0000000f,
+       0x0000003c,
+       0xffffff00,
+       0x00000040,
+       0x0000000f,
+       0x00000018,
+       0xfff80000,
+       0x00000044,
+       0xfff80000,
+       0x00000074,
+       0xffff0000,
+       0x00000078,
+       0xffffe000,
+       0x00000068,
+       0xfccc0000,
+       0x0000006c,
+       0x00000000,
+       0x00000070,
+       0x00000000,
+       0x00000004,
+       0xffffff00,
+       0x00000008,
+       0x00000000,
+       0x0000000c,
+       0x00000000,
+       0x00000800,
+};
+
+uint32_t nvc0_pcopy_code[] = {
+       0x04fe04bd,
+       0x3517f000,
+       0xf10010fe,
+       0xf1040017,
+       0xf0fff327,
+       0x22d00023,
+       0x0c25f0c0,
+       0xf40012d0,
+       0x17f11031,
+       0x27f01200,
+       0x0012d003,
+       0xf40031f4,
+       0x0ef40028,
+       0x8001cffd,
+       0xf40812c4,
+       0x21f4060b,
+       0x0412c4ca,
+       0xf5070bf4,
+       0xc4010221,
+       0x01d00c11,
+       0xf101f840,
+       0xfe770047,
+       0x47f1004b,
+       0x44cf2100,
+       0x0144f000,
+       0xb60444b6,
+       0xf7f13040,
+       0xf4b6061c,
+       0x1457f106,
+       0x00f5d101,
+       0xb6043594,
+       0x57fe0250,
+       0x0145fe00,
+       0x010052b7,
+       0x00ff67f1,
+       0x56fd60bd,
+       0x0253f004,
+       0xf80545fa,
+       0x0053f003,
+       0xd100e7f0,
+       0x549800fe,
+       0x0845b600,
+       0xb6015698,
+       0x46fd1864,
+       0x0047fe05,
+       0xf00204b9,
+       0x01f40643,
+       0x0604fa09,
+       0xfa060ef4,
+       0x03f80504,
+       0x27f100f8,
+       0x23cf1400,
+       0x1e3fc800,
+       0xf4170bf4,
+       0x21f40132,
+       0x1e3af053,
+       0xf00023d0,
+       0x24d00147,
+       0xcf00f880,
+       0x3dc84023,
+       0x090bf41e,
+       0xf40131f4,
+       0x37f05321,
+       0x8023d002,
+       0x37f100f8,
+       0x32cf1900,
+       0x0033cf40,
+       0x07ff24e4,
+       0xf11024b6,
+       0xbd010057,
+       0x5874bd64,
+       0x57580056,
+       0x0450b601,
+       0xf40446b8,
+       0x76bb4d08,
+       0x0447b800,
+       0xbb0f08f4,
+       0x74b60276,
+       0x0057bb03,
+       0xbbdf0ef4,
+       0x44b60246,
+       0x0045bb03,
+       0xfd014598,
+       0x54b00453,
+       0x201bf400,
+       0x58004558,
+       0x64b00146,
+       0x091bf400,
+       0xf4005380,
+       0x32f4300e,
+       0xf455f901,
+       0x0ef40c01,
+       0x0225f025,
+       0xf10125f0,
+       0xd0100047,
+       0x43d00042,
+       0x4027f040,
+       0xcf0002d0,
+       0x24f08002,
+       0x0024b040,
+       0xf1f71bf4,
+       0xf01d0027,
+       0x23d00137,
+       0xf800f800,
+       0x0027f100,
+       0xf034bd22,
+       0x23d00233,
+       0xf400f800,
+       0x01b0f030,
+       0x0101b000,
+       0xb00201b0,
+       0x04980301,
+       0x3045c71a,
+       0xc70150b6,
+       0x60b63446,
+       0x3847c701,
+       0xf40170b6,
+       0x84bd0232,
+       0x4ac494bd,
+       0x0445b60f,
+       0xa430b4bd,
+       0x0f18f404,
+       0xbbc0a5ff,
+       0x31f400cb,
+       0x220ef402,
+       0xf00c1bf4,
+       0xcbbb10c7,
+       0x160ef400,
+       0xf406a430,
+       0xc7f00c18,
+       0x00cbbb14,
+       0xf1070ef4,
+       0x380080c7,
+       0x80b601c8,
+       0x01b0b601,
+       0xf404b5b8,
+       0x90b6c308,
+       0x0497b801,
+       0xfdb208f4,
+       0x06800065,
+       0x1d08980e,
+       0xf40068fd,
+       0x64bd0502,
+       0x800075fd,
+       0x78fd1907,
+       0x1057f100,
+       0x0654b608,
+       0xd00056d0,
+       0x50b74057,
+       0x06980800,
+       0x0162b619,
+       0x980864b6,
+       0x72b60e07,
+       0x0567fd01,
+       0xb70056d0,
+       0xb4010050,
+       0x56d00060,
+       0x0160b400,
+       0xb44056d0,
+       0x56d00260,
+       0x0360b480,
+       0xb7c056d0,
+       0x98040050,
+       0x56d01b06,
+       0x1c069800,
+       0xf44056d0,
+       0x00f81030,
+       0xc7075798,
+       0x78c76879,
+       0x0380b664,
+       0xb06077c7,
+       0x1bf40e76,
+       0x0477f009,
+       0xf00f0ef4,
+       0x70b6027c,
+       0x0947fd11,
+       0x980677f0,
+       0x5b980c5a,
+       0x00abfd0e,
+       0xbb01b7f0,
+       0xb2b604b7,
+       0xc4abff01,
+       0x9805a7bb,
+       0xe7f00d5d,
+       0x04e8bb01,
+       0xff01e2b6,
+       0xd8bbb4de,
+       0x01e0b605,
+       0xbb0cef94,
+       0xfefd02eb,
+       0x026cf005,
+       0x020860b7,
+       0xd00864b6,
+       0xb7bb006f,
+       0x00cbbb04,
+       0x98085f98,
+       0xfbfd0e5b,
+       0x01b7f000,
+       0xb604b7bb,
+       0xfbbb01b2,
+       0x05f7bb00,
+       0x5f98f0f9,
+       0x01b7f009,
+       0xb604b8bb,
+       0xfbbb01b2,
+       0x05f8bb00,
+       0x78bbf0f9,
+       0x0282b600,
+       0xbb01b7f0,
+       0xb9bb04b8,
+       0x0b589804,
+       0xbb01e7f0,
+       0xe2b604e9,
+       0xf48eff01,
+       0xbb04f7bb,
+       0x79bb00cf,
+       0x0589bb00,
+       0x90fcf0fc,
+       0xbb00d9fd,
+       0x89fd00ad,
+       0x008ffd00,
+       0xbb00a8bb,
+       0x92b604a7,
+       0x0497bb01,
+       0x988069d0,
+       0x58980557,
+       0x00acbb04,
+       0xb6007abb,
+       0x84b60081,
+       0x058bfd10,
+       0x060062b7,
+       0xb70067d0,
+       0xd0040060,
+       0x00f80068,
+       0xb7026cf0,
+       0xb6020260,
+       0x57980864,
+       0x0067d005,
+       0x040060b7,
+       0xb6045798,
+       0x67d01074,
+       0x0060b700,
+       0x06579804,
+       0xf80067d0,
+       0xf900f900,
+       0x0007f110,
+       0x0604b608,
+       0xf00001cf,
+       0x1bf40114,
+       0xfc10fcfa,
+       0xc800f800,
+       0x1bf40d34,
+       0xd121f570,
+       0x0c47f103,
+       0x0644b608,
+       0xb6020598,
+       0x45d00450,
+       0x4040d000,
+       0xd00c57f0,
+       0x40b78045,
+       0x05980400,
+       0x1054b601,
+       0xb70045d0,
+       0xf1050040,
+       0xf00b0057,
+       0x45d00153,
+       0x4057f100,
+       0x0154b640,
+       0x808053f1,
+       0xf14045d0,
+       0xf1111057,
+       0xd0131253,
+       0x57f18045,
+       0x53f11514,
+       0x45d01716,
+       0x0157f1c0,
+       0x0153f026,
+       0x080047f1,
+       0xd00644b6,
+       0x21f50045,
+       0x47f103d1,
+       0x44b6080c,
+       0x02059806,
+       0xd00045d0,
+       0x57f04040,
+       0x8045d004,
+       0x040040b7,
+       0xb6010598,
+       0x45d01054,
+       0x0040b700,
+       0x0057f105,
+       0x0045d003,
+       0x111057f1,
+       0x131253f1,
+       0x984045d0,
+       0x40b70305,
+       0x45d00500,
+       0x0157f100,
+       0x0153f026,
+       0x080047f1,
+       0xd00644b6,
+       0x00f80045,
+       0x03d121f5,
+       0xf4003fc8,
+       0x21f50e0b,
+       0x47f101af,
+       0x0ef40200,
+       0x1067f11e,
+       0x0664b608,
+       0x800177f0,
+       0x07800e07,
+       0x1d079819,
+       0xd00067d0,
+       0x44bd4067,
+       0xbd0232f4,
+       0x043fc854,
+       0xf50a0bf4,
+       0xf403a821,
+       0x21f50a0e,
+       0x49f0029c,
+       0x0231f407,
+       0xc82c57f0,
+       0x0bf4083f,
+       0xa821f50a,
+       0x0a0ef403,
+       0x029c21f5,
+       0xf10849f0,
+       0xb6080057,
+       0x06980654,
+       0x4056d01e,
+       0xf14167f0,
+       0xfd440063,
+       0x54d00546,
+       0x0c3fc800,
+       0xf5070bf4,
+       0xf803eb21,
+       0x0027f100,
+       0xf034bd22,
+       0x23d00133,
+       0x0000f800,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
index 2886f2726a9e07ebe25eddb484a061fa2990a503..fb4f5943e01b5f947ee3119ef0988eda83b98171 100644 (file)
@@ -37,7 +37,7 @@ struct nvc0_fifo_priv {
 };
 
 struct nvc0_fifo_chan {
-       struct nouveau_bo *user;
+       struct nouveau_gpuobj *user;
        struct nouveau_gpuobj *ramfc;
 };
 
@@ -106,7 +106,7 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nvc0_fifo_priv *priv = pfifo->priv;
        struct nvc0_fifo_chan *fifoch;
-       u64 ib_virt, user_vinst;
+       u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
        int ret;
 
        chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL);
@@ -115,28 +115,13 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
        fifoch = chan->fifo_priv;
 
        /* allocate vram for control regs, map into polling area */
-       ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM,
-                            0, 0, &fifoch->user);
+       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC, &fifoch->user);
        if (ret)
                goto error;
 
-       ret = nouveau_bo_pin(fifoch->user, TTM_PL_FLAG_VRAM);
-       if (ret) {
-               nouveau_bo_ref(NULL, &fifoch->user);
-               goto error;
-       }
-
-       user_vinst = fifoch->user->bo.mem.start << PAGE_SHIFT;
-
-       ret = nouveau_bo_map(fifoch->user);
-       if (ret) {
-               nouveau_bo_unpin(fifoch->user);
-               nouveau_bo_ref(NULL, &fifoch->user);
-               goto error;
-       }
-
        nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000,
-                         fifoch->user->bo.mem.mm_node);
+                         *(struct nouveau_mem **)fifoch->user->node);
 
        chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
                                priv->user_vma.offset + (chan->id * 0x1000),
@@ -146,20 +131,6 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
                goto error;
        }
 
-       ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
-
-       /* zero channel regs */
-       nouveau_bo_wr32(fifoch->user, 0x0040/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0044/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0048/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x004c/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0050/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0058/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x005c/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0060/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0088/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x008c/4, 0);
-
        /* ramfc */
        ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
                                      chan->ramin->vinst, 0x100,
@@ -167,8 +138,8 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
        if (ret)
                goto error;
 
-       nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(user_vinst));
-       nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(user_vinst));
+       nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(fifoch->user->vinst));
+       nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(fifoch->user->vinst));
        nv_wo32(fifoch->ramfc, 0x10, 0x0000face);
        nv_wo32(fifoch->ramfc, 0x30, 0xfffff902);
        nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt));
@@ -223,11 +194,7 @@ nvc0_fifo_destroy_context(struct nouveau_channel *chan)
                return;
 
        nouveau_gpuobj_ref(NULL, &fifoch->ramfc);
-       if (fifoch->user) {
-               nouveau_bo_unmap(fifoch->user);
-               nouveau_bo_unpin(fifoch->user);
-               nouveau_bo_ref(NULL, &fifoch->user);
-       }
+       nouveau_gpuobj_ref(NULL, &fifoch->user);
        kfree(fifoch);
 }
 
@@ -240,6 +207,21 @@ nvc0_fifo_load_context(struct nouveau_channel *chan)
 int
 nvc0_fifo_unload_context(struct drm_device *dev)
 {
+       int i;
+
+       for (i = 0; i < 128; i++) {
+               if (!(nv_rd32(dev, 0x003004 + (i * 4)) & 1))
+                       continue;
+
+               nv_mask(dev, 0x003004 + (i * 4), 0x00000001, 0x00000000);
+               nv_wr32(dev, 0x002634, i);
+               if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
+                       NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
+                               i, nv_rd32(dev, 0x002634));
+                       return -EBUSY;
+               }
+       }
+
        return 0;
 }
 
@@ -309,6 +291,7 @@ nvc0_fifo_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+       struct nouveau_channel *chan;
        struct nvc0_fifo_priv *priv;
        int ret, i;
 
@@ -351,23 +334,74 @@ nvc0_fifo_init(struct drm_device *dev)
        nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
        nv_wr32(dev, 0x002100, 0xffffffff);
        nv_wr32(dev, 0x002140, 0xbfffffff);
+
+       /* restore PFIFO context table */
+       for (i = 0; i < 128; i++) {
+               chan = dev_priv->channels.ptr[i];
+               if (!chan || !chan->fifo_priv)
+                       continue;
+
+               nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 |
+                                                (chan->ramin->vinst >> 12));
+               nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001);
+       }
+       nvc0_fifo_playlist_update(dev);
+
        return 0;
 }
 
 struct nouveau_enum nvc0_fifo_fault_unit[] = {
-       { 0, "PGRAPH" },
-       { 3, "PEEPHOLE" },
-       { 4, "BAR1" },
-       { 5, "BAR3" },
-       { 7, "PFIFO" },
+       { 0x00, "PGRAPH" },
+       { 0x03, "PEEPHOLE" },
+       { 0x04, "BAR1" },
+       { 0x05, "BAR3" },
+       { 0x07, "PFIFO" },
+       { 0x10, "PBSP" },
+       { 0x11, "PPPP" },
+       { 0x13, "PCOUNTER" },
+       { 0x14, "PVP" },
+       { 0x15, "PCOPY0" },
+       { 0x16, "PCOPY1" },
+       { 0x17, "PDAEMON" },
        {}
 };
 
 struct nouveau_enum nvc0_fifo_fault_reason[] = {
-       { 0, "PT_NOT_PRESENT" },
-       { 1, "PT_TOO_SHORT" },
-       { 2, "PAGE_NOT_PRESENT" },
-       { 3, "VM_LIMIT_EXCEEDED" },
+       { 0x00, "PT_NOT_PRESENT" },
+       { 0x01, "PT_TOO_SHORT" },
+       { 0x02, "PAGE_NOT_PRESENT" },
+       { 0x03, "VM_LIMIT_EXCEEDED" },
+       { 0x04, "NO_CHANNEL" },
+       { 0x05, "PAGE_SYSTEM_ONLY" },
+       { 0x06, "PAGE_READ_ONLY" },
+       { 0x0a, "COMPRESSED_SYSRAM" },
+       { 0x0c, "INVALID_STORAGE_TYPE" },
+       {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_hubclient[] = {
+       { 0x01, "PCOPY0" },
+       { 0x02, "PCOPY1" },
+       { 0x04, "DISPATCH" },
+       { 0x05, "CTXCTL" },
+       { 0x06, "PFIFO" },
+       { 0x07, "BAR_READ" },
+       { 0x08, "BAR_WRITE" },
+       { 0x0b, "PVP" },
+       { 0x0c, "PPPP" },
+       { 0x0d, "PBSP" },
+       { 0x11, "PCOUNTER" },
+       { 0x12, "PDAEMON" },
+       { 0x14, "CCACHE" },
+       { 0x15, "CCACHE_POST" },
+       {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
+       { 0x01, "TEX" },
+       { 0x0c, "ESETUP" },
+       { 0x0e, "CTXCTL" },
+       { 0x0f, "PROP" },
        {}
 };
 
@@ -385,12 +419,20 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
        u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
        u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
        u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
+       u32 client = (stat & 0x00001f00) >> 8;
 
        NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
                (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
        nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
        printk("] from ");
        nouveau_enum_print(nvc0_fifo_fault_unit, unit);
+       if (stat & 0x00000040) {
+               printk("/");
+               nouveau_enum_print(nvc0_fifo_fault_hubclient, client);
+       } else {
+               printk("/GPC%d/", (stat & 0x1f000000) >> 24);
+               nouveau_enum_print(nvc0_fifo_fault_gpcclient, client);
+       }
        printk(" on channel 0x%010llx\n", (u64)inst << 12);
 }
 
index 3de9b721d8dbe61260af7487ce086fc23acaa758..ca6db204d644711dafcaa8e9eaf2c88deada27ae 100644 (file)
 #include "nouveau_mm.h"
 #include "nvc0_graph.h"
 
-static void nvc0_graph_isr(struct drm_device *);
-static void nvc0_runk140_isr(struct drm_device *);
-static int  nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan);
-
-void
-nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
+static int
+nvc0_graph_load_context(struct nouveau_channel *chan)
 {
+       struct drm_device *dev = chan->dev;
+
+       nv_wr32(dev, 0x409840, 0x00000030);
+       nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
+       nv_wr32(dev, 0x409504, 0x00000003);
+       if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
+               NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
+
+       return 0;
 }
 
-struct nouveau_channel *
-nvc0_graph_channel(struct drm_device *dev)
+static int
+nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
 {
-       return NULL;
+       nv_wr32(dev, 0x409840, 0x00000003);
+       nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
+       nv_wr32(dev, 0x409504, 0x00000009);
+       if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
+               return -EBUSY;
+       }
+
+       return 0;
 }
 
 static int
 nvc0_graph_construct_context(struct nouveau_channel *chan)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+       struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+       struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
        int ret, i;
        u32 *ctx;
@@ -89,9 +102,8 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
 static int
 nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
 {
-       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+       struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+       struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
        int i = 0, gpc, tp, ret;
        u32 magic;
@@ -158,29 +170,27 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
        return 0;
 }
 
-int
-nvc0_graph_create_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
 {
-       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv = pgraph->priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, engine);
        struct nvc0_graph_chan *grch;
-       struct drm_device *dev = chan->dev;
        struct nouveau_gpuobj *grctx;
        int ret, i;
 
-       chan->pgraph_ctx = kzalloc(sizeof(*grch), GFP_KERNEL);
-       if (!chan->pgraph_ctx)
+       grch = kzalloc(sizeof(*grch), GFP_KERNEL);
+       if (!grch)
                return -ENOMEM;
-       grch = chan->pgraph_ctx;
+       chan->engctx[NVOBJ_ENGINE_GR] = grch;
 
        ret = nouveau_gpuobj_new(dev, NULL, priv->grctx_size, 256,
                                 NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC,
                                 &grch->grctx);
        if (ret)
                goto error;
-       chan->ramin_grctx = grch->grctx;
        grctx = grch->grctx;
 
        ret = nvc0_graph_create_context_mmio_list(chan);
@@ -200,104 +210,49 @@ nvc0_graph_create_context(struct nouveau_channel *chan)
        for (i = 0; i < priv->grctx_size; i += 4)
                nv_wo32(grctx, i, priv->grctx_vals[i / 4]);
 
-        nv_wo32(grctx, 0xf4, 0);
-        nv_wo32(grctx, 0xf8, 0);
-        nv_wo32(grctx, 0x10, grch->mmio_nr);
-        nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
-        nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
-        nv_wo32(grctx, 0x1c, 1);
-        nv_wo32(grctx, 0x20, 0);
-        nv_wo32(grctx, 0x28, 0);
-        nv_wo32(grctx, 0x2c, 0);
+       nv_wo32(grctx, 0xf4, 0);
+       nv_wo32(grctx, 0xf8, 0);
+       nv_wo32(grctx, 0x10, grch->mmio_nr);
+       nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
+       nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
+       nv_wo32(grctx, 0x1c, 1);
+       nv_wo32(grctx, 0x20, 0);
+       nv_wo32(grctx, 0x28, 0);
+       nv_wo32(grctx, 0x2c, 0);
        pinstmem->flush(dev);
        return 0;
 
 error:
-       pgraph->destroy_context(chan);
+       priv->base.context_del(chan, engine);
        return ret;
 }
 
-void
-nvc0_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nvc0_graph_context_del(struct nouveau_channel *chan, int engine)
 {
-       struct nvc0_graph_chan *grch;
-
-       grch = chan->pgraph_ctx;
-       chan->pgraph_ctx = NULL;
-       if (!grch)
-               return;
+       struct nvc0_graph_chan *grch = chan->engctx[engine];
 
        nouveau_gpuobj_ref(NULL, &grch->mmio);
        nouveau_gpuobj_ref(NULL, &grch->unk418810);
        nouveau_gpuobj_ref(NULL, &grch->unk40800c);
        nouveau_gpuobj_ref(NULL, &grch->unk408004);
        nouveau_gpuobj_ref(NULL, &grch->grctx);
-       chan->ramin_grctx = NULL;
+       chan->engctx[engine] = NULL;
 }
 
-int
-nvc0_graph_load_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
-       struct drm_device *dev = chan->dev;
-
-       nv_wr32(dev, 0x409840, 0x00000030);
-       nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
-       nv_wr32(dev, 0x409504, 0x00000003);
-       if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
-               NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
-
        return 0;
 }
 
 static int
-nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
+nvc0_graph_fini(struct drm_device *dev, int engine)
 {
-       nv_wr32(dev, 0x409840, 0x00000003);
-       nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
-       nv_wr32(dev, 0x409504, 0x00000009);
-       if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
-               NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
-               return -EBUSY;
-       }
-
        return 0;
 }
 
-int
-nvc0_graph_unload_context(struct drm_device *dev)
-{
-       u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
-       return nvc0_graph_unload_context_to(dev, inst);
-}
-
-static void
-nvc0_graph_destroy(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv;
-
-       priv = pgraph->priv;
-       if (!priv)
-               return;
-
-       nouveau_irq_unregister(dev, 12);
-       nouveau_irq_unregister(dev, 25);
-
-       nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
-       nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
-       if (priv->grctx_vals)
-               kfree(priv->grctx_vals);
-       kfree(priv);
-}
-
-void
-nvc0_graph_takedown(struct drm_device *dev)
-{
-       nvc0_graph_destroy(dev);
-}
-
 static int
 nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
                          u32 class, u32 mthd, u32 data)
@@ -306,119 +261,10 @@ nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
        return 0;
 }
 
-static int
-nvc0_graph_create(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv;
-       int ret, gpc, i;
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-       pgraph->priv = priv;
-
-       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
-       if (ret)
-               goto error;
-
-       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
-       if (ret)
-               goto error;
-
-       for (i = 0; i < 0x1000; i += 4) {
-               nv_wo32(priv->unk4188b4, i, 0x00000010);
-               nv_wo32(priv->unk4188b8, i, 0x00000010);
-       }
-
-       priv->gpc_nr  =  nv_rd32(dev, 0x409604) & 0x0000001f;
-       priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
-       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-               priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
-               priv->tp_total += priv->tp_nr[gpc];
-       }
-
-       /*XXX: these need figuring out... */
-       switch (dev_priv->chipset) {
-       case 0xc0:
-               if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
-                       priv->magic_not_rop_nr = 0x07;
-                       /* filled values up to tp_total, the rest 0 */
-                       priv->magicgpc980[0]   = 0x22111000;
-                       priv->magicgpc980[1]   = 0x00000233;
-                       priv->magicgpc980[2]   = 0x00000000;
-                       priv->magicgpc980[3]   = 0x00000000;
-                       priv->magicgpc918      = 0x000ba2e9;
-               } else
-               if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
-                       priv->magic_not_rop_nr = 0x05;
-                       priv->magicgpc980[0]   = 0x11110000;
-                       priv->magicgpc980[1]   = 0x00233222;
-                       priv->magicgpc980[2]   = 0x00000000;
-                       priv->magicgpc980[3]   = 0x00000000;
-                       priv->magicgpc918      = 0x00092493;
-               } else
-               if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
-                       priv->magic_not_rop_nr = 0x06;
-                       priv->magicgpc980[0]   = 0x11110000;
-                       priv->magicgpc980[1]   = 0x03332222;
-                       priv->magicgpc980[2]   = 0x00000000;
-                       priv->magicgpc980[3]   = 0x00000000;
-                       priv->magicgpc918      = 0x00088889;
-               }
-               break;
-       case 0xc3: /* 450, 4/0/0/0, 2 */
-               priv->magic_not_rop_nr = 0x03;
-               priv->magicgpc980[0]   = 0x00003210;
-               priv->magicgpc980[1]   = 0x00000000;
-               priv->magicgpc980[2]   = 0x00000000;
-               priv->magicgpc980[3]   = 0x00000000;
-               priv->magicgpc918      = 0x00200000;
-               break;
-       case 0xc4: /* 460, 3/4/0/0, 4 */
-               priv->magic_not_rop_nr = 0x01;
-               priv->magicgpc980[0]   = 0x02321100;
-               priv->magicgpc980[1]   = 0x00000000;
-               priv->magicgpc980[2]   = 0x00000000;
-               priv->magicgpc980[3]   = 0x00000000;
-               priv->magicgpc918      = 0x00124925;
-               break;
-       }
-
-       if (!priv->magic_not_rop_nr) {
-               NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
-                        priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
-                        priv->tp_nr[3], priv->rop_nr);
-               /* use 0xc3's values... */
-               priv->magic_not_rop_nr = 0x03;
-               priv->magicgpc980[0]   = 0x00003210;
-               priv->magicgpc980[1]   = 0x00000000;
-               priv->magicgpc980[2]   = 0x00000000;
-               priv->magicgpc980[3]   = 0x00000000;
-               priv->magicgpc918      = 0x00200000;
-       }
-
-       nouveau_irq_register(dev, 12, nvc0_graph_isr);
-       nouveau_irq_register(dev, 25, nvc0_runk140_isr);
-       NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
-       NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
-       NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
-       NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
-       NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
-       return 0;
-
-error:
-       nvc0_graph_destroy(dev);
-       return ret;
-}
-
 static void
 nvc0_graph_init_obj418880(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv = pgraph->priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        int i;
 
        nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
@@ -449,35 +295,42 @@ nvc0_graph_init_regs(struct drm_device *dev)
 static void
 nvc0_graph_init_gpc_0(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       int gpc;
-       
-       //      TP      ROP UNKVAL(magic_not_rop_nr)
-       // 450: 4/0/0/0 2        3
-       // 460: 3/4/0/0 4        1
-       // 465: 3/4/4/0 4        7
-       // 470: 3/3/4/4 5        5
-       // 480: 3/4/4/4 6        6
-
-       // magicgpc918
-       // 450: 00200000 00000000001000000000000000000000
-       // 460: 00124925 00000000000100100100100100100101
-       // 465: 000ba2e9 00000000000010111010001011101001
-       // 470: 00092493 00000000000010010010010010010011
-       // 480: 00088889 00000000000010001000100010001001
-
-       /* filled values up to tp_total, remainder 0 */
-       // 450: 00003210 00000000 00000000 00000000
-       // 460: 02321100 00000000 00000000 00000000
-       // 465: 22111000 00000233 00000000 00000000
-       // 470: 11110000 00233222 00000000 00000000
-       // 480: 11110000 03332222 00000000 00000000
-       
-       nv_wr32(dev, GPC_BCAST(0x0980), priv->magicgpc980[0]);
-       nv_wr32(dev, GPC_BCAST(0x0984), priv->magicgpc980[1]);
-       nv_wr32(dev, GPC_BCAST(0x0988), priv->magicgpc980[2]);
-       nv_wr32(dev, GPC_BCAST(0x098c), priv->magicgpc980[3]);
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+       u32 data[TP_MAX / 8];
+       u8  tpnr[GPC_MAX];
+       int i, gpc, tpc;
+
+       /*
+        *      TP      ROP UNKVAL(magic_not_rop_nr)
+        * 450: 4/0/0/0 2        3
+        * 460: 3/4/0/0 4        1
+        * 465: 3/4/4/0 4        7
+        * 470: 3/3/4/4 5        5
+        * 480: 3/4/4/4 6        6
+        *
+        * magicgpc918
+        * 450: 00200000 00000000001000000000000000000000
+        * 460: 00124925 00000000000100100100100100100101
+        * 465: 000ba2e9 00000000000010111010001011101001
+        * 470: 00092493 00000000000010010010010010010011
+        * 480: 00088889 00000000000010001000100010001001
+        */
+
+       memset(data, 0x00, sizeof(data));
+       memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
+       for (i = 0, gpc = -1; i < priv->tp_total; i++) {
+               do {
+                       gpc = (gpc + 1) % priv->gpc_nr;
+               } while (!tpnr[gpc]);
+               tpc = priv->tp_nr[gpc] - tpnr[gpc]--;
+
+               data[i / 8] |= tpc << ((i % 8) * 4);
+       }
+
+       nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
+       nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
+       nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
+       nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
 
        for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
                nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
@@ -509,8 +362,7 @@ nvc0_graph_init_units(struct drm_device *dev)
 static void
 nvc0_graph_init_gpc_1(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        int gpc, tp;
 
        for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
@@ -535,8 +387,7 @@ nvc0_graph_init_gpc_1(struct drm_device *dev)
 static void
 nvc0_graph_init_rop(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        int rop;
 
        for (rop = 0; rop < priv->rop_nr; rop++) {
@@ -547,62 +398,36 @@ nvc0_graph_init_rop(struct drm_device *dev)
        }
 }
 
-static int
-nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base,
-                const char *code_fw, const char *data_fw)
+static void
+nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
+                   struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
 {
-       const struct firmware *fw;
-       char name[32];
-       int ret, i;
-
-       snprintf(name, sizeof(name), "nouveau/%s", data_fw);
-       ret = request_firmware(&fw, name, &dev->pdev->dev);
-       if (ret) {
-               NV_ERROR(dev, "failed to load %s\n", data_fw);
-               return ret;
-       }
+       int i;
 
        nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
-       for (i = 0; i < fw->size / 4; i++)
-               nv_wr32(dev, fuc_base + 0x01c4, ((u32 *)fw->data)[i]);
-       release_firmware(fw);
-
-       snprintf(name, sizeof(name), "nouveau/%s", code_fw);
-       ret = request_firmware(&fw, name, &dev->pdev->dev);
-       if (ret) {
-               NV_ERROR(dev, "failed to load %s\n", code_fw);
-               return ret;
-       }
+       for (i = 0; i < data->size / 4; i++)
+               nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
 
        nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
-       for (i = 0; i < fw->size / 4; i++) {
+       for (i = 0; i < code->size / 4; i++) {
                if ((i & 0x3f) == 0)
                        nv_wr32(dev, fuc_base + 0x0188, i >> 6);
-               nv_wr32(dev, fuc_base + 0x0184, ((u32 *)fw->data)[i]);
+               nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
        }
-       release_firmware(fw);
-
-       return 0;
 }
 
 static int
 nvc0_graph_init_ctxctl(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        u32 r000260;
-       int ret;
 
        /* load fuc microcode */
        r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
-       ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d");
-       if (ret == 0)
-               ret = nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad");
+       nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
+       nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
        nv_wr32(dev, 0x000260, r000260);
 
-       if (ret)
-               return ret;
-
        /* start both of them running */
        nv_wr32(dev, 0x409840, 0xffffffff);
        nv_wr32(dev, 0x41a10c, 0x00000000);
@@ -644,41 +469,19 @@ nvc0_graph_init_ctxctl(struct drm_device *dev)
        return 0;
 }
 
-int
-nvc0_graph_init(struct drm_device *dev)
+static int
+nvc0_graph_init(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        int ret;
 
-       dev_priv->engine.graph.accel_blocked = true;
-
-       switch (dev_priv->chipset) {
-       case 0xc0:
-       case 0xc3:
-       case 0xc4:
-               break;
-       default:
-               NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
-               if (nouveau_noaccel != 0)
-                       return 0;
-               break;
-       }
-
        nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
        nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
 
-       if (!pgraph->priv) {
-               ret = nvc0_graph_create(dev);
-               if (ret)
-                       return ret;
-       }
-
        nvc0_graph_init_obj418880(dev);
        nvc0_graph_init_regs(dev);
-       //nvc0_graph_init_unitplemented_magics(dev);
+       /*nvc0_graph_init_unitplemented_magics(dev);*/
        nvc0_graph_init_gpc_0(dev);
-       //nvc0_graph_init_unitplemented_c242(dev);
+       /*nvc0_graph_init_unitplemented_c242(dev);*/
 
        nv_wr32(dev, 0x400500, 0x00010001);
        nv_wr32(dev, 0x400100, 0xffffffff);
@@ -697,12 +500,13 @@ nvc0_graph_init(struct drm_device *dev)
        nv_wr32(dev, 0x400054, 0x34ce3464);
 
        ret = nvc0_graph_init_ctxctl(dev);
-       if (ret == 0)
-               dev_priv->engine.graph.accel_blocked = false;
+       if (ret)
+               return ret;
+
        return 0;
 }
 
-static int
+int
 nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -806,3 +610,187 @@ nvc0_runk140_isr(struct drm_device *dev)
                units &= ~(1 << unit);
        }
 }
+
+static int
+nvc0_graph_create_fw(struct drm_device *dev, const char *fwname,
+                    struct nvc0_graph_fuc *fuc)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       const struct firmware *fw;
+       char f[32];
+       int ret;
+
+       snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
+       ret = request_firmware(&fw, f, &dev->pdev->dev);
+       if (ret) {
+               snprintf(f, sizeof(f), "nouveau/%s", fwname);
+               ret = request_firmware(&fw, f, &dev->pdev->dev);
+               if (ret) {
+                       NV_ERROR(dev, "failed to load %s\n", fwname);
+                       return ret;
+               }
+       }
+
+       fuc->size = fw->size;
+       fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+       release_firmware(fw);
+       return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+static void
+nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
+{
+       if (fuc->data) {
+               kfree(fuc->data);
+               fuc->data = NULL;
+       }
+}
+
+static void
+nvc0_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nvc0_graph_priv *priv = nv_engine(dev, engine);
+
+       nvc0_graph_destroy_fw(&priv->fuc409c);
+       nvc0_graph_destroy_fw(&priv->fuc409d);
+       nvc0_graph_destroy_fw(&priv->fuc41ac);
+       nvc0_graph_destroy_fw(&priv->fuc41ad);
+
+       nouveau_irq_unregister(dev, 12);
+       nouveau_irq_unregister(dev, 25);
+
+       nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+       nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+       if (priv->grctx_vals)
+               kfree(priv->grctx_vals);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(priv);
+}
+
+int
+nvc0_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nvc0_graph_priv *priv;
+       int ret, gpc, i;
+
+       switch (dev_priv->chipset) {
+       case 0xc0:
+       case 0xc3:
+       case 0xc4:
+               break;
+       default:
+               NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
+               return 0;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->base.destroy = nvc0_graph_destroy;
+       priv->base.init = nvc0_graph_init;
+       priv->base.fini = nvc0_graph_fini;
+       priv->base.context_new = nvc0_graph_context_new;
+       priv->base.context_del = nvc0_graph_context_del;
+       priv->base.object_new = nvc0_graph_object_new;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
+       nouveau_irq_register(dev, 12, nvc0_graph_isr);
+       nouveau_irq_register(dev, 25, nvc0_runk140_isr);
+
+       if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
+           nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
+           nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
+           nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
+               ret = 0;
+               goto error;
+       }
+
+
+       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
+       if (ret)
+               goto error;
+
+       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+       if (ret)
+               goto error;
+
+       for (i = 0; i < 0x1000; i += 4) {
+               nv_wo32(priv->unk4188b4, i, 0x00000010);
+               nv_wo32(priv->unk4188b8, i, 0x00000010);
+       }
+
+       priv->gpc_nr  =  nv_rd32(dev, 0x409604) & 0x0000001f;
+       priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
+       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+               priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
+               priv->tp_total += priv->tp_nr[gpc];
+       }
+
+       /*XXX: these need figuring out... */
+       switch (dev_priv->chipset) {
+       case 0xc0:
+               if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
+                       priv->magic_not_rop_nr = 0x07;
+                       /* filled values up to tp_total, the rest 0 */
+                       priv->magicgpc918      = 0x000ba2e9;
+               } else
+               if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
+                       priv->magic_not_rop_nr = 0x05;
+                       priv->magicgpc918      = 0x00092493;
+               } else
+               if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
+                       priv->magic_not_rop_nr = 0x06;
+                       priv->magicgpc918      = 0x00088889;
+               }
+               break;
+       case 0xc3: /* 450, 4/0/0/0, 2 */
+               priv->magic_not_rop_nr = 0x03;
+               priv->magicgpc918      = 0x00200000;
+               break;
+       case 0xc4: /* 460, 3/4/0/0, 4 */
+               priv->magic_not_rop_nr = 0x01;
+               priv->magicgpc918      = 0x00124925;
+               break;
+       }
+
+       if (!priv->magic_not_rop_nr) {
+               NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
+                        priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
+                        priv->tp_nr[3], priv->rop_nr);
+               /* use 0xc3's values... */
+               priv->magic_not_rop_nr = 0x03;
+               priv->magicgpc918      = 0x00200000;
+       }
+
+       NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
+       NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
+       NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
+       NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
+       NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
+       return 0;
+
+error:
+       nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR);
+       return ret;
+}
+
+MODULE_FIRMWARE("nouveau/nvc0_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc0_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ad");
+MODULE_FIRMWARE("nouveau/fuc409c");
+MODULE_FIRMWARE("nouveau/fuc409d");
+MODULE_FIRMWARE("nouveau/fuc41ac");
+MODULE_FIRMWARE("nouveau/fuc41ad");
index 40e26f9c56c44c0af8a9dcaed0d0ac64872db5d8..f5d184e0689df4bad0f99ce792167c1c8ea960f9 100644 (file)
 #define GPC_MAX 4
 #define TP_MAX 32
 
-#define ROP_BCAST(r)   (0x408800 + (r))
-#define ROP_UNIT(u,r)  (0x410000 + (u) * 0x400 + (r))
-#define GPC_BCAST(r)   (0x418000 + (r))
-#define GPC_UNIT(t,r)  (0x500000 + (t) * 0x8000 + (r))
-#define TP_UNIT(t,m,r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+#define ROP_BCAST(r)     (0x408800 + (r))
+#define ROP_UNIT(u, r)   (0x410000 + (u) * 0x400 + (r))
+#define GPC_BCAST(r)     (0x418000 + (r))
+#define GPC_UNIT(t, r)   (0x500000 + (t) * 0x8000 + (r))
+#define TP_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+
+struct nvc0_graph_fuc {
+       u32 *data;
+       u32  size;
+};
 
 struct nvc0_graph_priv {
+       struct nouveau_exec_engine base;
+
+       struct nvc0_graph_fuc fuc409c;
+       struct nvc0_graph_fuc fuc409d;
+       struct nvc0_graph_fuc fuc41ac;
+       struct nvc0_graph_fuc fuc41ad;
+
        u8 gpc_nr;
        u8 rop_nr;
        u8 tp_nr[GPC_MAX];
@@ -46,15 +58,14 @@ struct nvc0_graph_priv {
        struct nouveau_gpuobj *unk4188b8;
 
        u8  magic_not_rop_nr;
-       u32 magicgpc980[4];
        u32 magicgpc918;
 };
 
 struct nvc0_graph_chan {
        struct nouveau_gpuobj *grctx;
-       struct nouveau_gpuobj *unk408004; // 0x418810 too
-       struct nouveau_gpuobj *unk40800c; // 0x419004 too
-       struct nouveau_gpuobj *unk418810; // 0x419848 too
+       struct nouveau_gpuobj *unk408004; /* 0x418810 too */
+       struct nouveau_gpuobj *unk40800c; /* 0x419004 too */
+       struct nouveau_gpuobj *unk418810; /* 0x419848 too */
        struct nouveau_gpuobj *mmio;
        int mmio_nr;
 };
index f880ff776db8562842142ebbc5482632e9ff2ecd..6df066114133dfc4beb9c1c142ce0391b15ab527 100644 (file)
@@ -1623,7 +1623,7 @@ nvc0_grctx_generate_rop(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       // ROPC_BROADCAST
+       /* ROPC_BROADCAST */
        nv_wr32(dev, 0x408800, 0x02802a3c);
        nv_wr32(dev, 0x408804, 0x00000040);
        nv_wr32(dev, 0x408808, 0x0003e00d);
@@ -1647,7 +1647,7 @@ nvc0_grctx_generate_gpc(struct drm_device *dev)
 {
        int i;
 
-       // GPC_BROADCAST
+       /* GPC_BROADCAST */
        nv_wr32(dev, 0x418380, 0x00000016);
        nv_wr32(dev, 0x418400, 0x38004e00);
        nv_wr32(dev, 0x418404, 0x71e0ffff);
@@ -1728,7 +1728,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       // GPC_BROADCAST.TP_BROADCAST
+       /* GPC_BROADCAST.TP_BROADCAST */
        nv_wr32(dev, 0x419848, 0x00000000);
        nv_wr32(dev, 0x419864, 0x0000012a);
        nv_wr32(dev, 0x419888, 0x00000000);
@@ -1741,7 +1741,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
        nv_wr32(dev, 0x419a1c, 0x00000000);
        nv_wr32(dev, 0x419a20, 0x00000800);
        if (dev_priv->chipset != 0xc0)
-               nv_wr32(dev, 0x00419ac4, 0x0007f440); // 0xc3
+               nv_wr32(dev, 0x00419ac4, 0x0007f440); /* 0xc3 */
        nv_wr32(dev, 0x419b00, 0x0a418820);
        nv_wr32(dev, 0x419b04, 0x062080e6);
        nv_wr32(dev, 0x419b08, 0x020398a4);
@@ -1797,8 +1797,8 @@ int
 nvc0_grctx_generate(struct nouveau_channel *chan)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+       struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+       struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
        int i, gpc, tp, id;
        u32 r000260, tmp;
@@ -1912,13 +1912,13 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                for (i = 1; i < 7; i++)
                        data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
 
-               // GPC_BROADCAST
+               /* GPC_BROADCAST */
                nv_wr32(dev, 0x418bb8, (priv->tp_total << 8) |
                                        priv->magic_not_rop_nr);
                for (i = 0; i < 6; i++)
                        nv_wr32(dev, 0x418b08 + (i * 4), data[i]);
 
-               // GPC_BROADCAST.TP_BROADCAST
+               /* GPC_BROADCAST.TP_BROADCAST */
                nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) |
                                       priv->magic_not_rop_nr |
                                       data2[0]);
@@ -1926,7 +1926,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                for (i = 0; i < 6; i++)
                        nv_wr32(dev, 0x419b00 + (i * 4), data[i]);
 
-               // UNK78xx
+               /* UNK78xx */
                nv_wr32(dev, 0x4078bc, (priv->tp_total << 8) |
                                        priv->magic_not_rop_nr);
                for (i = 0; i < 6; i++)
@@ -1944,7 +1944,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                gpc = -1;
                for (i = 0, gpc = -1; i < 32; i++) {
                        int ltp = i * (priv->tp_total - 1) / 32;
-                       
+
                        do {
                                gpc = (gpc + 1) % priv->gpc_nr;
                        } while (!tpnr[gpc]);
index 7bd7456890974025c74bfce11f8516bad909eacf..ebdb0fdb8348ad7b217e3d46027207789e0ad67f 100644 (file)
@@ -652,12 +652,12 @@ static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
 
 static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
 {
-       uint8_t count = U8((*ptr)++);
+       unsigned count = U8((*ptr)++);
        SDEBUG("   count: %d\n", count);
        if (arg == ATOM_UNIT_MICROSEC)
                udelay(count);
        else
-               schedule_timeout_uninterruptible(msecs_to_jiffies(count));
+               msleep(count);
 }
 
 static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
index 7fd88497b93042eacae1736a3762fe61e60e044e..49611e2365d984e539fe2f7d5169303e7e052f60 100644 (file)
@@ -726,6 +726,7 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2
 #define ATOM_ENCODER_CMD_DP_VIDEO_ON                  0x0d
 #define ATOM_ENCODER_CMD_QUERY_DP_LINK_TRAINING_STATUS    0x0e
 #define ATOM_ENCODER_CMD_SETUP                        0x0f
+#define ATOM_ENCODER_CMD_SETUP_PANEL_MODE             0x10
 
 // ucStatus
 #define ATOM_ENCODER_STATUS_LINK_TRAINING_COMPLETE    0x10
@@ -765,13 +766,19 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3
   USHORT usPixelClock;      // in 10KHz; for bios convenient
   ATOM_DIG_ENCODER_CONFIG_V3 acConfig;
   UCHAR ucAction;                              
-  UCHAR ucEncoderMode;
+  union {
+    UCHAR ucEncoderMode;
                             // =0: DP   encoder      
                             // =1: LVDS encoder          
                             // =2: DVI  encoder  
                             // =3: HDMI encoder
                             // =4: SDVO encoder
                             // =5: DP audio
+    UCHAR ucPanelMode;      // only valid when ucAction == ATOM_ENCODER_CMD_SETUP_PANEL_MODE
+                           // =0:     external DP
+                           // =1:     internal DP2
+                           // =0x11:  internal DP1 for NutMeg/Travis DP translator
+  };
   UCHAR ucLaneNum;          // how many lanes to enable
   UCHAR ucBitPerColor;      // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
   UCHAR ucReserved;
@@ -816,13 +823,19 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4
   UCHAR ucConfig;
   };
   UCHAR ucAction;                              
-  UCHAR ucEncoderMode;
+  union {
+    UCHAR ucEncoderMode;
                             // =0: DP   encoder      
                             // =1: LVDS encoder          
                             // =2: DVI  encoder  
                             // =3: HDMI encoder
                             // =4: SDVO encoder
                             // =5: DP audio
+    UCHAR ucPanelMode;      // only valid when ucAction == ATOM_ENCODER_CMD_SETUP_PANEL_MODE
+                           // =0:     external DP
+                           // =1:     internal DP2
+                           // =0x11:  internal DP1 for NutMeg/Travis DP translator
+  };
   UCHAR ucLaneNum;          // how many lanes to enable
   UCHAR ucBitPerColor;      // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
   UCHAR ucHPD_ID;           // HPD ID (1-6). =0 means to skip HDP programming. New comparing to previous version
@@ -836,6 +849,11 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4
 #define PANEL_12BIT_PER_COLOR                            0x04
 #define PANEL_16BIT_PER_COLOR                            0x05
 
+//define ucPanelMode
+#define DP_PANEL_MODE_EXTERNAL_DP_MODE                   0x00
+#define DP_PANEL_MODE_INTERNAL_DP2_MODE                  0x01
+#define DP_PANEL_MODE_INTERNAL_DP1_MODE                  0x11
+
 /****************************************************************************/ 
 // Structures used by UNIPHYTransmitterControlTable
 //                    LVTMATransmitterControlTable
index 529a3a704731ba39d77b423ac1ebe670697816f3..ec848787d7d9ee260e8edd6642563f6f7436fe94 100644 (file)
@@ -420,7 +420,7 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
 
        if (ASIC_IS_DCE5(rdev)) {
                args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
-               args.v3.ucSpreadSpectrumType = ss->type;
+               args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                switch (pll_id) {
                case ATOM_PPLL1:
                        args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
@@ -440,10 +440,12 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
                case ATOM_PPLL_INVALID:
                        return;
                }
-               args.v2.ucEnable = enable;
+               args.v3.ucEnable = enable;
+               if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK))
+                       args.v3.ucEnable = ATOM_DISABLE;
        } else if (ASIC_IS_DCE4(rdev)) {
                args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
-               args.v2.ucSpreadSpectrumType = ss->type;
+               args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                switch (pll_id) {
                case ATOM_PPLL1:
                        args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
@@ -464,32 +466,36 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
                        return;
                }
                args.v2.ucEnable = enable;
+               if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK))
+                       args.v2.ucEnable = ATOM_DISABLE;
        } else if (ASIC_IS_DCE3(rdev)) {
                args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
-               args.v1.ucSpreadSpectrumType = ss->type;
+               args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                args.v1.ucSpreadSpectrumStep = ss->step;
                args.v1.ucSpreadSpectrumDelay = ss->delay;
                args.v1.ucSpreadSpectrumRange = ss->range;
                args.v1.ucPpll = pll_id;
                args.v1.ucEnable = enable;
        } else if (ASIC_IS_AVIVO(rdev)) {
-               if (enable == ATOM_DISABLE) {
+               if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
+                   (ss->type & ATOM_EXTERNAL_SS_MASK)) {
                        atombios_disable_ss(crtc);
                        return;
                }
                args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
-               args.lvds_ss_2.ucSpreadSpectrumType = ss->type;
+               args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                args.lvds_ss_2.ucSpreadSpectrumStep = ss->step;
                args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay;
                args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;
                args.lvds_ss_2.ucEnable = enable;
        } else {
-               if (enable == ATOM_DISABLE) {
+               if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
+                   (ss->type & ATOM_EXTERNAL_SS_MASK)) {
                        atombios_disable_ss(crtc);
                        return;
                }
                args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
-               args.lvds_ss.ucSpreadSpectrumType = ss->type;
+               args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
                args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2;
                args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4;
                args.lvds_ss.ucEnable = enable;
@@ -512,6 +518,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
        struct radeon_device *rdev = dev->dev_private;
        struct drm_encoder *encoder = NULL;
        struct radeon_encoder *radeon_encoder = NULL;
+       struct drm_connector *connector = NULL;
        u32 adjusted_clock = mode->clock;
        int encoder_mode = 0;
        u32 dp_clock = mode->clock;
@@ -546,9 +553,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                if (encoder->crtc == crtc) {
                        radeon_encoder = to_radeon_encoder(encoder);
+                       connector = radeon_get_connector_for_encoder(encoder);
+                       if (connector)
+                               bpc = connector->display_info.bpc;
                        encoder_mode = atombios_get_encoder_mode(encoder);
-                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) {
-                               struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+                       if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
+                           radeon_encoder_is_dp_bridge(encoder)) {
                                if (connector) {
                                        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                                        struct radeon_connector_atom_dig *dig_connector =
@@ -612,7 +622,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
                                args.v1.ucTransmitterID = radeon_encoder->encoder_id;
                                args.v1.ucEncodeMode = encoder_mode;
-                               if (ss_enabled)
+                               if (ss_enabled && ss->percentage)
                                        args.v1.ucConfig |=
                                                ADJUST_DISPLAY_CONFIG_SS_ENABLE;
 
@@ -625,10 +635,11 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
                                args.v3.sInput.ucEncodeMode = encoder_mode;
                                args.v3.sInput.ucDispPllConfig = 0;
-                               if (ss_enabled)
+                               if (ss_enabled && ss->percentage)
                                        args.v3.sInput.ucDispPllConfig |=
                                                DISPPLL_CONFIG_SS_ENABLE;
-                               if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+                               if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT) ||
+                                   radeon_encoder_is_dp_bridge(encoder)) {
                                        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                                        if (encoder_mode == ATOM_ENCODER_MODE_DP) {
                                                args.v3.sInput.ucDispPllConfig |=
@@ -754,7 +765,10 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                                      u32 ref_div,
                                      u32 fb_div,
                                      u32 frac_fb_div,
-                                     u32 post_div)
+                                     u32 post_div,
+                                     int bpc,
+                                     bool ss_enabled,
+                                     struct radeon_atom_ss *ss)
 {
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -801,6 +815,8 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                        args.v3.ucPostDiv = post_div;
                        args.v3.ucPpll = pll_id;
                        args.v3.ucMiscInfo = (pll_id << 2);
+                       if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+                               args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
                        args.v3.ucTransmitterId = encoder_id;
                        args.v3.ucEncoderMode = encoder_mode;
                        break;
@@ -812,6 +828,17 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                        args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
                        args.v5.ucPostDiv = post_div;
                        args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
+                       if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+                               args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
+                       switch (bpc) {
+                       case 8:
+                       default:
+                               args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
+                               break;
+                       case 10:
+                               args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
+                               break;
+                       }
                        args.v5.ucTransmitterID = encoder_id;
                        args.v5.ucEncoderMode = encoder_mode;
                        args.v5.ucPpll = pll_id;
@@ -824,6 +851,23 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                        args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
                        args.v6.ucPostDiv = post_div;
                        args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
+                       if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
+                       switch (bpc) {
+                       case 8:
+                       default:
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
+                               break;
+                       case 10:
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
+                               break;
+                       case 12:
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
+                               break;
+                       case 16:
+                               args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
+                               break;
+                       }
                        args.v6.ucTransmitterID = encoder_id;
                        args.v6.ucEncoderMode = encoder_mode;
                        args.v6.ucPpll = pll_id;
@@ -855,6 +899,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        int encoder_mode = 0;
        struct radeon_atom_ss ss;
        bool ss_enabled = false;
+       int bpc = 8;
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                if (encoder->crtc == crtc) {
@@ -891,41 +936,30 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                struct radeon_connector_atom_dig *dig_connector =
                        radeon_connector->con_priv;
                int dp_clock;
+               bpc = connector->display_info.bpc;
 
                switch (encoder_mode) {
                case ATOM_ENCODER_MODE_DP:
                        /* DP/eDP */
                        dp_clock = dig_connector->dp_clock / 10;
-                       if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
-                               if (ASIC_IS_DCE4(rdev))
-                                       ss_enabled =
-                                               radeon_atombios_get_asic_ss_info(rdev, &ss,
-                                                                                dig->lcd_ss_id,
-                                                                                dp_clock);
-                               else
+                       if (ASIC_IS_DCE4(rdev))
+                               ss_enabled =
+                                       radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                                        ASIC_INTERNAL_SS_ON_DP,
+                                                                        dp_clock);
+                       else {
+                               if (dp_clock == 16200) {
                                        ss_enabled =
                                                radeon_atombios_get_ppll_ss_info(rdev, &ss,
-                                                                                dig->lcd_ss_id);
-                       } else {
-                               if (ASIC_IS_DCE4(rdev))
-                                       ss_enabled =
-                                               radeon_atombios_get_asic_ss_info(rdev, &ss,
-                                                                                ASIC_INTERNAL_SS_ON_DP,
-                                                                                dp_clock);
-                               else {
-                                       if (dp_clock == 16200) {
-                                               ss_enabled =
-                                                       radeon_atombios_get_ppll_ss_info(rdev, &ss,
-                                                                                        ATOM_DP_SS_ID2);
-                                               if (!ss_enabled)
-                                                       ss_enabled =
-                                                               radeon_atombios_get_ppll_ss_info(rdev, &ss,
-                                                                                                ATOM_DP_SS_ID1);
-                                       } else
+                                                                                ATOM_DP_SS_ID2);
+                                       if (!ss_enabled)
                                                ss_enabled =
                                                        radeon_atombios_get_ppll_ss_info(rdev, &ss,
                                                                                         ATOM_DP_SS_ID1);
-                               }
+                               } else
+                                       ss_enabled =
+                                               radeon_atombios_get_ppll_ss_info(rdev, &ss,
+                                                                                ATOM_DP_SS_ID1);
                        }
                        break;
                case ATOM_ENCODER_MODE_LVDS:
@@ -974,7 +1008,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
 
        atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
                                  encoder_mode, radeon_encoder->encoder_id, mode->clock,
-                                 ref_div, fb_div, frac_fb_div, post_div);
+                                 ref_div, fb_div, frac_fb_div, post_div, bpc, ss_enabled, &ss);
 
        if (ss_enabled) {
                /* calculate ss amount and step size */
@@ -982,7 +1016,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                        u32 step_size;
                        u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000;
                        ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
-                       ss.amount |= ((amount - (ss.amount * 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
+                       ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
                                ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
                        if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
                                step_size = (4 * amount * ref_div * (ss.rate * 2048)) /
@@ -1395,11 +1429,19 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
        uint32_t pll_in_use = 0;
 
        if (ASIC_IS_DCE4(rdev)) {
-               /* if crtc is driving DP and we have an ext clock, use that */
                list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
                        if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
+                               /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
+                                * depending on the asic:
+                                * DCE4: PPLL or ext clock
+                                * DCE5: DCPLL or ext clock
+                                *
+                                * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip
+                                * PPLL/DCPLL programming and only program the DP DTO for the
+                                * crtc virtual pixel clock.
+                                */
                                if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) {
-                                       if (rdev->clock.dp_extclk)
+                                       if (ASIC_IS_DCE5(rdev) || rdev->clock.dp_extclk)
                                                return ATOM_PPLL_INVALID;
                                }
                        }
@@ -1515,6 +1557,8 @@ static void atombios_crtc_commit(struct drm_crtc *crtc)
 static void atombios_crtc_disable(struct drm_crtc *crtc)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_atom_ss ss;
+
        atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 
        switch (radeon_crtc->pll_id) {
@@ -1522,7 +1566,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
        case ATOM_PPLL2:
                /* disable the ppll */
                atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
-                                         0, 0, ATOM_DISABLE, 0, 0, 0, 0);
+                                         0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
                break;
        default:
                break;
index 695de9a38506dea0aa19c8b2ec315486c7b26bb1..8c0f9e36ff8e1ee452db546d6b88611991a518ea 100644 (file)
@@ -43,158 +43,242 @@ static char *pre_emph_names[] = {
         "0dB", "3.5dB", "6dB", "9.5dB"
 };
 
-static const int dp_clocks[] = {
-       54000,  /* 1 lane, 1.62 Ghz */
-       90000,  /* 1 lane, 2.70 Ghz */
-       108000, /* 2 lane, 1.62 Ghz */
-       180000, /* 2 lane, 2.70 Ghz */
-       216000, /* 4 lane, 1.62 Ghz */
-       360000, /* 4 lane, 2.70 Ghz */
+/***** radeon AUX functions *****/
+union aux_channel_transaction {
+       PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
+       PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
 };
 
-static const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);
+static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
+                                u8 *send, int send_bytes,
+                                u8 *recv, int recv_size,
+                                u8 delay, u8 *ack)
+{
+       struct drm_device *dev = chan->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       union aux_channel_transaction args;
+       int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
+       unsigned char *base;
+       int recv_bytes;
+
+       memset(&args, 0, sizeof(args));
 
-/* common helper functions */
-static int dp_lanes_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
+       base = (unsigned char *)rdev->mode_info.atom_context->scratch;
+
+       memcpy(base, send, send_bytes);
+
+       args.v1.lpAuxRequest = 0;
+       args.v1.lpDataOut = 16;
+       args.v1.ucDataOutLen = 0;
+       args.v1.ucChannelID = chan->rec.i2c_id;
+       args.v1.ucDelay = delay / 10;
+       if (ASIC_IS_DCE4(rdev))
+               args.v2.ucHPD_ID = chan->rec.hpd;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+       *ack = args.v1.ucReplyStatus;
+
+       /* timeout */
+       if (args.v1.ucReplyStatus == 1) {
+               DRM_DEBUG_KMS("dp_aux_ch timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       /* flags not zero */
+       if (args.v1.ucReplyStatus == 2) {
+               DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
+               return -EBUSY;
+       }
+
+       /* error */
+       if (args.v1.ucReplyStatus == 3) {
+               DRM_DEBUG_KMS("dp_aux_ch error\n");
+               return -EIO;
+       }
+
+       recv_bytes = args.v1.ucDataOutLen;
+       if (recv_bytes > recv_size)
+               recv_bytes = recv_size;
+
+       if (recv && recv_size)
+               memcpy(recv, base + 16, recv_bytes);
+
+       return recv_bytes;
+}
+
+static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
+                                     u16 address, u8 *send, u8 send_bytes, u8 delay)
 {
-       int i;
-       u8 max_link_bw;
-       u8 max_lane_count;
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int ret;
+       u8 msg[20];
+       int msg_bytes = send_bytes + 4;
+       u8 ack;
 
-       if (!dpcd)
-               return 0;
+       if (send_bytes > 16)
+               return -1;
 
-       max_link_bw = dpcd[DP_MAX_LINK_RATE];
-       max_lane_count = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
+       msg[0] = address;
+       msg[1] = address >> 8;
+       msg[2] = AUX_NATIVE_WRITE << 4;
+       msg[3] = (msg_bytes << 4) | (send_bytes - 1);
+       memcpy(&msg[4], send, send_bytes);
 
-       switch (max_link_bw) {
-       case DP_LINK_BW_1_62:
-       default:
-               for (i = 0; i < num_dp_clocks; i++) {
-                       if (i % 2)
-                               continue;
-                       switch (max_lane_count) {
-                       case 1:
-                               if (i > 1)
-                                       return 0;
-                               break;
-                       case 2:
-                               if (i > 3)
-                                       return 0;
-                               break;
-                       case 4:
-                       default:
-                               break;
-                       }
-                       if (dp_clocks[i] > mode_clock) {
-                               if (i < 2)
-                                       return 1;
-                               else if (i < 4)
-                                       return 2;
-                               else
-                                       return 4;
-                       }
-               }
-               break;
-       case DP_LINK_BW_2_7:
-               for (i = 0; i < num_dp_clocks; i++) {
-                       switch (max_lane_count) {
-                       case 1:
-                               if (i > 1)
-                                       return 0;
-                               break;
-                       case 2:
-                               if (i > 3)
-                                       return 0;
-                               break;
-                       case 4:
-                       default:
-                               break;
-                       }
-                       if (dp_clocks[i] > mode_clock) {
-                               if (i < 2)
-                                       return 1;
-                               else if (i < 4)
-                                       return 2;
-                               else
-                                       return 4;
-                       }
-               }
-               break;
+       while (1) {
+               ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
+                                           msg, msg_bytes, NULL, 0, delay, &ack);
+               if (ret < 0)
+                       return ret;
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+                       break;
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(400);
+               else
+                       return -EIO;
        }
 
-       return 0;
+       return send_bytes;
 }
 
-static int dp_link_clock_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
+static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
+                                    u16 address, u8 *recv, int recv_bytes, u8 delay)
 {
-       int i;
-       u8 max_link_bw;
-       u8 max_lane_count;
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       u8 msg[4];
+       int msg_bytes = 4;
+       u8 ack;
+       int ret;
 
-       if (!dpcd)
-               return 0;
+       msg[0] = address;
+       msg[1] = address >> 8;
+       msg[2] = AUX_NATIVE_READ << 4;
+       msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
+
+       while (1) {
+               ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
+                                           msg, msg_bytes, recv, recv_bytes, delay, &ack);
+               if (ret == 0)
+                       return -EPROTO;
+               if (ret < 0)
+                       return ret;
+               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+                       return ret;
+               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+                       udelay(400);
+               else
+                       return -EIO;
+       }
+}
 
-       max_link_bw = dpcd[DP_MAX_LINK_RATE];
-       max_lane_count = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
+static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
+                                u16 reg, u8 val)
+{
+       radeon_dp_aux_native_write(radeon_connector, reg, &val, 1, 0);
+}
 
-       switch (max_link_bw) {
-       case DP_LINK_BW_1_62:
+static u8 radeon_read_dpcd_reg(struct radeon_connector *radeon_connector,
+                              u16 reg)
+{
+       u8 val = 0;
+
+       radeon_dp_aux_native_read(radeon_connector, reg, &val, 1, 0);
+
+       return val;
+}
+
+int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
+                        u8 write_byte, u8 *read_byte)
+{
+       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+       struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;
+       u16 address = algo_data->address;
+       u8 msg[5];
+       u8 reply[2];
+       unsigned retry;
+       int msg_bytes;
+       int reply_bytes = 1;
+       int ret;
+       u8 ack;
+
+       /* Set up the command byte */
+       if (mode & MODE_I2C_READ)
+               msg[2] = AUX_I2C_READ << 4;
+       else
+               msg[2] = AUX_I2C_WRITE << 4;
+
+       if (!(mode & MODE_I2C_STOP))
+               msg[2] |= AUX_I2C_MOT << 4;
+
+       msg[0] = address;
+       msg[1] = address >> 8;
+
+       switch (mode) {
+       case MODE_I2C_WRITE:
+               msg_bytes = 5;
+               msg[3] = msg_bytes << 4;
+               msg[4] = write_byte;
+               break;
+       case MODE_I2C_READ:
+               msg_bytes = 4;
+               msg[3] = msg_bytes << 4;
+               break;
        default:
-               for (i = 0; i < num_dp_clocks; i++) {
-                       if (i % 2)
-                               continue;
-                       switch (max_lane_count) {
-                       case 1:
-                               if (i > 1)
-                                       return 0;
-                               break;
-                       case 2:
-                               if (i > 3)
-                                       return 0;
-                               break;
-                       case 4:
-                       default:
-                               break;
-                       }
-                       if (dp_clocks[i] > mode_clock)
-                               return 162000;
-               }
+               msg_bytes = 4;
+               msg[3] = 3 << 4;
                break;
-       case DP_LINK_BW_2_7:
-               for (i = 0; i < num_dp_clocks; i++) {
-                       switch (max_lane_count) {
-                       case 1:
-                               if (i > 1)
-                                       return 0;
-                               break;
-                       case 2:
-                               if (i > 3)
-                                       return 0;
-                               break;
-                       case 4:
-                       default:
-                               break;
-                       }
-                       if (dp_clocks[i] > mode_clock)
-                               return (i % 2) ? 270000 : 162000;
-               }
        }
 
-       return 0;
-}
+       for (retry = 0; retry < 4; retry++) {
+               ret = radeon_process_aux_ch(auxch,
+                                           msg, msg_bytes, reply, reply_bytes, 0, &ack);
+               if (ret < 0) {
+                       DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
+                       return ret;
+               }
 
-int dp_mode_valid(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
-{
-       int lanes = dp_lanes_for_mode_clock(dpcd, mode_clock);
-       int dp_clock = dp_link_clock_for_mode_clock(dpcd, mode_clock);
+               switch (ack & AUX_NATIVE_REPLY_MASK) {
+               case AUX_NATIVE_REPLY_ACK:
+                       /* I2C-over-AUX Reply field is only valid
+                        * when paired with AUX ACK.
+                        */
+                       break;
+               case AUX_NATIVE_REPLY_NACK:
+                       DRM_DEBUG_KMS("aux_ch native nack\n");
+                       return -EREMOTEIO;
+               case AUX_NATIVE_REPLY_DEFER:
+                       DRM_DEBUG_KMS("aux_ch native defer\n");
+                       udelay(400);
+                       continue;
+               default:
+                       DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack);
+                       return -EREMOTEIO;
+               }
 
-       if ((lanes == 0) || (dp_clock == 0))
-               return MODE_CLOCK_HIGH;
+               switch (ack & AUX_I2C_REPLY_MASK) {
+               case AUX_I2C_REPLY_ACK:
+                       if (mode == MODE_I2C_READ)
+                               *read_byte = reply[0];
+                       return ret;
+               case AUX_I2C_REPLY_NACK:
+                       DRM_DEBUG_KMS("aux_i2c nack\n");
+                       return -EREMOTEIO;
+               case AUX_I2C_REPLY_DEFER:
+                       DRM_DEBUG_KMS("aux_i2c defer\n");
+                       udelay(400);
+                       break;
+               default:
+                       DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack);
+                       return -EREMOTEIO;
+               }
+       }
 
-       return MODE_OK;
+       DRM_ERROR("aux i2c too many retries, giving up\n");
+       return -EREMOTEIO;
 }
 
+/***** general DP utility functions *****/
+
 static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r)
 {
        return link_status[r - DP_LANE0_1_STATUS];
@@ -242,7 +326,7 @@ static bool dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],
        return true;
 }
 
-static u8 dp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
+static u8 dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
                                        int lane)
 
 {
@@ -255,7 +339,7 @@ static u8 dp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE]
        return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
 }
 
-static u8 dp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
+static u8 dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
                                             int lane)
 {
        int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
@@ -267,22 +351,8 @@ static u8 dp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_
        return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
 }
 
-/* XXX fix me -- chip specific */
 #define DP_VOLTAGE_MAX         DP_TRAIN_VOLTAGE_SWING_1200
-static u8 dp_pre_emphasis_max(u8 voltage_swing)
-{
-       switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-       case DP_TRAIN_VOLTAGE_SWING_400:
-               return DP_TRAIN_PRE_EMPHASIS_6;
-       case DP_TRAIN_VOLTAGE_SWING_600:
-               return DP_TRAIN_PRE_EMPHASIS_6;
-       case DP_TRAIN_VOLTAGE_SWING_800:
-               return DP_TRAIN_PRE_EMPHASIS_3_5;
-       case DP_TRAIN_VOLTAGE_SWING_1200:
-       default:
-               return DP_TRAIN_PRE_EMPHASIS_0;
-       }
-}
+#define DP_PRE_EMPHASIS_MAX    DP_TRAIN_PRE_EMPHASIS_9_5
 
 static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
                                int lane_count,
@@ -308,10 +378,10 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
        }
 
        if (v >= DP_VOLTAGE_MAX)
-               v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+               v |= DP_TRAIN_MAX_SWING_REACHED;
 
-       if (p >= dp_pre_emphasis_max(v))
-               p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+       if (p >= DP_PRE_EMPHASIS_MAX)
+               p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 
        DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n",
                  voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT],
@@ -321,110 +391,109 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
                train_set[lane] = v | p;
 }
 
-union aux_channel_transaction {
-       PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
-       PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
-};
-
-/* radeon aux chan functions */
-bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
-                          int num_bytes, u8 *read_byte,
-                          u8 read_buf_len, u8 delay)
+/* convert bits per color to bits per pixel */
+/* get bpc from the EDID */
+static int convert_bpc_to_bpp(int bpc)
 {
-       struct drm_device *dev = chan->dev;
-       struct radeon_device *rdev = dev->dev_private;
-       union aux_channel_transaction args;
-       int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
-       unsigned char *base;
-       int retry_count = 0;
-
-       memset(&args, 0, sizeof(args));
-
-       base = (unsigned char *)rdev->mode_info.atom_context->scratch;
-
-retry:
-       memcpy(base, req_bytes, num_bytes);
-
-       args.v1.lpAuxRequest = 0;
-       args.v1.lpDataOut = 16;
-       args.v1.ucDataOutLen = 0;
-       args.v1.ucChannelID = chan->rec.i2c_id;
-       args.v1.ucDelay = delay / 10;
-       if (ASIC_IS_DCE4(rdev))
-               args.v2.ucHPD_ID = chan->rec.hpd;
+       if (bpc == 0)
+               return 24;
+       else
+               return bpc * 3;
+}
 
-       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+/* get the max pix clock supported by the link rate and lane num */
+static int dp_get_max_dp_pix_clock(int link_rate,
+                                  int lane_num,
+                                  int bpp)
+{
+       return (link_rate * lane_num * 8) / bpp;
+}
 
-       if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) {
-               if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10)
-                       goto retry;
-               DRM_DEBUG_KMS("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n",
-                         req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3],
-                         chan->rec.i2c_id, args.v1.ucReplyStatus, retry_count);
-               return false;
+static int dp_get_max_link_rate(u8 dpcd[DP_DPCD_SIZE])
+{
+       switch (dpcd[DP_MAX_LINK_RATE]) {
+       case DP_LINK_BW_1_62:
+       default:
+               return 162000;
+       case DP_LINK_BW_2_7:
+               return 270000;
+       case DP_LINK_BW_5_4:
+               return 540000;
        }
+}
 
-       if (args.v1.ucDataOutLen && read_byte && read_buf_len) {
-               if (read_buf_len < args.v1.ucDataOutLen) {
-                       DRM_ERROR("Buffer to small for return answer %d %d\n",
-                                 read_buf_len, args.v1.ucDataOutLen);
-                       return false;
-               }
-               {
-                       int len = min(read_buf_len, args.v1.ucDataOutLen);
-                       memcpy(read_byte, base + 16, len);
-               }
-       }
-       return true;
+static u8 dp_get_max_lane_number(u8 dpcd[DP_DPCD_SIZE])
+{
+       return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
 }
 
-bool radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, uint16_t address,
-                               uint8_t send_bytes, uint8_t *send)
+static u8 dp_get_dp_link_rate_coded(int link_rate)
 {
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
-       u8 msg[20];
-       u8 msg_len, dp_msg_len;
-       bool ret;
+       switch (link_rate) {
+       case 162000:
+       default:
+               return DP_LINK_BW_1_62;
+       case 270000:
+               return DP_LINK_BW_2_7;
+       case 540000:
+               return DP_LINK_BW_5_4;
+       }
+}
 
-       dp_msg_len = 4;
-       msg[0] = address;
-       msg[1] = address >> 8;
-       msg[2] = AUX_NATIVE_WRITE << 4;
-       dp_msg_len += send_bytes;
-       msg[3] = (dp_msg_len << 4) | (send_bytes - 1);
+/***** radeon specific DP functions *****/
 
-       if (send_bytes > 16)
-               return false;
+/* First get the min lane# when low rate is used according to pixel clock
+ * (prefer low rate), second check max lane# supported by DP panel,
+ * if the max lane# < low rate lane# then use max lane# instead.
+ */
+static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
+                                       u8 dpcd[DP_DPCD_SIZE],
+                                       int pix_clock)
+{
+       int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+       int max_link_rate = dp_get_max_link_rate(dpcd);
+       int max_lane_num = dp_get_max_lane_number(dpcd);
+       int lane_num;
+       int max_dp_pix_clock;
+
+       for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
+               max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
+               if (pix_clock <= max_dp_pix_clock)
+                       break;
+       }
 
-       memcpy(&msg[4], send, send_bytes);
-       msg_len = 4 + send_bytes;
-       ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_len, NULL, 0, 0);
-       return ret;
+       return lane_num;
 }
 
-bool radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, uint16_t address,
-                              uint8_t delay, uint8_t expected_bytes,
-                              uint8_t *read_p)
+static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
+                                      u8 dpcd[DP_DPCD_SIZE],
+                                      int pix_clock)
 {
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
-       u8 msg[20];
-       u8 msg_len, dp_msg_len;
-       bool ret = false;
-       msg_len = 4;
-       dp_msg_len = 4;
-       msg[0] = address;
-       msg[1] = address >> 8;
-       msg[2] = AUX_NATIVE_READ << 4;
-       msg[3] = (dp_msg_len) << 4;
-       msg[3] |= expected_bytes - 1;
+       int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+       int lane_num, max_pix_clock;
+
+       if (radeon_connector_encoder_is_dp_bridge(connector))
+               return 270000;
+
+       lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
+       max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
+       if (pix_clock <= max_pix_clock)
+               return 162000;
+       max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
+       if (pix_clock <= max_pix_clock)
+               return 270000;
+       if (radeon_connector_is_dp12_capable(connector)) {
+               max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
+               if (pix_clock <= max_pix_clock)
+                       return 540000;
+       }
 
-       ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_len, read_p, expected_bytes, delay);
-       return ret;
+       return dp_get_max_link_rate(dpcd);
 }
 
-/* radeon dp functions */
-static u8 radeon_dp_encoder_service(struct radeon_device *rdev, int action, int dp_clock,
-                                   uint8_t ucconfig, uint8_t lane_num)
+static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
+                                   int action, int dp_clock,
+                                   u8 ucconfig, u8 lane_num)
 {
        DP_ENCODER_SERVICE_PARAMETERS args;
        int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
@@ -454,60 +523,86 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
 {
        struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
        u8 msg[25];
-       int ret;
+       int ret, i;
 
-       ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, 0, 8, msg);
-       if (ret) {
+       ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg, 8, 0);
+       if (ret > 0) {
                memcpy(dig_connector->dpcd, msg, 8);
-               {
-                       int i;
-                       DRM_DEBUG_KMS("DPCD: ");
-                       for (i = 0; i < 8; i++)
-                               DRM_DEBUG_KMS("%02x ", msg[i]);
-                       DRM_DEBUG_KMS("\n");
-               }
+               DRM_DEBUG_KMS("DPCD: ");
+               for (i = 0; i < 8; i++)
+                       DRM_DEBUG_KMS("%02x ", msg[i]);
+               DRM_DEBUG_KMS("\n");
                return true;
        }
        dig_connector->dpcd[0] = 0;
        return false;
 }
 
+static void radeon_dp_set_panel_mode(struct drm_encoder *encoder,
+                                    struct drm_connector *connector)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
+
+       if (!ASIC_IS_DCE4(rdev))
+               return;
+
+       if (radeon_connector_encoder_is_dp_bridge(connector))
+               panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
+
+       atombios_dig_encoder_setup(encoder,
+                                  ATOM_ENCODER_CMD_SETUP_PANEL_MODE,
+                                  panel_mode);
+}
+
 void radeon_dp_set_link_config(struct drm_connector *connector,
                               struct drm_display_mode *mode)
 {
-       struct radeon_connector *radeon_connector;
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        struct radeon_connector_atom_dig *dig_connector;
 
-       if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
-           (connector->connector_type != DRM_MODE_CONNECTOR_eDP))
-               return;
-
-       radeon_connector = to_radeon_connector(connector);
        if (!radeon_connector->con_priv)
                return;
        dig_connector = radeon_connector->con_priv;
 
-       dig_connector->dp_clock =
-               dp_link_clock_for_mode_clock(dig_connector->dpcd, mode->clock);
-       dig_connector->dp_lane_count =
-               dp_lanes_for_mode_clock(dig_connector->dpcd, mode->clock);
+       if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+           (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
+               dig_connector->dp_clock =
+                       radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+               dig_connector->dp_lane_count =
+                       radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
+       }
 }
 
-int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
+int radeon_dp_mode_valid_helper(struct drm_connector *connector,
                                struct drm_display_mode *mode)
 {
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector_atom_dig *dig_connector;
+       int dp_clock;
+
+       if (!radeon_connector->con_priv)
+               return MODE_CLOCK_HIGH;
+       dig_connector = radeon_connector->con_priv;
+
+       dp_clock =
+               radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+
+       if ((dp_clock == 540000) &&
+           (!radeon_connector_is_dp12_capable(connector)))
+               return MODE_CLOCK_HIGH;
 
-       return dp_mode_valid(dig_connector->dpcd, mode->clock);
+       return MODE_OK;
 }
 
-static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector,
-                                   u8 link_status[DP_LINK_STATUS_SIZE])
+static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
+                                     u8 link_status[DP_LINK_STATUS_SIZE])
 {
        int ret;
-       ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS, 100,
-                                       DP_LINK_STATUS_SIZE, link_status);
-       if (!ret) {
+       ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS,
+                                       link_status, DP_LINK_STATUS_SIZE, 100);
+       if (ret <= 0) {
                DRM_ERROR("displayport link status failed\n");
                return false;
        }
@@ -518,292 +613,309 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector,
        return true;
 }
 
-bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
-{
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+struct radeon_dp_link_train_info {
+       struct radeon_device *rdev;
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       int enc_id;
+       int dp_clock;
+       int dp_lane_count;
+       int rd_interval;
+       bool tp3_supported;
+       u8 dpcd[8];
+       u8 train_set[4];
        u8 link_status[DP_LINK_STATUS_SIZE];
+       u8 tries;
+};
 
-       if (!atom_dp_get_link_status(radeon_connector, link_status))
-               return false;
-       if (dp_channel_eq_ok(link_status, dig_connector->dp_lane_count))
-               return false;
-       return true;
+static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
+{
+       /* set the initial vs/emph on the source */
+       atombios_dig_transmitter_setup(dp_info->encoder,
+                                      ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
+                                      0, dp_info->train_set[0]); /* sets all lanes at once */
+
+       /* set the vs/emph on the sink */
+       radeon_dp_aux_native_write(dp_info->radeon_connector, DP_TRAINING_LANE0_SET,
+                                  dp_info->train_set, dp_info->dp_lane_count, 0);
 }
 
-static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state)
+static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
 {
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+       int rtp = 0;
 
-       if (dig_connector->dpcd[0] >= 0x11) {
-               radeon_dp_aux_native_write(radeon_connector, DP_SET_POWER, 1,
-                                          &power_state);
+       /* set training pattern on the source */
+       if (ASIC_IS_DCE4(dp_info->rdev)) {
+               switch (tp) {
+               case DP_TRAINING_PATTERN_1:
+                       rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
+                       break;
+               }
+               atombios_dig_encoder_setup(dp_info->encoder, rtp, 0);
+       } else {
+               switch (tp) {
+               case DP_TRAINING_PATTERN_1:
+                       rtp = 0;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       rtp = 1;
+                       break;
+               }
+               radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
+                                         dp_info->dp_clock, dp_info->enc_id, rtp);
        }
-}
 
-static void dp_set_downspread(struct radeon_connector *radeon_connector, u8 downspread)
-{
-       radeon_dp_aux_native_write(radeon_connector, DP_DOWNSPREAD_CTRL, 1,
-                                  &downspread);
+       /* enable training pattern on the sink */
+       radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, tp);
 }
 
-static void dp_set_link_bw_lanes(struct radeon_connector *radeon_connector,
-                                u8 link_configuration[DP_LINK_CONFIGURATION_SIZE])
+static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
 {
-       radeon_dp_aux_native_write(radeon_connector, DP_LINK_BW_SET, 2,
-                                  link_configuration);
-}
+       u8 tmp;
 
-static void dp_update_dpvs_emph(struct radeon_connector *radeon_connector,
-                               struct drm_encoder *encoder,
-                               u8 train_set[4])
-{
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
-       int i;
+       /* power up the sink */
+       if (dp_info->dpcd[0] >= 0x11)
+               radeon_write_dpcd_reg(dp_info->radeon_connector,
+                                     DP_SET_POWER, DP_SET_POWER_D0);
+
+       /* possibly enable downspread on the sink */
+       if (dp_info->dpcd[3] & 0x1)
+               radeon_write_dpcd_reg(dp_info->radeon_connector,
+                                     DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
+       else
+               radeon_write_dpcd_reg(dp_info->radeon_connector,
+                                     DP_DOWNSPREAD_CTRL, 0);
 
-       for (i = 0; i < dig_connector->dp_lane_count; i++)
-               atombios_dig_transmitter_setup(encoder,
-                                              ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
-                                              i, train_set[i]);
+       radeon_dp_set_panel_mode(dp_info->encoder, dp_info->connector);
 
-       radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_LANE0_SET,
-                                  dig_connector->dp_lane_count, train_set);
-}
+       /* set the lane count on the sink */
+       tmp = dp_info->dp_lane_count;
+       if (dp_info->dpcd[0] >= 0x11)
+               tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+       radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp);
 
-static void dp_set_training(struct radeon_connector *radeon_connector,
-                           u8 training)
-{
-       radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_PATTERN_SET,
-                                  1, &training);
-}
+       /* set the link rate on the sink */
+       tmp = dp_get_dp_link_rate_coded(dp_info->dp_clock);
+       radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);
 
-void dp_link_train(struct drm_encoder *encoder,
-                  struct drm_connector *connector)
-{
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
-       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       struct radeon_encoder_atom_dig *dig;
-       struct radeon_connector *radeon_connector;
-       struct radeon_connector_atom_dig *dig_connector;
-       int enc_id = 0;
-       bool clock_recovery, channel_eq;
-       u8 link_status[DP_LINK_STATUS_SIZE];
-       u8 link_configuration[DP_LINK_CONFIGURATION_SIZE];
-       u8 tries, voltage;
-       u8 train_set[4];
-       int i;
+       /* start training on the source */
+       if (ASIC_IS_DCE4(dp_info->rdev))
+               atombios_dig_encoder_setup(dp_info->encoder,
+                                          ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
+       else
+               radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_START,
+                                         dp_info->dp_clock, dp_info->enc_id, 0);
 
-       if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
-           (connector->connector_type != DRM_MODE_CONNECTOR_eDP))
-               return;
+       /* disable the training pattern on the sink */
+       radeon_write_dpcd_reg(dp_info->radeon_connector,
+                             DP_TRAINING_PATTERN_SET,
+                             DP_TRAINING_PATTERN_DISABLE);
 
-       if (!radeon_encoder->enc_priv)
-               return;
-       dig = radeon_encoder->enc_priv;
+       return 0;
+}
 
-       radeon_connector = to_radeon_connector(connector);
-       if (!radeon_connector->con_priv)
-               return;
-       dig_connector = radeon_connector->con_priv;
+static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info)
+{
+       udelay(400);
 
-       if (dig->dig_encoder)
-               enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
-       else
-               enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
-       if (dig->linkb)
-               enc_id |= ATOM_DP_CONFIG_LINK_B;
-       else
-               enc_id |= ATOM_DP_CONFIG_LINK_A;
+       /* disable the training pattern on the sink */
+       radeon_write_dpcd_reg(dp_info->radeon_connector,
+                             DP_TRAINING_PATTERN_SET,
+                             DP_TRAINING_PATTERN_DISABLE);
 
-       memset(link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
-       if (dig_connector->dp_clock == 270000)
-               link_configuration[0] = DP_LINK_BW_2_7;
+       /* disable the training pattern on the source */
+       if (ASIC_IS_DCE4(dp_info->rdev))
+               atombios_dig_encoder_setup(dp_info->encoder,
+                                          ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
        else
-               link_configuration[0] = DP_LINK_BW_1_62;
-       link_configuration[1] = dig_connector->dp_lane_count;
-       if (dig_connector->dpcd[0] >= 0x11)
-               link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+               radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
+                                         dp_info->dp_clock, dp_info->enc_id, 0);
 
-       /* power up the sink */
-       dp_set_power(radeon_connector, DP_SET_POWER_D0);
-       /* disable the training pattern on the sink */
-       dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE);
-       /* set link bw and lanes on the sink */
-       dp_set_link_bw_lanes(radeon_connector, link_configuration);
-       /* disable downspread on the sink */
-       dp_set_downspread(radeon_connector, 0);
-       if (ASIC_IS_DCE4(rdev)) {
-               /* start training on the source */
-               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
-               /* set training pattern 1 on the source */
-               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1);
-       } else {
-               /* start training on the source */
-               radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_START,
-                                         dig_connector->dp_clock, enc_id, 0);
-               /* set training pattern 1 on the source */
-               radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
-                                         dig_connector->dp_clock, enc_id, 0);
-       }
+       return 0;
+}
 
-       /* set initial vs/emph */
-       memset(train_set, 0, 4);
-       udelay(400);
-       /* set training pattern 1 on the sink */
-       dp_set_training(radeon_connector, DP_TRAINING_PATTERN_1);
+static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info)
+{
+       bool clock_recovery;
+       u8 voltage;
+       int i;
 
-       dp_update_dpvs_emph(radeon_connector, encoder, train_set);
+       radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_1);
+       memset(dp_info->train_set, 0, 4);
+       radeon_dp_update_vs_emph(dp_info);
+
+       udelay(400);
 
        /* clock recovery loop */
        clock_recovery = false;
-       tries = 0;
+       dp_info->tries = 0;
        voltage = 0xff;
-       for (;;) {
-               udelay(100);
-               if (!atom_dp_get_link_status(radeon_connector, link_status))
+       while (1) {
+               if (dp_info->rd_interval == 0)
+                       udelay(100);
+               else
+                       mdelay(dp_info->rd_interval * 4);
+
+               if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))
                        break;
 
-               if (dp_clock_recovery_ok(link_status, dig_connector->dp_lane_count)) {
+               if (dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {
                        clock_recovery = true;
                        break;
                }
 
-               for (i = 0; i < dig_connector->dp_lane_count; i++) {
-                       if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+               for (i = 0; i < dp_info->dp_lane_count; i++) {
+                       if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
                                break;
                }
-               if (i == dig_connector->dp_lane_count) {
+               if (i == dp_info->dp_lane_count) {
                        DRM_ERROR("clock recovery reached max voltage\n");
                        break;
                }
 
-               if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-                       ++tries;
-                       if (tries == 5) {
+               if ((dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+                       ++dp_info->tries;
+                       if (dp_info->tries == 5) {
                                DRM_ERROR("clock recovery tried 5 times\n");
                                break;
                        }
                } else
-                       tries = 0;
+                       dp_info->tries = 0;
 
-               voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+               voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
                /* Compute new train_set as requested by sink */
-               dp_get_adjust_train(link_status, dig_connector->dp_lane_count, train_set);
-               dp_update_dpvs_emph(radeon_connector, encoder, train_set);
+               dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);
+
+               radeon_dp_update_vs_emph(dp_info);
        }
-       if (!clock_recovery)
+       if (!clock_recovery) {
                DRM_ERROR("clock recovery failed\n");
-       else
+               return -1;
+       } else {
                DRM_DEBUG_KMS("clock recovery at voltage %d pre-emphasis %d\n",
-                         train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
-                         (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
+                         dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+                         (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
                          DP_TRAIN_PRE_EMPHASIS_SHIFT);
+               return 0;
+       }
+}
 
+static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info)
+{
+       bool channel_eq;
 
-       /* set training pattern 2 on the sink */
-       dp_set_training(radeon_connector, DP_TRAINING_PATTERN_2);
-       /* set training pattern 2 on the source */
-       if (ASIC_IS_DCE4(rdev))
-               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2);
+       if (dp_info->tp3_supported)
+               radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_3);
        else
-               radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
-                                         dig_connector->dp_clock, enc_id, 1);
+               radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_2);
 
        /* channel equalization loop */
-       tries = 0;
+       dp_info->tries = 0;
        channel_eq = false;
-       for (;;) {
-               udelay(400);
-               if (!atom_dp_get_link_status(radeon_connector, link_status))
+       while (1) {
+               if (dp_info->rd_interval == 0)
+                       udelay(400);
+               else
+                       mdelay(dp_info->rd_interval * 4);
+
+               if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))
                        break;
 
-               if (dp_channel_eq_ok(link_status, dig_connector->dp_lane_count)) {
+               if (dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
                        channel_eq = true;
                        break;
                }
 
                /* Try 5 times */
-               if (tries > 5) {
+               if (dp_info->tries > 5) {
                        DRM_ERROR("channel eq failed: 5 tries\n");
                        break;
                }
 
                /* Compute new train_set as requested by sink */
-               dp_get_adjust_train(link_status, dig_connector->dp_lane_count, train_set);
-               dp_update_dpvs_emph(radeon_connector, encoder, train_set);
+               dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);
 
-               tries++;
+               radeon_dp_update_vs_emph(dp_info);
+               dp_info->tries++;
        }
 
-       if (!channel_eq)
+       if (!channel_eq) {
                DRM_ERROR("channel eq failed\n");
-       else
+               return -1;
+       } else {
                DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n",
-                         train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
-                         (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
+                         dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+                         (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
                          >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
-
-       /* disable the training pattern on the sink */
-       dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE);
-
-       /* disable the training pattern on the source */
-       if (ASIC_IS_DCE4(rdev))
-               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
-       else
-               radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
-                                         dig_connector->dp_clock, enc_id, 0);
+               return 0;
+       }
 }
 
-int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
-                        uint8_t write_byte, uint8_t *read_byte)
+void radeon_dp_link_train(struct drm_encoder *encoder,
+                         struct drm_connector *connector)
 {
-       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
-       struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;
-       int ret = 0;
-       uint16_t address = algo_data->address;
-       uint8_t msg[5];
-       uint8_t reply[2];
-       int msg_len, dp_msg_len;
-       int reply_bytes;
-
-       /* Set up the command byte */
-       if (mode & MODE_I2C_READ)
-               msg[2] = AUX_I2C_READ << 4;
-       else
-               msg[2] = AUX_I2C_WRITE << 4;
-
-       if (!(mode & MODE_I2C_STOP))
-               msg[2] |= AUX_I2C_MOT << 4;
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_encoder_atom_dig *dig;
+       struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *dig_connector;
+       struct radeon_dp_link_train_info dp_info;
+       u8 tmp;
 
-       msg[0] = address;
-       msg[1] = address >> 8;
+       if (!radeon_encoder->enc_priv)
+               return;
+       dig = radeon_encoder->enc_priv;
 
-       reply_bytes = 1;
+       radeon_connector = to_radeon_connector(connector);
+       if (!radeon_connector->con_priv)
+               return;
+       dig_connector = radeon_connector->con_priv;
 
-       msg_len = 4;
-       dp_msg_len = 3;
-       switch (mode) {
-       case MODE_I2C_WRITE:
-               msg[4] = write_byte;
-               msg_len++;
-               dp_msg_len += 2;
-               break;
-       case MODE_I2C_READ:
-               dp_msg_len += 1;
-               break;
-       default:
-               break;
-       }
+       if ((dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) &&
+           (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))
+               return;
 
-       msg[3] = (dp_msg_len) << 4;
-       ret = radeon_process_aux_ch(auxch, msg, msg_len, reply, reply_bytes, 0);
+       dp_info.enc_id = 0;
+       if (dig->dig_encoder)
+               dp_info.enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
+       else
+               dp_info.enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
+       if (dig->linkb)
+               dp_info.enc_id |= ATOM_DP_CONFIG_LINK_B;
+       else
+               dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A;
 
-       if (ret) {
-               if (read_byte)
-                       *read_byte = reply[0];
-               return reply_bytes;
-       }
-       return -EREMOTEIO;
+       dp_info.rd_interval = radeon_read_dpcd_reg(radeon_connector, DP_TRAINING_AUX_RD_INTERVAL);
+       tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT);
+       if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED))
+               dp_info.tp3_supported = true;
+       else
+               dp_info.tp3_supported = false;
+
+       memcpy(dp_info.dpcd, dig_connector->dpcd, 8);
+       dp_info.rdev = rdev;
+       dp_info.encoder = encoder;
+       dp_info.connector = connector;
+       dp_info.radeon_connector = radeon_connector;
+       dp_info.dp_lane_count = dig_connector->dp_lane_count;
+       dp_info.dp_clock = dig_connector->dp_clock;
+
+       if (radeon_dp_link_train_init(&dp_info))
+               goto done;
+       if (radeon_dp_link_train_cr(&dp_info))
+               goto done;
+       if (radeon_dp_link_train_ce(&dp_info))
+               goto done;
+done:
+       if (radeon_dp_link_train_finish(&dp_info))
+               return;
 }
-
index 9073e3bfb08c7cde39ee411700e0ba838611fc2c..7c37638095f7d1fa01624116d464e1d2a22ce8d9 100644 (file)
@@ -1578,7 +1578,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        u32 sq_stack_resource_mgmt_2;
        u32 sq_stack_resource_mgmt_3;
        u32 vgt_cache_invalidation;
-       u32 hdp_host_path_cntl;
+       u32 hdp_host_path_cntl, tmp;
        int i, j, num_shader_engines, ps_thread_count;
 
        switch (rdev->family) {
@@ -1936,8 +1936,12 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
                rdev->config.evergreen.tile_config |= (3 << 0);
                break;
        }
-       rdev->config.evergreen.tile_config |=
-               ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+       /* num banks is 8 on all fusion asics */
+       if (rdev->flags & RADEON_IS_IGP)
+               rdev->config.evergreen.tile_config |= 8 << 4;
+       else
+               rdev->config.evergreen.tile_config |=
+                       ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
        rdev->config.evergreen.tile_config |=
                ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8;
        rdev->config.evergreen.tile_config |=
@@ -2141,6 +2145,10 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        for (i = SQ_ALU_CONST_BUFFER_SIZE_HS_0; i < 0x29000; i += 4)
                WREG32(i, 0);
 
+       tmp = RREG32(HDP_MISC_CNTL);
+       tmp |= HDP_FLUSH_INVALIDATE_CACHE;
+       WREG32(HDP_MISC_CNTL, tmp);
+
        hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
        WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
 
index fc40e0cc34516bb96af19f1a7615b6889a7425e3..f37e91ee8a1114aed16bab49143fd5d1fe206914 100644 (file)
@@ -64,6 +64,8 @@
 #define GB_BACKEND_MAP                                 0x98FC
 #define DMIF_ADDR_CONFIG                               0xBD4
 #define HDP_ADDR_CONFIG                                0x2F48
+#define HDP_MISC_CNTL                                          0x2F4C
+#define                HDP_FLUSH_INVALIDATE_CACHE              (1 << 0)
 
 #define        CC_SYS_RB_BACKEND_DISABLE                       0x3F88
 #define        GC_USER_RB_BACKEND_DISABLE                      0x9B7C
index 3d8a7634bbe99ade0344aeb2061bc5f3ac183757..b205ba1cdd8f9b562a2033c9fec000a7b0b83e7e 100644 (file)
@@ -417,7 +417,7 @@ static u32 cayman_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
                num_shader_engines = 1;
        if (num_shader_engines > rdev->config.cayman.max_shader_engines)
                num_shader_engines = rdev->config.cayman.max_shader_engines;
-       if (num_backends_per_asic > num_shader_engines)
+       if (num_backends_per_asic < num_shader_engines)
                num_backends_per_asic = num_shader_engines;
        if (num_backends_per_asic > (rdev->config.cayman.max_backends_per_se * num_shader_engines))
                num_backends_per_asic = rdev->config.cayman.max_backends_per_se * num_shader_engines;
@@ -829,7 +829,7 @@ static void cayman_gpu_init(struct radeon_device *rdev)
        rdev->config.cayman.tile_config |=
                ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
        rdev->config.cayman.tile_config |=
-               (gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT;
+               ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
        rdev->config.cayman.tile_config |=
                ((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12;
 
@@ -931,6 +931,10 @@ static void cayman_gpu_init(struct radeon_device *rdev)
        WREG32(CB_PERF_CTR3_SEL_0, 0);
        WREG32(CB_PERF_CTR3_SEL_1, 0);
 
+       tmp = RREG32(HDP_MISC_CNTL);
+       tmp |= HDP_FLUSH_INVALIDATE_CACHE;
+       WREG32(HDP_MISC_CNTL, tmp);
+
        hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
        WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
 
index 0f9a08b53fbd4b9b4e4e90e8c63aad02a554f229..9736746da2d6d79b3a9b4c3e6e2e286fc524c901 100644 (file)
 #define        HDP_NONSURFACE_INFO                             0x2C08
 #define        HDP_NONSURFACE_SIZE                             0x2C0C
 #define HDP_ADDR_CONFIG                                0x2F48
+#define HDP_MISC_CNTL                                  0x2F4C
+#define        HDP_FLUSH_INVALIDATE_CACHE                      (1 << 0)
 
 #define        CC_SYS_RB_BACKEND_DISABLE                       0x3F88
 #define        GC_USER_SYS_RB_BACKEND_DISABLE                  0x3F8C
 #define                MULTI_GPU_TILE_SIZE_MASK                0x03000000
 #define                MULTI_GPU_TILE_SIZE_SHIFT               24
 #define                ROW_SIZE(x)                             ((x) << 28)
-#define                ROW_SIZE_MASK                           0x30000007
+#define                ROW_SIZE_MASK                           0x30000000
 #define                ROW_SIZE_SHIFT                          28
 #define                NUM_LOWER_PIPES(x)                      ((x) << 30)
 #define                NUM_LOWER_PIPES_MASK                    0x40000000
index ca576191d0588bb23356b2c40d25afa668736cb8..d948265db87e7140bae6bc1c0fc15005ba2940bd 100644 (file)
@@ -782,6 +782,7 @@ static struct radeon_asic evergreen_asic = {
        .hpd_fini = &evergreen_hpd_fini,
        .hpd_sense = &evergreen_hpd_sense,
        .hpd_set_polarity = &evergreen_hpd_set_polarity,
+       .ioctl_wait_idle = r600_ioctl_wait_idle,
        .gui_idle = &r600_gui_idle,
        .pm_misc = &evergreen_pm_misc,
        .pm_prepare = &evergreen_pm_prepare,
@@ -828,6 +829,7 @@ static struct radeon_asic sumo_asic = {
        .hpd_fini = &evergreen_hpd_fini,
        .hpd_sense = &evergreen_hpd_sense,
        .hpd_set_polarity = &evergreen_hpd_set_polarity,
+       .ioctl_wait_idle = r600_ioctl_wait_idle,
        .gui_idle = &r600_gui_idle,
        .pm_misc = &evergreen_pm_misc,
        .pm_prepare = &evergreen_pm_prepare,
@@ -874,6 +876,7 @@ static struct radeon_asic btc_asic = {
        .hpd_fini = &evergreen_hpd_fini,
        .hpd_sense = &evergreen_hpd_sense,
        .hpd_set_polarity = &evergreen_hpd_set_polarity,
+       .ioctl_wait_idle = r600_ioctl_wait_idle,
        .gui_idle = &r600_gui_idle,
        .pm_misc = &evergreen_pm_misc,
        .pm_prepare = &evergreen_pm_prepare,
@@ -920,6 +923,7 @@ static struct radeon_asic cayman_asic = {
        .hpd_fini = &evergreen_hpd_fini,
        .hpd_sense = &evergreen_hpd_sense,
        .hpd_set_polarity = &evergreen_hpd_set_polarity,
+       .ioctl_wait_idle = r600_ioctl_wait_idle,
        .gui_idle = &r600_gui_idle,
        .pm_misc = &evergreen_pm_misc,
        .pm_prepare = &evergreen_pm_prepare,
index 8caf546c8e92f189d6576939081b7afa1a7a33c2..5b991f7c6e2add24f1b4290b270cf1d44282915f 100644 (file)
@@ -505,12 +505,18 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
         * DDC_VGA           = RADEON_GPIO_VGA_DDC
         * DDC_LCD           = RADEON_GPIOPAD_MASK
         * DDC_GPIO          = RADEON_MDGPIO_MASK
-        * r1xx/r2xx
+        * r1xx
         * DDC_MONID         = RADEON_GPIO_MONID
         * DDC_CRT2          = RADEON_GPIO_CRT2_DDC
-        * r3xx
+        * r200
         * DDC_MONID         = RADEON_GPIO_MONID
         * DDC_CRT2          = RADEON_GPIO_DVI_DDC
+        * r300/r350
+        * DDC_MONID         = RADEON_GPIO_DVI_DDC
+        * DDC_CRT2          = RADEON_GPIO_DVI_DDC
+        * rv2xx/rv3xx
+        * DDC_MONID         = RADEON_GPIO_MONID
+        * DDC_CRT2          = RADEON_GPIO_MONID
         * rs3xx/rs4xx
         * DDC_MONID         = RADEON_GPIOPAD_MASK
         * DDC_CRT2          = RADEON_GPIO_MONID
@@ -537,17 +543,26 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
                    rdev->family == CHIP_RS400 ||
                    rdev->family == CHIP_RS480)
                        ddc_line = RADEON_GPIOPAD_MASK;
-               else
+               else if (rdev->family == CHIP_R300 ||
+                        rdev->family == CHIP_R350) {
+                       ddc_line = RADEON_GPIO_DVI_DDC;
+                       ddc = DDC_DVI;
+               } else
                        ddc_line = RADEON_GPIO_MONID;
                break;
        case DDC_CRT2:
-               if (rdev->family == CHIP_RS300 ||
-                   rdev->family == CHIP_RS400 ||
-                   rdev->family == CHIP_RS480)
-                       ddc_line = RADEON_GPIO_MONID;
-               else if (rdev->family >= CHIP_R300) {
+               if (rdev->family == CHIP_R200 ||
+                   rdev->family == CHIP_R300 ||
+                   rdev->family == CHIP_R350) {
                        ddc_line = RADEON_GPIO_DVI_DDC;
                        ddc = DDC_DVI;
+               } else if (rdev->family == CHIP_RS300 ||
+                          rdev->family == CHIP_RS400 ||
+                          rdev->family == CHIP_RS480)
+                       ddc_line = RADEON_GPIO_MONID;
+               else if (rdev->family >= CHIP_RV350) {
+                       ddc_line = RADEON_GPIO_MONID;
+                       ddc = DDC_MONID;
                } else
                        ddc_line = RADEON_GPIO_CRT2_DDC;
                break;
@@ -709,26 +724,42 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
        struct drm_device *dev = rdev->ddev;
        struct radeon_i2c_bus_rec i2c;
 
+       /* actual hw pads
+        * r1xx/rs2xx/rs3xx
+        * 0x60, 0x64, 0x68, 0x6c, gpiopads, mm
+        * r200
+        * 0x60, 0x64, 0x68, mm
+        * r300/r350
+        * 0x60, 0x64, mm
+        * rv2xx/rv3xx/rs4xx
+        * 0x60, 0x64, 0x68, gpiopads, mm
+        */
 
+       /* 0x60 */
        i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
        rdev->i2c_bus[0] = radeon_i2c_create(dev, &i2c, "DVI_DDC");
-
+       /* 0x64 */
        i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
        rdev->i2c_bus[1] = radeon_i2c_create(dev, &i2c, "VGA_DDC");
 
+       /* mm i2c */
        i2c.valid = true;
        i2c.hw_capable = true;
        i2c.mm_i2c = true;
        i2c.i2c_id = 0xa0;
        rdev->i2c_bus[2] = radeon_i2c_create(dev, &i2c, "MM_I2C");
 
-       if (rdev->family == CHIP_RS300 ||
-           rdev->family == CHIP_RS400 ||
-           rdev->family == CHIP_RS480) {
+       if (rdev->family == CHIP_R300 ||
+           rdev->family == CHIP_R350) {
+               /* only 2 sw i2c pads */
+       } else if (rdev->family == CHIP_RS300 ||
+                  rdev->family == CHIP_RS400 ||
+                  rdev->family == CHIP_RS480) {
                u16 offset;
                u8 id, blocks, clk, data;
                int i;
 
+               /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
 
@@ -740,6 +771,7 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
                                if (id == 136) {
                                        clk = RBIOS8(offset + 3 + (i * 5) + 3);
                                        data = RBIOS8(offset + 3 + (i * 5) + 4);
+                                       /* gpiopad */
                                        i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
                                                                    (1 << clk), (1 << data));
                                        rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
@@ -747,14 +779,15 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
                                }
                        }
                }
-
-       } else if (rdev->family >= CHIP_R300) {
+       } else if (rdev->family >= CHIP_R200) {
+               /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
        } else {
+               /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
-
+               /* 0x6c */
                i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "CRT2_DDC");
        }
@@ -2504,6 +2537,12 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
        return true;
 }
 
+static const char *thermal_controller_names[] = {
+       "NONE",
+       "lm63",
+       "adm1032",
+};
+
 void radeon_combios_get_power_modes(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
@@ -2524,6 +2563,54 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
                return;
        }
 
+       /* check for a thermal chip */
+       offset = combios_get_table_offset(dev, COMBIOS_OVERDRIVE_INFO_TABLE);
+       if (offset) {
+               u8 thermal_controller = 0, gpio = 0, i2c_addr = 0, clk_bit = 0, data_bit = 0;
+               struct radeon_i2c_bus_rec i2c_bus;
+
+               rev = RBIOS8(offset);
+
+               if (rev == 0) {
+                       thermal_controller = RBIOS8(offset + 3);
+                       gpio = RBIOS8(offset + 4) & 0x3f;
+                       i2c_addr = RBIOS8(offset + 5);
+               } else if (rev == 1) {
+                       thermal_controller = RBIOS8(offset + 4);
+                       gpio = RBIOS8(offset + 5) & 0x3f;
+                       i2c_addr = RBIOS8(offset + 6);
+               } else if (rev == 2) {
+                       thermal_controller = RBIOS8(offset + 4);
+                       gpio = RBIOS8(offset + 5) & 0x3f;
+                       i2c_addr = RBIOS8(offset + 6);
+                       clk_bit = RBIOS8(offset + 0xa);
+                       data_bit = RBIOS8(offset + 0xb);
+               }
+               if ((thermal_controller > 0) && (thermal_controller < 3)) {
+                       DRM_INFO("Possible %s thermal controller at 0x%02x\n",
+                                thermal_controller_names[thermal_controller],
+                                i2c_addr >> 1);
+                       if (gpio == DDC_LCD) {
+                               /* MM i2c */
+                               i2c_bus.valid = true;
+                               i2c_bus.hw_capable = true;
+                               i2c_bus.mm_i2c = true;
+                               i2c_bus.i2c_id = 0xa0;
+                       } else if (gpio == DDC_GPIO)
+                               i2c_bus = combios_setup_i2c_bus(rdev, gpio, 1 << clk_bit, 1 << data_bit);
+                       else
+                               i2c_bus = combios_setup_i2c_bus(rdev, gpio, 0, 0);
+                       rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
+                       if (rdev->pm.i2c_bus) {
+                               struct i2c_board_info info = { };
+                               const char *name = thermal_controller_names[thermal_controller];
+                               info.addr = i2c_addr >> 1;
+                               strlcpy(info.type, name, sizeof(info.type));
+                               i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
+                       }
+               }
+       }
+
        if (rdev->flags & RADEON_IS_MOBILITY) {
                offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
                if (offset) {
index 5f45fa12bb8b88471f5a301e44a893c97a6f96b3..ee1dccb3fec9792e721c17aae9b0eb81d832c396 100644 (file)
@@ -50,20 +50,21 @@ void radeon_connector_hotplug(struct drm_connector *connector)
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
 
-       if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
-               radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
-
-       if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
-           (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
-               if ((radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
-                   (radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_eDP)) {
-                       if (radeon_dp_needs_link_train(radeon_connector)) {
-                               if (connector->encoder)
-                                       dp_link_train(connector->encoder, connector);
-                       }
-               }
-       }
+       radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
+
+       /* powering up/down the eDP panel generates hpd events which
+        * can interfere with modesetting.
+        */
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+               return;
 
+       /* pre-r600 did not always have the hpd pins mapped accurately to connectors */
+       if (rdev->family >= CHIP_R600) {
+               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+               else
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       }
 }
 
 static void radeon_property_change_mode(struct drm_encoder *encoder)
@@ -1054,23 +1055,124 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
        int ret;
 
        if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+               struct drm_encoder *encoder;
+               struct drm_display_mode *mode;
+
                if (!radeon_dig_connector->edp_on)
                        atombios_set_edp_panel_power(connector,
                                                     ATOM_TRANSMITTER_ACTION_POWER_ON);
-       }
-       ret = radeon_ddc_get_modes(radeon_connector);
-       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+               ret = radeon_ddc_get_modes(radeon_connector);
                if (!radeon_dig_connector->edp_on)
                        atombios_set_edp_panel_power(connector,
                                                     ATOM_TRANSMITTER_ACTION_POWER_OFF);
-       }
+
+               if (ret > 0) {
+                       encoder = radeon_best_single_encoder(connector);
+                       if (encoder) {
+                               radeon_fixup_lvds_native_mode(encoder, connector);
+                               /* add scaled modes */
+                               radeon_add_common_modes(encoder, connector);
+                       }
+                       return ret;
+               }
+
+               encoder = radeon_best_single_encoder(connector);
+               if (!encoder)
+                       return 0;
+
+               /* we have no EDID modes */
+               mode = radeon_fp_native_mode(encoder);
+               if (mode) {
+                       ret = 1;
+                       drm_mode_probed_add(connector, mode);
+                       /* add the width/height from vbios tables if available */
+                       connector->display_info.width_mm = mode->width_mm;
+                       connector->display_info.height_mm = mode->height_mm;
+                       /* add scaled modes */
+                       radeon_add_common_modes(encoder, connector);
+               }
+       } else
+               ret = radeon_ddc_get_modes(radeon_connector);
 
        return ret;
 }
 
+bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector)
+{
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+       int i;
+       bool found = false;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
+
+               obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       continue;
+
+               encoder = obj_to_encoder(obj);
+               radeon_encoder = to_radeon_encoder(encoder);
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_TRAVIS:
+               case ENCODER_OBJECT_ID_NUTMEG:
+                       found = true;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return found;
+}
+
+bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
+{
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+       int i;
+       bool found = false;
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
+
+               obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       continue;
+
+               encoder = obj_to_encoder(obj);
+               radeon_encoder = to_radeon_encoder(encoder);
+               if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
+                       found = true;
+       }
+
+       return found;
+}
+
+bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
+{
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+
+       if (ASIC_IS_DCE5(rdev) &&
+           (rdev->clock.dp_extclk >= 53900) &&
+           radeon_connector_encoder_is_hbr2(connector)) {
+               return true;
+       }
+
+       return false;
+}
+
 static enum drm_connector_status
 radeon_dp_detect(struct drm_connector *connector, bool force)
 {
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
        enum drm_connector_status ret = connector_status_disconnected;
        struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
@@ -1081,6 +1183,15 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
        }
 
        if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+               struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+               if (encoder) {
+                       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+                       struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+
+                       /* check if panel is valid */
+                       if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
+                               ret = connector_status_connected;
+               }
                /* eDP is always DP */
                radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
                if (!radeon_dig_connector->edp_on)
@@ -1093,12 +1204,18 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                                                     ATOM_TRANSMITTER_ACTION_POWER_OFF);
        } else {
                radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
-               if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-                       if (radeon_dp_getdpcd(radeon_connector))
-                               ret = connector_status_connected;
+               if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
+                       ret = connector_status_connected;
+                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+                               radeon_dp_getdpcd(radeon_connector);
                } else {
-                       if (radeon_ddc_probe(radeon_connector))
-                               ret = connector_status_connected;
+                       if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
+                               if (radeon_dp_getdpcd(radeon_connector))
+                                       ret = connector_status_connected;
+                       } else {
+                               if (radeon_ddc_probe(radeon_connector))
+                                       ret = connector_status_connected;
+                       }
                }
        }
 
@@ -1114,11 +1231,38 @@ static int radeon_dp_mode_valid(struct drm_connector *connector,
 
        /* XXX check mode bandwidth */
 
-       if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
-           (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
-               return radeon_dp_mode_valid_helper(radeon_connector, mode);
-       else
+       if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+               struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+
+               if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
+                       return MODE_PANEL;
+
+               if (encoder) {
+                       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+                       struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+
+               /* AVIVO hardware supports downscaling modes larger than the panel
+                        * to the panel size, but I'm not sure this is desirable.
+                        */
+                       if ((mode->hdisplay > native_mode->hdisplay) ||
+                           (mode->vdisplay > native_mode->vdisplay))
+                               return MODE_PANEL;
+
+                       /* if scaling is disabled, block non-native modes */
+                       if (radeon_encoder->rmx_type == RMX_OFF) {
+                               if ((mode->hdisplay != native_mode->hdisplay) ||
+                                   (mode->vdisplay != native_mode->vdisplay))
+                                       return MODE_PANEL;
+                       }
+               }
                return MODE_OK;
+       } else {
+               if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+                   (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
+                       return radeon_dp_mode_valid_helper(connector, mode);
+               else
+                       return MODE_OK;
+       }
 }
 
 struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
@@ -1151,8 +1295,11 @@ radeon_add_atom_connector(struct drm_device *dev,
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *radeon_dig_connector;
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
        uint32_t subpixel_order = SubPixelNone;
        bool shared_ddc = false;
+       bool is_dp_bridge = false;
 
        if (connector_type == DRM_MODE_CONNECTOR_Unknown)
                return;
@@ -1184,6 +1331,21 @@ radeon_add_atom_connector(struct drm_device *dev,
                }
        }
 
+       /* check if it's a dp bridge */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               radeon_encoder = to_radeon_encoder(encoder);
+               if (radeon_encoder->devices & supported_device) {
+                       switch (radeon_encoder->encoder_id) {
+                       case ENCODER_OBJECT_ID_TRAVIS:
+                       case ENCODER_OBJECT_ID_NUTMEG:
+                               is_dp_bridge = true;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
        radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
        if (!radeon_connector)
                return;
@@ -1201,61 +1363,39 @@ radeon_add_atom_connector(struct drm_device *dev,
                if (!radeon_connector->router_bus)
                        DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
        }
-       switch (connector_type) {
-       case DRM_MODE_CONNECTOR_VGA:
-               drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
-               }
-               radeon_connector->dac_load_detect = true;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.load_detect_property,
-                                             1);
-               /* no HPD on analog connectors */
-               radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-               connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-               connector->interlace_allowed = true;
-               connector->doublescan_allowed = true;
-               break;
-       case DRM_MODE_CONNECTOR_DVIA:
-               drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
-               }
-               radeon_connector->dac_load_detect = true;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.load_detect_property,
-                                             1);
-               /* no HPD on analog connectors */
-               radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-               connector->interlace_allowed = true;
-               connector->doublescan_allowed = true;
-               break;
-       case DRM_MODE_CONNECTOR_DVII:
-       case DRM_MODE_CONNECTOR_DVID:
+
+       if (is_dp_bridge) {
                radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
                if (!radeon_dig_connector)
                        goto failed;
                radeon_dig_connector->igp_lane_info = igp_lane_info;
                radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+               drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
                if (i2c_bus->valid) {
+                       /* add DP i2c bus */
+                       if (connector_type == DRM_MODE_CONNECTOR_eDP)
+                               radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
+                       else
+                               radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
+                       if (!radeon_dig_connector->dp_i2c_bus)
+                               DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                               DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                }
-               subpixel_order = SubPixelHorizontalRGB;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.coherent_mode_property,
-                                             1);
-               if (ASIC_IS_AVIVO(rdev)) {
+               switch (connector_type) {
+               case DRM_MODE_CONNECTOR_VGA:
+               case DRM_MODE_CONNECTOR_DVIA:
+               default:
+                       connector->interlace_allowed = true;
+                       connector->doublescan_allowed = true;
+                       break;
+               case DRM_MODE_CONNECTOR_DVII:
+               case DRM_MODE_CONNECTOR_DVID:
+               case DRM_MODE_CONNECTOR_HDMIA:
+               case DRM_MODE_CONNECTOR_HDMIB:
+               case DRM_MODE_CONNECTOR_DisplayPort:
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.underscan_property,
                                                      UNDERSCAN_OFF);
@@ -1265,131 +1405,234 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.underscan_vborder_property,
                                                      0);
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = true;
+                       if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+                               connector->doublescan_allowed = true;
+                       else
+                               connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_LVDS:
+               case DRM_MODE_CONNECTOR_eDP:
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     dev->mode_config.scaling_mode_property,
+                                                     DRM_MODE_SCALE_FULLSCREEN);
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = false;
+                       connector->doublescan_allowed = false;
+                       break;
                }
-               if (connector_type == DRM_MODE_CONNECTOR_DVII) {
+       } else {
+               switch (connector_type) {
+               case DRM_MODE_CONNECTOR_VGA:
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
                        radeon_connector->dac_load_detect = true;
                        drm_connector_attach_property(&radeon_connector->base,
                                                      rdev->mode_info.load_detect_property,
                                                      1);
-               }
-               connector->interlace_allowed = true;
-               if (connector_type == DRM_MODE_CONNECTOR_DVII)
+                       /* no HPD on analog connectors */
+                       radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+                       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+                       connector->interlace_allowed = true;
                        connector->doublescan_allowed = true;
-               else
-                       connector->doublescan_allowed = false;
-               break;
-       case DRM_MODE_CONNECTOR_HDMIA:
-       case DRM_MODE_CONNECTOR_HDMIB:
-               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
-               if (!radeon_dig_connector)
-                       goto failed;
-               radeon_dig_connector->igp_lane_info = igp_lane_info;
-               radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
-               }
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.coherent_mode_property,
-                                             1);
-               if (ASIC_IS_AVIVO(rdev)) {
+                       break;
+               case DRM_MODE_CONNECTOR_DVIA:
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
+                       radeon_connector->dac_load_detect = true;
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_property,
-                                                     UNDERSCAN_OFF);
+                                                     rdev->mode_info.load_detect_property,
+                                                     1);
+                       /* no HPD on analog connectors */
+                       radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+                       connector->interlace_allowed = true;
+                       connector->doublescan_allowed = true;
+                       break;
+               case DRM_MODE_CONNECTOR_DVII:
+               case DRM_MODE_CONNECTOR_DVID:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
+                       subpixel_order = SubPixelHorizontalRGB;
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_hborder_property,
-                                                     0);
+                                                     rdev->mode_info.coherent_mode_property,
+                                                     1);
+                       if (ASIC_IS_AVIVO(rdev)) {
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_property,
+                                                             UNDERSCAN_OFF);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_hborder_property,
+                                                             0);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_vborder_property,
+                                                             0);
+                       }
+                       if (connector_type == DRM_MODE_CONNECTOR_DVII) {
+                               radeon_connector->dac_load_detect = true;
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.load_detect_property,
+                                                             1);
+                       }
+                       connector->interlace_allowed = true;
+                       if (connector_type == DRM_MODE_CONNECTOR_DVII)
+                               connector->doublescan_allowed = true;
+                       else
+                               connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_HDMIA:
+               case DRM_MODE_CONNECTOR_HDMIB:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_vborder_property,
-                                                     0);
-               }
-               subpixel_order = SubPixelHorizontalRGB;
-               connector->interlace_allowed = true;
-               if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
-                       connector->doublescan_allowed = true;
-               else
-                       connector->doublescan_allowed = false;
-               break;
-       case DRM_MODE_CONNECTOR_DisplayPort:
-       case DRM_MODE_CONNECTOR_eDP:
-               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
-               if (!radeon_dig_connector)
-                       goto failed;
-               radeon_dig_connector->igp_lane_info = igp_lane_info;
-               radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       /* add DP i2c bus */
-                       if (connector_type == DRM_MODE_CONNECTOR_eDP)
-                               radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
+                                                     rdev->mode_info.coherent_mode_property,
+                                                     1);
+                       if (ASIC_IS_AVIVO(rdev)) {
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_property,
+                                                             UNDERSCAN_OFF);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_hborder_property,
+                                                             0);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_vborder_property,
+                                                             0);
+                       }
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = true;
+                       if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+                               connector->doublescan_allowed = true;
                        else
+                               connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_DisplayPort:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               /* add DP i2c bus */
                                radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
-                       if (!radeon_dig_connector->dp_i2c_bus)
-                               DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
-               }
-               subpixel_order = SubPixelHorizontalRGB;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.coherent_mode_property,
-                                             1);
-               if (ASIC_IS_AVIVO(rdev)) {
+                               if (!radeon_dig_connector->dp_i2c_bus)
+                                       DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
+                       subpixel_order = SubPixelHorizontalRGB;
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_property,
-                                                     UNDERSCAN_OFF);
+                                                     rdev->mode_info.coherent_mode_property,
+                                                     1);
+                       if (ASIC_IS_AVIVO(rdev)) {
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_property,
+                                                             UNDERSCAN_OFF);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_hborder_property,
+                                                             0);
+                               drm_connector_attach_property(&radeon_connector->base,
+                                                             rdev->mode_info.underscan_vborder_property,
+                                                             0);
+                       }
+                       connector->interlace_allowed = true;
+                       /* in theory with a DP to VGA converter... */
+                       connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_eDP:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               /* add DP i2c bus */
+                               radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
+                               if (!radeon_dig_connector->dp_i2c_bus)
+                                       DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_hborder_property,
-                                                     0);
+                                                     dev->mode_config.scaling_mode_property,
+                                                     DRM_MODE_SCALE_FULLSCREEN);
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = false;
+                       connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_SVIDEO:
+               case DRM_MODE_CONNECTOR_Composite:
+               case DRM_MODE_CONNECTOR_9PinDIN:
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
+                       radeon_connector->dac_load_detect = true;
                        drm_connector_attach_property(&radeon_connector->base,
-                                                     rdev->mode_info.underscan_vborder_property,
-                                                     0);
-               }
-               connector->interlace_allowed = true;
-               /* in theory with a DP to VGA converter... */
-               connector->doublescan_allowed = false;
-               break;
-       case DRM_MODE_CONNECTOR_SVIDEO:
-       case DRM_MODE_CONNECTOR_Composite:
-       case DRM_MODE_CONNECTOR_9PinDIN:
-               drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
-               radeon_connector->dac_load_detect = true;
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.load_detect_property,
-                                             1);
-               drm_connector_attach_property(&radeon_connector->base,
-                                             rdev->mode_info.tv_std_property,
-                                             radeon_atombios_get_tv_info(rdev));
-               /* no HPD on analog connectors */
-               radeon_connector->hpd.hpd = RADEON_HPD_NONE;
-               connector->interlace_allowed = false;
-               connector->doublescan_allowed = false;
-               break;
-       case DRM_MODE_CONNECTOR_LVDS:
-               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
-               if (!radeon_dig_connector)
-                       goto failed;
-               radeon_dig_connector->igp_lane_info = igp_lane_info;
-               radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
-               if (i2c_bus->valid) {
-                       radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                       if (!radeon_connector->ddc_bus)
-                               DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                                                     rdev->mode_info.load_detect_property,
+                                                     1);
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     rdev->mode_info.tv_std_property,
+                                                     radeon_atombios_get_tv_info(rdev));
+                       /* no HPD on analog connectors */
+                       radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+                       connector->interlace_allowed = false;
+                       connector->doublescan_allowed = false;
+                       break;
+               case DRM_MODE_CONNECTOR_LVDS:
+                       radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+                       if (!radeon_dig_connector)
+                               goto failed;
+                       radeon_dig_connector->igp_lane_info = igp_lane_info;
+                       radeon_connector->con_priv = radeon_dig_connector;
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
+                       if (i2c_bus->valid) {
+                               radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+                               if (!radeon_connector->ddc_bus)
+                                       DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+                       }
+                       drm_connector_attach_property(&radeon_connector->base,
+                                                     dev->mode_config.scaling_mode_property,
+                                                     DRM_MODE_SCALE_FULLSCREEN);
+                       subpixel_order = SubPixelHorizontalRGB;
+                       connector->interlace_allowed = false;
+                       connector->doublescan_allowed = false;
+                       break;
                }
-               drm_connector_attach_property(&radeon_connector->base,
-                                             dev->mode_config.scaling_mode_property,
-                                             DRM_MODE_SCALE_FULLSCREEN);
-               subpixel_order = SubPixelHorizontalRGB;
-               connector->interlace_allowed = false;
-               connector->doublescan_allowed = false;
-               break;
        }
 
        if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
index 890217e678d37f7591e7004bb4253e0f06f2d998..5b61364e31f4b2be689c481969d62302f1f2e5c0 100644 (file)
@@ -923,6 +923,9 @@ int radeon_resume_kms(struct drm_device *dev)
        radeon_fbdev_set_suspend(rdev, 0);
        console_unlock();
 
+       /* init dig PHYs */
+       if (rdev->is_atom_bios)
+               radeon_atom_encoder_init(rdev);
        /* reset hpd state */
        radeon_hpd_init(rdev);
        /* blat the mode back in */
index bdbab5c43bdc05f3305155d35303ab1bfdf25a5e..ae247eec87c0be7181b4649ee4fc79d890c9b19a 100644 (file)
@@ -1087,8 +1087,9 @@ void radeon_compute_pll_legacy(struct radeon_pll *pll,
        *frac_fb_div_p = best_frac_feedback_div;
        *ref_div_p = best_ref_div;
        *post_div_p = best_post_div;
-       DRM_DEBUG_KMS("%d %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
-                     freq, best_freq / 1000, best_feedback_div, best_frac_feedback_div,
+       DRM_DEBUG_KMS("%lld %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+                     (long long)freq,
+                     best_freq / 1000, best_feedback_div, best_frac_feedback_div,
                      best_ref_div, best_post_div);
 
 }
@@ -1344,6 +1345,11 @@ int radeon_modeset_init(struct radeon_device *rdev)
        if (!ret) {
                return ret;
        }
+
+       /* init dig PHYs */
+       if (rdev->is_atom_bios)
+               radeon_atom_encoder_init(rdev);
+
        /* initialize hpd */
        radeon_hpd_init(rdev);
 
index 63d2de8771dc1ab20dade4b96270a51b0ad5409e..1d330606292feb8d2bec2fafc1ea3593bb82a980 100644 (file)
  *   2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
  *   2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK, clock crystal query
  *   2.9.0 - r600 tiling (s3tc,rgtc) working, SET_PREDICATION packet 3 on r600 + eg, backend query
+ *   2.10.0 - fusion 2D tiling
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       9
+#define KMS_DRIVER_MINOR       10
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
index b4274883227fee64e283f39934050cefa6d36cde..1b557554696e09b871486236b8449e7e2f131311 100644 (file)
@@ -229,6 +229,22 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
        return NULL;
 }
 
+static struct drm_connector *
+radeon_get_connector_for_encoder_init(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               radeon_connector = to_radeon_connector(connector);
+               if (radeon_encoder->devices & radeon_connector->devices)
+                       return connector;
+       }
+       return NULL;
+}
+
 struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
@@ -250,6 +266,25 @@ struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder
        return NULL;
 }
 
+bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder)
+{
+       struct drm_encoder *other_encoder = radeon_atom_get_external_encoder(encoder);
+
+       if (other_encoder) {
+               struct radeon_encoder *radeon_encoder = to_radeon_encoder(other_encoder);
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_TRAVIS:
+               case ENCODER_OBJECT_ID_NUTMEG:
+                       return true;
+               default:
+                       return false;
+               }
+       }
+
+       return false;
+}
+
 void radeon_panel_mode_fixup(struct drm_encoder *encoder,
                             struct drm_display_mode *adjusted_mode)
 {
@@ -621,6 +656,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
 
+       /* dp bridges are always DP */
+       if (radeon_encoder_is_dp_bridge(encoder))
+               return ATOM_ENCODER_MODE_DP;
+
        connector = radeon_get_connector_for_encoder(encoder);
        if (!connector) {
                switch (radeon_encoder->encoder_id) {
@@ -668,7 +707,6 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                return ATOM_ENCODER_MODE_LVDS;
                break;
        case DRM_MODE_CONNECTOR_DisplayPort:
-       case DRM_MODE_CONNECTOR_eDP:
                dig_connector = radeon_connector->con_priv;
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
@@ -682,6 +720,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                } else
                        return ATOM_ENCODER_MODE_DVI;
                break;
+       case DRM_MODE_CONNECTOR_eDP:
+               return ATOM_ENCODER_MODE_DP;
        case DRM_MODE_CONNECTOR_DVIA:
        case DRM_MODE_CONNECTOR_VGA:
                return ATOM_ENCODER_MODE_CRT;
@@ -747,7 +787,7 @@ union dig_encoder_control {
 };
 
 void
-atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
+atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -760,6 +800,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
        int dp_clock = 0;
        int dp_lane_count = 0;
        int hpd_id = RADEON_HPD_NONE;
+       int bpc = 8;
 
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -769,6 +810,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
                dp_clock = dig_connector->dp_clock;
                dp_lane_count = dig_connector->dp_lane_count;
                hpd_id = radeon_connector->hpd.hpd;
+               bpc = connector->display_info.bpc;
        }
 
        /* no dig encoder assigned */
@@ -791,7 +833,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
 
        args.v1.ucAction = action;
        args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
-       args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
+       if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
+               args.v3.ucPanelMode = panel_mode;
+       else
+               args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
 
        if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) ||
            (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST))
@@ -810,7 +855,27 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
                                args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
                }
                args.v4.acConfig.ucDigSel = dig->dig_encoder;
-               args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+               switch (bpc) {
+               case 0:
+                       args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE;
+                       break;
+               case 6:
+                       args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR;
+                       break;
+               case 8:
+               default:
+                       args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+                       break;
+               case 10:
+                       args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+                       break;
+               case 12:
+                       args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+                       break;
+               case 16:
+                       args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+                       break;
+               }
                if (hpd_id == RADEON_HPD_NONE)
                        args.v4.ucHPD_ID = 0;
                else
@@ -819,7 +884,27 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
                if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
                        args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
                args.v3.acConfig.ucDigSel = dig->dig_encoder;
-               args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+               switch (bpc) {
+               case 0:
+                       args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE;
+                       break;
+               case 6:
+                       args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR;
+                       break;
+               case 8:
+               default:
+                       args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+                       break;
+               case 10:
+                       args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+                       break;
+               case 12:
+                       args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+                       break;
+               case 16:
+                       args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+                       break;
+               }
        } else {
                if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
                        args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
@@ -859,7 +944,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct drm_connector *connector;
        union dig_transmitter_control args;
        int index = 0;
        uint8_t frev, crev;
@@ -870,6 +955,11 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        int connector_object_id = 0;
        int igp_lane_info = 0;
 
+       if (action == ATOM_TRANSMITTER_ACTION_INIT)
+               connector = radeon_get_connector_for_encoder_init(encoder);
+       else
+               connector = radeon_get_connector_for_encoder(encoder);
+
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
                struct radeon_connector_atom_dig *dig_connector =
@@ -931,10 +1021,10 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                else
                        args.v3.ucLaneNum = 4;
 
-               if (dig->linkb) {
+               if (dig->linkb)
                        args.v3.acConfig.ucLinkSel = 1;
+               if (dig->dig_encoder & 1)
                        args.v3.acConfig.ucEncoderSel = 1;
-               }
 
                /* Select the PLL for the PHY
                 * DP PHY should be clocked from external src if there is
@@ -946,11 +1036,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                }
 
                if (ASIC_IS_DCE5(rdev)) {
-                       if (is_dp && rdev->clock.dp_extclk)
-                               args.v4.acConfig.ucRefClkSource = 3; /* external src */
-                       else
+                       /* On DCE5 DCPLL usually generates the DP ref clock */
+                       if (is_dp) {
+                               if (rdev->clock.dp_extclk)
+                                       args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK;
+                               else
+                                       args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL;
+                       } else
                                args.v4.acConfig.ucRefClkSource = pll_id;
                } else {
+                       /* On DCE4, if there is an external clock, it generates the DP ref clock */
                        if (is_dp && rdev->clock.dp_extclk)
                                args.v3.acConfig.ucRefClkSource = 2; /* external src */
                        else
@@ -1047,7 +1142,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
-void
+bool
 atombios_set_edp_panel_power(struct drm_connector *connector, int action)
 {
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1058,23 +1153,37 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action)
        uint8_t frev, crev;
 
        if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
-               return;
+               goto done;
 
        if (!ASIC_IS_DCE4(rdev))
-               return;
+               goto done;
 
        if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
            (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
-               return;
+               goto done;
 
        if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
-               return;
+               goto done;
 
        memset(&args, 0, sizeof(args));
 
        args.v1.ucAction = action;
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+       /* wait for the panel to power up */
+       if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) {
+               int i;
+
+               for (i = 0; i < 300; i++) {
+                       if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+                               return true;
+                       mdelay(1);
+               }
+               return false;
+       }
+done:
+       return true;
 }
 
 union external_encoder_control {
@@ -1092,13 +1201,19 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder);
        union external_encoder_control args;
-       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+       struct drm_connector *connector;
        int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
        u8 frev, crev;
        int dp_clock = 0;
        int dp_lane_count = 0;
        int connector_object_id = 0;
        u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+       int bpc = 8;
+
+       if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
+               connector = radeon_get_connector_for_encoder_init(encoder);
+       else
+               connector = radeon_get_connector_for_encoder(encoder);
 
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1109,6 +1224,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
                dp_lane_count = dig_connector->dp_lane_count;
                connector_object_id =
                        (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+               bpc = connector->display_info.bpc;
        }
 
        memset(&args, 0, sizeof(args));
@@ -1166,7 +1282,27 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
                                args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
                                break;
                        }
-                       args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+                       switch (bpc) {
+                       case 0:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_BPC_UNDEFINE;
+                               break;
+                       case 6:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_6BIT_PER_COLOR;
+                               break;
+                       case 8:
+                       default:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+                               break;
+                       case 10:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+                               break;
+                       case 12:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+                               break;
+                       case 16:
+                               args.v3.sExtEncoder.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+                               break;
+                       }
                        break;
                default:
                        DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
@@ -1307,9 +1443,11 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                                                                     ATOM_TRANSMITTER_ACTION_POWER_ON);
                                        radeon_dig_connector->edp_on = true;
                                }
-                               dp_link_train(encoder, connector);
                                if (ASIC_IS_DCE4(rdev))
-                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON);
+                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
+                               radeon_dp_link_train(encoder, connector);
+                               if (ASIC_IS_DCE4(rdev))
+                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
                        }
                        if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
                                atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
@@ -1322,7 +1460,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                                struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
                                if (ASIC_IS_DCE4(rdev))
-                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
+                                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
                                if (connector &&
                                    (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
                                        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1601,12 +1739,9 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        /* DCE4/5 */
        if (ASIC_IS_DCE4(rdev)) {
                dig = radeon_encoder->enc_priv;
-               if (ASIC_IS_DCE41(rdev)) {
-                       if (dig->linkb)
-                               return 1;
-                       else
-                               return 0;
-               } else {
+               if (ASIC_IS_DCE41(rdev))
+                       return radeon_crtc->crtc_id;
+               else {
                        switch (radeon_encoder->encoder_id) {
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                                if (dig->linkb)
@@ -1662,6 +1797,34 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        return 1;
 }
 
+/* This only needs to be called once at startup */
+void
+radeon_atom_encoder_init(struct radeon_device *rdev)
+{
+       struct drm_device *dev = rdev->ddev;
+       struct drm_encoder *encoder;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+               struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+                       break;
+               default:
+                       break;
+               }
+
+               if (ext_encoder && ASIC_IS_DCE41(rdev))
+                       atombios_external_encoder_setup(encoder, ext_encoder,
+                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+       }
+}
+
 static void
 radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
                             struct drm_display_mode *mode,
@@ -1696,19 +1859,17 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
                        /* disable the transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
                        /* setup and enable the encoder */
-                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP);
+                       atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0);
 
-                       /* init and enable the transmitter */
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+                       /* enable the transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                } else {
                        /* disable the encoder and transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
-                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
 
                        /* setup and enable the encoder and transmitter */
-                       atombios_dig_encoder_setup(encoder, ATOM_ENABLE);
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+                       atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0);
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                }
@@ -1733,12 +1894,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        if (ext_encoder) {
-               if (ASIC_IS_DCE41(rdev)) {
-                       atombios_external_encoder_setup(encoder, ext_encoder,
-                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+               if (ASIC_IS_DCE41(rdev))
                        atombios_external_encoder_setup(encoder, ext_encoder,
                                                        EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
-               else
+               else
                        atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
        }
 
@@ -1845,8 +2004,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
 
-       if (radeon_encoder->active_device &
-           (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
+       if ((radeon_encoder->active_device &
+            (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
+           radeon_encoder_is_dp_bridge(encoder)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                if (dig)
                        dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
@@ -1855,11 +2015,17 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
        radeon_atom_output_lock(encoder, true);
        radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
-       /* select the clock/data port if it uses a router */
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+
+               /* select the clock/data port if it uses a router */
                if (radeon_connector->router.cd_valid)
                        radeon_router_select_cd_port(radeon_connector);
+
+               /* turn eDP panel on for mode set */
+               if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+                       atombios_set_edp_panel_power(connector,
+                                                    ATOM_TRANSMITTER_ACTION_POWER_ON);
        }
 
        /* this is needed for the pll/ss setup to work correctly in some cases */
@@ -1914,7 +2080,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
                else {
                        /* disable the encoder and transmitter */
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
-                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+                       atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
                }
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DDI:
@@ -2116,8 +2282,6 @@ radeon_add_atom_encoder(struct drm_device *dev,
                } else {
                        drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
                        radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
-                       if (ASIC_IS_AVIVO(rdev))
-                               radeon_encoder->underscan_type = UNDERSCAN_AUTO;
                }
                drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
                break;
@@ -2150,8 +2314,6 @@ radeon_add_atom_encoder(struct drm_device *dev,
                } else {
                        drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
                        radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
-                       if (ASIC_IS_AVIVO(rdev))
-                               radeon_encoder->underscan_type = UNDERSCAN_AUTO;
                }
                drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
                break;
index 983cbac75af0159d493c7b81dbe2da1fd90866e6..781196db792f15ff919df30323cf37c5aca4ab63 100644 (file)
@@ -888,6 +888,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
 
        i2c->rec = *rec;
        i2c->adapter.owner = THIS_MODULE;
+       i2c->adapter.class = I2C_CLASS_DDC;
        i2c->dev = dev;
        i2c_set_adapdata(&i2c->adapter, i2c);
        if (rec->mm_i2c ||
@@ -947,6 +948,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
 
        i2c->rec = *rec;
        i2c->adapter.owner = THIS_MODULE;
+       i2c->adapter.class = I2C_CLASS_DDC;
        i2c->dev = dev;
        snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
                 "Radeon aux bus %s", name);
index 9c57538231d5f2c9b42c1516797472e149583f04..977a341266b6d2d5c52fa5073c7f1a21a8dcdd37 100644 (file)
@@ -464,22 +464,27 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev);
 extern struct drm_connector *
 radeon_get_connector_for_encoder(struct drm_encoder *encoder);
 
+extern bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder);
+extern bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector);
+extern bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector);
+extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector);
+
 extern void radeon_connector_hotplug(struct drm_connector *connector);
-extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
-extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
+extern int radeon_dp_mode_valid_helper(struct drm_connector *connector,
                                       struct drm_display_mode *mode);
 extern void radeon_dp_set_link_config(struct drm_connector *connector,
                                      struct drm_display_mode *mode);
-extern void dp_link_train(struct drm_encoder *encoder,
-                         struct drm_connector *connector);
+extern void radeon_dp_link_train(struct drm_encoder *encoder,
+                                struct drm_connector *connector);
 extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
-extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action);
+extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
+extern void radeon_atom_encoder_init(struct radeon_device *rdev);
 extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
                                           int action, uint8_t lane_num,
                                           uint8_t lane_set);
 extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
-                               uint8_t write_byte, uint8_t *read_byte);
+                               u8 write_byte, u8 *read_byte);
 
 extern void radeon_i2c_init(struct radeon_device *rdev);
 extern void radeon_i2c_fini(struct radeon_device *rdev);
@@ -545,7 +550,7 @@ struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, i
 extern void atombios_dvo_setup(struct drm_encoder *encoder, int action);
 extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
 extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
-extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action);
+extern bool atombios_set_edp_panel_power(struct drm_connector *connector, int action);
 extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
 
 extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
index 498b284e5ef955d11b3ccc3b4a9aaad7bd275df6..58434e804d91c5863c460390addcf10c2530bc29 100644 (file)
@@ -215,7 +215,6 @@ static int vga_switchoff(struct vga_switcheroo_client *client)
 /* stage one happens before delay */
 static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
 {
-       int ret;
        int i;
        struct vga_switcheroo_client *active = NULL;
 
@@ -228,11 +227,6 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
        if (!active)
                return 0;
 
-       /* power up the first device */
-       ret = pci_enable_device(new_client->pdev);
-       if (ret)
-               return ret;
-
        if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
                vga_switchon(new_client);
 
index be8d4cb5861cbce7999a2c09bc7305c1ba3b558f..8a1021f2e319e1f1918fadd25550bf9e1a7c4b84 100644 (file)
@@ -61,7 +61,7 @@ struct vga_device {
        unsigned int mem_lock_cnt;      /* legacy MEM lock count */
        unsigned int io_norm_cnt;       /* normal IO count */
        unsigned int mem_norm_cnt;      /* normal MEM count */
-
+       bool bridge_has_one_vga;
        /* allow IRQ enable/disable hook */
        void *cookie;
        void (*irq_set_state)(void *cookie, bool enable);
@@ -165,6 +165,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
        unsigned int wants, legacy_wants, match;
        struct vga_device *conflict;
        unsigned int pci_bits;
+       u32 flags = 0;
+
        /* Account for "normal" resources to lock. If we decode the legacy,
         * counterpart, we need to request it as well
         */
@@ -237,16 +239,23 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
                /* looks like he doesn't have a lock, we can steal
                 * them from him
                 */
-               vga_irq_set_state(conflict, false);
 
+               flags = 0;
                pci_bits = 0;
-               if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
-                       pci_bits |= PCI_COMMAND_MEMORY;
-               if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
-                       pci_bits |= PCI_COMMAND_IO;
 
-               pci_set_vga_state(conflict->pdev, false, pci_bits,
-                                 change_bridge);
+               if (!conflict->bridge_has_one_vga) {
+                       vga_irq_set_state(conflict, false);
+                       flags |= PCI_VGA_STATE_CHANGE_DECODES;
+                       if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+                               pci_bits |= PCI_COMMAND_MEMORY;
+                       if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+                               pci_bits |= PCI_COMMAND_IO;
+               }
+
+               if (change_bridge)
+                       flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
+
+               pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
                conflict->owns &= ~lwants;
                /* If he also owned non-legacy, that is no longer the case */
                if (lwants & VGA_RSRC_LEGACY_MEM)
@@ -261,14 +270,24 @@ enable_them:
         * also have in "decodes". We can lock resources we don't decode but
         * not own them.
         */
+       flags = 0;
        pci_bits = 0;
-       if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
-               pci_bits |= PCI_COMMAND_MEMORY;
-       if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
-               pci_bits |= PCI_COMMAND_IO;
-       pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(wants & VGA_RSRC_LEGACY_MASK));
 
-       vga_irq_set_state(vgadev, true);
+       if (!vgadev->bridge_has_one_vga) {
+               flags |= PCI_VGA_STATE_CHANGE_DECODES;
+               if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+                       pci_bits |= PCI_COMMAND_MEMORY;
+               if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+                       pci_bits |= PCI_COMMAND_IO;
+       }
+       if (!!(wants & VGA_RSRC_LEGACY_MASK))
+               flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
+
+       pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
+
+       if (!vgadev->bridge_has_one_vga) {
+               vga_irq_set_state(vgadev, true);
+       }
        vgadev->owns |= (wants & vgadev->decodes);
 lock_them:
        vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
@@ -421,6 +440,62 @@ bail:
 }
 EXPORT_SYMBOL(vga_put);
 
+/* Rules for using a bridge to control a VGA descendant decoding:
+   if a bridge has only one VGA descendant then it can be used
+   to control the VGA routing for that device.
+   It should always use the bridge closest to the device to control it.
+   If a bridge has a direct VGA descendant, but also have a sub-bridge
+   VGA descendant then we cannot use that bridge to control the direct VGA descendant.
+   So for every device we register, we need to iterate all its parent bridges
+   so we can invalidate any devices using them properly.
+*/
+static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
+{
+       struct vga_device *same_bridge_vgadev;
+       struct pci_bus *new_bus, *bus;
+       struct pci_dev *new_bridge, *bridge;
+
+       vgadev->bridge_has_one_vga = true;
+
+       if (list_empty(&vga_list))
+               return;
+
+       /* okay iterate the new devices bridge hierarachy */
+       new_bus = vgadev->pdev->bus;
+       while (new_bus) {
+               new_bridge = new_bus->self;
+
+               if (new_bridge) {
+                       /* go through list of devices already registered */
+                       list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
+                               bus = same_bridge_vgadev->pdev->bus;
+                               bridge = bus->self;
+
+                               /* see if the share a bridge with this device */
+                               if (new_bridge == bridge) {
+                                       /* if their direct parent bridge is the same
+                                          as any bridge of this device then it can't be used
+                                          for that device */
+                                       same_bridge_vgadev->bridge_has_one_vga = false;
+                               }
+
+                               /* now iterate the previous devices bridge hierarchy */
+                               /* if the new devices parent bridge is in the other devices
+                                  hierarchy then we can't use it to control this device */
+                               while (bus) {
+                                       bridge = bus->self;
+                                       if (bridge) {
+                                               if (bridge == vgadev->pdev->bus->self)
+                                                       vgadev->bridge_has_one_vga = false;
+                                       }
+                                       bus = bus->parent;
+                               }
+                       }
+               }
+               new_bus = new_bus->parent;
+       }
+}
+
 /*
  * Currently, we assume that the "initial" setup of the system is
  * not sane, that is we come up with conflicting devices and let
@@ -500,6 +575,8 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
                vga_default = pci_dev_get(pdev);
 #endif
 
+       vga_arbiter_check_bridge_sharing(vgadev);
+
        /* Add to the list */
        list_add(&vgadev->list, &vga_list);
        vga_count++;
@@ -1222,6 +1299,7 @@ static int __init vga_arb_device_init(void)
 {
        int rc;
        struct pci_dev *pdev;
+       struct vga_device *vgadev;
 
        rc = misc_register(&vga_arb_device);
        if (rc < 0)
@@ -1238,6 +1316,13 @@ static int __init vga_arb_device_init(void)
                vga_arbiter_add_pci_device(pdev);
 
        pr_info("vgaarb: loaded\n");
+
+       list_for_each_entry(vgadev, &vga_list, list) {
+               if (vgadev->bridge_has_one_vga)
+                       pr_info("vgaarb: bridge control possible %s\n", pci_name(vgadev->pdev));
+               else
+                       pr_info("vgaarb: no bridge control possible %s\n", pci_name(vgadev->pdev));
+       }
        return rc;
 }
 subsys_initcall(vga_arb_device_init);
index 326652f673f7e0fc1b709320204046290e6c7ae7..646068e5100bac8c6e3e9840bd0ac53596e4728a 100644 (file)
@@ -79,6 +79,7 @@ config I2C_AMD8111
 config I2C_I801
        tristate "Intel 82801 (ICH/PCH)"
        depends on PCI
+       select CHECK_SIGNATURE if X86 && DMI
        help
          If you say yes to this option, support will be included for the Intel
          801 family of mainboard I2C interfaces.  Specifically, the following
@@ -101,6 +102,7 @@ config I2C_I801
            6 Series (PCH)
            Patsburg (PCH)
            DH89xxCC (PCH)
+           Panther Point (PCH)
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-i801.
@@ -671,15 +673,19 @@ config I2C_XILINX
          will be called xilinx_i2c.
 
 config I2C_EG20T
-       tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH"
+       tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)"
        depends on PCI
        help
          This driver is for PCH(Platform controller Hub) I2C of EG20T which
          is an IOH(Input/Output Hub) for x86 embedded processor.
          This driver can access PCH I2C bus device.
 
-         This driver also supports the ML7213, a companion chip for the
-         Atom E6xx series and compatible with the Intel EG20T PCH.
+         This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+         Output Hub), ML7213 and ML7223.
+         ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
+         for MP(Media Phone) use.
+         ML7213/ML7223 is companion chip for Intel Atom E6xx series.
+         ML7213/ML7223 is completely compatible for Intel EG20T PCH.
 
 comment "External I2C/SMBus adapter drivers"
 
index 878a12026af2e2fa1b89225563248fe597659c02..8abfa4a03ce1d7610f34417d7033581c39cb3a8f 100644 (file)
@@ -182,10 +182,12 @@ static DEFINE_MUTEX(pch_mutex);
 /* Definition for ML7213 by OKI SEMICONDUCTOR */
 #define PCI_VENDOR_ID_ROHM             0x10DB
 #define PCI_DEVICE_ID_ML7213_I2C       0x802D
+#define PCI_DEVICE_ID_ML7223_I2C       0x8010
 
 static struct pci_device_id __devinitdata pch_pcidev_id[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
+       { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
        {0,}
 };
 
index ec36208c9977a7dca0201dad5fcd21b6b922d163..ab26840d0c7087073dbbba598953ebfca699b7b9 100644 (file)
@@ -50,6 +50,7 @@
   Patsburg (PCH) IDF    0x1d71     32     hard     yes     yes     yes
   Patsburg (PCH) IDF    0x1d72     32     hard     yes     yes     yes
   DH89xxCC (PCH)        0x2330     32     hard     yes     yes     yes
+  Panther Point (PCH)   0x1e22     32     hard     yes     yes     yes
 
   Features supported by this driver:
   Software PEC                     no
 /* Older devices have their ID defined in <linux/pci_ids.h> */
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS  0x1c22
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS     0x1d22
-#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0        0x1d70
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1        0x1d71
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2        0x1d72
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
 #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS     0x2330
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS        0x3b30
 
@@ -159,6 +160,8 @@ static struct pci_driver i801_driver;
 #define FEATURE_BLOCK_BUFFER   (1 << 1)
 #define FEATURE_BLOCK_PROC     (1 << 2)
 #define FEATURE_I2C_BLOCK_READ (1 << 3)
+/* Not really a feature, but it's convenient to handle it as such */
+#define FEATURE_IDF            (1 << 15)
 
 static const char *i801_feature_names[] = {
        "SMBus PEC",
@@ -629,12 +632,13 @@ static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
        { 0, }
 };
 
 MODULE_DEVICE_TABLE(pci, i801_ids);
 
-#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
+#if defined CONFIG_X86 && defined CONFIG_DMI
 static unsigned char apanel_addr;
 
 /* Scan the system ROM for the signature "FJKEYINF" */
@@ -664,11 +668,7 @@ static void __init input_apanel_init(void)
        }
        iounmap(bios);
 }
-#else
-static void __init input_apanel_init(void) {}
-#endif
 
-#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
 struct dmi_onboard_device_info {
        const char *name;
        u8 type;
@@ -734,7 +734,30 @@ static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
                dmi_check_onboard_device(type, name, adap);
        }
 }
-#endif
+
+/* Register optional slaves */
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv)
+{
+       /* Only register slaves on main SMBus channel */
+       if (priv->features & FEATURE_IDF)
+               return;
+
+       if (apanel_addr) {
+               struct i2c_board_info info;
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               info.addr = apanel_addr;
+               strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
+               i2c_new_device(&priv->adapter, &info);
+       }
+
+       if (dmi_name_in_vendors("FUJITSU"))
+               dmi_walk(dmi_check_onboard_devices, &priv->adapter);
+}
+#else
+static void __init input_apanel_init(void) {}
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
+#endif /* CONFIG_X86 && CONFIG_DMI */
 
 static int __devinit i801_probe(struct pci_dev *dev,
                                const struct pci_device_id *id)
@@ -754,6 +777,11 @@ static int __devinit i801_probe(struct pci_dev *dev,
 
        priv->pci_dev = dev;
        switch (dev->device) {
+       case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0:
+       case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1:
+       case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2:
+               priv->features |= FEATURE_IDF;
+               /* fall through */
        default:
                priv->features |= FEATURE_I2C_BLOCK_READ;
                /* fall through */
@@ -839,21 +867,7 @@ static int __devinit i801_probe(struct pci_dev *dev,
                goto exit_release;
        }
 
-       /* Register optional slaves */
-#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
-       if (apanel_addr) {
-               struct i2c_board_info info;
-
-               memset(&info, 0, sizeof(struct i2c_board_info));
-               info.addr = apanel_addr;
-               strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
-               i2c_new_device(&priv->adapter, &info);
-       }
-#endif
-#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
-       if (dmi_name_in_vendors("FUJITSU"))
-               dmi_walk(dmi_check_onboard_devices, &priv->adapter);
-#endif
+       i801_probe_optional_slaves(priv);
 
        pci_set_drvdata(dev, priv);
        return 0;
@@ -913,7 +927,8 @@ static struct pci_driver i801_driver = {
 
 static int __init i2c_i801_init(void)
 {
-       input_apanel_init();
+       if (dmi_name_in_vendors("FUJITSU"))
+               input_apanel_init();
        return pci_register_driver(&i801_driver);
 }
 
index e10e5cf3751a211058588bd33e66320b3dc48779..0c731ca69f1506d70b05da8c2d895c6493e4b1f3 100644 (file)
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
 
 #include <plat/i2c.h>
 
 /* maximum threshold value */
 #define MAX_I2C_FIFO_THRESHOLD 15
 
-/* per-transfer delay, required for the hardware to stabilize */
-#define I2C_DELAY              150
-
 enum i2c_status {
        I2C_NOP,
        I2C_ON_GOING,
@@ -120,9 +118,6 @@ enum i2c_operation {
        I2C_READ = 0x01
 };
 
-/* controller response timeout in ms */
-#define I2C_TIMEOUT_MS 2000
-
 /**
  * struct i2c_nmk_client - client specific data
  * @slave_adr: 7-bit slave address
@@ -151,6 +146,7 @@ struct i2c_nmk_client {
  * @stop: stop condition
  * @xfer_complete: acknowledge completion for a I2C message
  * @result: controller propogated result
+ * @busy: Busy doing transfer
  */
 struct nmk_i2c_dev {
        struct platform_device          *pdev;
@@ -163,6 +159,8 @@ struct nmk_i2c_dev {
        int                             stop;
        struct completion               xfer_complete;
        int                             result;
+       struct regulator                *regulator;
+       bool                            busy;
 };
 
 /* controller's abort causes */
@@ -209,7 +207,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
        writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
 
        for (i = 0; i < LOOP_ATTEMPTS; i++) {
-               timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT_MS);
+               timeout = jiffies + dev->adap.timeout;
 
                while (!time_after(jiffies, timeout)) {
                        if ((readl(dev->virtbase + I2C_CR) &
@@ -253,11 +251,9 @@ static int init_hw(struct nmk_i2c_dev *dev)
 {
        int stat;
 
-       clk_enable(dev->clk);
-
        stat = flush_i2c_fifo(dev);
        if (stat)
-               return stat;
+               goto exit;
 
        /* disable the controller */
        i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
@@ -268,10 +264,8 @@ static int init_hw(struct nmk_i2c_dev *dev)
 
        dev->cli.operation = I2C_NO_OPERATION;
 
-       clk_disable(dev->clk);
-
-       udelay(I2C_DELAY);
-       return 0;
+exit:
+       return stat;
 }
 
 /* enable peripheral, master mode operation */
@@ -424,7 +418,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
                        dev->virtbase + I2C_IMSCR);
 
        timeout = wait_for_completion_interruptible_timeout(
-               &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+               &dev->xfer_complete, dev->adap.timeout);
 
        if (timeout < 0) {
                dev_err(&dev->pdev->dev,
@@ -434,14 +428,32 @@ static int read_i2c(struct nmk_i2c_dev *dev)
        }
 
        if (timeout == 0) {
-               /* controller has timedout, re-init the h/w */
-               dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
-               (void) init_hw(dev);
+               /* Controller timed out */
+               dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
+                               dev->cli.slave_adr);
                status = -ETIMEDOUT;
        }
        return status;
 }
 
+static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
+{
+       int count;
+
+       for (count = (no_bytes - 2);
+                       (count > 0) &&
+                       (dev->cli.count != 0);
+                       count--) {
+               /* write to the Tx FIFO */
+               writeb(*dev->cli.buffer,
+                       dev->virtbase + I2C_TFR);
+               dev->cli.buffer++;
+               dev->cli.count--;
+               dev->cli.xfer_bytes++;
+       }
+
+}
+
 /**
  * write_i2c() - Write data to I2C client.
  * @dev: private data of I2C Driver
@@ -469,8 +481,13 @@ static int write_i2c(struct nmk_i2c_dev *dev)
        init_completion(&dev->xfer_complete);
 
        /* enable interrupts by settings the masks */
-       irq_mask = (I2C_IT_TXFNE | I2C_IT_TXFOVR |
-                       I2C_IT_MAL | I2C_IT_BERR);
+       irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
+
+       /* Fill the TX FIFO with transmit data */
+       fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD);
+
+       if (dev->cli.count != 0)
+               irq_mask |= I2C_IT_TXFNE;
 
        /*
         * check if we want to transfer a single or multiple bytes, if so
@@ -488,7 +505,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
                        dev->virtbase + I2C_IMSCR);
 
        timeout = wait_for_completion_interruptible_timeout(
-               &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+               &dev->xfer_complete, dev->adap.timeout);
 
        if (timeout < 0) {
                dev_err(&dev->pdev->dev,
@@ -498,15 +515,60 @@ static int write_i2c(struct nmk_i2c_dev *dev)
        }
 
        if (timeout == 0) {
-               /* controller has timedout, re-init the h/w */
-               dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
-               (void) init_hw(dev);
+               /* Controller timed out */
+               dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
+                               dev->cli.slave_adr);
                status = -ETIMEDOUT;
        }
 
        return status;
 }
 
+/**
+ * nmk_i2c_xfer_one() - transmit a single I2C message
+ * @dev: device with a message encoded into it
+ * @flags: message flags
+ */
+static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
+{
+       int status;
+
+       if (flags & I2C_M_RD) {
+               /* read operation */
+               dev->cli.operation = I2C_READ;
+               status = read_i2c(dev);
+       } else {
+               /* write operation */
+               dev->cli.operation = I2C_WRITE;
+               status = write_i2c(dev);
+       }
+
+       if (status || (dev->result)) {
+               u32 i2c_sr;
+               u32 cause;
+
+               i2c_sr = readl(dev->virtbase + I2C_SR);
+               /*
+                * Check if the controller I2C operation status
+                * is set to ABORT(11b).
+                */
+               if (((i2c_sr >> 2) & 0x3) == 0x3) {
+                       /* get the abort cause */
+                       cause = (i2c_sr >> 4) & 0x7;
+                       dev_err(&dev->pdev->dev, "%s\n", cause
+                               >= ARRAY_SIZE(abort_causes) ?
+                               "unknown reason" :
+                               abort_causes[cause]);
+               }
+
+               (void) init_hw(dev);
+
+               status = status ? status : dev->result;
+       }
+
+       return status;
+}
+
 /**
  * nmk_i2c_xfer() - I2C transfer function used by kernel framework
  * @i2c_adap: Adapter pointer to the controller
@@ -559,53 +621,55 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
 {
        int status;
        int i;
-       u32 cause;
        struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+       int j;
+
+       dev->busy = true;
+
+       if (dev->regulator)
+               regulator_enable(dev->regulator);
+       pm_runtime_get_sync(&dev->pdev->dev);
+
+       clk_enable(dev->clk);
 
        status = init_hw(dev);
        if (status)
-               return status;
+               goto out;
 
-       clk_enable(dev->clk);
+       /* Attempt three times to send the message queue */
+       for (j = 0; j < 3; j++) {
+               /* setup the i2c controller */
+               setup_i2c_controller(dev);
 
-       /* setup the i2c controller */
-       setup_i2c_controller(dev);
+               for (i = 0; i < num_msgs; i++) {
+                       if (unlikely(msgs[i].flags & I2C_M_TEN)) {
+                               dev_err(&dev->pdev->dev, "10 bit addressing"
+                                               "not supported\n");
 
-       for (i = 0; i < num_msgs; i++) {
-               if (unlikely(msgs[i].flags & I2C_M_TEN)) {
-                       dev_err(&dev->pdev->dev, "10 bit addressing"
-                                       "not supported\n");
-                       return -EINVAL;
-               }
-               dev->cli.slave_adr      = msgs[i].addr;
-               dev->cli.buffer         = msgs[i].buf;
-               dev->cli.count          = msgs[i].len;
-               dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
-               dev->result = 0;
-
-               if (msgs[i].flags & I2C_M_RD) {
-                       /* it is a read operation */
-                       dev->cli.operation = I2C_READ;
-                       status = read_i2c(dev);
-               } else {
-                       /* write operation */
-                       dev->cli.operation = I2C_WRITE;
-                       status = write_i2c(dev);
-               }
-               if (status || (dev->result)) {
-                       /* get the abort cause */
-                       cause = (readl(dev->virtbase + I2C_SR) >> 4) & 0x7;
-                       dev_err(&dev->pdev->dev, "error during I2C"
-                                       "message xfer: %d\n", cause);
-                       dev_err(&dev->pdev->dev, "%s\n",
-                               cause >= ARRAY_SIZE(abort_causes)
-                               ? "unknown reason" : abort_causes[cause]);
-                       clk_disable(dev->clk);
-                       return status;
+                               status = -EINVAL;
+                               goto out;
+                       }
+                       dev->cli.slave_adr      = msgs[i].addr;
+                       dev->cli.buffer         = msgs[i].buf;
+                       dev->cli.count          = msgs[i].len;
+                       dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
+                       dev->result = 0;
+
+                       status = nmk_i2c_xfer_one(dev, msgs[i].flags);
+                       if (status != 0)
+                               break;
                }
-               udelay(I2C_DELAY);
+               if (status == 0)
+                       break;
        }
+
+out:
        clk_disable(dev->clk);
+       pm_runtime_put_sync(&dev->pdev->dev);
+       if (dev->regulator)
+               regulator_disable(dev->regulator);
+
+       dev->busy = false;
 
        /* return the no. messages processed */
        if (status)
@@ -666,17 +730,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
                         */
                        disable_interrupts(dev, I2C_IT_TXFNE);
                } else {
-                       for (count = (MAX_I2C_FIFO_THRESHOLD - tft - 2);
-                                       (count > 0) &&
-                                       (dev->cli.count != 0);
-                                       count--) {
-                               /* write to the Tx FIFO */
-                               writeb(*dev->cli.buffer,
-                                       dev->virtbase + I2C_TFR);
-                               dev->cli.buffer++;
-                               dev->cli.count--;
-                               dev->cli.xfer_bytes++;
-                       }
+                       fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
                        /*
                         * if done, close the transfer by disabling the
                         * corresponding TXFNE interrupt
@@ -729,16 +783,11 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
                        }
                }
 
-               i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTD);
-               i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS);
-
-               disable_interrupts(dev,
-                               (I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF
-                                       | I2C_IT_TXFOVR | I2C_IT_RXFNF
-                                       | I2C_IT_RXFF | I2C_IT_RXFE));
+               disable_all_interrupts(dev);
+               clear_all_interrupts(dev);
 
                if (dev->cli.count) {
-                       dev->result = -1;
+                       dev->result = -EIO;
                        dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
                                        "xfered\n", dev->cli.count);
                        (void) init_hw(dev);
@@ -749,7 +798,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 
        /* Master Arbitration lost interrupt */
        case I2C_IT_MAL:
-               dev->result = -1;
+               dev->result = -EIO;
                (void) init_hw(dev);
 
                i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
@@ -763,7 +812,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
         * during the transaction.
         */
        case I2C_IT_BERR:
-               dev->result = -1;
+               dev->result = -EIO;
                /* get the status */
                if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
                        (void) init_hw(dev);
@@ -779,7 +828,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
         * the Tx FIFO is full.
         */
        case I2C_IT_TXFOVR:
-               dev->result = -1;
+               dev->result = -EIO;
                (void) init_hw(dev);
 
                dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
@@ -805,6 +854,38 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
+
+#ifdef CONFIG_PM
+static int nmk_i2c_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev);
+
+       if (nmk_i2c->busy)
+               return -EBUSY;
+
+       return 0;
+}
+
+static int nmk_i2c_resume(struct device *dev)
+{
+       return 0;
+}
+#else
+#define nmk_i2c_suspend        NULL
+#define nmk_i2c_resume NULL
+#endif
+
+/*
+ * We use noirq so that we suspend late and resume before the wakeup interrupt
+ * to ensure that we do the !pm_runtime_suspended() check in resume before
+ * there has been a regular pm runtime resume (via pm_runtime_get_sync()).
+ */
+static const struct dev_pm_ops nmk_i2c_pm = {
+       .suspend_noirq  = nmk_i2c_suspend,
+       .resume_noirq   = nmk_i2c_resume,
+};
+
 static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -830,7 +911,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err_no_mem;
        }
-
+       dev->busy = false;
        dev->pdev = pdev;
        platform_set_drvdata(pdev, dev);
 
@@ -860,6 +941,15 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
+       dev->regulator = regulator_get(&pdev->dev, "v-i2c");
+       if (IS_ERR(dev->regulator)) {
+               dev_warn(&pdev->dev, "could not get i2c regulator\n");
+               dev->regulator = NULL;
+       }
+
+       pm_suspend_ignore_children(&pdev->dev, true);
+       pm_runtime_enable(&pdev->dev);
+
        dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                dev_err(&pdev->dev, "could not get i2c clock\n");
@@ -872,6 +962,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
        adap->owner     = THIS_MODULE;
        adap->class     = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        adap->algo      = &nmk_i2c_algo;
+       adap->timeout   = pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
+               msecs_to_jiffies(20000);
        snprintf(adap->name, sizeof(adap->name),
                 "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
 
@@ -887,12 +979,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
        i2c_set_adapdata(adap, dev);
 
-       ret = init_hw(dev);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "error in initializing i2c hardware\n");
-               goto err_init_hw;
-       }
-
        dev_info(&pdev->dev, "initialize %s on virtual "
                "base %p\n", adap->name, dev->virtbase);
 
@@ -904,10 +990,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
        return 0;
 
- err_init_hw:
  err_add_adap:
        clk_put(dev->clk);
  err_no_clk:
+       if (dev->regulator)
+               regulator_put(dev->regulator);
+       pm_runtime_disable(&pdev->dev);
        free_irq(dev->irq, dev);
  err_irq:
        iounmap(dev->virtbase);
@@ -938,6 +1026,9 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
        if (res)
                release_mem_region(res->start, resource_size(res));
        clk_put(dev->clk);
+       if (dev->regulator)
+               regulator_put(dev->regulator);
+       pm_runtime_disable(&pdev->dev);
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
 
@@ -948,6 +1039,7 @@ static struct platform_driver nmk_i2c_driver = {
        .driver = {
                .owner = THIS_MODULE,
                .name = DRIVER_NAME,
+               .pm = &nmk_i2c_pm,
        },
        .probe = nmk_i2c_probe,
        .remove = __devexit_p(nmk_i2c_remove),
index fc5fbd1012c98af5a8b458a1b058ea5c2374e4e1..4b95f7a63a3b04de69618f80ea3f3a25c57273ce 100644 (file)
@@ -2,13 +2,13 @@
  * i2c-parport-light.c I2C bus over parallel port                           *
  * ------------------------------------------------------------------------ *
    Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
-   
+
    Based on older i2c-velleman.c driver
    Copyright (C) 1995-2000 Simon G. Vogl
    With some changes from:
    Frodo Looijaard <frodol@dds.nl>
    Kyösti Mälkki <kmalkki@cc.hut.fi>
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
@@ -114,7 +114,7 @@ static struct i2c_algo_bit_data parport_algo_data = {
        .getscl         = parport_getscl,
        .udelay         = 50,
        .timeout        = HZ,
-}; 
+};
 
 /* ----- Driver registration ---------------------------------------------- */
 
@@ -132,7 +132,7 @@ static struct i2c_smbus_alert_setup alert_data = {
 static struct i2c_client *ara;
 static struct lineop parport_ctrl_irq = {
        .val            = (1 << 4),
-       .port           = CTRL,
+       .port           = PORT_CTRL,
 };
 
 static int __devinit i2c_parport_probe(struct platform_device *pdev)
@@ -245,7 +245,7 @@ static int __init i2c_parport_init(void)
        if (irq != 0)
                pr_info(DRVNAME ": using irq %d\n", irq);
 
-        if (!adapter_parm[type].getscl.val)
+       if (!adapter_parm[type].getscl.val)
                parport_algo_data.getscl = NULL;
 
        /* Sets global pdev as a side effect */
index 2dbba163b10202cf51aba175f7ffbf9cfd57aea2..24565687ac9bc06548bfa8dd17bfb488bcd96291 100644 (file)
@@ -2,13 +2,13 @@
  * i2c-parport.c I2C bus over parallel port                                 *
  * ------------------------------------------------------------------------ *
    Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org>
-   
+
    Based on older i2c-philips-par.c driver
    Copyright (C) 1995-2000 Simon G. Vogl
    With some changes from:
    Frodo Looijaard <frodol@dds.nl>
    Kyösti Mälkki <kmalkki@cc.hut.fi>
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
@@ -78,13 +78,13 @@ static unsigned char port_read_control(struct parport *p)
        return parport_read_control(p);
 }
 
-static void (*port_write[])(struct parport *, unsigned char) = {
+static void (* const port_write[])(struct parport *, unsigned char) = {
        port_write_data,
        NULL,
        port_write_control,
 };
 
-static unsigned char (*port_read[])(struct parport *) = {
+static unsigned char (* const port_read[])(struct parport *) = {
        port_read_data,
        port_read_status,
        port_read_control,
@@ -147,7 +147,7 @@ static const struct i2c_algo_bit_data parport_algo_data = {
        .getscl         = parport_getscl,
        .udelay         = 10, /* ~50 kbps */
        .timeout        = HZ,
-}; 
+};
 
 /* ----- I2c and parallel port call-back functions and structures --------- */
 
@@ -164,10 +164,10 @@ void i2c_parport_irq(void *data)
                        "SMBus alert received but no ARA client!\n");
 }
 
-static void i2c_parport_attach (struct parport *port)
+static void i2c_parport_attach(struct parport *port)
 {
        struct i2c_par *adapter;
-       
+
        adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
        if (adapter == NULL) {
                printk(KERN_ERR "i2c-parport: Failed to kzalloc\n");
@@ -180,7 +180,7 @@ static void i2c_parport_attach (struct parport *port)
                NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
        if (!adapter->pdev) {
                printk(KERN_ERR "i2c-parport: Unable to register with parport\n");
-               goto ERROR0;
+               goto err_free;
        }
 
        /* Fill the rest of the structure */
@@ -200,7 +200,7 @@ static void i2c_parport_attach (struct parport *port)
 
        if (parport_claim_or_block(adapter->pdev) < 0) {
                printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");
-               goto ERROR1;
+               goto err_unregister;
        }
 
        /* Reset hardware to a sane state (SCL and SDA high) */
@@ -215,7 +215,7 @@ static void i2c_parport_attach (struct parport *port)
 
        if (i2c_bit_add_bus(&adapter->adapter) < 0) {
                printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
-               goto ERROR1;
+               goto err_unregister;
        }
 
        /* Setup SMBus alert if supported */
@@ -234,16 +234,16 @@ static void i2c_parport_attach (struct parport *port)
        mutex_lock(&adapter_list_lock);
        list_add_tail(&adapter->node, &adapter_list);
        mutex_unlock(&adapter_list_lock);
-        return;
+       return;
 
-ERROR1:
+ err_unregister:
        parport_release(adapter->pdev);
        parport_unregister_device(adapter->pdev);
-ERROR0:
+ err_free:
        kfree(adapter);
 }
 
-static void i2c_parport_detach (struct parport *port)
+static void i2c_parport_detach(struct parport *port)
 {
        struct i2c_par *adapter, *_n;
 
@@ -260,7 +260,7 @@ static void i2c_parport_detach (struct parport *port)
                        /* Un-init if needed (power off...) */
                        if (adapter_parm[type].init.val)
                                line_set(port, 0, &adapter_parm[type].init);
-                               
+
                        parport_release(adapter->pdev);
                        parport_unregister_device(adapter->pdev);
                        list_del(&adapter->node);
index a9f66816546c519f9bd1cd31f54a21683f29d6b6..3fe652302ea7d2286bad2f5d9f0d696395d8a55c 100644 (file)
@@ -2,7 +2,7 @@
  * i2c-parport.h I2C bus over parallel port                                 *
  * ------------------------------------------------------------------------ *
    Copyright (C) 2003-2010 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
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  * ------------------------------------------------------------------------ */
 
-#ifdef DATA
-#undef DATA
-#endif
-
-#define DATA   0
-#define STAT   1
-#define CTRL   2
+#define PORT_DATA      0
+#define PORT_STAT      1
+#define PORT_CTRL      2
 
 struct lineop {
        u8 val;
@@ -41,61 +37,61 @@ struct adapter_parm {
        unsigned int smbus_alert:1;
 };
 
-static struct adapter_parm adapter_parm[] = {
+static const struct adapter_parm adapter_parm[] = {
        /* type 0: Philips adapter */
        {
-               .setsda = { 0x80, DATA, 1 },
-               .setscl = { 0x08, CTRL, 0 },
-               .getsda = { 0x80, STAT, 0 },
-               .getscl = { 0x08, STAT, 0 },
+               .setsda = { 0x80, PORT_DATA, 1 },
+               .setscl = { 0x08, PORT_CTRL, 0 },
+               .getsda = { 0x80, PORT_STAT, 0 },
+               .getscl = { 0x08, PORT_STAT, 0 },
        },
        /* type 1: home brew teletext adapter */
        {
-               .setsda = { 0x02, DATA, 0 },
-               .setscl = { 0x01, DATA, 0 },
-               .getsda = { 0x80, STAT, 1 },
+               .setsda = { 0x02, PORT_DATA, 0 },
+               .setscl = { 0x01, PORT_DATA, 0 },
+               .getsda = { 0x80, PORT_STAT, 1 },
        },
        /* type 2: Velleman K8000 adapter */
        {
-               .setsda = { 0x02, CTRL, 1 },
-               .setscl = { 0x08, CTRL, 1 },
-               .getsda = { 0x10, STAT, 0 },
+               .setsda = { 0x02, PORT_CTRL, 1 },
+               .setscl = { 0x08, PORT_CTRL, 1 },
+               .getsda = { 0x10, PORT_STAT, 0 },
        },
        /* type 3: ELV adapter */
        {
-               .setsda = { 0x02, DATA, 1 },
-               .setscl = { 0x01, DATA, 1 },
-               .getsda = { 0x40, STAT, 1 },
-               .getscl = { 0x08, STAT, 1 },
+               .setsda = { 0x02, PORT_DATA, 1 },
+               .setscl = { 0x01, PORT_DATA, 1 },
+               .getsda = { 0x40, PORT_STAT, 1 },
+               .getscl = { 0x08, PORT_STAT, 1 },
        },
        /* type 4: ADM1032 evaluation board */
        {
-               .setsda = { 0x02, DATA, 1 },
-               .setscl = { 0x01, DATA, 1 },
-               .getsda = { 0x10, STAT, 1 },
-               .init   = { 0xf0, DATA, 0 },
+               .setsda = { 0x02, PORT_DATA, 1 },
+               .setscl = { 0x01, PORT_DATA, 1 },
+               .getsda = { 0x10, PORT_STAT, 1 },
+               .init   = { 0xf0, PORT_DATA, 0 },
                .smbus_alert = 1,
        },
        /* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
        {
-               .setsda = { 0x02, DATA, 1 },
-               .setscl = { 0x01, DATA, 1 },
-               .getsda = { 0x10, STAT, 1 },
+               .setsda = { 0x02, PORT_DATA, 1 },
+               .setscl = { 0x01, PORT_DATA, 1 },
+               .getsda = { 0x10, PORT_STAT, 1 },
        },
        /* type 6: Barco LPT->DVI (K5800236) adapter */
        {
-               .setsda = { 0x02, DATA, 1 },
-               .setscl = { 0x01, DATA, 1 },
-               .getsda = { 0x20, STAT, 0 },
-               .getscl = { 0x40, STAT, 0 },
-               .init   = { 0xfc, DATA, 0 },
+               .setsda = { 0x02, PORT_DATA, 1 },
+               .setscl = { 0x01, PORT_DATA, 1 },
+               .getsda = { 0x20, PORT_STAT, 0 },
+               .getscl = { 0x40, PORT_STAT, 0 },
+               .init   = { 0xfc, PORT_DATA, 0 },
        },
        /* type 7: One For All JP1 parallel port adapter */
        {
-               .setsda = { 0x01, DATA, 0 },
-               .setscl = { 0x02, DATA, 0 },
-               .getsda = { 0x80, STAT, 1 },
-               .init   = { 0x04, DATA, 1 },
+               .setsda = { 0x01, PORT_DATA, 0 },
+               .setscl = { 0x02, PORT_DATA, 0 },
+               .getsda = { 0x80, PORT_STAT, 1 },
+               .init   = { 0x04, PORT_DATA, 1 },
        },
 };
 
index 81ccd7875627e0c1e28b2086b039685168fb39b8..f633a53b6dbe0bb3c43daecc345dfac5d4982e7e 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/i2c/i2c-sh_mobile.h>
 
 /* Transmit operation:                                                      */
 /*                                                                          */
@@ -117,7 +118,7 @@ struct sh_mobile_i2c_data {
        struct device *dev;
        void __iomem *reg;
        struct i2c_adapter adap;
-
+       unsigned long bus_speed;
        struct clk *clk;
        u_int8_t icic;
        u_int8_t iccl;
@@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd)
         * We also round off the result.
         */
        num = i2c_clk * 5;
-       denom = NORMAL_SPEED * 9;
+       denom = pd->bus_speed * 9;
        tmp = num * 10 / denom;
        if (tmp % 10 >= 5)
                pd->iccl = (u_int8_t)((num/denom) + 1);
@@ -574,10 +575,10 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
 
 static int sh_mobile_i2c_probe(struct platform_device *dev)
 {
+       struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data;
        struct sh_mobile_i2c_data *pd;
        struct i2c_adapter *adap;
        struct resource *res;
-       char clk_name[8];
        int size;
        int ret;
 
@@ -587,10 +588,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                return -ENOMEM;
        }
 
-       snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id);
-       pd->clk = clk_get(&dev->dev, clk_name);
+       pd->clk = clk_get(&dev->dev, NULL);
        if (IS_ERR(pd->clk)) {
-               dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name);
+               dev_err(&dev->dev, "cannot get clock\n");
                ret = PTR_ERR(pd->clk);
                goto err;
        }
@@ -620,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                goto err_irq;
        }
 
+       /* Use platformd data bus speed or NORMAL_SPEED */
+       pd->bus_speed = NORMAL_SPEED;
+       if (pdata && pdata->bus_speed)
+               pd->bus_speed = pdata->bus_speed;
+
        /* The IIC blocks on SH-Mobile ARM processors
         * come with two new bits in ICIC.
         */
@@ -660,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
                goto err_all;
        }
 
+       dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n",
+                adap->nr, pd->bus_speed);
        return 0;
 
  err_all:
index b4ab39b741eb768bd1a0d733b9329546fd0fe428..4d9319665e328176993886494516e208181c38aa 100644 (file)
 #define BYTES_PER_FIFO_WORD 4
 
 #define I2C_CNFG                               0x000
+#define I2C_CNFG_DEBOUNCE_CNT_SHIFT            12
 #define I2C_CNFG_PACKET_MODE_EN                        (1<<10)
 #define I2C_CNFG_NEW_MASTER_FSM                        (1<<11)
+#define I2C_STATUS                             0x01C
 #define I2C_SL_CNFG                            0x020
 #define I2C_SL_CNFG_NEWSL                      (1<<2)
 #define I2C_SL_ADDR1                           0x02c
@@ -77,6 +79,7 @@
 #define I2C_ERR_NONE                           0x00
 #define I2C_ERR_NO_ACK                         0x01
 #define I2C_ERR_ARBITRATION_LOST               0x02
+#define I2C_ERR_UNKNOWN_INTERRUPT              0x04
 
 #define PACKET_HEADER0_HEADER_SIZE_SHIFT       28
 #define PACKET_HEADER0_PACKET_ID_SHIFT         16
@@ -121,6 +124,7 @@ struct tegra_i2c_dev {
        void __iomem *base;
        int cont_id;
        int irq;
+       bool irq_disabled;
        int is_dvc;
        struct completion msg_complete;
        int msg_err;
@@ -325,11 +329,17 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
        if (i2c_dev->is_dvc)
                tegra_dvc_init(i2c_dev);
 
-       val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN;
+       val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
+               (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
        i2c_writel(i2c_dev, val, I2C_CNFG);
        i2c_writel(i2c_dev, 0, I2C_INT_MASK);
        clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8);
 
+       if (!i2c_dev->is_dvc) {
+               u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
+               i2c_writel(i2c_dev, sl_cfg | I2C_SL_CNFG_NEWSL, I2C_SL_CNFG);
+       }
+
        val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
                0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
        i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
@@ -338,6 +348,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
                err = -ETIMEDOUT;
 
        clk_disable(i2c_dev->clk);
+
+       if (i2c_dev->irq_disabled) {
+               i2c_dev->irq_disabled = 0;
+               enable_irq(i2c_dev->irq);
+       }
+
        return err;
 }
 
@@ -350,8 +366,19 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
        status = i2c_readl(i2c_dev, I2C_INT_STATUS);
 
        if (status == 0) {
-               dev_warn(i2c_dev->dev, "interrupt with no status\n");
-               return IRQ_NONE;
+               dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
+                        i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
+                        i2c_readl(i2c_dev, I2C_STATUS),
+                        i2c_readl(i2c_dev, I2C_CNFG));
+               i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
+
+               if (!i2c_dev->irq_disabled) {
+                       disable_irq_nosync(i2c_dev->irq);
+                       i2c_dev->irq_disabled = 1;
+               }
+
+               complete(&i2c_dev->msg_complete);
+               goto err;
        }
 
        if (unlikely(status & status_err)) {
@@ -391,6 +418,8 @@ err:
                I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
                I2C_INT_RX_FIFO_DATA_REQ);
        i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+       if (i2c_dev->is_dvc)
+               dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
        return IRQ_HANDLED;
 }
 
@@ -424,12 +453,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
        packet_header = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
        packet_header |= I2C_HEADER_IE_ENABLE;
+       if (!stop)
+               packet_header |= I2C_HEADER_REPEAT_START;
        if (msg->flags & I2C_M_TEN)
                packet_header |= I2C_HEADER_10BIT_ADDR;
        if (msg->flags & I2C_M_IGNORE_NAK)
                packet_header |= I2C_HEADER_CONT_ON_NAK;
-       if (msg->flags & I2C_M_NOSTART)
-               packet_header |= I2C_HEADER_REPEAT_START;
        if (msg->flags & I2C_M_RD)
                packet_header |= I2C_HEADER_READ;
        i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
index 404843e8611b158d3feb1efc5a4c281d3fde660b..d2f3db3cf3ed523db978fa7e4f4d1adea9ef7c27 100644 (file)
@@ -272,7 +272,7 @@ static void ide_release(struct pcmcia_device *link)
 } /* ide_release */
 
 
-static struct pcmcia_device_id ide_ids[] = {
+static const struct pcmcia_device_id ide_ids[] = {
        PCMCIA_DEVICE_FUNC_ID(4),
        PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),        /* Corsair */
        PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000),        /* Hitachi */
index 88d8e4cb419a1d0d6cc17828894dc4d3b67e0201..be0921ef6b52ace2a2e15a5d1437c6134799dbf0 100644 (file)
@@ -41,6 +41,7 @@ struct evdev {
 struct evdev_client {
        unsigned int head;
        unsigned int tail;
+       unsigned int packet_head; /* [future] position of the first element of next packet */
        spinlock_t buffer_lock; /* protects access to buffer, head and tail */
        struct fasync_struct *fasync;
        struct evdev *evdev;
@@ -72,12 +73,16 @@ static void evdev_pass_event(struct evdev_client *client,
                client->buffer[client->tail].type = EV_SYN;
                client->buffer[client->tail].code = SYN_DROPPED;
                client->buffer[client->tail].value = 0;
-       }
 
-       spin_unlock(&client->buffer_lock);
+               client->packet_head = client->tail;
+       }
 
-       if (event->type == EV_SYN)
+       if (event->type == EV_SYN && event->code == SYN_REPORT) {
+               client->packet_head = client->head;
                kill_fasync(&client->fasync, SIGIO, POLL_IN);
+       }
+
+       spin_unlock(&client->buffer_lock);
 }
 
 /*
@@ -159,7 +164,6 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
                return error;
 
        rcu_assign_pointer(evdev->grab, client);
-       synchronize_rcu();
 
        return 0;
 }
@@ -182,7 +186,6 @@ static void evdev_attach_client(struct evdev *evdev,
        spin_lock(&evdev->client_lock);
        list_add_tail_rcu(&client->node, &evdev->client_list);
        spin_unlock(&evdev->client_lock);
-       synchronize_rcu();
 }
 
 static void evdev_detach_client(struct evdev *evdev,
@@ -387,12 +390,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
        if (count < input_event_size())
                return -EINVAL;
 
-       if (client->head == client->tail && evdev->exist &&
+       if (client->packet_head == client->tail && evdev->exist &&
            (file->f_flags & O_NONBLOCK))
                return -EAGAIN;
 
        retval = wait_event_interruptible(evdev->wait,
-               client->head != client->tail || !evdev->exist);
+               client->packet_head != client->tail || !evdev->exist);
        if (retval)
                return retval;
 
@@ -421,7 +424,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
        poll_wait(file, &evdev->wait, wait);
 
        mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
-       if (client->head != client->tail)
+       if (client->packet_head != client->tail)
                mask |= POLLIN | POLLRDNORM;
 
        return mask;
index 3037842a60d8a10e0533033b665aca490c10b030..b1aabde87523176f17ce0896e98403d4fda6f0a1 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/jiffies.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
+#include <linux/workqueue.h>
 #include <linux/input-polldev.h>
 
 MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
@@ -20,44 +21,6 @@ MODULE_DESCRIPTION("Generic implementation of a polled input device");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("0.1");
 
-static DEFINE_MUTEX(polldev_mutex);
-static int polldev_users;
-static struct workqueue_struct *polldev_wq;
-
-static int input_polldev_start_workqueue(void)
-{
-       int retval;
-
-       retval = mutex_lock_interruptible(&polldev_mutex);
-       if (retval)
-               return retval;
-
-       if (!polldev_users) {
-               polldev_wq = create_singlethread_workqueue("ipolldevd");
-               if (!polldev_wq) {
-                       pr_err("failed to create ipolldevd workqueue\n");
-                       retval = -ENOMEM;
-                       goto out;
-               }
-       }
-
-       polldev_users++;
-
- out:
-       mutex_unlock(&polldev_mutex);
-       return retval;
-}
-
-static void input_polldev_stop_workqueue(void)
-{
-       mutex_lock(&polldev_mutex);
-
-       if (!--polldev_users)
-               destroy_workqueue(polldev_wq);
-
-       mutex_unlock(&polldev_mutex);
-}
-
 static void input_polldev_queue_work(struct input_polled_dev *dev)
 {
        unsigned long delay;
@@ -66,7 +29,7 @@ static void input_polldev_queue_work(struct input_polled_dev *dev)
        if (delay >= HZ)
                delay = round_jiffies_relative(delay);
 
-       queue_delayed_work(polldev_wq, &dev->work, delay);
+       queue_delayed_work(system_freezable_wq, &dev->work, delay);
 }
 
 static void input_polled_device_work(struct work_struct *work)
@@ -81,18 +44,13 @@ static void input_polled_device_work(struct work_struct *work)
 static int input_open_polled_device(struct input_dev *input)
 {
        struct input_polled_dev *dev = input_get_drvdata(input);
-       int error;
-
-       error = input_polldev_start_workqueue();
-       if (error)
-               return error;
 
        if (dev->open)
                dev->open(dev);
 
        /* Only start polling if polling is enabled */
        if (dev->poll_interval > 0)
-               queue_delayed_work(polldev_wq, &dev->work, 0);
+               queue_delayed_work(system_freezable_wq, &dev->work, 0);
 
        return 0;
 }
@@ -102,13 +60,6 @@ static void input_close_polled_device(struct input_dev *input)
        struct input_polled_dev *dev = input_get_drvdata(input);
 
        cancel_delayed_work_sync(&dev->work);
-       /*
-        * Clean up work struct to remove references to the workqueue.
-        * It may be destroyed by the next call. This causes problems
-        * at next device open-close in case of poll_interval == 0.
-        */
-       INIT_DELAYED_WORK(&dev->work, dev->work.work.func);
-       input_polldev_stop_workqueue();
 
        if (dev->close)
                dev->close(dev);
@@ -295,4 +246,3 @@ void input_unregister_polled_device(struct input_polled_dev *dev)
        input_unregister_device(dev->input);
 }
 EXPORT_SYMBOL(input_unregister_polled_device);
-
index ebbceedc92f4fb8a9f8bc959734be4b442586d01..75e11c7b70fda5fb8d9ecc66a33d3ed460649a01 100644 (file)
@@ -451,7 +451,6 @@ int input_grab_device(struct input_handle *handle)
        }
 
        rcu_assign_pointer(dev->grab, handle);
-       synchronize_rcu();
 
  out:
        mutex_unlock(&dev->mutex);
index 5688b5c88f2491a15b173b0a6f6a6e1c7998a5e5..c24ec2d5f9266cb969bd3a73ea229c08adcc8d9b 100644 (file)
@@ -180,7 +180,6 @@ static void joydev_attach_client(struct joydev *joydev,
        spin_lock(&joydev->client_lock);
        list_add_tail_rcu(&client->node, &joydev->client_list);
        spin_unlock(&joydev->client_lock);
-       synchronize_rcu();
 }
 
 static void joydev_detach_client(struct joydev *joydev,
index b16bed038f7245634aa3a6ffbbac45b40d168878..69badb4e06aaa9bb067520bb373055e045e787ed 100644 (file)
@@ -32,6 +32,16 @@ config KEYBOARD_ADP5588
          To compile this driver as a module, choose M here: the
          module will be called adp5588-keys.
 
+config KEYBOARD_ADP5589
+       tristate "ADP5589 I2C QWERTY Keypad and IO Expander"
+       depends on I2C
+       help
+         Say Y here if you want to use a ADP5589 attached to your
+         system I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adp5589-keys.
+
 config KEYBOARD_AMIGA
        tristate "Amiga keyboard"
        depends on AMIGA
@@ -325,6 +335,18 @@ config KEYBOARD_MCS
          To compile this driver as a module, choose M here: the
          module will be called mcs_touchkey.
 
+config KEYBOARD_MPR121
+       tristate "Freescale MPR121 Touchkey"
+       depends on I2C
+       help
+         Say Y here if you have Freescale MPR121 touchkey controller
+         chip in your system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mpr121_touchkey.
+
 config KEYBOARD_IMX
        tristate "IMX keypad support"
        depends on ARCH_MXC
index 878e6c20deb0e1f231526e26846aedd1e1ce60d4..c49cf8e04cd72d7b75f044228ce8bf30c3b2d866 100644 (file)
@@ -6,6 +6,7 @@
 
 obj-$(CONFIG_KEYBOARD_ADP5520)         += adp5520-keys.o
 obj-$(CONFIG_KEYBOARD_ADP5588)         += adp5588-keys.o
+obj-$(CONFIG_KEYBOARD_ADP5589)         += adp5589-keys.o
 obj-$(CONFIG_KEYBOARD_AMIGA)           += amikbd.o
 obj-$(CONFIG_KEYBOARD_ATARI)           += atakbd.o
 obj-$(CONFIG_KEYBOARD_ATKBD)           += atkbd.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_KEYBOARD_MAPLE)          += maple_keyb.o
 obj-$(CONFIG_KEYBOARD_MATRIX)          += matrix_keypad.o
 obj-$(CONFIG_KEYBOARD_MAX7359)         += max7359_keypad.o
 obj-$(CONFIG_KEYBOARD_MCS)             += mcs_touchkey.o
+obj-$(CONFIG_KEYBOARD_MPR121)          += mpr121_touchkey.o
 obj-$(CONFIG_KEYBOARD_NEWTON)          += newtonkbd.o
 obj-$(CONFIG_KEYBOARD_NOMADIK)         += nomadik-ske-keypad.o
 obj-$(CONFIG_KEYBOARD_OMAP)            += omap-keypad.o
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
new file mode 100644 (file)
index 0000000..6315986
--- /dev/null
@@ -0,0 +1,771 @@
+/*
+ * Description:  keypad driver for ADP5589
+ *              I2C QWERTY Keypad and IO Expander
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2010-2011 Analog Devices Inc.
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/input/adp5589.h>
+
+/* GENERAL_CFG Register */
+#define OSC_EN         (1 << 7)
+#define CORE_CLK(x)    (((x) & 0x3) << 5)
+#define LCK_TRK_LOGIC  (1 << 4)
+#define LCK_TRK_GPI    (1 << 3)
+#define INT_CFG                (1 << 1)
+#define RST_CFG                (1 << 0)
+
+/* INT_EN Register */
+#define LOGIC2_IEN     (1 << 5)
+#define LOGIC1_IEN     (1 << 4)
+#define LOCK_IEN       (1 << 3)
+#define OVRFLOW_IEN    (1 << 2)
+#define GPI_IEN                (1 << 1)
+#define EVENT_IEN      (1 << 0)
+
+/* Interrupt Status Register */
+#define LOGIC2_INT     (1 << 5)
+#define LOGIC1_INT     (1 << 4)
+#define LOCK_INT       (1 << 3)
+#define OVRFLOW_INT    (1 << 2)
+#define GPI_INT                (1 << 1)
+#define EVENT_INT      (1 << 0)
+
+/* STATUS Register */
+
+#define LOGIC2_STAT    (1 << 7)
+#define LOGIC1_STAT    (1 << 6)
+#define LOCK_STAT      (1 << 5)
+#define KEC            0xF
+
+/* PIN_CONFIG_D Register */
+#define C4_EXTEND_CFG  (1 << 6)        /* RESET2 */
+#define R4_EXTEND_CFG  (1 << 5)        /* RESET1 */
+
+/* LOCK_CFG */
+#define LOCK_EN                (1 << 0)
+
+#define PTIME_MASK     0x3
+#define LTIME_MASK     0x3
+
+/* Key Event Register xy */
+#define KEY_EV_PRESSED         (1 << 7)
+#define KEY_EV_MASK            (0x7F)
+
+#define KEYP_MAX_EVENT         16
+
+#define MAXGPIO                        19
+#define ADP_BANK(offs)         ((offs) >> 3)
+#define ADP_BIT(offs)          (1u << ((offs) & 0x7))
+
+struct adp5589_kpad {
+       struct i2c_client *client;
+       struct input_dev *input;
+       unsigned short keycode[ADP5589_KEYMAPSIZE];
+       const struct adp5589_gpi_map *gpimap;
+       unsigned short gpimapsize;
+       unsigned extend_cfg;
+#ifdef CONFIG_GPIOLIB
+       unsigned char gpiomap[MAXGPIO];
+       bool export_gpio;
+       struct gpio_chip gc;
+       struct mutex gpio_lock; /* Protect cached dir, dat_out */
+       u8 dat_out[3];
+       u8 dir[3];
+#endif
+};
+
+static int adp5589_read(struct i2c_client *client, u8 reg)
+{
+       int ret = i2c_smbus_read_byte_data(client, reg);
+
+       if (ret < 0)
+               dev_err(&client->dev, "Read Error\n");
+
+       return ret;
+}
+
+static int adp5589_write(struct i2c_client *client, u8 reg, u8 val)
+{
+       return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
+{
+       struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+       return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) &
+                 bit);
+}
+
+static void adp5589_gpio_set_value(struct gpio_chip *chip,
+                                  unsigned off, int val)
+{
+       struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+       mutex_lock(&kpad->gpio_lock);
+
+       if (val)
+               kpad->dat_out[bank] |= bit;
+       else
+               kpad->dat_out[bank] &= ~bit;
+
+       adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
+                     kpad->dat_out[bank]);
+
+       mutex_unlock(&kpad->gpio_lock);
+}
+
+static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
+{
+       struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       int ret;
+
+       mutex_lock(&kpad->gpio_lock);
+
+       kpad->dir[bank] &= ~bit;
+       ret = adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
+                           kpad->dir[bank]);
+
+       mutex_unlock(&kpad->gpio_lock);
+
+       return ret;
+}
+
+static int adp5589_gpio_direction_output(struct gpio_chip *chip,
+                                        unsigned off, int val)
+{
+       struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+       unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+       unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+       int ret;
+
+       mutex_lock(&kpad->gpio_lock);
+
+       kpad->dir[bank] |= bit;
+
+       if (val)
+               kpad->dat_out[bank] |= bit;
+       else
+               kpad->dat_out[bank] &= ~bit;
+
+       ret = adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
+                           kpad->dat_out[bank]);
+       ret |= adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
+                            kpad->dir[bank]);
+
+       mutex_unlock(&kpad->gpio_lock);
+
+       return ret;
+}
+
+static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad,
+                               const struct adp5589_kpad_platform_data *pdata)
+{
+       bool pin_used[MAXGPIO];
+       int n_unused = 0;
+       int i;
+
+       memset(pin_used, false, sizeof(pin_used));
+
+       for (i = 0; i < MAXGPIO; i++)
+               if (pdata->keypad_en_mask & (1 << i))
+                       pin_used[i] = true;
+
+       for (i = 0; i < kpad->gpimapsize; i++)
+               pin_used[kpad->gpimap[i].pin - ADP5589_GPI_PIN_BASE] = true;
+
+       if (kpad->extend_cfg & R4_EXTEND_CFG)
+               pin_used[4] = true;
+
+       if (kpad->extend_cfg & C4_EXTEND_CFG)
+               pin_used[12] = true;
+
+       for (i = 0; i < MAXGPIO; i++)
+               if (!pin_used[i])
+                       kpad->gpiomap[n_unused++] = i;
+
+       return n_unused;
+}
+
+static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad)
+{
+       struct device *dev = &kpad->client->dev;
+       const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
+       const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;
+       int i, error;
+
+       if (!gpio_data)
+               return 0;
+
+       kpad->gc.ngpio = adp5589_build_gpiomap(kpad, pdata);
+       if (kpad->gc.ngpio == 0) {
+               dev_info(dev, "No unused gpios left to export\n");
+               return 0;
+       }
+
+       kpad->export_gpio = true;
+
+       kpad->gc.direction_input = adp5589_gpio_direction_input;
+       kpad->gc.direction_output = adp5589_gpio_direction_output;
+       kpad->gc.get = adp5589_gpio_get_value;
+       kpad->gc.set = adp5589_gpio_set_value;
+       kpad->gc.can_sleep = 1;
+
+       kpad->gc.base = gpio_data->gpio_start;
+       kpad->gc.label = kpad->client->name;
+       kpad->gc.owner = THIS_MODULE;
+
+       mutex_init(&kpad->gpio_lock);
+
+       error = gpiochip_add(&kpad->gc);
+       if (error) {
+               dev_err(dev, "gpiochip_add failed, err: %d\n", error);
+               return error;
+       }
+
+       for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+               kpad->dat_out[i] = adp5589_read(kpad->client,
+                                               ADP5589_GPO_DATA_OUT_A + i);
+               kpad->dir[i] = adp5589_read(kpad->client,
+                                           ADP5589_GPIO_DIRECTION_A + i);
+       }
+
+       if (gpio_data->setup) {
+               error = gpio_data->setup(kpad->client,
+                                        kpad->gc.base, kpad->gc.ngpio,
+                                        gpio_data->context);
+               if (error)
+                       dev_warn(dev, "setup failed, %d\n", error);
+       }
+
+       return 0;
+}
+
+static void __devexit adp5589_gpio_remove(struct adp5589_kpad *kpad)
+{
+       struct device *dev = &kpad->client->dev;
+       const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
+       const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;
+       int error;
+
+       if (!kpad->export_gpio)
+               return;
+
+       if (gpio_data->teardown) {
+               error = gpio_data->teardown(kpad->client,
+                                           kpad->gc.base, kpad->gc.ngpio,
+                                           gpio_data->context);
+               if (error)
+                       dev_warn(dev, "teardown failed %d\n", error);
+       }
+
+       error = gpiochip_remove(&kpad->gc);
+       if (error)
+               dev_warn(dev, "gpiochip_remove failed %d\n", error);
+}
+#else
+static inline int adp5589_gpio_add(struct adp5589_kpad *kpad)
+{
+       return 0;
+}
+
+static inline void adp5589_gpio_remove(struct adp5589_kpad *kpad)
+{
+}
+#endif
+
+static void adp5589_report_switches(struct adp5589_kpad *kpad,
+                                   int key, int key_val)
+{
+       int i;
+
+       for (i = 0; i < kpad->gpimapsize; i++) {
+               if (key_val == kpad->gpimap[i].pin) {
+                       input_report_switch(kpad->input,
+                                           kpad->gpimap[i].sw_evt,
+                                           key & KEY_EV_PRESSED);
+                       break;
+               }
+       }
+}
+
+static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt)
+{
+       int i;
+
+       for (i = 0; i < ev_cnt; i++) {
+               int key = adp5589_read(kpad->client, ADP5589_FIFO_1 + i);
+               int key_val = key & KEY_EV_MASK;
+
+               if (key_val >= ADP5589_GPI_PIN_BASE &&
+                   key_val <= ADP5589_GPI_PIN_END) {
+                       adp5589_report_switches(kpad, key, key_val);
+               } else {
+                       input_report_key(kpad->input,
+                                        kpad->keycode[key_val - 1],
+                                        key & KEY_EV_PRESSED);
+               }
+       }
+}
+
+static irqreturn_t adp5589_irq(int irq, void *handle)
+{
+       struct adp5589_kpad *kpad = handle;
+       struct i2c_client *client = kpad->client;
+       int status, ev_cnt;
+
+       status = adp5589_read(client, ADP5589_INT_STATUS);
+
+       if (status & OVRFLOW_INT)       /* Unlikely and should never happen */
+               dev_err(&client->dev, "Event Overflow Error\n");
+
+       if (status & EVENT_INT) {
+               ev_cnt = adp5589_read(client, ADP5589_STATUS) & KEC;
+               if (ev_cnt) {
+                       adp5589_report_events(kpad, ev_cnt);
+                       input_sync(kpad->input);
+               }
+       }
+
+       adp5589_write(client, ADP5589_INT_STATUS, status);      /* Status is W1C */
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key)
+{
+       int i;
+
+       for (i = 0; i < ADP5589_KEYMAPSIZE; i++)
+               if (key == kpad->keycode[i])
+                       return (i + 1) | KEY_EV_PRESSED;
+
+       dev_err(&kpad->client->dev, "RESET/UNLOCK key not in keycode map\n");
+
+       return -EINVAL;
+}
+
+static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
+{
+       struct i2c_client *client = kpad->client;
+       const struct adp5589_kpad_platform_data *pdata =
+           client->dev.platform_data;
+       int i, ret;
+       unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
+       unsigned char pull_mask = 0;
+
+       ret = adp5589_write(client, ADP5589_PIN_CONFIG_A,
+                           pdata->keypad_en_mask & 0xFF);
+       ret |= adp5589_write(client, ADP5589_PIN_CONFIG_B,
+                            (pdata->keypad_en_mask >> 8) & 0xFF);
+       ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C,
+                            (pdata->keypad_en_mask >> 16) & 0xFF);
+
+       if (pdata->en_keylock) {
+               ret |= adp5589_write(client, ADP5589_UNLOCK1,
+                                    pdata->unlock_key1);
+               ret |= adp5589_write(client, ADP5589_UNLOCK2,
+                                    pdata->unlock_key2);
+               ret |= adp5589_write(client, ADP5589_UNLOCK_TIMERS,
+                                    pdata->unlock_timer & LTIME_MASK);
+               ret |= adp5589_write(client, ADP5589_LOCK_CFG, LOCK_EN);
+       }
+
+       for (i = 0; i < KEYP_MAX_EVENT; i++)
+               ret |= adp5589_read(client, ADP5589_FIFO_1 + i);
+
+       for (i = 0; i < pdata->gpimapsize; i++) {
+               unsigned short pin = pdata->gpimap[i].pin;
+
+               if (pin <= ADP5589_GPI_PIN_ROW_END) {
+                       evt_mode1 |= (1 << (pin - ADP5589_GPI_PIN_ROW_BASE));
+               } else {
+                       evt_mode2 |=
+                           ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) & 0xFF);
+                       evt_mode3 |=
+                           ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) >> 8);
+               }
+       }
+
+       if (pdata->gpimapsize) {
+               ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_A, evt_mode1);
+               ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_B, evt_mode2);
+               ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_C, evt_mode3);
+       }
+
+       if (pdata->pull_dis_mask & pdata->pullup_en_100k &
+           pdata->pullup_en_300k & pdata->pulldown_en_300k)
+               dev_warn(&client->dev, "Conflicting pull resistor config\n");
+
+       for (i = 0; i < MAXGPIO; i++) {
+               unsigned val = 0;
+
+               if (pdata->pullup_en_300k & (1 << i))
+                       val = 0;
+               else if (pdata->pulldown_en_300k & (1 << i))
+                       val = 1;
+               else if (pdata->pullup_en_100k & (1 << i))
+                       val = 2;
+               else if (pdata->pull_dis_mask & (1 << i))
+                       val = 3;
+
+               pull_mask |= val << (2 * (i & 0x3));
+
+               if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) {
+                       ret |= adp5589_write(client,
+                                            ADP5589_RPULL_CONFIG_A + (i >> 2),
+                                            pull_mask);
+                       pull_mask = 0;
+               }
+       }
+
+       if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) {
+               ret |= adp5589_write(client, ADP5589_RESET1_EVENT_A,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset1_key_1));
+               ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset1_key_2));
+               ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset1_key_3));
+               kpad->extend_cfg |= R4_EXTEND_CFG;
+       }
+
+       if (pdata->reset2_key_1 && pdata->reset2_key_2) {
+               ret |= adp5589_write(client, ADP5589_RESET2_EVENT_A,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset2_key_1));
+               ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B,
+                                    adp5589_get_evcode(kpad,
+                                                       pdata->reset2_key_2));
+               kpad->extend_cfg |= C4_EXTEND_CFG;
+       }
+
+       if (kpad->extend_cfg) {
+               ret |= adp5589_write(client, ADP5589_RESET_CFG,
+                                    pdata->reset_cfg);
+               ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D,
+                                    kpad->extend_cfg);
+       }
+
+       for (i = 0; i <= ADP_BANK(MAXGPIO); i++)
+               ret |= adp5589_write(client, ADP5589_DEBOUNCE_DIS_A + i,
+                                    pdata->debounce_dis_mask >> (i * 8));
+
+       ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG,
+                            pdata->scan_cycle_time & PTIME_MASK);
+       ret |= adp5589_write(client, ADP5589_INT_STATUS, LOGIC2_INT |
+                            LOGIC1_INT | OVRFLOW_INT | LOCK_INT |
+                            GPI_INT | EVENT_INT);      /* Status is W1C */
+
+       ret |= adp5589_write(client, ADP5589_GENERAL_CFG,
+                            INT_CFG | OSC_EN | CORE_CLK(3));
+       ret |= adp5589_write(client, ADP5589_INT_EN,
+                            OVRFLOW_IEN | GPI_IEN | EVENT_IEN);
+
+       if (ret < 0) {
+               dev_err(&client->dev, "Write Error\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad)
+{
+       int gpi_stat1 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_A);
+       int gpi_stat2 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_B);
+       int gpi_stat3 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_C);
+       int gpi_stat_tmp, pin_loc;
+       int i;
+
+       for (i = 0; i < kpad->gpimapsize; i++) {
+               unsigned short pin = kpad->gpimap[i].pin;
+
+               if (pin <= ADP5589_GPI_PIN_ROW_END) {
+                       gpi_stat_tmp = gpi_stat1;
+                       pin_loc = pin - ADP5589_GPI_PIN_ROW_BASE;
+               } else if ((pin - ADP5589_GPI_PIN_COL_BASE) < 8) {
+                       gpi_stat_tmp = gpi_stat2;
+                       pin_loc = pin - ADP5589_GPI_PIN_COL_BASE;
+               } else {
+                       gpi_stat_tmp = gpi_stat3;
+                       pin_loc = pin - ADP5589_GPI_PIN_COL_BASE - 8;
+               }
+
+               if (gpi_stat_tmp < 0) {
+                       dev_err(&kpad->client->dev,
+                               "Can't read GPIO_DAT_STAT switch"
+                               " %d default to OFF\n", pin);
+                       gpi_stat_tmp = 0;
+               }
+
+               input_report_switch(kpad->input,
+                                   kpad->gpimap[i].sw_evt,
+                                   !(gpi_stat_tmp & (1 << pin_loc)));
+       }
+
+       input_sync(kpad->input);
+}
+
+static int __devinit adp5589_probe(struct i2c_client *client,
+                                  const struct i2c_device_id *id)
+{
+       struct adp5589_kpad *kpad;
+       const struct adp5589_kpad_platform_data *pdata;
+       struct input_dev *input;
+       unsigned int revid;
+       int ret, i;
+       int error;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+               return -EIO;
+       }
+
+       pdata = client->dev.platform_data;
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       if (!((pdata->keypad_en_mask & 0xFF) &&
+                       (pdata->keypad_en_mask >> 8)) || !pdata->keymap) {
+               dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
+               return -EINVAL;
+       }
+
+       if (pdata->keymapsize != ADP5589_KEYMAPSIZE) {
+               dev_err(&client->dev, "invalid keymapsize\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->gpimap && pdata->gpimapsize) {
+               dev_err(&client->dev, "invalid gpimap from pdata\n");
+               return -EINVAL;
+       }
+
+       if (pdata->gpimapsize > ADP5589_GPIMAPSIZE_MAX) {
+               dev_err(&client->dev, "invalid gpimapsize\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < pdata->gpimapsize; i++) {
+               unsigned short pin = pdata->gpimap[i].pin;
+
+               if (pin < ADP5589_GPI_PIN_BASE || pin > ADP5589_GPI_PIN_END) {
+                       dev_err(&client->dev, "invalid gpi pin data\n");
+                       return -EINVAL;
+               }
+
+               if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) &
+                               pdata->keypad_en_mask) {
+                       dev_err(&client->dev, "invalid gpi row/col data\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (!client->irq) {
+               dev_err(&client->dev, "no IRQ?\n");
+               return -EINVAL;
+       }
+
+       kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
+       input = input_allocate_device();
+       if (!kpad || !input) {
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       kpad->client = client;
+       kpad->input = input;
+
+       ret = adp5589_read(client, ADP5589_ID);
+       if (ret < 0) {
+               error = ret;
+               goto err_free_mem;
+       }
+
+       revid = (u8) ret & ADP5589_DEVICE_ID_MASK;
+
+       input->name = client->name;
+       input->phys = "adp5589-keys/input0";
+       input->dev.parent = &client->dev;
+
+       input_set_drvdata(input, kpad);
+
+       input->id.bustype = BUS_I2C;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = revid;
+
+       input->keycodesize = sizeof(kpad->keycode[0]);
+       input->keycodemax = pdata->keymapsize;
+       input->keycode = kpad->keycode;
+
+       memcpy(kpad->keycode, pdata->keymap,
+              pdata->keymapsize * input->keycodesize);
+
+       kpad->gpimap = pdata->gpimap;
+       kpad->gpimapsize = pdata->gpimapsize;
+
+       /* setup input device */
+       __set_bit(EV_KEY, input->evbit);
+
+       if (pdata->repeat)
+               __set_bit(EV_REP, input->evbit);
+
+       for (i = 0; i < input->keycodemax; i++)
+               __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
+       __clear_bit(KEY_RESERVED, input->keybit);
+
+       if (kpad->gpimapsize)
+               __set_bit(EV_SW, input->evbit);
+       for (i = 0; i < kpad->gpimapsize; i++)
+               __set_bit(kpad->gpimap[i].sw_evt, input->swbit);
+
+       error = input_register_device(input);
+       if (error) {
+               dev_err(&client->dev, "unable to register input device\n");
+               goto err_free_mem;
+       }
+
+       error = request_threaded_irq(client->irq, NULL, adp5589_irq,
+                                    IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                    client->dev.driver->name, kpad);
+       if (error) {
+               dev_err(&client->dev, "irq %d busy?\n", client->irq);
+               goto err_unreg_dev;
+       }
+
+       error = adp5589_setup(kpad);
+       if (error)
+               goto err_free_irq;
+
+       if (kpad->gpimapsize)
+               adp5589_report_switch_state(kpad);
+
+       error = adp5589_gpio_add(kpad);
+       if (error)
+               goto err_free_irq;
+
+       device_init_wakeup(&client->dev, 1);
+       i2c_set_clientdata(client, kpad);
+
+       dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, kpad);
+err_unreg_dev:
+       input_unregister_device(input);
+       input = NULL;
+err_free_mem:
+       input_free_device(input);
+       kfree(kpad);
+
+       return error;
+}
+
+static int __devexit adp5589_remove(struct i2c_client *client)
+{
+       struct adp5589_kpad *kpad = i2c_get_clientdata(client);
+
+       adp5589_write(client, ADP5589_GENERAL_CFG, 0);
+       free_irq(client->irq, kpad);
+       input_unregister_device(kpad->input);
+       adp5589_gpio_remove(kpad);
+       kfree(kpad);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int adp5589_suspend(struct device *dev)
+{
+       struct adp5589_kpad *kpad = dev_get_drvdata(dev);
+       struct i2c_client *client = kpad->client;
+
+       disable_irq(client->irq);
+
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+
+       return 0;
+}
+
+static int adp5589_resume(struct device *dev)
+{
+       struct adp5589_kpad *kpad = dev_get_drvdata(dev);
+       struct i2c_client *client = kpad->client;
+
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+
+       enable_irq(client->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume);
+
+static const struct i2c_device_id adp5589_id[] = {
+       {"adp5589-keys", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, adp5589_id);
+
+static struct i2c_driver adp5589_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .owner = THIS_MODULE,
+               .pm = &adp5589_dev_pm_ops,
+       },
+       .probe = adp5589_probe,
+       .remove = __devexit_p(adp5589_remove),
+       .id_table = adp5589_id,
+};
+
+static int __init adp5589_init(void)
+{
+       return i2c_add_driver(&adp5589_driver);
+}
+module_init(adp5589_init);
+
+static void __exit adp5589_exit(void)
+{
+       i2c_del_driver(&adp5589_driver);
+}
+module_exit(adp5589_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP5589 Keypad driver");
index eb3006361ee4440179b46377e272f97e6c7010b3..6e6145b9a4c10b2d84bfd3cce75b1ea12a100b43 100644 (file)
@@ -324,7 +324,12 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
        unsigned int type = button->type ?: EV_KEY;
        int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
 
-       input_event(input, type, button->code, !!state);
+       if (type == EV_ABS) {
+               if (state)
+                       input_event(input, type, button->code, button->value);
+       } else {
+               input_event(input, type, button->code, !!state);
+       }
        input_sync(input);
 }
 
@@ -363,7 +368,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
                                         struct gpio_button_data *bdata,
                                         struct gpio_keys_button *button)
 {
-       char *desc = button->desc ? button->desc : "gpio_keys";
+       const char *desc = button->desc ? button->desc : "gpio_keys";
        struct device *dev = &pdev->dev;
        unsigned long irqflags;
        int irq, error;
@@ -468,7 +473,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, ddata);
        input_set_drvdata(input, ddata);
 
-       input->name = pdev->name;
+       input->name = pdata->name ? : pdev->name;
        input->phys = "gpio-keys/input0";
        input->dev.parent = &pdev->dev;
        input->open = gpio_keys_open;
diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
new file mode 100644 (file)
index 0000000..0a9e811
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Touchkey driver for Freescale MPR121 Controllor
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Author: Zhang Jiejing <jiejing.zhang@freescale.com>
+ *
+ * Based on mcs_touchkey.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/i2c/mpr121_touchkey.h>
+
+/* Register definitions */
+#define ELE_TOUCH_STATUS_0_ADDR        0x0
+#define ELE_TOUCH_STATUS_1_ADDR        0X1
+#define MHD_RISING_ADDR                0x2b
+#define NHD_RISING_ADDR                0x2c
+#define NCL_RISING_ADDR                0x2d
+#define FDL_RISING_ADDR                0x2e
+#define MHD_FALLING_ADDR       0x2f
+#define NHD_FALLING_ADDR       0x30
+#define NCL_FALLING_ADDR       0x31
+#define FDL_FALLING_ADDR       0x32
+#define ELE0_TOUCH_THRESHOLD_ADDR      0x41
+#define ELE0_RELEASE_THRESHOLD_ADDR    0x42
+#define AFE_CONF_ADDR                  0x5c
+#define FILTER_CONF_ADDR               0x5d
+
+/*
+ * ELECTRODE_CONF_ADDR: This register configures the number of
+ * enabled capacitance sensing inputs and its run/suspend mode.
+ */
+#define ELECTRODE_CONF_ADDR            0x5e
+#define AUTO_CONFIG_CTRL_ADDR          0x7b
+#define AUTO_CONFIG_USL_ADDR           0x7d
+#define AUTO_CONFIG_LSL_ADDR           0x7e
+#define AUTO_CONFIG_TL_ADDR            0x7f
+
+/* Threshold of touch/release trigger */
+#define TOUCH_THRESHOLD                        0x0f
+#define RELEASE_THRESHOLD              0x0a
+/* Masks for touch and release triggers */
+#define TOUCH_STATUS_MASK              0xfff
+/* MPR121 has 12 keys */
+#define MPR121_MAX_KEY_COUNT           12
+
+struct mpr121_touchkey {
+       struct i2c_client       *client;
+       struct input_dev        *input_dev;
+       unsigned int            key_val;
+       unsigned int            statusbits;
+       unsigned int            keycount;
+       u16                     keycodes[MPR121_MAX_KEY_COUNT];
+};
+
+struct mpr121_init_register {
+       int addr;
+       u8 val;
+};
+
+static const struct mpr121_init_register init_reg_table[] __devinitconst = {
+       { MHD_RISING_ADDR,      0x1 },
+       { NHD_RISING_ADDR,      0x1 },
+       { MHD_FALLING_ADDR,     0x1 },
+       { NHD_FALLING_ADDR,     0x1 },
+       { NCL_FALLING_ADDR,     0xff },
+       { FDL_FALLING_ADDR,     0x02 },
+       { FILTER_CONF_ADDR,     0x04 },
+       { AFE_CONF_ADDR,        0x0b },
+       { AUTO_CONFIG_CTRL_ADDR, 0x0b },
+};
+
+static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
+{
+       struct mpr121_touchkey *mpr121 = dev_id;
+       struct i2c_client *client = mpr121->client;
+       struct input_dev *input = mpr121->input_dev;
+       unsigned int key_num, key_val, pressed;
+       int reg;
+
+       reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
+       if (reg < 0) {
+               dev_err(&client->dev, "i2c read error [%d]\n", reg);
+               goto out;
+       }
+
+       reg <<= 8;
+       reg |= i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_0_ADDR);
+       if (reg < 0) {
+               dev_err(&client->dev, "i2c read error [%d]\n", reg);
+               goto out;
+       }
+
+       reg &= TOUCH_STATUS_MASK;
+       /* use old press bit to figure out which bit changed */
+       key_num = ffs(reg ^ mpr121->statusbits) - 1;
+       pressed = reg & (1 << key_num);
+       mpr121->statusbits = reg;
+
+       key_val = mpr121->keycodes[key_num];
+
+       input_event(input, EV_MSC, MSC_SCAN, key_num);
+       input_report_key(input, key_val, pressed);
+       input_sync(input);
+
+       dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
+               pressed ? "pressed" : "released");
+
+out:
+       return IRQ_HANDLED;
+}
+
+static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
+                                     struct mpr121_touchkey *mpr121,
+                                     struct i2c_client *client)
+{
+       const struct mpr121_init_register *reg;
+       unsigned char usl, lsl, tl;
+       int i, t, vdd, ret;
+
+       /* Set up touch/release threshold for ele0-ele11 */
+       for (i = 0; i <= MPR121_MAX_KEY_COUNT; i++) {
+               t = ELE0_TOUCH_THRESHOLD_ADDR + (i * 2);
+               ret = i2c_smbus_write_byte_data(client, t, TOUCH_THRESHOLD);
+               if (ret < 0)
+                       goto err_i2c_write;
+               ret = i2c_smbus_write_byte_data(client, t + 1,
+                                               RELEASE_THRESHOLD);
+               if (ret < 0)
+                       goto err_i2c_write;
+       }
+
+       /* Set up init register */
+       for (i = 0; i < ARRAY_SIZE(init_reg_table); i++) {
+               reg = &init_reg_table[i];
+               ret = i2c_smbus_write_byte_data(client, reg->addr, reg->val);
+               if (ret < 0)
+                       goto err_i2c_write;
+       }
+
+
+       /*
+        * Capacitance on sensing input varies and needs to be compensated.
+        * The internal MPR121-auto-configuration can do this if it's
+        * registers are set properly (based on pdata->vdd_uv).
+        */
+       vdd = pdata->vdd_uv / 1000;
+       usl = ((vdd - 700) * 256) / vdd;
+       lsl = (usl * 65) / 100;
+       tl = (usl * 90) / 100;
+       ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl);
+       ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl);
+       ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl);
+       ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
+                                        mpr121->keycount);
+       if (ret != 0)
+               goto err_i2c_write;
+
+       dev_dbg(&client->dev, "set up with %x keys.\n", mpr121->keycount);
+
+       return 0;
+
+err_i2c_write:
+       dev_err(&client->dev, "i2c write error: %d\n", ret);
+       return ret;
+}
+
+static int __devinit mpr_touchkey_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       const struct mpr121_platform_data *pdata = client->dev.platform_data;
+       struct mpr121_touchkey *mpr121;
+       struct input_dev *input_dev;
+       int error;
+       int i;
+
+       if (!pdata) {
+               dev_err(&client->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       if (!pdata->keymap || !pdata->keymap_size) {
+               dev_err(&client->dev, "missing keymap data\n");
+               return -EINVAL;
+       }
+
+       if (pdata->keymap_size > MPR121_MAX_KEY_COUNT) {
+               dev_err(&client->dev, "too many keys defined\n");
+               return -EINVAL;
+       }
+
+       if (!client->irq) {
+               dev_err(&client->dev, "irq number should not be zero\n");
+               return -EINVAL;
+       }
+
+       mpr121 = kzalloc(sizeof(struct mpr121_touchkey), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!mpr121 || !input_dev) {
+               dev_err(&client->dev, "Failed to allocate memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       mpr121->client = client;
+       mpr121->input_dev = input_dev;
+       mpr121->keycount = pdata->keymap_size;
+
+       input_dev->name = "Freescale MPR121 Touchkey";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+       input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+
+       input_dev->keycode = mpr121->keycodes;
+       input_dev->keycodesize = sizeof(mpr121->keycodes[0]);
+       input_dev->keycodemax = mpr121->keycount;
+
+       for (i = 0; i < pdata->keymap_size; i++) {
+               input_set_capability(input_dev, EV_KEY, pdata->keymap[i]);
+               mpr121->keycodes[i] = pdata->keymap[i];
+       }
+
+       error = mpr121_phys_init(pdata, mpr121, client);
+       if (error) {
+               dev_err(&client->dev, "Failed to init register\n");
+               goto err_free_mem;
+       }
+
+       error = request_threaded_irq(client->irq, NULL,
+                                    mpr_touchkey_interrupt,
+                                    IRQF_TRIGGER_FALLING,
+                                    client->dev.driver->name, mpr121);
+       if (error) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto err_free_mem;
+       }
+
+       error = input_register_device(input_dev);
+       if (error)
+               goto err_free_irq;
+
+       i2c_set_clientdata(client, mpr121);
+       device_init_wakeup(&client->dev, pdata->wakeup);
+
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, mpr121);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(mpr121);
+       return error;
+}
+
+static int __devexit mpr_touchkey_remove(struct i2c_client *client)
+{
+       struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
+
+       free_irq(client->irq, mpr121);
+       input_unregister_device(mpr121->input_dev);
+       kfree(mpr121);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mpr_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+
+       i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00);
+
+       return 0;
+}
+
+static int mpr_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
+
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+
+       i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
+                                 mpr121->keycount);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
+
+static const struct i2c_device_id mpr121_id[] = {
+       { "mpr121_touchkey", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mpr121_id);
+
+static struct i2c_driver mpr_touchkey_driver = {
+       .driver = {
+               .name   = "mpr121",
+               .owner  = THIS_MODULE,
+               .pm     = &mpr121_touchkey_pm_ops,
+       },
+       .id_table       = mpr121_id,
+       .probe          = mpr_touchkey_probe,
+       .remove         = __devexit_p(mpr_touchkey_remove),
+};
+
+static int __init mpr_touchkey_init(void)
+{
+       return i2c_add_driver(&mpr_touchkey_driver);
+}
+module_init(mpr_touchkey_init);
+
+static void __exit mpr_touchkey_exit(void)
+{
+       i2c_del_driver(&mpr_touchkey_driver);
+}
+module_exit(mpr_touchkey_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touch Key driver for Freescale MPR121 Chip");
index 0e2a19cb43d812ad784f74ed07dfc9fc8f60fa84..f23a743817dbb1932445a4704046dd7e4ac58d37 100644 (file)
@@ -413,7 +413,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
        return 0;
 err5:
        for (i = irq_idx - 1; i >=0; i--)
-               free_irq(row_gpios[i], NULL);
+               free_irq(row_gpios[i], omap_kp);
 err4:
        input_unregister_device(omap_kp->input);
        input_dev = NULL;
@@ -444,11 +444,11 @@ static int __devexit omap_kp_remove(struct platform_device *pdev)
                        gpio_free(col_gpios[i]);
                for (i = 0; i < omap_kp->rows; i++) {
                        gpio_free(row_gpios[i]);
-                       free_irq(gpio_to_irq(row_gpios[i]), NULL);
+                       free_irq(gpio_to_irq(row_gpios[i]), omap_kp);
                }
        } else {
                omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
-               free_irq(omap_kp->irq, NULL);
+               free_irq(omap_kp->irq, omap_kp);
        }
 
        del_timer_sync(&omap_kp->timer);
index fba8404c7297536d80fcbc2a3efac6129f996ace..ca7b89196ab79a4ceee7b05ebe2ce65044c055b3 100644 (file)
@@ -248,6 +248,7 @@ static const struct i2c_device_id qt1070_id[] = {
        { "qt1070", 0 },
        { },
 };
+MODULE_DEVICE_TABLE(i2c, qt1070_id);
 
 static struct i2c_driver qt1070_driver = {
        .driver = {
index d7dafd9425b69b0682035822185900b8e8ac3d72..834cf98e7efb060fdcc163aa223312d8806d001a 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/input.h>
 #include <linux/input/sh_keysc.h>
 #include <linux/bitmap.h>
-#include <linux/clk.h>
+#include <linux/pm_runtime.h>
 #include <linux/io.h>
 #include <linux/slab.h>
 
@@ -37,7 +37,6 @@ static const struct {
 
 struct sh_keysc_priv {
        void __iomem *iomem_base;
-       struct clk *clk;
        DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
        struct input_dev *input;
        struct sh_keysc_info pdata;
@@ -169,7 +168,6 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        struct sh_keysc_info *pdata;
        struct resource *res;
        struct input_dev *input;
-       char clk_name[8];
        int i;
        int irq, error;
 
@@ -210,19 +208,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
                goto err1;
        }
 
-       snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id);
-       priv->clk = clk_get(&pdev->dev, clk_name);
-       if (IS_ERR(priv->clk)) {
-               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
-               error = PTR_ERR(priv->clk);
-               goto err2;
-       }
-
        priv->input = input_allocate_device();
        if (!priv->input) {
                dev_err(&pdev->dev, "failed to allocate input device\n");
                error = -ENOMEM;
-               goto err3;
+               goto err2;
        }
 
        input = priv->input;
@@ -241,10 +231,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        input->keycodesize = sizeof(pdata->keycodes[0]);
        input->keycodemax = ARRAY_SIZE(pdata->keycodes);
 
-       error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
+       error = request_threaded_irq(irq, NULL, sh_keysc_isr, IRQF_ONESHOT,
+                                    dev_name(&pdev->dev), pdev);
        if (error) {
                dev_err(&pdev->dev, "failed to request IRQ\n");
-               goto err4;
+               goto err3;
        }
 
        for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
@@ -254,10 +245,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
        error = input_register_device(input);
        if (error) {
                dev_err(&pdev->dev, "failed to register input device\n");
-               goto err5;
+               goto err4;
        }
 
-       clk_enable(priv->clk);
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
 
        sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
                       pdata->scan_timing);
@@ -267,12 +259,10 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
 
        return 0;
 
- err5:
-       free_irq(irq, pdev);
  err4:
-       input_free_device(input);
+       free_irq(irq, pdev);
  err3:
-       clk_put(priv->clk);
+       input_free_device(input);
  err2:
        iounmap(priv->iomem_base);
  err1:
@@ -292,8 +282,8 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
        free_irq(platform_get_irq(pdev, 0), pdev);
        iounmap(priv->iomem_base);
 
-       clk_disable(priv->clk);
-       clk_put(priv->clk);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 
        platform_set_drvdata(pdev, NULL);
        kfree(priv);
@@ -301,6 +291,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#if CONFIG_PM_SLEEP
 static int sh_keysc_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -311,14 +302,13 @@ static int sh_keysc_suspend(struct device *dev)
        value = sh_keysc_read(priv, KYCR1);
 
        if (device_may_wakeup(dev)) {
-               value |= 0x80;
+               sh_keysc_write(priv, KYCR1, value | 0x80);
                enable_irq_wake(irq);
        } else {
-               value &= ~0x80;
+               sh_keysc_write(priv, KYCR1, value & ~0x80);
+               pm_runtime_put_sync(dev);
        }
 
-       sh_keysc_write(priv, KYCR1, value);
-
        return 0;
 }
 
@@ -329,16 +319,17 @@ static int sh_keysc_resume(struct device *dev)
 
        if (device_may_wakeup(dev))
                disable_irq_wake(irq);
+       else
+               pm_runtime_get_sync(dev);
 
        return 0;
 }
+#endif
 
-static const struct dev_pm_ops sh_keysc_dev_pm_ops = {
-       .suspend = sh_keysc_suspend,
-       .resume = sh_keysc_resume,
-};
+static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops,
+                        sh_keysc_suspend, sh_keysc_resume);
 
-struct platform_driver sh_keysc_device_driver = {
+static struct platform_driver sh_keysc_device_driver = {
        .probe          = sh_keysc_probe,
        .remove         = __devexit_p(sh_keysc_remove),
        .driver         = {
index 99ce9032d08cd61f437fb5e3256db537cfa751e8..2b3b73ec6689599596704a5bd175ee98d7b2d23b 100644 (file)
@@ -66,12 +66,11 @@ struct tegra_kbc {
        void __iomem *mmio;
        struct input_dev *idev;
        unsigned int irq;
-       unsigned int wake_enable_rows;
-       unsigned int wake_enable_cols;
        spinlock_t lock;
        unsigned int repoll_dly;
        unsigned long cp_dly_jiffies;
        bool use_fn_map;
+       bool use_ghost_filter;
        const struct tegra_kbc_platform_data *pdata;
        unsigned short keycode[KBC_MAX_KEY * 2];
        unsigned short current_keys[KBC_MAX_KPENT];
@@ -260,6 +259,8 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
        unsigned int num_down = 0;
        unsigned long flags;
        bool fn_keypress = false;
+       bool key_in_same_row = false;
+       bool key_in_same_col = false;
 
        spin_lock_irqsave(&kbc->lock, flags);
        for (i = 0; i < KBC_MAX_KPENT; i++) {
@@ -284,6 +285,34 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
                val >>= 8;
        }
 
+       /*
+        * Matrix keyboard designs are prone to keyboard ghosting.
+        * Ghosting occurs if there are 3 keys such that -
+        * any 2 of the 3 keys share a row, and any 2 of them share a column.
+        * If so ignore the key presses for this iteration.
+        */
+       if ((kbc->use_ghost_filter) && (num_down >= 3)) {
+               for (i = 0; i < num_down; i++) {
+                       unsigned int j;
+                       u8 curr_col = scancodes[i] & 0x07;
+                       u8 curr_row = scancodes[i] >> KBC_ROW_SHIFT;
+
+                       /*
+                        * Find 2 keys such that one key is in the same row
+                        * and the other is in the same column as the i-th key.
+                        */
+                       for (j = i + 1; j < num_down; j++) {
+                               u8 col = scancodes[j] & 0x07;
+                               u8 row = scancodes[j] >> KBC_ROW_SHIFT;
+
+                               if (col == curr_col)
+                                       key_in_same_col = true;
+                               if (row == curr_row)
+                                       key_in_same_row = true;
+                       }
+               }
+       }
+
        /*
         * If the platform uses Fn keymaps, translate keys on a Fn keypress.
         * Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
@@ -297,6 +326,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
 
        spin_unlock_irqrestore(&kbc->lock, flags);
 
+       /* Ignore the key presses for this iteration? */
+       if (key_in_same_col && key_in_same_row)
+               return;
+
        tegra_kbc_report_released_keys(kbc->idev,
                                       kbc->current_keys, kbc->num_pressed_keys,
                                       keycodes, num_down);
@@ -383,21 +416,11 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
        int i;
        unsigned int rst_val;
 
-       BUG_ON(pdata->wake_cnt > KBC_MAX_KEY);
-       rst_val = (filter && pdata->wake_cnt) ? ~0 : 0;
+       /* Either mask all keys or none. */
+       rst_val = (filter && !pdata->wakeup) ? ~0 : 0;
 
        for (i = 0; i < KBC_MAX_ROW; i++)
                writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
-
-       if (filter) {
-               for (i = 0; i < pdata->wake_cnt; i++) {
-                       u32 val, addr;
-                       addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0;
-                       val = readl(kbc->mmio + addr);
-                       val &= ~(1 << pdata->wake_cfg[i].col);
-                       writel(val, kbc->mmio + addr);
-               }
-       }
 }
 
 static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
@@ -559,7 +582,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
        struct resource *res;
        int irq;
        int err;
-       int i;
        int num_rows = 0;
        unsigned int debounce_cnt;
        unsigned int scan_time_rows;
@@ -616,13 +638,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
                goto err_iounmap;
        }
 
-       kbc->wake_enable_rows = 0;
-       kbc->wake_enable_cols = 0;
-       for (i = 0; i < pdata->wake_cnt; i++) {
-               kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row);
-               kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col);
-       }
-
        /*
         * The time delay between two consecutive reads of the FIFO is
         * the sum of the repeat time and the time taken for scanning
@@ -652,6 +667,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
                input_dev->keycodemax *= 2;
 
        kbc->use_fn_map = pdata->use_fn_map;
+       kbc->use_ghost_filter = pdata->use_ghost_filter;
        keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
        matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
                                   input_dev->keycode, input_dev->keybit);
index c431d09e401ac2f91d0627990c781cc2f183a69f..c3a62c42cd28838a64fa4cb432d2ac4e430a0fc0 100644 (file)
@@ -79,13 +79,7 @@ struct ad714x_slider_drv {
 struct ad714x_wheel_drv {
        int abs_pos;
        int flt_pos;
-       int pre_mean_value;
        int pre_highest_stage;
-       int pre_mean_value_no_offset;
-       int mean_value;
-       int mean_value_no_offset;
-       int pos_offset;
-       int pos_ratio;
        int highest_stage;
        enum ad714x_device_state state;
        struct input_dev *input;
@@ -158,10 +152,10 @@ static void ad714x_use_com_int(struct ad714x_chip *ad714x,
        unsigned short data;
        unsigned short mask;
 
-       mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
+       mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
 
        ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
-       data |= 1 << start_stage;
+       data |= 1 << end_stage;
        ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
 
        ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
@@ -175,10 +169,10 @@ static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
        unsigned short data;
        unsigned short mask;
 
-       mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
+       mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
 
        ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
-       data &= ~(1 << start_stage);
+       data &= ~(1 << end_stage);
        ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
 
        ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
@@ -404,7 +398,6 @@ static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)
                                ad714x_slider_cal_highest_stage(ad714x, idx);
                                ad714x_slider_cal_abs_pos(ad714x, idx);
                                ad714x_slider_cal_flt_pos(ad714x, idx);
-
                                input_report_abs(sw->input, ABS_X, sw->flt_pos);
                                input_report_key(sw->input, BTN_TOUCH, 1);
                        } else {
@@ -468,104 +461,41 @@ static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
 /*
  * When the scroll wheel is activated, we compute the absolute position based
  * on the sensor values. To calculate the position, we first determine the
- * sensor that has the greatest response among the sensors that constitutes
- * the scrollwheel. Then we determined the sensors on either sides of the
+ * sensor that has the greatest response among the sensors that constitutes
+ * the scrollwheel. Then we determined the sensors on either sides of the
  * sensor with the highest response and we apply weights to these sensors. The
- * result of this computation gives us the mean value which defined by the
- * following formula:
- * For i= second_before_highest_stage to i= second_after_highest_stage
- *         v += Sensor response(i)*WEIGHT*(i+3)
- *         w += Sensor response(i)
- * Mean_Value=v/w
- * pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio
+ * result of this computation gives us the mean value.
  */
 
-#define WEIGHT_FACTOR 30
-/* This constant prevents the "PositionOffset" from reaching a big value */
-#define OFFSET_POSITION_CLAMP  120
 static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
 {
        struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
        struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
        int stage_num = hw->end_stage - hw->start_stage + 1;
-       int second_before, first_before, highest, first_after, second_after;
+       int first_before, highest, first_after;
        int a_param, b_param;
 
-       /* Calculate Mean value */
-
-       second_before = (sw->highest_stage + stage_num - 2) % stage_num;
        first_before = (sw->highest_stage + stage_num - 1) % stage_num;
        highest = sw->highest_stage;
        first_after = (sw->highest_stage + stage_num + 1) % stage_num;
-       second_after = (sw->highest_stage + stage_num + 2) % stage_num;
-
-       if (((sw->highest_stage - hw->start_stage) > 1) &&
-           ((hw->end_stage - sw->highest_stage) > 1)) {
-               a_param = ad714x->sensor_val[second_before] *
-                       (second_before - hw->start_stage + 3) +
-                       ad714x->sensor_val[first_before] *
-                       (second_before - hw->start_stage + 3) +
-                       ad714x->sensor_val[highest] *
-                       (second_before - hw->start_stage + 3) +
-                       ad714x->sensor_val[first_after] *
-                       (first_after - hw->start_stage + 3) +
-                       ad714x->sensor_val[second_after] *
-                       (second_after - hw->start_stage + 3);
-       } else {
-               a_param = ad714x->sensor_val[second_before] *
-                       (second_before - hw->start_stage + 1) +
-                       ad714x->sensor_val[first_before] *
-                       (second_before - hw->start_stage + 2) +
-                       ad714x->sensor_val[highest] *
-                       (second_before - hw->start_stage + 3) +
-                       ad714x->sensor_val[first_after] *
-                       (first_after - hw->start_stage + 4) +
-                       ad714x->sensor_val[second_after] *
-                       (second_after - hw->start_stage + 5);
-       }
-       a_param *= WEIGHT_FACTOR;
 
-       b_param = ad714x->sensor_val[second_before] +
+       a_param = ad714x->sensor_val[highest] *
+               (highest - hw->start_stage) +
+               ad714x->sensor_val[first_before] *
+               (highest - hw->start_stage - 1) +
+               ad714x->sensor_val[first_after] *
+               (highest - hw->start_stage + 1);
+       b_param = ad714x->sensor_val[highest] +
                ad714x->sensor_val[first_before] +
-               ad714x->sensor_val[highest] +
-               ad714x->sensor_val[first_after] +
-               ad714x->sensor_val[second_after];
-
-       sw->pre_mean_value = sw->mean_value;
-       sw->mean_value = a_param / b_param;
-
-       /* Calculate the offset */
-
-       if ((sw->pre_highest_stage == hw->end_stage) &&
-                       (sw->highest_stage == hw->start_stage))
-               sw->pos_offset = sw->mean_value;
-       else if ((sw->pre_highest_stage == hw->start_stage) &&
-                       (sw->highest_stage == hw->end_stage))
-               sw->pos_offset = sw->pre_mean_value;
-
-       if (sw->pos_offset > OFFSET_POSITION_CLAMP)
-               sw->pos_offset = OFFSET_POSITION_CLAMP;
-
-       /* Calculate the mean value without the offset */
-
-       sw->pre_mean_value_no_offset = sw->mean_value_no_offset;
-       sw->mean_value_no_offset = sw->mean_value - sw->pos_offset;
-       if (sw->mean_value_no_offset < 0)
-               sw->mean_value_no_offset = 0;
-
-       /* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */
-
-       if ((sw->pre_highest_stage == hw->end_stage) &&
-                       (sw->highest_stage == hw->start_stage))
-               sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) /
-                       hw->max_coord;
-       else if ((sw->pre_highest_stage == hw->start_stage) &&
-                       (sw->highest_stage == hw->end_stage))
-               sw->pos_ratio = (sw->mean_value_no_offset * 100) /
-                       hw->max_coord;
-       sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio;
+               ad714x->sensor_val[first_after];
+
+       sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) *
+                       a_param) / b_param;
+
        if (sw->abs_pos > hw->max_coord)
                sw->abs_pos = hw->max_coord;
+       else if (sw->abs_pos < 0)
+               sw->abs_pos = 0;
 }
 
 static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
@@ -639,9 +569,8 @@ static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)
                                ad714x_wheel_cal_highest_stage(ad714x, idx);
                                ad714x_wheel_cal_abs_pos(ad714x, idx);
                                ad714x_wheel_cal_flt_pos(ad714x, idx);
-
                                input_report_abs(sw->input, ABS_WHEEL,
-                                       sw->abs_pos);
+                                       sw->flt_pos);
                                input_report_key(sw->input, BTN_TOUCH, 1);
                        } else {
                                /* When the user lifts off the sensor, configure
@@ -1149,6 +1078,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                        input[alloc_idx]->id.bustype = bus_type;
                        input[alloc_idx]->id.product = ad714x->product;
                        input[alloc_idx]->id.version = ad714x->version;
+                       input[alloc_idx]->name = "ad714x_captouch_slider";
+                       input[alloc_idx]->dev.parent = dev;
 
                        error = input_register_device(input[alloc_idx]);
                        if (error)
@@ -1179,6 +1110,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                        input[alloc_idx]->id.bustype = bus_type;
                        input[alloc_idx]->id.product = ad714x->product;
                        input[alloc_idx]->id.version = ad714x->version;
+                       input[alloc_idx]->name = "ad714x_captouch_wheel";
+                       input[alloc_idx]->dev.parent = dev;
 
                        error = input_register_device(input[alloc_idx]);
                        if (error)
@@ -1212,6 +1145,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                        input[alloc_idx]->id.bustype = bus_type;
                        input[alloc_idx]->id.product = ad714x->product;
                        input[alloc_idx]->id.version = ad714x->version;
+                       input[alloc_idx]->name = "ad714x_captouch_pad";
+                       input[alloc_idx]->dev.parent = dev;
 
                        error = input_register_device(input[alloc_idx]);
                        if (error)
@@ -1240,6 +1175,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
                input[alloc_idx]->id.bustype = bus_type;
                input[alloc_idx]->id.product = ad714x->product;
                input[alloc_idx]->id.version = ad714x->version;
+               input[alloc_idx]->name = "ad714x_captouch_button";
+               input[alloc_idx]->dev.parent = dev;
 
                error = input_register_device(input[alloc_idx]);
                if (error)
@@ -1249,7 +1186,9 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
        }
 
        error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
-                       IRQF_TRIGGER_FALLING, "ad714x_captouch", ad714x);
+                               plat_data->irqflags ?
+                                       plat_data->irqflags : IRQF_TRIGGER_FALLING,
+                               "ad714x_captouch", ad714x);
        if (error) {
                dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
                goto err_unreg_dev;
index 9ccdb82d869a09245c80bf125a99c5fcac5cffd7..1de58e8a1b71216180808f7bd2c2e7d233f1cce7 100644 (file)
@@ -737,14 +737,17 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,
 
        mutex_lock(&ati_remote2_mutex);
 
-       if (mask != ar2->channel_mask && !ati_remote2_setup(ar2, mask))
-               ar2->channel_mask = mask;
+       if (mask != ar2->channel_mask) {
+               r = ati_remote2_setup(ar2, mask);
+               if (!r)
+                       ar2->channel_mask = mask;
+       }
 
        mutex_unlock(&ati_remote2_mutex);
 
        usb_autopm_put_interface(ar2->intf[0]);
 
-       return count;
+       return r ? r : count;
 }
 
 static ssize_t ati_remote2_show_mode_mask(struct device *dev,
index 7e64d01da2beb9238f78e567b210179e551b161b..2c8b84dd9dacca5bac905810fbf3cc452ad0541a 100644 (file)
@@ -2,6 +2,7 @@
  * rotary_encoder.c
  *
  * (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
  *
  * state machine code inspired by code from Tim Ruetz
  *
@@ -38,52 +39,66 @@ struct rotary_encoder {
 
        bool armed;
        unsigned char dir;      /* 0 - clockwise, 1 - CCW */
+
+       char last_stable;
 };
 
-static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
+static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata)
 {
-       struct rotary_encoder *encoder = dev_id;
-       struct rotary_encoder_platform_data *pdata = encoder->pdata;
        int a = !!gpio_get_value(pdata->gpio_a);
        int b = !!gpio_get_value(pdata->gpio_b);
-       int state;
 
        a ^= pdata->inverted_a;
        b ^= pdata->inverted_b;
-       state = (a << 1) | b;
 
-       switch (state) {
+       return ((a << 1) | b);
+}
 
-       case 0x0:
-               if (!encoder->armed)
-                       break;
+static void rotary_encoder_report_event(struct rotary_encoder *encoder)
+{
+       struct rotary_encoder_platform_data *pdata = encoder->pdata;
 
-               if (pdata->relative_axis) {
-                       input_report_rel(encoder->input, pdata->axis,
-                                        encoder->dir ? -1 : 1);
-               } else {
-                       unsigned int pos = encoder->pos;
-
-                       if (encoder->dir) {
-                               /* turning counter-clockwise */
-                               if (pdata->rollover)
-                                       pos += pdata->steps;
-                               if (pos)
-                                       pos--;
-                       } else {
-                               /* turning clockwise */
-                               if (pdata->rollover || pos < pdata->steps)
-                                       pos++;
-                       }
+       if (pdata->relative_axis) {
+               input_report_rel(encoder->input,
+                                pdata->axis, encoder->dir ? -1 : 1);
+       } else {
+               unsigned int pos = encoder->pos;
+
+               if (encoder->dir) {
+                       /* turning counter-clockwise */
                        if (pdata->rollover)
-                               pos %= pdata->steps;
-                       encoder->pos = pos;
-                       input_report_abs(encoder->input, pdata->axis,
-                                        encoder->pos);
+                               pos += pdata->steps;
+                       if (pos)
+                               pos--;
+               } else {
+                       /* turning clockwise */
+                       if (pdata->rollover || pos < pdata->steps)
+                               pos++;
                }
-               input_sync(encoder->input);
 
-               encoder->armed = false;
+               if (pdata->rollover)
+                       pos %= pdata->steps;
+
+               encoder->pos = pos;
+               input_report_abs(encoder->input, pdata->axis, encoder->pos);
+       }
+
+       input_sync(encoder->input);
+}
+
+static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
+{
+       struct rotary_encoder *encoder = dev_id;
+       int state;
+
+       state = rotary_encoder_get_state(encoder->pdata);
+
+       switch (state) {
+       case 0x0:
+               if (encoder->armed) {
+                       rotary_encoder_report_event(encoder);
+                       encoder->armed = false;
+               }
                break;
 
        case 0x1:
@@ -100,11 +115,37 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
+{
+       struct rotary_encoder *encoder = dev_id;
+       int state;
+
+       state = rotary_encoder_get_state(encoder->pdata);
+
+       switch (state) {
+       case 0x00:
+       case 0x03:
+               if (state != encoder->last_stable) {
+                       rotary_encoder_report_event(encoder);
+                       encoder->last_stable = state;
+               }
+               break;
+
+       case 0x01:
+       case 0x02:
+               encoder->dir = (encoder->last_stable + state) & 0x01;
+               break;
+       }
+
+       return IRQ_HANDLED;
+}
+
 static int __devinit rotary_encoder_probe(struct platform_device *pdev)
 {
        struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;
        struct rotary_encoder *encoder;
        struct input_dev *input;
+       irq_handler_t handler;
        int err;
 
        if (!pdata) {
@@ -175,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
        }
 
        /* request the IRQs */
-       err = request_irq(encoder->irq_a, &rotary_encoder_irq,
+       if (pdata->half_period) {
+               handler = &rotary_encoder_half_period_irq;
+               encoder->last_stable = rotary_encoder_get_state(pdata);
+       } else {
+               handler = &rotary_encoder_irq;
+       }
+
+       err = request_irq(encoder->irq_a, handler,
                          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                          DRV_NAME, encoder);
        if (err) {
@@ -184,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
                goto exit_free_gpio_b;
        }
 
-       err = request_irq(encoder->irq_b, &rotary_encoder_irq,
+       err = request_irq(encoder->irq_b, handler,
                          IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
                          DRV_NAME, encoder);
        if (err) {
@@ -252,6 +300,5 @@ module_exit(rotary_encoder_exit);
 
 MODULE_ALIAS("platform:" DRV_NAME);
 MODULE_DESCRIPTION("GPIO rotary encoder driver");
-MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
 MODULE_LICENSE("GPL v2");
-
index f16972bddca473b54f8388fe6ba2709b0b65dd77..38e4b507b94cc629ef330cf173b1b41d3765e904 100644 (file)
@@ -89,7 +89,7 @@ static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
        return 0;
 
 free_irq:
-       free_irq(irq, NULL);
+       free_irq(irq, pwr);
 free_input_dev:
        input_free_device(pwr);
        return err;
index 04d9bf320a4f9c090b8d4f46aeca8e848bc4f988..32503565faf90faf229c4560d7fdfcda3f8c8561 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/serio.h>
 #include <linux/libps2.h>
 #include "psmouse.h"
@@ -242,15 +243,37 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
        input_sync(dev);
 }
 
+static void elantech_set_slot(struct input_dev *dev, int slot, bool active,
+                             unsigned int x, unsigned int y)
+{
+       input_mt_slot(dev, slot);
+       input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
+       if (active) {
+               input_report_abs(dev, ABS_MT_POSITION_X, x);
+               input_report_abs(dev, ABS_MT_POSITION_Y, y);
+       }
+}
+
+/* x1 < x2 and y1 < y2 when two fingers, x = y = 0 when not pressed */
+static void elantech_report_semi_mt_data(struct input_dev *dev,
+                                        unsigned int num_fingers,
+                                        unsigned int x1, unsigned int y1,
+                                        unsigned int x2, unsigned int y2)
+{
+       elantech_set_slot(dev, 0, num_fingers != 0, x1, y1);
+       elantech_set_slot(dev, 1, num_fingers == 2, x2, y2);
+}
+
 /*
  * Interpret complete data packets and report absolute mode input events for
  * hardware version 2. (6 byte packets)
  */
 static void elantech_report_absolute_v2(struct psmouse *psmouse)
 {
+       struct elantech_data *etd = psmouse->private;
        struct input_dev *dev = psmouse->dev;
        unsigned char *packet = psmouse->packet;
-       int fingers, x1, y1, x2, y2;
+       unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0, pres = 0;
 
        /* byte 0: n1  n0   .   .   .   .   R   L */
        fingers = (packet[0] & 0xc0) >> 6;
@@ -270,14 +293,18 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
                 * byte 1:  .   .   .   .   .  x10 x9  x8
                 * byte 2: x7  x6  x5  x4  x4  x2  x1  x0
                 */
-               input_report_abs(dev, ABS_X,
-                       ((packet[1] & 0x07) << 8) | packet[2]);
+               x1 = ((packet[1] & 0x07) << 8) | packet[2];
                /*
                 * byte 4:  .   .   .   .   .   .  y9  y8
                 * byte 5: y7  y6  y5  y4  y3  y2  y1  y0
                 */
-               input_report_abs(dev, ABS_Y,
-                       ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]));
+               y1 = ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]);
+
+               input_report_abs(dev, ABS_X, x1);
+               input_report_abs(dev, ABS_Y, y1);
+
+               pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
+               width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);
                break;
 
        case 2:
@@ -303,23 +330,24 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
                 */
                input_report_abs(dev, ABS_X, x1 << 2);
                input_report_abs(dev, ABS_Y, y1 << 2);
-               /*
-                * For compatibility with the proprietary X Elantech driver
-                * report both coordinates as hat coordinates
-                */
-               input_report_abs(dev, ABS_HAT0X, x1);
-               input_report_abs(dev, ABS_HAT0Y, y1);
-               input_report_abs(dev, ABS_HAT1X, x2);
-               input_report_abs(dev, ABS_HAT1Y, y2);
+
+               /* Unknown so just report sensible values */
+               pres = 127;
+               width = 7;
                break;
        }
 
+       elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
        input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
        input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
        input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
        input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
        input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
        input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+       if (etd->reports_pressure) {
+               input_report_abs(dev, ABS_PRESSURE, pres);
+               input_report_abs(dev, ABS_TOOL_WIDTH, width);
+       }
 
        input_sync(dev);
 }
@@ -478,10 +506,16 @@ static void elantech_set_input_params(struct psmouse *psmouse)
                __set_bit(BTN_TOOL_QUADTAP, dev->keybit);
                input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);
                input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);
-               input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0);
-               input_set_abs_params(dev, ABS_HAT0Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0);
-               input_set_abs_params(dev, ABS_HAT1X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0);
-               input_set_abs_params(dev, ABS_HAT1Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0);
+               if (etd->reports_pressure) {
+                       input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
+                                            ETP_PMAX_V2, 0, 0);
+                       input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
+                                            ETP_WMAX_V2, 0, 0);
+               }
+               __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+               input_mt_init_slots(dev, 2);
+               input_set_abs_params(dev, ABS_MT_POSITION_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);
+               input_set_abs_params(dev, ABS_MT_POSITION_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);
                break;
        }
 }
@@ -725,6 +759,10 @@ int elantech_init(struct psmouse *psmouse)
                etd->debug = 1;
                /* Don't know how to do parity checking for version 2 */
                etd->paritycheck = 0;
+
+               if (etd->fw_version >= 0x020800)
+                       etd->reports_pressure = true;
+
        } else {
                etd->hw_version = 1;
                etd->paritycheck = 1;
index aa4aac5d21983988e8e8de6c3d150d579dba0ae0..fabb2b99615cda63347e8d0bee9f9f15f70cc3ae 100644 (file)
 #define ETP_YMIN_V2                    (   0 + ETP_EDGE_FUZZ_V2)
 #define ETP_YMAX_V2                    ( 768 - ETP_EDGE_FUZZ_V2)
 
+#define ETP_PMIN_V2                    0
+#define ETP_PMAX_V2                    255
+#define ETP_WMIN_V2                    0
+#define ETP_WMAX_V2                    15
+
 /*
  * For two finger touches the coordinate of each finger gets reported
  * separately but with reduced resolution.
@@ -102,6 +107,7 @@ struct elantech_data {
        unsigned char capabilities;
        bool paritycheck;
        bool jumpy_cursor;
+       bool reports_pressure;
        unsigned char hw_version;
        unsigned int fw_version;
        unsigned int single_finger_reports;
index 7630273e9474051c3ba4886012e61f1088b43a81..257e033986e40f61ad9a6bcb957439bd5d3f744f 100644 (file)
@@ -508,7 +508,6 @@ static void mousedev_attach_client(struct mousedev *mousedev,
        spin_lock(&mousedev->client_lock);
        list_add_tail_rcu(&client->node, &mousedev->client_list);
        spin_unlock(&mousedev->client_lock);
-       synchronize_rcu();
 }
 
 static void mousedev_detach_client(struct mousedev *mousedev,
index 434fd800cd24e7eb54adf896b8ec20e7f17e4dc5..cabd9e54863f9643664eb1e71c5cd5217d3fe528 100644 (file)
@@ -248,6 +248,18 @@ config TOUCHSCREEN_LPC32XX
          To compile this driver as a module, choose M here: the
          module will be called lpc32xx_ts.
 
+config TOUCHSCREEN_MAX11801
+       tristate "MAX11801 based touchscreens"
+       depends on I2C
+       help
+         Say Y here if you have a MAX11801 based touchscreen
+         controller.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called max11801_ts.
+
 config TOUCHSCREEN_MCS5000
        tristate "MELFAS MCS-5000 touchscreen"
        depends on I2C
index ca94098d4c92b8116815c17a9ac742e77aa622e3..282d6f76ae26d10576332903ea633b8b03a17d05 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU)     += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)       += inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)    += intel-mid-touch.o
 obj-$(CONFIG_TOUCHSCREEN_LPC32XX)      += lpc32xx_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MAX11801)     += max11801_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MC13783)      += mc13783_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MCS5000)      += mcs5000_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MIGOR)                += migor_ts.o
index 1de1c19dad30f2e0ef089f0901e8d6d0b2584b43..5196861b86ef2d8c2d4d559b5471caa4e1e464b4 100644 (file)
@@ -109,6 +109,7 @@ struct ads7846 {
        u16                     pressure_max;
 
        bool                    swap_xy;
+       bool                    use_internal;
 
        struct ads7846_packet   *packet;
 
@@ -307,7 +308,6 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
        struct ads7846 *ts = dev_get_drvdata(dev);
        struct ser_req *req;
        int status;
-       int use_internal;
 
        req = kzalloc(sizeof *req, GFP_KERNEL);
        if (!req)
@@ -315,11 +315,8 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
 
        spi_message_init(&req->msg);
 
-       /* FIXME boards with ads7846 might use external vref instead ... */
-       use_internal = (ts->model == 7846);
-
        /* maybe turn on internal vREF, and let it settle */
-       if (use_internal) {
+       if (ts->use_internal) {
                req->ref_on = REF_ON;
                req->xfer[0].tx_buf = &req->ref_on;
                req->xfer[0].len = 1;
@@ -331,8 +328,14 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
                /* for 1uF, settle for 800 usec; no cap, 100 usec.  */
                req->xfer[1].delay_usecs = ts->vref_delay_usecs;
                spi_message_add_tail(&req->xfer[1], &req->msg);
+
+               /* Enable reference voltage */
+               command |= ADS_PD10_REF_ON;
        }
 
+       /* Enable ADC in every case */
+       command |= ADS_PD10_ADC_ON;
+
        /* take sample */
        req->command = (u8) command;
        req->xfer[2].tx_buf = &req->command;
@@ -416,7 +419,7 @@ name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
 { \
        struct ads7846 *ts = dev_get_drvdata(dev); \
        ssize_t v = ads7846_read12_ser(dev, \
-                       READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
+                       READ_12BIT_SER(var)); \
        if (v < 0) \
                return v; \
        return sprintf(buf, "%u\n", adjust(ts, v)); \
@@ -509,6 +512,7 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
                if (!ts->vref_mv) {
                        dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
                        ts->vref_mv = 2500;
+                       ts->use_internal = true;
                }
                break;
        case 7845:
@@ -969,6 +973,13 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784
                                pdata->gpio_pendown);
                        return err;
                }
+               err = gpio_direction_input(pdata->gpio_pendown);
+               if (err) {
+                       dev_err(&spi->dev, "failed to setup pendown GPIO%d\n",
+                               pdata->gpio_pendown);
+                       gpio_free(pdata->gpio_pendown);
+                       return err;
+               }
 
                ts->gpio_pendown = pdata->gpio_pendown;
 
@@ -1340,8 +1351,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        if (ts->model == 7845)
                ads7845_read12_ser(&spi->dev, PWRDOWN);
        else
-               (void) ads7846_read12_ser(&spi->dev,
-                               READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+               (void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux));
 
        err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
        if (err)
index 4012436633b18ef0d087b95ca4f6792c6c8e290b..1e61387c73cafa01f40825a710427414a4a7e2aa 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/firmware.h>
 #include <linux/i2c.h>
 #include <linux/i2c/atmel_mxt_ts.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 
 #define MXT_PRESS              (1 << 6)
 #define MXT_DETECT             (1 << 7)
 
+/* Touch orient bits */
+#define MXT_XY_SWITCH          (1 << 0)
+#define MXT_X_INVERT           (1 << 1)
+#define MXT_Y_INVERT           (1 << 2)
+
 /* Touchscreen absolute values */
-#define MXT_MAX_XC             0x3ff
-#define MXT_MAX_YC             0x3ff
 #define MXT_MAX_AREA           0xff
 
 #define MXT_MAX_FINGER         10
@@ -246,6 +249,8 @@ struct mxt_data {
        struct mxt_info info;
        struct mxt_finger finger[MXT_MAX_FINGER];
        unsigned int irq;
+       unsigned int max_x;
+       unsigned int max_y;
 };
 
 static bool mxt_object_readable(unsigned int type)
@@ -499,19 +504,21 @@ static void mxt_input_report(struct mxt_data *data, int single_id)
                if (!finger[id].status)
                        continue;
 
-               input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
-                               finger[id].status != MXT_RELEASE ?
-                               finger[id].area : 0);
-               input_report_abs(input_dev, ABS_MT_POSITION_X,
-                               finger[id].x);
-               input_report_abs(input_dev, ABS_MT_POSITION_Y,
-                               finger[id].y);
-               input_mt_sync(input_dev);
+               input_mt_slot(input_dev, id);
+               input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
+                               finger[id].status != MXT_RELEASE);
 
-               if (finger[id].status == MXT_RELEASE)
-                       finger[id].status = 0;
-               else
+               if (finger[id].status != MXT_RELEASE) {
                        finger_num++;
+                       input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+                                       finger[id].area);
+                       input_report_abs(input_dev, ABS_MT_POSITION_X,
+                                       finger[id].x);
+                       input_report_abs(input_dev, ABS_MT_POSITION_Y,
+                                       finger[id].y);
+               } else {
+                       finger[id].status = 0;
+               }
        }
 
        input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
@@ -549,8 +556,13 @@ static void mxt_input_touchevent(struct mxt_data *data,
        if (!(status & (MXT_PRESS | MXT_MOVE)))
                return;
 
-       x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
-       y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
+       x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
+       y = (message->message[2] << 4) | ((message->message[3] & 0xf));
+       if (data->max_x < 1024)
+               x = x >> 2;
+       if (data->max_y < 1024)
+               y = y >> 2;
+
        area = message->message[4];
 
        dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
@@ -804,10 +816,6 @@ static int mxt_initialize(struct mxt_data *data)
        if (error)
                return error;
 
-       error = mxt_make_highchg(data);
-       if (error)
-               return error;
-
        mxt_handle_pdata(data);
 
        /* Backup to memory */
@@ -845,6 +853,20 @@ static int mxt_initialize(struct mxt_data *data)
        return 0;
 }
 
+static void mxt_calc_resolution(struct mxt_data *data)
+{
+       unsigned int max_x = data->pdata->x_size - 1;
+       unsigned int max_y = data->pdata->y_size - 1;
+
+       if (data->pdata->orient & MXT_XY_SWITCH) {
+               data->max_x = max_y;
+               data->max_y = max_x;
+       } else {
+               data->max_x = max_x;
+               data->max_y = max_y;
+       }
+}
+
 static ssize_t mxt_object_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
@@ -981,6 +1003,10 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 
        enable_irq(data->irq);
 
+       error = mxt_make_highchg(data);
+       if (error)
+               return error;
+
        return count;
 }
 
@@ -1052,31 +1078,33 @@ static int __devinit mxt_probe(struct i2c_client *client,
        input_dev->open = mxt_input_open;
        input_dev->close = mxt_input_close;
 
+       data->client = client;
+       data->input_dev = input_dev;
+       data->pdata = pdata;
+       data->irq = client->irq;
+
+       mxt_calc_resolution(data);
+
        __set_bit(EV_ABS, input_dev->evbit);
        __set_bit(EV_KEY, input_dev->evbit);
        __set_bit(BTN_TOUCH, input_dev->keybit);
 
        /* For single touch */
        input_set_abs_params(input_dev, ABS_X,
-                            0, MXT_MAX_XC, 0, 0);
+                            0, data->max_x, 0, 0);
        input_set_abs_params(input_dev, ABS_Y,
-                            0, MXT_MAX_YC, 0, 0);
+                            0, data->max_y, 0, 0);
 
        /* For multi touch */
+       input_mt_init_slots(input_dev, MXT_MAX_FINGER);
        input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
                             0, MXT_MAX_AREA, 0, 0);
        input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-                            0, MXT_MAX_XC, 0, 0);
+                            0, data->max_x, 0, 0);
        input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-                            0, MXT_MAX_YC, 0, 0);
+                            0, data->max_y, 0, 0);
 
        input_set_drvdata(input_dev, data);
-
-       data->client = client;
-       data->input_dev = input_dev;
-       data->pdata = pdata;
-       data->irq = client->irq;
-
        i2c_set_clientdata(client, data);
 
        error = mxt_initialize(data);
@@ -1090,6 +1118,10 @@ static int __devinit mxt_probe(struct i2c_client *client,
                goto err_free_object;
        }
 
+       error = mxt_make_highchg(data);
+       if (error)
+               goto err_free_irq;
+
        error = input_register_device(input_dev);
        if (error)
                goto err_free_irq;
index 3d9b5166ebe95d79712b9382d4f22ef666386e7c..432c69be6ac61561a383b026eac149588daca99f 100644 (file)
@@ -317,7 +317,7 @@ err_unmap_regs:
 err_release_mem:
        release_mem_region(res->start, resource_size(res));
 err_free_dev:
-       input_free_device(ts_dev->input);
+       input_free_device(input_dev);
 err_free_mem:
        kfree(ts_dev);
        return err;
index 45f93d0f5592e2c3adcdcfdad32ce83696312647..211811ae552538b529b32ce470991b266454a9c7 100644 (file)
@@ -396,14 +396,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
        set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
 
        if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
-                       IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) {
+                       IRQF_SHARED | IRQF_DISABLED, "h3600_action", ts->dev)) {
                printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
                err = -EBUSY;
                goto fail1;
        }
 
        if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
-                       IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) {
+                       IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", ts->dev)) {
                printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
                err = -EBUSY;
                goto fail2;
@@ -439,8 +439,8 @@ static void h3600ts_disconnect(struct serio *serio)
 {
        struct h3600_dev *ts = serio_get_drvdata(serio);
 
-       free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
-       free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
+       free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev);
+       free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
        input_get_device(ts->dev);
        input_unregister_device(ts->dev);
        serio_close(serio);
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
new file mode 100644 (file)
index 0000000..4f2713d
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Driver for MAXI MAX11801 - A Resistive touch screen controller with
+ * i2c interface
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Author: Zhang Jiejing <jiejing.zhang@freescale.com>
+ *
+ * Based on mcs5000_ts.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+
+/*
+ * This driver aims to support the series of MAXI touch chips max11801
+ * through max11803. The main difference between these 4 chips can be
+ * found in the table below:
+ * -----------------------------------------------------
+ * | CHIP     |  AUTO MODE SUPPORT(FIFO) | INTERFACE    |
+ * |----------------------------------------------------|
+ * | max11800 |  YES                     |   SPI        |
+ * | max11801 |  YES                     |   I2C        |
+ * | max11802 |  NO                      |   SPI        |
+ * | max11803 |  NO                      |   I2C        |
+ * ------------------------------------------------------
+ *
+ * Currently, this driver only supports max11801.
+ *
+ * Data Sheet:
+ * http://www.maxim-ic.com/datasheet/index.mvp/id/5943
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+
+/* Register Address define */
+#define GENERNAL_STATUS_REG            0x00
+#define GENERNAL_CONF_REG              0x01
+#define MESURE_RES_CONF_REG            0x02
+#define MESURE_AVER_CONF_REG           0x03
+#define ADC_SAMPLE_TIME_CONF_REG       0x04
+#define PANEL_SETUPTIME_CONF_REG       0x05
+#define DELAY_CONVERSION_CONF_REG      0x06
+#define TOUCH_DETECT_PULLUP_CONF_REG   0x07
+#define AUTO_MODE_TIME_CONF_REG                0x08 /* only for max11800/max11801 */
+#define APERTURE_CONF_REG              0x09 /* only for max11800/max11801 */
+#define AUX_MESURE_CONF_REG            0x0a
+#define OP_MODE_CONF_REG               0x0b
+
+/* FIFO is found only in max11800 and max11801 */
+#define FIFO_RD_CMD                    (0x50 << 1)
+#define MAX11801_FIFO_INT              (1 << 2)
+#define MAX11801_FIFO_OVERFLOW         (1 << 3)
+
+#define XY_BUFSIZE                     4
+#define XY_BUF_OFFSET                  4
+
+#define MAX11801_MAX_X                 0xfff
+#define MAX11801_MAX_Y                 0xfff
+
+#define MEASURE_TAG_OFFSET             2
+#define MEASURE_TAG_MASK               (3 << MEASURE_TAG_OFFSET)
+#define EVENT_TAG_OFFSET               0
+#define EVENT_TAG_MASK                 (3 << EVENT_TAG_OFFSET)
+#define MEASURE_X_TAG                  (0 << MEASURE_TAG_OFFSET)
+#define MEASURE_Y_TAG                  (1 << MEASURE_TAG_OFFSET)
+
+/* These are the state of touch event state machine */
+enum {
+       EVENT_INIT,
+       EVENT_MIDDLE,
+       EVENT_RELEASE,
+       EVENT_FIFO_END
+};
+
+struct max11801_data {
+       struct i2c_client               *client;
+       struct input_dev                *input_dev;
+};
+
+static u8 read_register(struct i2c_client *client, int addr)
+{
+       /* XXX: The chip ignores LSB of register address */
+       return i2c_smbus_read_byte_data(client, addr << 1);
+}
+
+static int max11801_write_reg(struct i2c_client *client, int addr, int data)
+{
+       /* XXX: The chip ignores LSB of register address */
+       return i2c_smbus_write_byte_data(client, addr << 1, data);
+}
+
+static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id)
+{
+       struct max11801_data *data = dev_id;
+       struct i2c_client *client = data->client;
+       int status, i, ret;
+       u8 buf[XY_BUFSIZE];
+       int x = -1;
+       int y = -1;
+
+       status = read_register(data->client, GENERNAL_STATUS_REG);
+
+       if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) {
+               status = read_register(data->client, GENERNAL_STATUS_REG);
+
+               ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD,
+                                                   XY_BUFSIZE, buf);
+
+               /*
+                * We should get 4 bytes buffer that contains X,Y
+                * and event tag
+                */
+               if (ret < XY_BUFSIZE)
+                       goto out;
+
+               for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) {
+                       if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG)
+                               x = (buf[i] << XY_BUF_OFFSET) +
+                                   (buf[i + 1] >> XY_BUF_OFFSET);
+                       else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG)
+                               y = (buf[i] << XY_BUF_OFFSET) +
+                                   (buf[i + 1] >> XY_BUF_OFFSET);
+               }
+
+               if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK))
+                       goto out;
+
+               switch (buf[1] & EVENT_TAG_MASK) {
+               case EVENT_INIT:
+                       /* fall through */
+               case EVENT_MIDDLE:
+                       input_report_abs(data->input_dev, ABS_X, x);
+                       input_report_abs(data->input_dev, ABS_Y, y);
+                       input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1);
+                       input_sync(data->input_dev);
+                       break;
+
+               case EVENT_RELEASE:
+                       input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0);
+                       input_sync(data->input_dev);
+                       break;
+
+               case EVENT_FIFO_END:
+                       break;
+               }
+       }
+out:
+       return IRQ_HANDLED;
+}
+
+static void __devinit max11801_ts_phy_init(struct max11801_data *data)
+{
+       struct i2c_client *client = data->client;
+
+       /* Average X,Y, take 16 samples, average eight media sample */
+       max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff);
+       /* X,Y panel setup time set to 20us */
+       max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11);
+       /* Rough pullup time (2uS), Fine pullup time (10us)  */
+       max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10);
+       /* Auto mode init period = 5ms , scan period = 5ms*/
+       max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa);
+       /* Aperture X,Y set to +- 4LSB */
+       max11801_write_reg(client, APERTURE_CONF_REG, 0x33);
+       /* Enable Power, enable Automode, enable Aperture, enable Average X,Y */
+       max11801_write_reg(client, OP_MODE_CONF_REG, 0x36);
+}
+
+static int __devinit max11801_ts_probe(struct i2c_client *client,
+                                      const struct i2c_device_id *id)
+{
+       struct max11801_data *data;
+       struct input_dev *input_dev;
+       int error;
+
+       data = kzalloc(sizeof(struct max11801_data), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!data || !input_dev) {
+               dev_err(&client->dev, "Failed to allocate memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       data->client = client;
+       data->input_dev = input_dev;
+
+       input_dev->name = "max11801_ts";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+
+       __set_bit(EV_ABS, input_dev->evbit);
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
+       input_set_abs_params(input_dev, ABS_X, 0, MAX11801_MAX_X, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0);
+       input_set_drvdata(input_dev, data);
+
+       max11801_ts_phy_init(data);
+
+       error = request_threaded_irq(client->irq, NULL, max11801_ts_interrupt,
+                                    IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                    "max11801_ts", data);
+       if (error) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto err_free_mem;
+       }
+
+       error = input_register_device(data->input_dev);
+       if (error)
+               goto err_free_irq;
+
+       i2c_set_clientdata(client, data);
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, data);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(data);
+       return error;
+}
+
+static __devexit int max11801_ts_remove(struct i2c_client *client)
+{
+       struct max11801_data *data = i2c_get_clientdata(client);
+
+       free_irq(client->irq, data);
+       input_unregister_device(data->input_dev);
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id max11801_ts_id[] = {
+       {"max11801", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
+
+static struct i2c_driver max11801_ts_driver = {
+       .driver = {
+               .name   = "max11801_ts",
+               .owner  = THIS_MODULE,
+       },
+       .id_table       = max11801_ts_id,
+       .probe          = max11801_ts_probe,
+       .remove         = __devexit_p(max11801_ts_remove),
+};
+
+static int __init max11801_ts_init(void)
+{
+       return i2c_add_driver(&max11801_ts_driver);
+}
+
+static void __exit max11801_ts_exit(void)
+{
+       i2c_del_driver(&max11801_ts_driver);
+}
+
+module_init(max11801_ts_init);
+module_exit(max11801_ts_exit);
+
+MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller");
+MODULE_LICENSE("GPL");
index 80467f262331e2c94ae9686f21e473b4d203f3f5..fadc11545b1eed03124b1c6cd152db8c737345de 100644 (file)
@@ -27,9 +27,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c/tsc2007.h>
 
-#define TS_POLL_DELAY                  1 /* ms delay between samples */
-#define TS_POLL_PERIOD                 1 /* ms delay between samples */
-
 #define TSC2007_MEASURE_TEMP0          (0x0 << 4)
 #define TSC2007_MEASURE_AUX            (0x2 << 4)
 #define TSC2007_MEASURE_TEMP1          (0x4 << 4)
@@ -75,6 +72,9 @@ struct tsc2007 {
 
        u16                     model;
        u16                     x_plate_ohms;
+       u16                     max_rt;
+       unsigned long           poll_delay;
+       unsigned long           poll_period;
 
        bool                    pendown;
        int                     irq;
@@ -156,6 +156,7 @@ static void tsc2007_work(struct work_struct *work)
 {
        struct tsc2007 *ts =
                container_of(to_delayed_work(work), struct tsc2007, work);
+       bool debounced = false;
        struct ts_event tc;
        u32 rt;
 
@@ -184,13 +185,14 @@ static void tsc2007_work(struct work_struct *work)
        tsc2007_read_values(ts, &tc);
 
        rt = tsc2007_calculate_pressure(ts, &tc);
-       if (rt > MAX_12BIT) {
+       if (rt > ts->max_rt) {
                /*
                 * Sample found inconsistent by debouncing or pressure is
                 * beyond the maximum. Don't report it to user space,
                 * repeat at least once more the measurement.
                 */
                dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
+               debounced = true;
                goto out;
 
        }
@@ -225,9 +227,9 @@ static void tsc2007_work(struct work_struct *work)
        }
 
  out:
-       if (ts->pendown)
+       if (ts->pendown || debounced)
                schedule_delayed_work(&ts->work,
-                                     msecs_to_jiffies(TS_POLL_PERIOD));
+                                     msecs_to_jiffies(ts->poll_period));
        else
                enable_irq(ts->irq);
 }
@@ -239,7 +241,7 @@ static irqreturn_t tsc2007_irq(int irq, void *handle)
        if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
                disable_irq_nosync(ts->irq);
                schedule_delayed_work(&ts->work,
-                                     msecs_to_jiffies(TS_POLL_DELAY));
+                                     msecs_to_jiffies(ts->poll_delay));
        }
 
        if (ts->clear_penirq)
@@ -292,6 +294,9 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
 
        ts->model             = pdata->model;
        ts->x_plate_ohms      = pdata->x_plate_ohms;
+       ts->max_rt            = pdata->max_rt ? : MAX_12BIT;
+       ts->poll_delay        = pdata->poll_delay ? : 1;
+       ts->poll_period       = pdata->poll_period ? : 1;
        ts->get_pendown_state = pdata->get_pendown_state;
        ts->clear_penirq      = pdata->clear_penirq;
 
@@ -305,9 +310,10 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
        input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 
-       input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
-       input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
-       input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
+       input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
+                       pdata->fuzzz, 0);
 
        if (pdata->init_platform_hw)
                pdata->init_platform_hw();
index 91f06a3ef00223a4403230579fa71f9cc404c7c1..61f516f376dc8d9dd2db0c9d366054c6cec4f266 100644 (file)
@@ -149,7 +149,7 @@ static void avmcs_release(struct pcmcia_device *link)
 } /* avmcs_release */
 
 
-static struct pcmcia_device_id avmcs_ids[] = {
+static const struct pcmcia_device_id avmcs_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
        PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
        PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
index ac4dd7857cbd3e50edb12b3eb715614a0e17643c..8f0ad2a52e8705adf33ca60624e871107918b315 100644 (file)
@@ -146,7 +146,7 @@ static void avma1cs_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 } /* avma1cs_release */
 
-static struct pcmcia_device_id avma1cs_ids[] = {
+static const struct pcmcia_device_id avma1cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
        PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
        PCMCIA_DEVICE_NULL
index 9e5e87be756b179db066467b8c3eefdba1d67b9c..f0b6c0ef99bbf58f25cf7ca49a420e31913b6b91 100644 (file)
@@ -200,7 +200,7 @@ static int elsa_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id elsa_ids[] = {
+static const struct pcmcia_device_id elsa_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
        PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
        PCMCIA_DEVICE_NULL
index 360204bc2777d6f2b941f478ab0a11d2881f07fb..06473f81f0395fd74d54dd44fd18b72c6a187b82 100644 (file)
@@ -186,7 +186,7 @@ static int sedlbauer_resume(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id sedlbauer_ids[] = {
+static const struct pcmcia_device_id sedlbauer_ids[] = {
        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a),
        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
        PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
index 360f9ec7c8023e73796ce66a1c6594324c0109a6..161a1938552ee6ba836c6a7a4ba6dcd9b459cd15 100644 (file)
@@ -183,7 +183,7 @@ static int teles_resume(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id teles_ids[] = {
+static const struct pcmcia_device_id teles_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
        PCMCIA_DEVICE_NULL,
 };
index bbc298fd2a1550b2a8de727d389273b47e82694a..496b7efbc6b079976646a7e9c593d652003cad0f 100644 (file)
@@ -76,7 +76,7 @@ static unsigned int switchlocked;
 #define BUSY_TIMEOUT      32767
 
 /* list of supported pcmcia devices */
-static struct pcmcia_device_id pcmcia_ids[] = {
+static const struct pcmcia_device_id pcmcia_ids[] = {
        /* vendor and device strings followed by their crc32 hashes */
        PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay1Controller", 0xd9f522ed,
                                0xc3901202),
index 6799e75d74e0387c251200a7e266506a8c59704d..33dc2829b01bc1ac7a54cbb21450aaee70307a49 100644 (file)
@@ -694,7 +694,7 @@ static int pcmciamtd_probe(struct pcmcia_device *link)
        return pcmciamtd_config(link);
 }
 
-static struct pcmcia_device_id pcmciamtd_ids[] = {
+static const struct pcmcia_device_id pcmciamtd_ids[] = {
        PCMCIA_DEVICE_FUNC_ID(1),
        PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCS-2M", "2MB SRAM", 0x547e66dc, 0x1fed36cd, 0x36eadd21),
        PCMCIA_DEVICE_PROD_ID12("IBM", "2MB SRAM", 0xb569a6e5, 0x36eadd21),
index af9fb0ff8210d5b3d34c3a2e788123b2a7745aaf..191f3bb3c41a7440a6cf831655c6431f31ec55f6 100644 (file)
@@ -115,7 +115,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
                mode = UBI_READONLY;
 
        dbg_gen("open device %d, volume %d, mode %d",
-               ubi_num, vol_id, mode);
+               ubi_num, vol_id, mode);
 
        desc = ubi_open_volume(ubi_num, vol_id, mode);
        if (IS_ERR(desc))
@@ -158,7 +158,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
        loff_t new_offset;
 
        if (vol->updating) {
-                /* Update is in progress, seeking is prohibited */
+               /* Update is in progress, seeking is prohibited */
                dbg_err("updating");
                return -EBUSY;
        }
@@ -561,18 +561,18 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
        }
 
        /* Set volume property command */
-       case UBI_IOCSETPROP:
+       case UBI_IOCSETVOLPROP:
        {
-               struct ubi_set_prop_req req;
+               struct ubi_set_vol_prop_req req;
 
                err = copy_from_user(&req, argp,
-                               sizeof(struct ubi_set_prop_req));
+                                    sizeof(struct ubi_set_vol_prop_req));
                if (err) {
                        err = -EFAULT;
                        break;
                }
                switch (req.property) {
-               case UBI_PROP_DIRECT_WRITE:
+               case UBI_VOL_PROP_DIRECT_WRITE:
                        mutex_lock(&ubi->device_mutex);
                        desc->vol->direct_writes = !!req.value;
                        mutex_unlock(&ubi->device_mutex);
@@ -1100,5 +1100,5 @@ const struct file_operations ubi_ctrl_cdev_operations = {
        .owner          = THIS_MODULE,
        .unlocked_ioctl = ctrl_cdev_ioctl,
        .compat_ioctl   = ctrl_cdev_compat_ioctl,
-       .llseek         = noop_llseek,
+       .llseek         = no_llseek,
 };
index d4d07e5f138f2ccdd4267d5166ee93647a71873f..2224cbe41ddf5cdab3b67c3dcd1c418c1a691f0b 100644 (file)
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 
-unsigned int ubi_msg_flags;
 unsigned int ubi_chk_flags;
 unsigned int ubi_tst_flags;
 
-module_param_named(debug_msgs, ubi_msg_flags, uint, S_IRUGO | S_IWUSR);
 module_param_named(debug_chks, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
 module_param_named(debug_tsts, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
 
-MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
 MODULE_PARM_DESC(debug_chks, "Debug check flags");
 MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
 
@@ -75,15 +72,15 @@ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
 {
        printk(KERN_DEBUG "Volume identifier header dump:\n");
        printk(KERN_DEBUG "\tmagic     %08x\n", be32_to_cpu(vid_hdr->magic));
-       printk(KERN_DEBUG "\tversion   %d\n",   (int)vid_hdr->version);
-       printk(KERN_DEBUG "\tvol_type  %d\n",   (int)vid_hdr->vol_type);
-       printk(KERN_DEBUG "\tcopy_flag %d\n",   (int)vid_hdr->copy_flag);
-       printk(KERN_DEBUG "\tcompat    %d\n",   (int)vid_hdr->compat);
-       printk(KERN_DEBUG "\tvol_id    %d\n",   be32_to_cpu(vid_hdr->vol_id));
-       printk(KERN_DEBUG "\tlnum      %d\n",   be32_to_cpu(vid_hdr->lnum));
-       printk(KERN_DEBUG "\tdata_size %d\n",   be32_to_cpu(vid_hdr->data_size));
-       printk(KERN_DEBUG "\tused_ebs  %d\n",   be32_to_cpu(vid_hdr->used_ebs));
-       printk(KERN_DEBUG "\tdata_pad  %d\n",   be32_to_cpu(vid_hdr->data_pad));
+       printk(KERN_DEBUG "\tversion   %d\n",  (int)vid_hdr->version);
+       printk(KERN_DEBUG "\tvol_type  %d\n",  (int)vid_hdr->vol_type);
+       printk(KERN_DEBUG "\tcopy_flag %d\n",  (int)vid_hdr->copy_flag);
+       printk(KERN_DEBUG "\tcompat    %d\n",  (int)vid_hdr->compat);
+       printk(KERN_DEBUG "\tvol_id    %d\n",  be32_to_cpu(vid_hdr->vol_id));
+       printk(KERN_DEBUG "\tlnum      %d\n",  be32_to_cpu(vid_hdr->lnum));
+       printk(KERN_DEBUG "\tdata_size %d\n",  be32_to_cpu(vid_hdr->data_size));
+       printk(KERN_DEBUG "\tused_ebs  %d\n",  be32_to_cpu(vid_hdr->used_ebs));
+       printk(KERN_DEBUG "\tdata_pad  %d\n",  be32_to_cpu(vid_hdr->data_pad));
        printk(KERN_DEBUG "\tsqnum     %llu\n",
                (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
        printk(KERN_DEBUG "\thdr_crc   %08x\n", be32_to_cpu(vid_hdr->hdr_crc));
index 0b0c2888c65694e4ca2782340c41da7c1f91cc5d..3f1a09c5c438dde93c11e48529cc2a3cec5d93a7 100644 (file)
 #ifndef __UBI_DEBUG_H__
 #define __UBI_DEBUG_H__
 
+struct ubi_ec_hdr;
+struct ubi_vid_hdr;
+struct ubi_volume;
+struct ubi_vtbl_record;
+struct ubi_scan_volume;
+struct ubi_scan_leb;
+struct ubi_mkvol_req;
+
 #ifdef CONFIG_MTD_UBI_DEBUG
 #include <linux/random.h>
 
-#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
-
 #define ubi_assert(expr)  do {                                               \
        if (unlikely(!(expr))) {                                             \
                printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
        }                                                                    \
 } while (0)
 
-#define dbg_msg(fmt, ...)                                    \
-       printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
-              current->pid, __func__, ##__VA_ARGS__)
-
-#define dbg_do_msg(typ, fmt, ...) do {                       \
-       if (ubi_msg_flags & typ)                             \
-               dbg_msg(fmt, ##__VA_ARGS__);                 \
-} while (0)
+#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
 
 #define ubi_dbg_dump_stack() dump_stack()
 
-struct ubi_ec_hdr;
-struct ubi_vid_hdr;
-struct ubi_volume;
-struct ubi_vtbl_record;
-struct ubi_scan_volume;
-struct ubi_scan_leb;
-struct ubi_mkvol_req;
+#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  \
+               print_hex_dump(l, ps, pt, r, g, b, len, a)
+
+#define ubi_dbg_msg(type, fmt, ...) \
+       pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__)
+
+/* Just a debugging messages not related to any specific UBI subsystem */
+#define dbg_msg(fmt, ...) ubi_dbg_msg("msg", fmt, ##__VA_ARGS__)
+/* General debugging messages */
+#define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__)
+/* Messages from the eraseblock association sub-system */
+#define dbg_eba(fmt, ...) ubi_dbg_msg("eba", fmt, ##__VA_ARGS__)
+/* Messages from the wear-leveling sub-system */
+#define dbg_wl(fmt, ...)  ubi_dbg_msg("wl", fmt, ##__VA_ARGS__)
+/* Messages from the input/output sub-system */
+#define dbg_io(fmt, ...)  ubi_dbg_msg("io", fmt, ##__VA_ARGS__)
+/* Initialization and build messages */
+#define dbg_bld(fmt, ...) ubi_dbg_msg("bld", fmt, ##__VA_ARGS__)
 
 void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
 void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
@@ -62,43 +72,6 @@ void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
 void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
 void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
 
-extern unsigned int ubi_msg_flags;
-
-/*
- * Debugging message type flags (must match msg_type_names in debug.c).
- *
- * UBI_MSG_GEN: general messages
- * UBI_MSG_EBA: journal messages
- * UBI_MSG_WL: mount messages
- * UBI_MSG_IO: commit messages
- * UBI_MSG_BLD: LEB find messages
- */
-enum {
-       UBI_MSG_GEN  = 0x1,
-       UBI_MSG_EBA  = 0x2,
-       UBI_MSG_WL   = 0x4,
-       UBI_MSG_IO   = 0x8,
-       UBI_MSG_BLD  = 0x10,
-};
-
-#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  \
-               print_hex_dump(l, ps, pt, r, g, b, len, a)
-
-/* General debugging messages */
-#define dbg_gen(fmt, ...) dbg_do_msg(UBI_MSG_GEN, fmt, ##__VA_ARGS__)
-
-/* Messages from the eraseblock association sub-system */
-#define dbg_eba(fmt, ...) dbg_do_msg(UBI_MSG_EBA, fmt, ##__VA_ARGS__)
-
-/* Messages from the wear-leveling sub-system */
-#define dbg_wl(fmt, ...) dbg_do_msg(UBI_MSG_WL, fmt, ##__VA_ARGS__)
-
-/* Messages from the input/output sub-system */
-#define dbg_io(fmt, ...) dbg_do_msg(UBI_MSG_IO, fmt, ##__VA_ARGS__)
-
-/* Initialization and build messages */
-#define dbg_bld(fmt, ...) dbg_do_msg(UBI_MSG_BLD, fmt, ##__VA_ARGS__)
-
 extern unsigned int ubi_chk_flags;
 
 /*
@@ -184,31 +157,61 @@ static inline int ubi_dbg_is_erase_failure(void)
 
 #else
 
-#define ubi_assert(expr)                 ({})
-#define dbg_err(fmt, ...)                ({})
-#define dbg_msg(fmt, ...)                ({})
-#define dbg_gen(fmt, ...)                ({})
-#define dbg_eba(fmt, ...)                ({})
-#define dbg_wl(fmt, ...)                 ({})
-#define dbg_io(fmt, ...)                 ({})
-#define dbg_bld(fmt, ...)                ({})
-#define ubi_dbg_dump_stack()             ({})
-#define ubi_dbg_dump_ec_hdr(ec_hdr)      ({})
-#define ubi_dbg_dump_vid_hdr(vid_hdr)    ({})
-#define ubi_dbg_dump_vol_info(vol)       ({})
-#define ubi_dbg_dump_vtbl_record(r, idx) ({})
-#define ubi_dbg_dump_sv(sv)              ({})
-#define ubi_dbg_dump_seb(seb, type)      ({})
-#define ubi_dbg_dump_mkvol_req(req)      ({})
-#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})
-#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a)  ({})
-
-#define ubi_dbg_is_bgt_disabled()  0
-#define ubi_dbg_is_bitflip()       0
-#define ubi_dbg_is_write_failure() 0
-#define ubi_dbg_is_erase_failure() 0
-#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
-#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
+/* Use "if (0)" to make compiler check arguments even if debugging is off */
+#define ubi_assert(expr)  do {                                               \
+       if (0) {                                                             \
+               printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
+                      __func__, __LINE__, current->pid);                    \
+       }                                                                    \
+} while (0)
+
+#define dbg_err(fmt, ...) do {                                               \
+       if (0)                                                               \
+               ubi_err(fmt, ##__VA_ARGS__);                                 \
+} while (0)
+
+#define ubi_dbg_msg(fmt, ...) do {                                           \
+       if (0)                                                               \
+               pr_debug(fmt "\n", ##__VA_ARGS__);                           \
+} while (0)
+
+#define dbg_msg(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gen(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_eba(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_wl(fmt, ...)   ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...)   ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_bld(fmt, ...)  ubi_dbg_msg(fmt, ##__VA_ARGS__)
+
+static inline void ubi_dbg_dump_stack(void)                          { return; }
+static inline void
+ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)                 { return; }
+static inline void
+ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)              { return; }
+static inline void
+ubi_dbg_dump_vol_info(const struct ubi_volume *vol)                  { return; }
+static inline void
+ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)   { return; }
+static inline void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) { return; }
+static inline void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb,
+                                   int type)                        { return; }
+static inline void
+ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)              { return; }
+static inline void ubi_dbg_dump_flash(struct ubi_device *ubi,
+                                     int pnum, int offset, int len) { return; }
+static inline void
+ubi_dbg_print_hex_dump(const char *l, const char *ps, int pt, int r,
+                      int g, const void *b, size_t len, bool a)     { return; }
+
+static inline int ubi_dbg_is_bgt_disabled(void)                    { return 0; }
+static inline int ubi_dbg_is_bitflip(void)                         { return 0; }
+static inline int ubi_dbg_is_write_failure(void)                   { return 0; }
+static inline int ubi_dbg_is_erase_failure(void)                   { return 0; }
+static inline int ubi_dbg_check_all_ff(struct ubi_device *ubi,
+                                      int pnum, int offset,
+                                      int len)                    { return 0; }
+static inline int ubi_dbg_check_write(struct ubi_device *ubi,
+                                     const void *buf, int pnum,
+                                     int offset, int len)         { return 0; }
 
 #endif /* !CONFIG_MTD_UBI_DEBUG */
 #endif /* !__UBI_DEBUG_H__ */
index e347cc4388edd5cad5e96d471458a642450f4271..8c1b1c7bc4a7dca93d75ccd2067f1094169b7783 100644 (file)
@@ -189,8 +189,8 @@ retry:
                }
 
                if (retries++ < UBI_IO_RETRIES) {
-                       dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
-                              " read only %zd bytes, retry",
+                       dbg_io("error %d%s while reading %d bytes from PEB "
+                              "%d:%d, read only %zd bytes, retry",
                               err, errstr, len, pnum, offset, read);
                        yield();
                        goto retry;
@@ -465,7 +465,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
        }
 
        err = patt_count;
-       ubi_msg("PEB %d passed torture test, do not mark it a bad", pnum);
+       ubi_msg("PEB %d passed torture test, do not mark it as bad", pnum);
 
 out:
        mutex_unlock(&ubi->buf_mutex);
index d2d12ab7def427c22cb6303d986ae3206575cb39..2135a53732ffce0dc0b4b7806637449f7ddec1f6 100644 (file)
@@ -1103,7 +1103,7 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
                 * otherwise, only print a warning.
                 */
                if (si->corr_peb_count >= max_corr) {
-                       ubi_err("too many corrupted PEBs, refusing this device");
+                       ubi_err("too many corrupted PEBs, refusing");
                        return -EINVAL;
                }
        }
index 503ea9b273094670d0933baafbfbfb04ae6d88cd..6fb8ec2174a53cd96b1e2646442e7e311d018cc5 100644 (file)
@@ -164,7 +164,7 @@ struct ubi_ec_hdr {
        __be32  image_seq;
        __u8    padding2[32];
        __be32  hdr_crc;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_vid_hdr - on-flash UBI volume identifier header.
@@ -292,7 +292,7 @@ struct ubi_vid_hdr {
        __be64  sqnum;
        __u8    padding3[12];
        __be32  hdr_crc;
-} __attribute__ ((packed));
+} __packed;
 
 /* Internal UBI volumes count */
 #define UBI_INT_VOL_COUNT 1
@@ -373,6 +373,6 @@ struct ubi_vtbl_record {
        __u8    flags;
        __u8    padding[23];
        __be32  crc;
-} __attribute__ ((packed));
+} __packed;
 
 #endif /* !__UBI_MEDIA_H__ */
index f1be8b79663cbfc3a5d87828cf8b12c2cd7d4c28..c6c22295898e97ef3fdbfa16fd4171ec650fb55a 100644 (file)
@@ -341,8 +341,8 @@ struct ubi_wl_entry;
  *      protected from the wear-leveling worker)
  * @pq_head: protection queue head
  * @wl_lock: protects the @used, @free, @pq, @pq_head, @lookuptbl, @move_from,
- *          @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
- *          @erroneous, and @erroneous_peb_count fields
+ *          @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
+ *          @erroneous, and @erroneous_peb_count fields
  * @move_mutex: serializes eraseblock moves
  * @work_sem: synchronizes the WL worker with use tasks
  * @wl_scheduled: non-zero if the wear-leveling was scheduled
index b4cf57db25561c8323ba97dbccdbc53a50d51306..ff2c4956eeff0aa08bbe0e528151104dd04fba68 100644 (file)
@@ -1570,7 +1570,8 @@ void ubi_wl_close(struct ubi_device *ubi)
  * @ec: the erase counter to check
  *
  * This function returns zero if the erase counter of physical eraseblock @pnum
- * is equivalent to @ec, and a negative error code if not or if an error occurred.
+ * is equivalent to @ec, and a negative error code if not or if an error
+ * occurred.
  */
 static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
 {
index c11bb4de86308171dcd8241eda70ff3eaa5aaf98..c0e1b1eb87a9d5ffa4b37bea76359472e2122075 100644 (file)
@@ -315,7 +315,7 @@ pcmcia_failed:
        return ret ?: -ENODEV;
 }
 
-static /*const*/ struct pcmcia_device_id softingcs_ids[] = {
+static const struct pcmcia_device_id softingcs_ids[] = {
        /* softing */
        PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
        PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
index 81ac330f931d67b6b15eab36faa415b20fbbca9f..34c5e1cbf65d30aa2f7491be4eb493375ac6482c 100644 (file)
@@ -1150,7 +1150,7 @@ static int el3_close(struct net_device *dev)
        return 0;
 }
 
-static struct pcmcia_device_id tc574_ids[] = {
+static const struct pcmcia_device_id tc574_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
        PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
        PCMCIA_DEVICE_NULL,
index 79b9ca0dbdb4351f3c7182833fae229e1b765222..4a1a358098075341d27d6e8de596bfb6428ba193 100644 (file)
@@ -908,7 +908,7 @@ static int el3_close(struct net_device *dev)
     return 0;
 }
 
-static struct pcmcia_device_id tc589_ids[] = {
+static const struct pcmcia_device_id tc589_ids[] = {
        PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
        PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
index 3077d72e8222b6fd78a6f6b2a8c08fd5c66eca85..9953db71196993c9eb6d7515a131a5d370e657c6 100644 (file)
@@ -687,7 +687,7 @@ static void block_output(struct net_device *dev, int count,
     outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
 }
 
-static struct pcmcia_device_id axnet_ids[] = {
+static const struct pcmcia_device_id axnet_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
        PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
        PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
index 27bfad76fc4077bdaa74187a79c2f0beb53c4ffc..980e65c14936e28957ac29187853b555a0d60a09 100644 (file)
@@ -316,7 +316,7 @@ static int com20020_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id com20020_ids[] = {
+static const struct pcmcia_device_id com20020_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
                        "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
        PCMCIA_DEVICE_PROD_ID12("SoHard AG",
index 530ab5a10bd3a8395e0ff4ef68b9732d21fda100..723815e7a9973e77116d6a089871449dddb93f2c 100644 (file)
@@ -667,7 +667,7 @@ static int fmvj18x_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id fmvj18x_ids[] = {
+static const struct pcmcia_device_id fmvj18x_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
        PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
        PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
index 15d57f5b6f2967b0eadb3335b1ec835230ec7f1b..6006d5488fbed8e07c17076a6630f7ccdb4aa680 100644 (file)
@@ -340,7 +340,7 @@ static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
     outb(0x40, dev->base_addr);
 }
 
-static struct pcmcia_device_id ibmtr_ids[] = {
+static const struct pcmcia_device_id ibmtr_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
        PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
        PCMCIA_DEVICE_NULL,
index 76683d97d83b11504a0cc2049aae45383659d79f..9d70b65952201c646d90f0e21bd9658d34ad2502 100644 (file)
@@ -1494,7 +1494,7 @@ static void set_multicast_list(struct net_device *dev)
 
 } /* set_multicast_list */
 
-static struct pcmcia_device_id nmclan_ids[] = {
+static const struct pcmcia_device_id nmclan_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941),
        PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet+", 0xebf1d60, 0xad673aaf),
        PCMCIA_DEVICE_NULL,
index e953793a33fffab32fe71a315e338c35f5b8fa5f..b4fd7c3ed07792dc6a88816c72946ee9c424f1ca 100644 (file)
@@ -1463,7 +1463,7 @@ failed:
 
 /*====================================================================*/
 
-static struct pcmcia_device_id pcnet_ids[] = {
+static const struct pcmcia_device_id pcnet_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15),
index 288e4f1317ee71943e417c55d6141cb3e0b5bf73..1cd9394c33598eb500796e9e6921ad5128d14cd9 100644 (file)
@@ -2014,7 +2014,7 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
        return rc;
 }
 
-static struct pcmcia_device_id smc91c92_ids[] = {
+static const struct pcmcia_device_id smc91c92_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
        PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
index a46b7fd6c0f5483f4a117f4c3c9a7e00b7b93e81..e33b190d716fc7f7cf0c56a8ca0783110e999c47 100644 (file)
@@ -1738,7 +1738,7 @@ do_stop(struct net_device *dev)
     return 0;
 }
 
-static struct pcmcia_device_id xirc2ps_ids[] = {
+static const struct pcmcia_device_id xirc2ps_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a),
        PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a),
        PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
index df2484d4547489c64404c0a8ab3e8579fb7cceba..c983c10e0f6a8336b855dc810f237172cf1c6ef2 100644 (file)
@@ -164,7 +164,7 @@ static int airo_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id airo_ids[] = {
+static const struct pcmcia_device_id airo_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a),
        PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005),
        PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007),
index 05263516c113f50cfcbff36e3ec94998832f203a..ec295c4f677d583876a92351638b0e15c31578a7 100644 (file)
@@ -122,7 +122,7 @@ static int atmel_config(struct pcmcia_device *link)
 {
        local_info_t *dev;
        int ret;
-       struct pcmcia_device_id *did;
+       const struct pcmcia_device_id *did;
 
        dev = link->priv;
        did = dev_get_drvdata(&link->dev);
@@ -211,7 +211,7 @@ static int atmel_resume(struct pcmcia_device *link)
        .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
         .driver_info = (kernel_ulong_t)(info), }
 
-static struct pcmcia_device_id atmel_ids[] = {
+static const struct pcmcia_device_id atmel_ids[] = {
        PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
        PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
        PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
index 7dcba5fafdc7fe04820bde7a10571f327fd6796d..2c8461dcf1b0b8f39df2c179a38f4200f4d4b46d 100644 (file)
@@ -32,7 +32,7 @@
 #include <pcmcia/cisreg.h>
 
 
-static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
+static const struct pcmcia_device_id b43_pcmcia_tbl[] = {
        PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
        PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
        PCMCIA_DEVICE_NULL,
index 2176edede39b78db45e337e313c860802b92f66b..c052a0d5cbdd909b68d0641aaed990065d1ea981 100644 (file)
@@ -620,7 +620,7 @@ static int hostap_cs_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id hostap_cs_ids[] = {
+static const struct pcmcia_device_id hostap_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
        PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
index 63ed5798365c217669be46c7152a6b86f623b01d..e269351798611b501f05a459fc28f5e59b563cc2 100644 (file)
@@ -983,7 +983,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev)
 /* Module initialization                                            */
 /********************************************************************/
 
-static struct pcmcia_device_id if_cs_ids[] = {
+static const struct pcmcia_device_id if_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
        PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
        PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
index 32954c4b243a9dc70bbb0fd350c6c79ff67875d3..88e3c0ebcaadb119f92e33eacd23f4abc1950735 100644 (file)
@@ -237,7 +237,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link)
 /* Module initialization                                           */
 /********************************************************************/
 
-static struct pcmcia_device_id orinoco_cs_ids[] = {
+static const struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
        PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
        PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
index db34c282e59b39340a9bf7c6c51f529bf020a1c0..81f3673d31d43c9f856076719a0ee5b8cf95feed 100644 (file)
@@ -301,7 +301,7 @@ spectrum_cs_resume(struct pcmcia_device *link)
 /* Module initialization                                           */
 /********************************************************************/
 
-static struct pcmcia_device_id spectrum_cs_ids[] = {
+static const struct pcmcia_device_id spectrum_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
        PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
        PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
index 0764d1a30d13f2637ae624d43446e26a07f6ffd9..2a06ebcd67c5cd1f24beba30df18de1d79cc3c12 100644 (file)
@@ -2781,7 +2781,7 @@ static const struct file_operations int_proc_fops = {
 };
 #endif
 
-static struct pcmcia_device_id ray_ids[] = {
+static const struct pcmcia_device_id ray_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
        PCMCIA_DEVICE_NULL,
 };
index fc08f36fe1f512697423990015df2ca0f049ac11..6bc7c92fbff73b580c5f0fc334f21407322aebad 100644 (file)
@@ -2000,7 +2000,7 @@ static int wl3501_resume(struct pcmcia_device *link)
 }
 
 
-static struct pcmcia_device_id wl3501_ids[] = {
+static const struct pcmcia_device_id wl3501_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),
        PCMCIA_DEVICE_NULL
 };
index 787ebdeae31032b853e6e2fce73750f4bf5e4e91..067ad517c1f51eae3ca4e0adbe5dc705d39066aa 100644 (file)
@@ -178,7 +178,7 @@ static void parport_cs_release(struct pcmcia_device *link)
 } /* parport_cs_release */
 
 
-static struct pcmcia_device_id parport_ids[] = {
+static const struct pcmcia_device_id parport_ids[] = {
        PCMCIA_DEVICE_FUNC_ID(3),
        PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
        PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
index 22c9b27fdd8d8bd0bc9790416cd2ef883f5b67e9..56098b3e17c054a678253c028221610dc17f3ff5 100644 (file)
@@ -3284,31 +3284,34 @@ static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode,
  * @dev: the PCI device
  * @decode: true = enable decoding, false = disable decoding
  * @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
- * @change_bridge: traverse ancestors and change bridges
+ * @change_bridge_flags: traverse ancestors and change bridges
+ * CHANGE_BRIDGE_ONLY / CHANGE_BRIDGE
  */
 int pci_set_vga_state(struct pci_dev *dev, bool decode,
-                     unsigned int command_bits, bool change_bridge)
+                     unsigned int command_bits, u32 flags)
 {
        struct pci_bus *bus;
        struct pci_dev *bridge;
        u16 cmd;
        int rc;
 
-       WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
+       WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
 
        /* ARCH specific VGA enables */
-       rc = pci_set_vga_state_arch(dev, decode, command_bits, change_bridge);
+       rc = pci_set_vga_state_arch(dev, decode, command_bits, flags);
        if (rc)
                return rc;
 
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       if (decode == true)
-               cmd |= command_bits;
-       else
-               cmd &= ~command_bits;
-       pci_write_config_word(dev, PCI_COMMAND, cmd);
+       if (flags & PCI_VGA_STATE_CHANGE_DECODES) {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               if (decode == true)
+                       cmd |= command_bits;
+               else
+                       cmd &= ~command_bits;
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
 
-       if (change_bridge == false)
+       if (!(flags & PCI_VGA_STATE_CHANGE_BRIDGE))
                return 0;
 
        bus = dev->bus;
index 100c4412457de1357348c9e9eb5b3c29ae8bbdd8..749c2a16012c582bca165db93f14cf4c21ec5293 100644 (file)
@@ -45,7 +45,7 @@ MODULE_LICENSE("GPL");
 
 static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
 {
-       struct pcmcia_device_id *did = p_drv->id_table;
+       const struct pcmcia_device_id *did = p_drv->id_table;
        unsigned int i;
        u32 hash;
 
@@ -784,7 +784,7 @@ static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filenam
 
 
 static inline int pcmcia_devmatch(struct pcmcia_device *dev,
-                                 struct pcmcia_device_id *did)
+                                 const struct pcmcia_device_id *did)
 {
        if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
                if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
@@ -890,7 +890,7 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
        struct pcmcia_driver *p_drv = to_pcmcia_drv(drv);
-       struct pcmcia_device_id *did = p_drv->id_table;
+       const struct pcmcia_device_id *did = p_drv->id_table;
        struct pcmcia_dynid *dynid;
 
        /* match dynamic devices first */
index fb9740d3e9a76e5b30317860ebafee954eef0a6c..2eea664bc079665823804114d9aa4e82af9885fc 100644 (file)
@@ -43,7 +43,7 @@
 
 int __init pcmcia_collie_init(struct device *dev);
 
-static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
+static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) __devinitdata = {
 #ifdef CONFIG_SA1100_ASSABET
        pcmcia_assabet_init,
 #endif
index 485c09eef424eeb3d1b2e4f06c191cc33722a4f3..5cb999b50f95a7580d90fe6ea3675282ccdea6f4 100644 (file)
@@ -753,4 +753,11 @@ config SAMSUNG_LAPTOP
          To compile this driver as a module, choose M here: the module
          will be called samsung-laptop.
 
+config MXM_WMI
+       tristate "WMI support for MXM Laptop Graphics"
+       depends on ACPI_WMI
+       ---help---
+          MXM is a standard for laptop graphics cards, the WMI interface
+         is required for switchable nvidia graphics machines
+
 endif # X86_PLATFORM_DEVICES
index 029e8861d086d19cbc5c28bafb15a449717a0af4..a7ab3bc7b3a182cefb4eefa38f5d0263dfe37a23 100644 (file)
@@ -42,3 +42,4 @@ obj-$(CONFIG_XO15_EBOOK)      += xo15-ebook.o
 obj-$(CONFIG_IBM_RTL)          += ibm_rtl.o
 obj-$(CONFIG_SAMSUNG_LAPTOP)   += samsung-laptop.o
 obj-$(CONFIG_INTEL_MFLD_THERMAL)       += intel_mid_thermal.o
+obj-$(CONFIG_MXM_WMI)          += mxm-wmi.o
diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c
new file mode 100644 (file)
index 0000000..0aea63b
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * MXM WMI driver
+ *
+ * Copyright(C) 2010 Red Hat.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Dave Airlie");
+MODULE_DESCRIPTION("MXM WMI Driver");
+MODULE_LICENSE("GPL");
+
+#define MXM_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
+
+MODULE_ALIAS("wmi:"MXM_WMMX_GUID);
+
+#define MXM_WMMX_FUNC_MXDS 0x5344584D /* "MXDS" */
+#define MXM_WMMX_FUNC_MXMX 0x53445344 /* "MXMX" */
+
+struct mxds_args {
+       u32 func;
+       u32 args;
+       u32 xarg;
+};
+
+int mxm_wmi_call_mxds(int adapter)
+{
+       struct mxds_args args = {
+               .func = MXM_WMMX_FUNC_MXDS,
+               .args = 0,
+               .xarg = 1,
+       };
+       struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+
+       printk("calling mux switch %d\n", adapter);
+
+       status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
+                                    &output);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       printk("mux switched %d\n", status);
+       return 0;
+                           
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_call_mxds);
+
+int mxm_wmi_call_mxmx(int adapter)
+{
+       struct mxds_args args = {
+               .func = MXM_WMMX_FUNC_MXMX,
+               .args = 0,
+               .xarg = 1,
+       };
+       struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+
+       printk("calling mux switch %d\n", adapter);
+
+       status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
+                                    &output);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       printk("mux mutex set switched %d\n", status);
+       return 0;
+                           
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_call_mxmx);
+
+bool mxm_wmi_supported(void)
+{
+       bool guid_valid;
+       guid_valid = wmi_has_guid(MXM_WMMX_GUID);
+       return guid_valid;
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_supported);
+
+static int __init mxm_wmi_init(void)
+{
+       return 0;
+}
+
+static void __exit mxm_wmi_exit(void)
+{
+}
+
+module_init(mxm_wmi_init);
+module_exit(mxm_wmi_exit);
index 2b771f18d1adc836f36c6c509060af409f9f1bed..c388eda1e2b195943200e4af7308ee1c69935083 100644 (file)
@@ -253,13 +253,11 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
  */
 void dasd_alias_lcu_setup_complete(struct dasd_device *device)
 {
-       struct dasd_eckd_private *private;
        unsigned long flags;
        struct alias_server *server;
        struct alias_lcu *lcu;
        struct dasd_uid uid;
 
-       private = (struct dasd_eckd_private *) device->private;
        device->discipline->get_uid(device, &uid);
        lcu = NULL;
        spin_lock_irqsave(&aliastree.lock, flags);
@@ -279,13 +277,11 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device)
 
 void dasd_alias_wait_for_lcu_setup(struct dasd_device *device)
 {
-       struct dasd_eckd_private *private;
        unsigned long flags;
        struct alias_server *server;
        struct alias_lcu *lcu;
        struct dasd_uid uid;
 
-       private = (struct dasd_eckd_private *) device->private;
        device->discipline->get_uid(device, &uid);
        lcu = NULL;
        spin_lock_irqsave(&aliastree.lock, flags);
index 3ebdf5f92f8f945fabad2e9744fa82f106b8a33b..30fb979d684d0043d2b1f6b0aff2fda6ebe8cfcd 100644 (file)
@@ -1611,10 +1611,8 @@ static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr,
 
 static int dasd_eckd_start_analysis(struct dasd_block *block)
 {
-       struct dasd_eckd_private *private;
        struct dasd_ccw_req *init_cqr;
 
-       private = (struct dasd_eckd_private *) block->base->private;
        init_cqr = dasd_eckd_analysis_ccw(block->base);
        if (IS_ERR(init_cqr))
                return PTR_ERR(init_cqr);
@@ -2264,7 +2262,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
                                               unsigned int blk_per_trk,
                                               unsigned int blksize)
 {
-       struct dasd_eckd_private *private;
        unsigned long *idaws;
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
@@ -2283,7 +2280,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
        unsigned int recoffs;
 
        basedev = block->base;
-       private = (struct dasd_eckd_private *) basedev->private;
        if (rq_data_dir(req) == READ)
                cmd = DASD_ECKD_CCW_READ_TRACK_DATA;
        else if (rq_data_dir(req) == WRITE)
@@ -2556,8 +2552,7 @@ static int prepare_itcw(struct itcw *itcw,
 
        dcw = itcw_add_dcw(itcw, pfx_cmd, 0,
                     &pfxdata, sizeof(pfxdata), total_data_size);
-
-       return rc;
+       return IS_ERR(dcw) ? PTR_ERR(dcw) : 0;
 }
 
 static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
@@ -2573,7 +2568,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
                                               unsigned int blk_per_trk,
                                               unsigned int blksize)
 {
-       struct dasd_eckd_private *private;
        struct dasd_ccw_req *cqr;
        struct req_iterator iter;
        struct bio_vec *bv;
@@ -2594,7 +2588,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
        unsigned int count, count_to_trk_end;
 
        basedev = block->base;
-       private = (struct dasd_eckd_private *) basedev->private;
        if (rq_data_dir(req) == READ) {
                cmd = DASD_ECKD_CCW_READ_TRACK_DATA;
                itcw_op = ITCW_OP_READ;
@@ -2801,7 +2794,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
                                               struct dasd_block *block,
                                               struct request *req)
 {
-       struct dasd_eckd_private *private;
        unsigned long *idaws;
        struct dasd_device *basedev;
        struct dasd_ccw_req *cqr;
@@ -2836,7 +2828,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
        trkcount = last_trk - first_trk + 1;
        first_offs = 0;
        basedev = block->base;
-       private = (struct dasd_eckd_private *) basedev->private;
 
        if (rq_data_dir(req) == READ)
                cmd = DASD_ECKD_CCW_READ_TRACK;
index dcee3c5c89543db8c8cdddc77b50841341b353c7..a4f117d9fdc6aa0bcc10c9741293b6a862c128c0 100644 (file)
@@ -119,18 +119,6 @@ config S390_TAPE
 comment "S/390 tape interface support"
        depends on S390_TAPE
 
-config S390_TAPE_BLOCK
-       def_bool y
-       prompt "Support for tape block devices"
-       depends on S390_TAPE && BLOCK
-       help
-         Select this option if you want to access your channel-attached tape
-         devices using the block device interface.  This interface is similar
-         to CD-ROM devices on other platforms.  The tapes can only be
-         accessed read-only when using this interface.  Have a look at
-         <file:Documentation/s390/TAPE> for further information about creating
-         volumes for and using this interface.  It is safe to say "Y" here.
-
 comment "S/390 tape hardware support"
        depends on S390_TAPE
 
index efb500ab66c07d84c79176328d6596d92aa8ca00..f3c325207445513c5aca471d413845b6a90980d3 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
-        sclp_cmd.o sclp_config.o sclp_cpi_sys.o
+        sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -22,7 +22,6 @@ obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o
 obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
 obj-$(CONFIG_VMCP) += vmcp.o
 
-tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o
 tape-$(CONFIG_PROC_FS) += tape_proc.o
 tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y)
 obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o
index e0702d3ea33ba669223b5237f3a60acba8cfa35e..4600aa10a1c6c5824f36168fb83b414d2e4e915b 100644 (file)
@@ -97,7 +97,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv)
 {
        struct monwrite_hdr *monhdr = &monpriv->hdr;
        struct mon_buf *monbuf;
-       int rc;
+       int rc = 0;
 
        if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
            monhdr->mon_function > MONWRITE_START_CONFIG ||
@@ -135,7 +135,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv)
                        mon_buf_count++;
        }
        monpriv->current_buf = monbuf;
-       return 0;
+       return rc;
 }
 
 static int monwrite_new_data(struct mon_private *monpriv)
index e21a5c39ef20f2f29609ee989eb75213e6f99f84..810ac38631c35ac919ba7fb110c80d38d75b260f 100644 (file)
@@ -598,7 +598,6 @@ __raw3270_size_device(struct raw3270 *rp)
        static const unsigned char wbuf[] =
                { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
        struct raw3270_ua *uap;
-       unsigned short count;
        int rc;
 
        /*
@@ -653,7 +652,6 @@ __raw3270_size_device(struct raw3270 *rp)
        if (rc)
                return rc;
        /* Got a Query Reply */
-       count = sizeof(rp->init_data) - rp->init_request.rescnt;
        uap = (struct raw3270_ua *) (rp->init_data + 1);
        /* Paranoia check. */
        if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
index 6bb5a6bdfab52a6d7e66dbcd872b0b2ed9d9ed37..49a1bb52bc87a378b44bc169931377a1290c5225 100644 (file)
@@ -28,6 +28,7 @@
 #define EVTYP_CONFMGMDATA      0x04
 #define EVTYP_SDIAS            0x1C
 #define EVTYP_ASYNC            0x0A
+#define EVTYP_OCF              0x1E
 
 #define EVTYP_OPCMD_MASK       0x80000000
 #define EVTYP_MSG_MASK         0x40000000
@@ -40,6 +41,7 @@
 #define EVTYP_CONFMGMDATA_MASK 0x10000000
 #define EVTYP_SDIAS_MASK       0x00000010
 #define EVTYP_ASYNC_MASK       0x00400000
+#define EVTYP_OCF_MASK         0x00000004
 
 #define GNRLMSGFLGS_DOM                0x8000
 #define GNRLMSGFLGS_SNDALRM    0x4000
@@ -186,4 +188,26 @@ sclp_ascebc_str(unsigned char *str, int nr)
        (MACHINE_IS_VM) ? ASCEBC(str, nr) : ASCEBC_500(str, nr);
 }
 
+static inline struct gds_vector *
+sclp_find_gds_vector(void *start, void *end, u16 id)
+{
+       struct gds_vector *v;
+
+       for (v = start; (void *) v < end; v = (void *) v + v->length)
+               if (v->gds_id == id)
+                       return v;
+       return NULL;
+}
+
+static inline struct gds_subvector *
+sclp_find_gds_subvector(void *start, void *end, u8 key)
+{
+       struct gds_subvector *sv;
+
+       for (sv = start; (void *) sv < end; sv = (void *) sv + sv->length)
+               if (sv->key == key)
+                       return sv;
+       return NULL;
+}
+
 #endif  /* __SCLP_H__ */
index 16e232a99fb7f09150f9e6ecac15c171bc9575f1..95b909ac2b73bf4359b4ea1903db8a817d802e18 100644 (file)
@@ -71,21 +71,9 @@ static struct sclp_register sclp_conf_register =
 
 static int __init sclp_conf_init(void)
 {
-       int rc;
-
        INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
        INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
-
-       rc = sclp_register(&sclp_conf_register);
-       if (rc)
-               return rc;
-
-       if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) {
-               pr_warning("no configuration management.\n");
-               sclp_unregister(&sclp_conf_register);
-               rc = -ENOSYS;
-       }
-       return rc;
+       return sclp_register(&sclp_conf_register);
 }
 
 __initcall(sclp_conf_init);
diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c
new file mode 100644 (file)
index 0000000..ab294d5
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *  drivers/s390/char/sclp_ocf.c
+ *    SCLP OCF communication parameters sysfs interface
+ *
+ *    Copyright IBM Corp. 2011
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#define KMSG_COMPONENT "sclp_ocf"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <asm/ebcdic.h>
+#include <asm/sclp.h>
+
+#include "sclp.h"
+
+#define OCF_LENGTH_HMC_NETWORK 8UL
+#define OCF_LENGTH_CPC_NAME 8UL
+
+static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1];
+static char cpc_name[OCF_LENGTH_CPC_NAME + 1];
+
+static DEFINE_SPINLOCK(sclp_ocf_lock);
+static struct work_struct sclp_ocf_change_work;
+
+static struct kset *ocf_kset;
+
+static void sclp_ocf_change_notify(struct work_struct *work)
+{
+       kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE);
+}
+
+/* Handler for OCF event. Look for the CPC image name. */
+static void sclp_ocf_handler(struct evbuf_header *evbuf)
+{
+       struct gds_vector *v;
+       struct gds_subvector *sv, *netid, *cpc;
+       size_t size;
+
+       /* Find the 0x9f00 block. */
+       v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length,
+                                0x9f00);
+       if (!v)
+               return;
+       /* Find the 0x9f22 block inside the 0x9f00 block. */
+       v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22);
+       if (!v)
+               return;
+       /* Find the 0x81 block inside the 0x9f22 block. */
+       sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81);
+       if (!sv)
+               return;
+       /* Find the 0x01 block inside the 0x81 block. */
+       netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1);
+       /* Find the 0x02 block inside the 0x81 block. */
+       cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2);
+       /* Copy network name and cpc name. */
+       spin_lock(&sclp_ocf_lock);
+       if (netid) {
+               size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length);
+               memcpy(hmc_network, netid + 1, size);
+               EBCASC(hmc_network, size);
+               hmc_network[size] = 0;
+       }
+       if (cpc) {
+               size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length);
+               memcpy(cpc_name, cpc + 1, size);
+               EBCASC(cpc_name, size);
+               cpc_name[size] = 0;
+       }
+       spin_unlock(&sclp_ocf_lock);
+       schedule_work(&sclp_ocf_change_work);
+}
+
+static struct sclp_register sclp_ocf_event = {
+       .receive_mask = EVTYP_OCF_MASK,
+       .receiver_fn = sclp_ocf_handler,
+};
+
+static ssize_t cpc_name_show(struct kobject *kobj,
+                            struct kobj_attribute *attr, char *page)
+{
+       int rc;
+
+       spin_lock_irq(&sclp_ocf_lock);
+       rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name);
+       spin_unlock_irq(&sclp_ocf_lock);
+       return rc;
+}
+
+static struct kobj_attribute cpc_name_attr =
+       __ATTR(cpc_name, 0444, cpc_name_show, NULL);
+
+static ssize_t hmc_network_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *page)
+{
+       int rc;
+
+       spin_lock_irq(&sclp_ocf_lock);
+       rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network);
+       spin_unlock_irq(&sclp_ocf_lock);
+       return rc;
+}
+
+static struct kobj_attribute hmc_network_attr =
+       __ATTR(hmc_network, 0444, hmc_network_show, NULL);
+
+static struct attribute *ocf_attrs[] = {
+       &cpc_name_attr.attr,
+       &hmc_network_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ocf_attr_group = {
+       .attrs = ocf_attrs,
+};
+
+static int __init ocf_init(void)
+{
+       int rc;
+
+       INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify);
+       ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj);
+       if (!ocf_kset)
+               return -ENOMEM;
+
+       rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group);
+       if (rc) {
+               kset_unregister(ocf_kset);
+               return rc;
+       }
+
+       return sclp_register(&sclp_ocf_event);
+}
+
+device_initcall(ocf_init);
index 6a1c58dc61a78e920c4e626ab61b04f1747c3418..fa733ecd3d70fe8c21915dc915d2c058a000eefa 100644 (file)
@@ -69,9 +69,6 @@ static DEFINE_MUTEX(sdias_mutex);
 
 static void sdias_callback(struct sclp_req *request, void *data)
 {
-       struct sdias_sccb *cbsccb;
-
-       cbsccb = (struct sdias_sccb *) request->sccb;
        sclp_req_done = 1;
        wake_up(&sdias_wq); /* Inform caller, that request is complete */
        TRACE("callback done\n");
index 8258d590505f1444e9a4a4ed8cab036fe400b72e..a879c139926ac0deb7ed012684813ca90f934113 100644 (file)
@@ -408,118 +408,72 @@ static int sclp_switch_cases(unsigned char *buf, int count)
        return op - buf;
 }
 
-static void
-sclp_get_input(unsigned char *start, unsigned char *end)
+static void sclp_get_input(struct gds_subvector *sv)
 {
+       unsigned char *str;
        int count;
 
-       count = end - start;
+       str = (unsigned char *) (sv + 1);
+       count = sv->length - sizeof(*sv);
        if (sclp_tty_tolower)
-               EBC_TOLOWER(start, count);
-       count = sclp_switch_cases(start, count);
+               EBC_TOLOWER(str, count);
+       count = sclp_switch_cases(str, count);
        /* convert EBCDIC to ASCII (modify original input in SCCB) */
-       sclp_ebcasc_str(start, count);
+       sclp_ebcasc_str(str, count);
 
        /* transfer input to high level driver */
-       sclp_tty_input(start, count);
-}
-
-static inline struct gds_vector *
-find_gds_vector(struct gds_vector *start, struct gds_vector *end, u16 id)
-{
-       struct gds_vector *vec;
-
-       for (vec = start; vec < end; vec = (void *) vec + vec->length)
-               if (vec->gds_id == id)
-                       return vec;
-       return NULL;
+       sclp_tty_input(str, count);
 }
 
-static inline struct gds_subvector *
-find_gds_subvector(struct gds_subvector *start,
-                  struct gds_subvector *end, u8 key)
+static inline void sclp_eval_selfdeftextmsg(struct gds_subvector *sv)
 {
-       struct gds_subvector *subvec;
+       void *end;
 
-       for (subvec = start; subvec < end;
-            subvec = (void *) subvec + subvec->length)
-               if (subvec->key == key)
-                       return subvec;
-       return NULL;
+       end = (void *) sv + sv->length;
+       for (sv = sv + 1; (void *) sv < end; sv = (void *) sv + sv->length)
+               if (sv->key == 0x30)
+                       sclp_get_input(sv);
 }
 
-static inline void
-sclp_eval_selfdeftextmsg(struct gds_subvector *start,
-                        struct gds_subvector *end)
+static inline void sclp_eval_textcmd(struct gds_vector *v)
 {
-       struct gds_subvector *subvec;
-
-       subvec = start;
-       while (subvec < end) {
-               subvec = find_gds_subvector(subvec, end, 0x30);
-               if (!subvec)
-                       break;
-               sclp_get_input((unsigned char *)(subvec + 1),
-                              (unsigned char *) subvec + subvec->length);
-               subvec = (void *) subvec + subvec->length;
-       }
-}
+       struct gds_subvector *sv;
+       void *end;
 
-static inline void
-sclp_eval_textcmd(struct gds_subvector *start,
-                 struct gds_subvector *end)
-{
-       struct gds_subvector *subvec;
+       end = (void *) v + v->length;
+       for (sv = (struct gds_subvector *) (v + 1);
+            (void *) sv < end; sv = (void *) sv + sv->length)
+               if (sv->key == GDS_KEY_SELFDEFTEXTMSG)
+                       sclp_eval_selfdeftextmsg(sv);
 
-       subvec = start;
-       while (subvec < end) {
-               subvec = find_gds_subvector(subvec, end,
-                                           GDS_KEY_SELFDEFTEXTMSG);
-               if (!subvec)
-                       break;
-               sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1),
-                                        (void *)subvec + subvec->length);
-               subvec = (void *) subvec + subvec->length;
-       }
 }
 
-static inline void
-sclp_eval_cpmsu(struct gds_vector *start, struct gds_vector *end)
+static inline void sclp_eval_cpmsu(struct gds_vector *v)
 {
-       struct gds_vector *vec;
+       void *end;
 
-       vec = start;
-       while (vec < end) {
-               vec = find_gds_vector(vec, end, GDS_ID_TEXTCMD);
-               if (!vec)
-                       break;
-               sclp_eval_textcmd((struct gds_subvector *)(vec + 1),
-                                 (void *) vec + vec->length);
-               vec = (void *) vec + vec->length;
-       }
+       end = (void *) v + v->length;
+       for (v = v + 1; (void *) v < end; v = (void *) v + v->length)
+               if (v->gds_id == GDS_ID_TEXTCMD)
+                       sclp_eval_textcmd(v);
 }
 
 
-static inline void
-sclp_eval_mdsmu(struct gds_vector *start, void *end)
+static inline void sclp_eval_mdsmu(struct gds_vector *v)
 {
-       struct gds_vector *vec;
-
-       vec = find_gds_vector(start, end, GDS_ID_CPMSU);
-       if (vec)
-               sclp_eval_cpmsu(vec + 1, (void *) vec + vec->length);
+       v = sclp_find_gds_vector(v + 1, (void *) v + v->length, GDS_ID_CPMSU);
+       if (v)
+               sclp_eval_cpmsu(v);
 }
 
-static void
-sclp_tty_receiver(struct evbuf_header *evbuf)
+static void sclp_tty_receiver(struct evbuf_header *evbuf)
 {
-       struct gds_vector *start, *end, *vec;
+       struct gds_vector *v;
 
-       start = (struct gds_vector *)(evbuf + 1);
-       end = (void *) evbuf + evbuf->length;
-       vec = find_gds_vector(start, end, GDS_ID_MDSMU);
-       if (vec)
-               sclp_eval_mdsmu(vec + 1, (void *) vec + vec->length);
+       v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length,
+                                GDS_ID_MDSMU);
+       if (v)
+               sclp_eval_mdsmu(v);
 }
 
 static void
index b98dcbd16711e7978d8c1fc58394f4797d851fe8..a7d570728882cae1ce2443baa44044e1f824f00e 100644 (file)
@@ -796,10 +796,8 @@ static void tape_3590_med_state_set(struct tape_device *device,
 static int
 tape_3590_done(struct tape_device *device, struct tape_request *request)
 {
-       struct tape_3590_disc_data *disc_data;
 
        DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
-       disc_data = device->discdata;
 
        switch (request->op) {
        case TO_BSB:
@@ -1394,17 +1392,12 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
 static int tape_3590_crypt_error(struct tape_device *device,
                                 struct tape_request *request, struct irb *irb)
 {
-       u8 cu_rc, ekm_rc1;
+       u8 cu_rc;
        u16 ekm_rc2;
-       u32 drv_rc;
-       const char *bus_id;
        char *sense;
 
        sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
-       bus_id = dev_name(&device->cdev->dev);
        cu_rc = sense[0];
-       drv_rc = *((u32*) &sense[5]) & 0xffffff;
-       ekm_rc1 = sense[9];
        ekm_rc2 = *((u16*) &sense[10]);
        if ((cu_rc == 0) && (ekm_rc2 == 0xee31))
                /* key not defined on EKM */
@@ -1429,7 +1422,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
                     struct irb *irb)
 {
        struct tape_3590_sense *sense;
-       int rc;
 
 #ifdef CONFIG_S390_TAPE_BLOCK
        if (request->op == TO_BLOCK) {
@@ -1454,7 +1446,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
         *   - "break":     basic error recovery is done
         *   - "goto out:": just print error message if available
         */
-       rc = -EIO;
        switch (sense->rc_rqc) {
 
        case 0x1110:
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
deleted file mode 100644 (file)
index 1b3924c..0000000
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- *  drivers/s390/char/tape_block.c
- *    block device frontend for tape device driver
- *
- *  S390 and zSeries version
- *    Copyright (C) 2001,2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Carsten Otte <cotte@de.ibm.com>
- *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
- *              Stefan Bader <shbader@de.ibm.com>
- */
-
-#define KMSG_COMPONENT "tape"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <linux/buffer_head.h>
-#include <linux/kernel.h>
-
-#include <asm/debug.h>
-
-#define TAPE_DBF_AREA  tape_core_dbf
-
-#include "tape.h"
-
-#define TAPEBLOCK_MAX_SEC      100
-#define TAPEBLOCK_MIN_REQUEUE  3
-
-/*
- * 2003/11/25  Stefan Bader <shbader@de.ibm.com>
- *
- * In 2.5/2.6 the block device request function is very likely to be called
- * with disabled interrupts (e.g. generic_unplug_device). So the driver can't
- * just call any function that tries to allocate CCW requests from that con-
- * text since it might sleep. There are two choices to work around this:
- *     a) do not allocate with kmalloc but use its own memory pool
- *      b) take requests from the queue outside that context, knowing that
- *         allocation might sleep
- */
-
-/*
- * file operation structure for tape block frontend
- */
-static DEFINE_MUTEX(tape_block_mutex);
-static int tapeblock_open(struct block_device *, fmode_t);
-static int tapeblock_release(struct gendisk *, fmode_t);
-static unsigned int tapeblock_check_events(struct gendisk *, unsigned int);
-static int tapeblock_revalidate_disk(struct gendisk *);
-
-static const struct block_device_operations tapeblock_fops = {
-       .owner           = THIS_MODULE,
-       .open            = tapeblock_open,
-       .release         = tapeblock_release,
-       .check_events    = tapeblock_check_events,
-       .revalidate_disk = tapeblock_revalidate_disk,
-};
-
-static int tapeblock_major = 0;
-
-static void
-tapeblock_trigger_requeue(struct tape_device *device)
-{
-       /* Protect against rescheduling. */
-       if (atomic_cmpxchg(&device->blk_data.requeue_scheduled, 0, 1) != 0)
-               return;
-       schedule_work(&device->blk_data.requeue_task);
-}
-
-/*
- * Post finished request.
- */
-static void
-__tapeblock_end_request(struct tape_request *ccw_req, void *data)
-{
-       struct tape_device *device;
-       struct request *req;
-
-       DBF_LH(6, "__tapeblock_end_request()\n");
-
-       device = ccw_req->device;
-       req = (struct request *) data;
-       blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO);
-       if (ccw_req->rc == 0)
-               /* Update position. */
-               device->blk_data.block_position =
-                 (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B;
-       else
-               /* We lost the position information due to an error. */
-               device->blk_data.block_position = -1;
-       device->discipline->free_bread(ccw_req);
-       if (!list_empty(&device->req_queue) ||
-           blk_peek_request(device->blk_data.request_queue))
-               tapeblock_trigger_requeue(device);
-}
-
-/*
- * Feed the tape device CCW queue with requests supplied in a list.
- */
-static int
-tapeblock_start_request(struct tape_device *device, struct request *req)
-{
-       struct tape_request *   ccw_req;
-       int                     rc;
-
-       DBF_LH(6, "tapeblock_start_request(%p, %p)\n", device, req);
-
-       ccw_req = device->discipline->bread(device, req);
-       if (IS_ERR(ccw_req)) {
-               DBF_EVENT(1, "TBLOCK: bread failed\n");
-               blk_end_request_all(req, -EIO);
-               return PTR_ERR(ccw_req);
-       }
-       ccw_req->callback = __tapeblock_end_request;
-       ccw_req->callback_data = (void *) req;
-       ccw_req->retries = TAPEBLOCK_RETRIES;
-
-       rc = tape_do_io_async(device, ccw_req);
-       if (rc) {
-               /*
-                * Start/enqueueing failed. No retries in
-                * this case.
-                */
-               blk_end_request_all(req, -EIO);
-               device->discipline->free_bread(ccw_req);
-       }
-
-       return rc;
-}
-
-/*
- * Move requests from the block device request queue to the tape device ccw
- * queue.
- */
-static void
-tapeblock_requeue(struct work_struct *work) {
-       struct tape_blk_data *  blkdat;
-       struct tape_device *    device;
-       struct request_queue *  queue;
-       int                     nr_queued;
-       struct request *        req;
-       struct list_head *      l;
-       int                     rc;
-
-       blkdat = container_of(work, struct tape_blk_data, requeue_task);
-       device = blkdat->device;
-       if (!device)
-               return;
-
-       spin_lock_irq(get_ccwdev_lock(device->cdev));
-       queue  = device->blk_data.request_queue;
-
-       /* Count number of requests on ccw queue. */
-       nr_queued = 0;
-       list_for_each(l, &device->req_queue)
-               nr_queued++;
-       spin_unlock(get_ccwdev_lock(device->cdev));
-
-       spin_lock_irq(&device->blk_data.request_queue_lock);
-       while (
-               blk_peek_request(queue) &&
-               nr_queued < TAPEBLOCK_MIN_REQUEUE
-       ) {
-               req = blk_fetch_request(queue);
-               if (rq_data_dir(req) == WRITE) {
-                       DBF_EVENT(1, "TBLOCK: Rejecting write request\n");
-                       spin_unlock_irq(&device->blk_data.request_queue_lock);
-                       blk_end_request_all(req, -EIO);
-                       spin_lock_irq(&device->blk_data.request_queue_lock);
-                       continue;
-               }
-               nr_queued++;
-               spin_unlock_irq(&device->blk_data.request_queue_lock);
-               rc = tapeblock_start_request(device, req);
-               spin_lock_irq(&device->blk_data.request_queue_lock);
-       }
-       spin_unlock_irq(&device->blk_data.request_queue_lock);
-       atomic_set(&device->blk_data.requeue_scheduled, 0);
-}
-
-/*
- * Tape request queue function. Called from ll_rw_blk.c
- */
-static void
-tapeblock_request_fn(struct request_queue *queue)
-{
-       struct tape_device *device;
-
-       device = (struct tape_device *) queue->queuedata;
-       DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device);
-       BUG_ON(device == NULL);
-       tapeblock_trigger_requeue(device);
-}
-
-/*
- * This function is called for every new tapedevice
- */
-int
-tapeblock_setup_device(struct tape_device * device)
-{
-       struct tape_blk_data *  blkdat;
-       struct gendisk *        disk;
-       int                     rc;
-
-       blkdat = &device->blk_data;
-       blkdat->device = device;
-       spin_lock_init(&blkdat->request_queue_lock);
-       atomic_set(&blkdat->requeue_scheduled, 0);
-
-       blkdat->request_queue = blk_init_queue(
-               tapeblock_request_fn,
-               &blkdat->request_queue_lock
-       );
-       if (!blkdat->request_queue)
-               return -ENOMEM;
-
-       rc = elevator_change(blkdat->request_queue, "noop");
-       if (rc)
-               goto cleanup_queue;
-
-       blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE);
-       blk_queue_max_hw_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC);
-       blk_queue_max_segments(blkdat->request_queue, -1L);
-       blk_queue_max_segment_size(blkdat->request_queue, -1L);
-       blk_queue_segment_boundary(blkdat->request_queue, -1L);
-
-       disk = alloc_disk(1);
-       if (!disk) {
-               rc = -ENOMEM;
-               goto cleanup_queue;
-       }
-
-       disk->major = tapeblock_major;
-       disk->first_minor = device->first_minor;
-       disk->fops = &tapeblock_fops;
-       disk->private_data = tape_get_device(device);
-       disk->queue = blkdat->request_queue;
-       set_capacity(disk, 0);
-       sprintf(disk->disk_name, "btibm%d",
-               device->first_minor / TAPE_MINORS_PER_DEV);
-
-       blkdat->disk = disk;
-       blkdat->medium_changed = 1;
-       blkdat->request_queue->queuedata = tape_get_device(device);
-
-       add_disk(disk);
-
-       tape_get_device(device);
-       INIT_WORK(&blkdat->requeue_task, tapeblock_requeue);
-
-       return 0;
-
-cleanup_queue:
-       blk_cleanup_queue(blkdat->request_queue);
-       blkdat->request_queue = NULL;
-
-       return rc;
-}
-
-void
-tapeblock_cleanup_device(struct tape_device *device)
-{
-       flush_work_sync(&device->blk_data.requeue_task);
-       tape_put_device(device);
-
-       if (!device->blk_data.disk) {
-               goto cleanup_queue;
-       }
-
-       del_gendisk(device->blk_data.disk);
-       device->blk_data.disk->private_data = NULL;
-       tape_put_device(device);
-       put_disk(device->blk_data.disk);
-
-       device->blk_data.disk = NULL;
-cleanup_queue:
-       device->blk_data.request_queue->queuedata = NULL;
-       tape_put_device(device);
-
-       blk_cleanup_queue(device->blk_data.request_queue);
-       device->blk_data.request_queue = NULL;
-}
-
-/*
- * Detect number of blocks of the tape.
- * FIXME: can we extent this to detect the blocks size as well ?
- */
-static int
-tapeblock_revalidate_disk(struct gendisk *disk)
-{
-       struct tape_device *    device;
-       unsigned int            nr_of_blks;
-       int                     rc;
-
-       device = (struct tape_device *) disk->private_data;
-       BUG_ON(!device);
-
-       if (!device->blk_data.medium_changed)
-               return 0;
-
-       rc = tape_mtop(device, MTFSFM, 1);
-       if (rc)
-               return rc;
-
-       rc = tape_mtop(device, MTTELL, 1);
-       if (rc < 0)
-               return rc;
-
-       pr_info("%s: Determining the size of the recorded area...\n",
-               dev_name(&device->cdev->dev));
-       DBF_LH(3, "Image file ends at %d\n", rc);
-       nr_of_blks = rc;
-
-       /* This will fail for the first file. Catch the error by checking the
-        * position. */
-       tape_mtop(device, MTBSF, 1);
-
-       rc = tape_mtop(device, MTTELL, 1);
-       if (rc < 0)
-               return rc;
-
-       if (rc > nr_of_blks)
-               return -EINVAL;
-
-       DBF_LH(3, "Image file starts at %d\n", rc);
-       device->bof = rc;
-       nr_of_blks -= rc;
-
-       pr_info("%s: The size of the recorded area is %i blocks\n",
-               dev_name(&device->cdev->dev), nr_of_blks);
-       set_capacity(device->blk_data.disk,
-               nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512));
-
-       device->blk_data.block_position = 0;
-       device->blk_data.medium_changed = 0;
-       return 0;
-}
-
-static unsigned int
-tapeblock_check_events(struct gendisk *disk, unsigned int clearing)
-{
-       struct tape_device *device;
-
-       device = (struct tape_device *) disk->private_data;
-       DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n",
-               device, device->blk_data.medium_changed);
-
-       return device->blk_data.medium_changed ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-/*
- * Block frontend tape device open function.
- */
-static int
-tapeblock_open(struct block_device *bdev, fmode_t mode)
-{
-       struct gendisk *        disk = bdev->bd_disk;
-       struct tape_device *    device;
-       int                     rc;
-
-       mutex_lock(&tape_block_mutex);
-       device = tape_get_device(disk->private_data);
-
-       if (device->required_tapemarks) {
-               DBF_EVENT(2, "TBLOCK: missing tapemarks\n");
-               pr_warning("%s: Opening the tape failed because of missing "
-                          "end-of-file marks\n", dev_name(&device->cdev->dev));
-               rc = -EPERM;
-               goto put_device;
-       }
-
-       rc = tape_open(device);
-       if (rc)
-               goto put_device;
-
-       rc = tapeblock_revalidate_disk(disk);
-       if (rc)
-               goto release;
-
-       /*
-        * Note: The reference to <device> is hold until the release function
-        *       is called.
-        */
-       tape_state_set(device, TS_BLKUSE);
-       mutex_unlock(&tape_block_mutex);
-       return 0;
-
-release:
-       tape_release(device);
- put_device:
-       tape_put_device(device);
-       mutex_unlock(&tape_block_mutex);
-       return rc;
-}
-
-/*
- * Block frontend tape device release function.
- *
- * Note: One reference to the tape device was made by the open function. So
- *       we just get the pointer here and release the reference.
- */
-static int
-tapeblock_release(struct gendisk *disk, fmode_t mode)
-{
-       struct tape_device *device = disk->private_data;
-       mutex_lock(&tape_block_mutex);
-       tape_state_set(device, TS_IN_USE);
-       tape_release(device);
-       tape_put_device(device);
-       mutex_unlock(&tape_block_mutex);
-
-       return 0;
-}
-
-/*
- * Initialize block device frontend.
- */
-int
-tapeblock_init(void)
-{
-       int rc;
-
-       /* Register the tape major number to the kernel */
-       rc = register_blkdev(tapeblock_major, "tBLK");
-       if (rc < 0)
-               return rc;
-
-       if (tapeblock_major == 0)
-               tapeblock_major = rc;
-       return 0;
-}
-
-/*
- * Deregister major for block device frontend
- */
-void
-tapeblock_exit(void)
-{
-       unregister_blkdev(tapeblock_major, "tBLK");
-}
index 3c3f342149ecd09d7b48334550047425fe42105c..e7650170274ac3e3ee12e6f1deca3bdd1e826b95 100644 (file)
@@ -564,7 +564,6 @@ int
 tape_std_mtreten(struct tape_device *device, int mt_count)
 {
        struct tape_request *request;
-       int rc;
 
        request = tape_alloc_request(4, 0);
        if (IS_ERR(request))
@@ -576,7 +575,7 @@ tape_std_mtreten(struct tape_device *device, int mt_count)
        tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL);
        tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr);
        /* execute it, MTRETEN rc gets ignored */
-       rc = tape_do_io_interruptible(device, request);
+       tape_do_io_interruptible(device, request);
        tape_free_request(request);
        return tape_mtop(device, MTREW, 1);
 }
index 0689fcf23a118b0b8917bd3a16199ce6539107a1..75c3f1f8fd434301c3ba4a07a632e0ffefa6aac3 100644 (file)
@@ -326,6 +326,36 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
        s390_process_res_acc(&link);
 }
 
+static void chsc_process_sei_chp_avail(struct chsc_sei_area *sei_area)
+{
+       struct channel_path *chp;
+       struct chp_id chpid;
+       u8 *data;
+       int num;
+
+       CIO_CRW_EVENT(4, "chsc: channel path availability information\n");
+       if (sei_area->rs != 0)
+               return;
+       data = sei_area->ccdf;
+       chp_id_init(&chpid);
+       for (num = 0; num <= __MAX_CHPID; num++) {
+               if (!chp_test_bit(data, num))
+                       continue;
+               chpid.id = num;
+
+               CIO_CRW_EVENT(4, "Update information for channel path "
+                             "%x.%02x\n", chpid.cssid, chpid.id);
+               chp = chpid_to_chp(chpid);
+               if (!chp) {
+                       chp_new(chpid);
+                       continue;
+               }
+               mutex_lock(&chp->lock);
+               chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+               mutex_unlock(&chp->lock);
+       }
+}
+
 struct chp_config_data {
        u8 map[32];
        u8 op;
@@ -376,9 +406,12 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area)
        case 1: /* link incident*/
                chsc_process_sei_link_incident(sei_area);
                break;
-       case 2: /* i/o resource accessibiliy */
+       case 2: /* i/o resource accessibility */
                chsc_process_sei_res_acc(sei_area);
                break;
+       case 7: /* channel-path-availability information */
+               chsc_process_sei_chp_avail(sei_area);
+               break;
        case 8: /* channel-path-configuration notification */
                chsc_process_sei_chp_config(sei_area);
                break;
index 6084103672b5ee9df3732958cff89f8d78653ec0..52c233fa2b1281d14a2881618465606447bef365 100644 (file)
@@ -408,9 +408,10 @@ ccw_device_done(struct ccw_device *cdev, int state)
                CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel "
                              "%04x\n", cdev->private->dev_id.devno,
                              sch->schid.sch_no);
-               if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK)
+               if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) {
+                       cdev->private->state = DEV_STATE_NOT_OPER;
                        ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
-               else
+               else
                        ccw_device_set_disconnected(cdev);
                cdev->private->flags.donotify = 0;
                break;
@@ -840,9 +841,6 @@ call_handler:
 static void
 ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
 {
-       struct subchannel *sch;
-
-       sch = to_subchannel(cdev->dev.parent);
        ccw_device_set_timeout(cdev, 0);
        /* Start delayed path verification. */
        ccw_device_online_verify(cdev, 0);
index 651976b54af80395547d675f1c538580521e0644..f98698d5735e887e0fb6cc46f00a63012ecdccb5 100644 (file)
@@ -418,12 +418,9 @@ int ccw_device_resume(struct ccw_device *cdev)
 int
 ccw_device_call_handler(struct ccw_device *cdev)
 {
-       struct subchannel *sch;
        unsigned int stctl;
        int ending_status;
 
-       sch = to_subchannel(cdev->dev.parent);
-
        /*
         * we allow for the device action handler if .
         *  - we received ending status
index e8f267eb88873b2a65e8d0cb05bcce3dc5c2c33c..55e8f721e38a7209e5875c60c1af7b3c1486fb1a 100644 (file)
@@ -1446,7 +1446,7 @@ set:
 static int handle_outbound(struct qdio_q *q, unsigned int callflags,
                           int bufnr, int count)
 {
-       unsigned char state;
+       unsigned char state = 0;
        int used, rc = 0;
 
        qperf_inc(q, outbound_call);
index 67302b944ab34e996364c60f849ea3961ad6b81e..16e4a25596e78a03e53adc88d6170008b1ef3f2a 100644 (file)
@@ -1183,8 +1183,12 @@ static void ap_scan_bus(struct work_struct *unused)
                INIT_LIST_HEAD(&ap_dev->list);
                setup_timer(&ap_dev->timeout, ap_request_timeout,
                            (unsigned long) ap_dev);
-               if (device_type == 0)
-                       ap_probe_device_type(ap_dev);
+               if (device_type == 0) {
+                       if (ap_probe_device_type(ap_dev)) {
+                               kfree(ap_dev);
+                               continue;
+                       }
+               }
                else
                        ap_dev->device_type = device_type;
 
index e77dd02eccddcba823d2f7faec9f13a97237689d..7d1609fa233c118e10afdd58463b40dcaad3e56b 100644 (file)
@@ -202,7 +202,7 @@ static int aha152x_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id aha152x_ids[] = {
+static const struct pcmcia_device_id aha152x_ids[] = {
        PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e),
        PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e),
        PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20),
index cd69c2670f810dd7ca7a738a5a75ef0ba4b28a52..714b248f5d5e675bae69c9f4361db060dcce02a6 100644 (file)
@@ -178,7 +178,7 @@ static int fdomain_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id fdomain_ids[] = {
+static const struct pcmcia_device_id fdomain_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20),
        PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
        PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f),
index 54bdf6d85c6d4e0346369fed960becdaa958216f..ca86721a71b94730b995b99a7c3e7aded4b1951f 100644 (file)
@@ -1752,7 +1752,7 @@ static int nsp_cs_resume(struct pcmcia_device *link)
 /*======================================================================*
  *     module entry point
  *====================================================================*/
-static struct pcmcia_device_id nsp_cs_ids[] = {
+static const struct pcmcia_device_id nsp_cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16       ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
        PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
        PCMCIA_DEVICE_PROD_ID123("KME    ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
index 9c96ca889ec97ac03d9bdaec0329b3e967c2250e..bcaf89fe0c9ed886099925a53d1f2cc27b46f412 100644 (file)
@@ -270,7 +270,7 @@ static int qlogic_resume(struct pcmcia_device *link)
        return 0;
 }
 
-static struct pcmcia_device_id qlogic_ids[] = {
+static const struct pcmcia_device_id qlogic_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
        PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
        PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
index 8552296edaa1e8062504e4b8ee63d46cc19694e2..f5b52731abd946949f768c224f950fee2b6693f1 100644 (file)
@@ -865,7 +865,7 @@ MODULE_AUTHOR("Bob Tracy <rct@frus.com>");
 MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");
 MODULE_LICENSE("GPL");
 
-static struct pcmcia_device_id sym53c500_ids[] = {
+static const struct pcmcia_device_id sym53c500_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("BASICS by New Media Corporation", "SCSI Sym53C500", 0x23c78a9d, 0x0099e7f7),
        PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "SCSI Bus Toaster Sym53C500", 0x085a850b, 0x45432eb8),
        PCMCIA_DEVICE_PROD_ID2("SCSI9000", 0x21648f44),
index 8856bcca9d2933db4a8f98526bc716c6640bb075..ae2cd1c1fda8868d5febe3e151e7849045c571cd 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/spi/spi.h>
 
 #include <asm/coldfire.h>
+#include <asm/mcfsim.h>
 #include <asm/mcfqspi.h>
 
 #define        DRIVER_NAME "mcfqspi"
index bb93685d8b93e9fbf8d9474069aa6945314738cf..8a1b8a7fa15fc67028ed9c089a87a06931e20444 100644 (file)
@@ -772,7 +772,7 @@ static int das16cs_pcmcia_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id das16cs_id_table[] = {
+static const struct pcmcia_device_id das16cs_id_table[] = {
        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039),
        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009),
        PCMCIA_DEVICE_NULL
index 0b32a2df776829c497274fd8074b3b34e05d726e..6d91d3028178c5ac61ae9d4e9eaf70f45d9f6924 100644 (file)
@@ -219,7 +219,7 @@ static int das08_pcmcia_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id das08_cs_id_table[] = {
+static const struct pcmcia_device_id das08_cs_id_table[] = {
        PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001),
        PCMCIA_DEVICE_NULL
 };
index 6b7372eed90d639ecb0d475440be01857b1d9114..2672629e9ff92937bacca4e084b4be642391eeff 100644 (file)
@@ -552,7 +552,7 @@ static int dio700_cs_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id dio700_cs_ids[] = {
+static const struct pcmcia_device_id dio700_cs_ids[] = {
        /* N.B. These IDs should match those in dio700_boards */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),        /* daqcard-700 */
        PCMCIA_DEVICE_NULL
index c9c28584db67dbc910c0c1882a2e071d6198c2e4..49b824c7bd2eb2820df373a2aa1af3947074a76e 100644 (file)
@@ -304,7 +304,7 @@ static int dio24_cs_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id dio24_cs_ids[] = {
+static const struct pcmcia_device_id dio24_cs_ids[] = {
        /* N.B. These IDs should match those in dio24_boards */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x475c),        /* daqcard-dio24 */
        PCMCIA_DEVICE_NULL
index 6facbc8bf77660093b7b504cb65eb08c737589e1..832a5178b638e38c0ceff0335ce7758712c7a16d 100644 (file)
@@ -267,7 +267,7 @@ static int labpc_cs_resume(struct pcmcia_device *link)
        return 0;
 }                              /* labpc_cs_resume */
 
-static struct pcmcia_device_id labpc_cs_ids[] = {
+static const struct pcmcia_device_id labpc_cs_ids[] = {
        /* N.B. These IDs should match those in labpc_cs_boards (ni_labpc.c) */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0103),        /* daqcard-1200 */
        PCMCIA_DEVICE_NULL
index 49563273f605c659b05467f25d836d912291b796..53ec24bb6dcec06b7c89610d22d9178873b99467 100644 (file)
@@ -416,7 +416,7 @@ static int ni_getboardtype(struct comedi_device *dev,
 
 #ifdef MODULE
 
-static struct pcmcia_device_id ni_mio_cs_ids[] = {
+static const struct pcmcia_device_id ni_mio_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010d),        /* DAQCard-ai-16xe-50 */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010c),        /* DAQCard-ai-16e-4 */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x02c4),        /* DAQCard-6062E */
index 82942e5728a50cae765ee071ca789fd7b41753c5..e0bb73445dd80daf2ee8a50c48b14ba7a78fc32e 100644 (file)
@@ -1087,7 +1087,7 @@ static int daqp_cs_resume(struct pcmcia_device *link)
 
 #ifdef MODULE
 
-static struct pcmcia_device_id daqp_cs_id_table[] = {
+static const struct pcmcia_device_id daqp_cs_id_table[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0027),
        PCMCIA_DEVICE_NULL
 };
index 10af47700efb19aee2d4b8ec4bf53cf5713bcfd5..68ea035635f48bbcd794e28c4033de2c1050e72b 100644 (file)
@@ -284,7 +284,7 @@ static int ft1000_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static struct pcmcia_device_id ft1000_ids[] = {
+static const struct pcmcia_device_id ft1000_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x02cc, 0x0100),
        PCMCIA_DEVICE_MANF_CARD(0x02cc, 0x1000),
        PCMCIA_DEVICE_MANF_CARD(0x02cc, 0x1300),
index 6555891e149c809c56a014f7f1511a063a3cb8df..a3a727c3b40f2a6a21fbb86e075e9ab6d802752e 100644 (file)
@@ -378,7 +378,7 @@ int wl_adapter_close(struct net_device *dev)
 } /* wl_adapter_close */
 /*============================================================================*/
 
-static struct pcmcia_device_id wl_adapter_ids[] = {
+static const struct pcmcia_device_id wl_adapter_ids[] = {
 #if !((HCF_TYPE) & HCF_TYPE_HII5)
        PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0003),
        PCMCIA_DEVICE_PROD_ID12("Agere Systems", "Wireless PC Card Model 0110",
index d005b9eeebbcc1f751763c7ab039c9dea13333ca..05032e2cc95465dbc29949138b7f333272b91579 100644 (file)
@@ -157,7 +157,7 @@ static void ixj_cs_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }
 
-static struct pcmcia_device_id ixj_ids[] = {
+static const struct pcmcia_device_id ixj_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0257, 0x0600),
        PCMCIA_DEVICE_NULL
 };
index 444155a305ae1a3ad26d35a19b79ff83643167d6..655c7948261c79771ef7b788f1a0ca7559336408 100644 (file)
@@ -33,7 +33,7 @@
 #include <pcmcia/ss.h>
 #include <pcmcia/ds.h>
 
-static struct pcmcia_device_id ipw_ids[] = {
+static const struct pcmcia_device_id ipw_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),
        PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0200),
        PCMCIA_DEVICE_NULL
index 652bdac8ce8ec4a56e9cb99506d0d61744c9661b..6d5d6e679fc7f59c568a0a1afbac800e51f91e49 100644 (file)
@@ -1420,7 +1420,7 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port,
        port->flags             = UPF_BOOT_AUTOCONF;
        port->ops               = &atmel_pops;
        port->fifosize          = 1;
-       port->line              = pdev->id;
+       port->line              = data->num;
        port->dev               = &pdev->dev;
        port->mapbase   = pdev->resource[0].start;
        port->irq       = pdev->resource[1].start;
index 1ef4df9bf7e4f785bc609778a0819958ab9d1685..eef736ff810af9d03a5a5036b682b4ac479b6084 100644 (file)
@@ -670,7 +670,7 @@ failed:
        return -ENODEV;
 }
 
-static struct pcmcia_device_id serial_ids[] = {
+static const struct pcmcia_device_id serial_ids[] = {
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
index 3775c035a6c56c994078357e9f1a55c5b2b02312..3b6f50eaec9134f596cd15958464578fea8ae1e6 100644 (file)
@@ -187,7 +187,7 @@ static int sl811_cs_probe(struct pcmcia_device *link)
        return sl811_cs_config(link);
 }
 
-static struct pcmcia_device_id sl811_ids[] = {
+static const struct pcmcia_device_id sl811_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */
        PCMCIA_DEVICE_NULL,
 };
index 397d3057d336a201b744a6ceadec16eaed651c0e..1bffbe0ed7787d96bd8b36cc25d2bd74a1c3572f 100644 (file)
@@ -820,6 +820,8 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
        int res;
        char buf[16];
 
+       memset(&bprm, 0, sizeof(bprm));
+
        /* Create the file name */
        sprintf(buf, "/lib/lib%d.so", id);
 
@@ -835,6 +837,12 @@ static int load_flat_shared_library(int id, struct lib_info *libs)
        if (!bprm.cred)
                goto out;
 
+       /* We don't really care about recalculating credentials at this point
+        * as we're past the point of no return and are dealing with shared
+        * libraries.
+        */
+       bprm.cred_prepared = 1;
+
        res = prepare_binprm(&bprm);
 
        if (!IS_ERR_VALUE(res))
index 0d329ff8ed4cf65127c7e017bda08f988977e12e..9b026ea8baa94a92205213249723491237ae803d 100644 (file)
@@ -100,6 +100,7 @@ struct dlm_cluster {
        unsigned int cl_log_debug;
        unsigned int cl_protocol;
        unsigned int cl_timewarn_cs;
+       unsigned int cl_waitwarn_us;
 };
 
 enum {
@@ -114,6 +115,7 @@ enum {
        CLUSTER_ATTR_LOG_DEBUG,
        CLUSTER_ATTR_PROTOCOL,
        CLUSTER_ATTR_TIMEWARN_CS,
+       CLUSTER_ATTR_WAITWARN_US,
 };
 
 struct cluster_attribute {
@@ -166,6 +168,7 @@ CLUSTER_ATTR(scan_secs, 1);
 CLUSTER_ATTR(log_debug, 0);
 CLUSTER_ATTR(protocol, 0);
 CLUSTER_ATTR(timewarn_cs, 1);
+CLUSTER_ATTR(waitwarn_us, 0);
 
 static struct configfs_attribute *cluster_attrs[] = {
        [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
@@ -179,6 +182,7 @@ static struct configfs_attribute *cluster_attrs[] = {
        [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
        [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr,
        [CLUSTER_ATTR_TIMEWARN_CS] = &cluster_attr_timewarn_cs.attr,
+       [CLUSTER_ATTR_WAITWARN_US] = &cluster_attr_waitwarn_us.attr,
        NULL,
 };
 
@@ -439,6 +443,7 @@ static struct config_group *make_cluster(struct config_group *g,
        cl->cl_log_debug = dlm_config.ci_log_debug;
        cl->cl_protocol = dlm_config.ci_protocol;
        cl->cl_timewarn_cs = dlm_config.ci_timewarn_cs;
+       cl->cl_waitwarn_us = dlm_config.ci_waitwarn_us;
 
        space_list = &sps->ss_group;
        comm_list = &cms->cs_group;
@@ -986,6 +991,7 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
 #define DEFAULT_LOG_DEBUG          0
 #define DEFAULT_PROTOCOL           0
 #define DEFAULT_TIMEWARN_CS      500 /* 5 sec = 500 centiseconds */
+#define DEFAULT_WAITWARN_US       0
 
 struct dlm_config_info dlm_config = {
        .ci_tcp_port = DEFAULT_TCP_PORT,
@@ -998,6 +1004,7 @@ struct dlm_config_info dlm_config = {
        .ci_scan_secs = DEFAULT_SCAN_SECS,
        .ci_log_debug = DEFAULT_LOG_DEBUG,
        .ci_protocol = DEFAULT_PROTOCOL,
-       .ci_timewarn_cs = DEFAULT_TIMEWARN_CS
+       .ci_timewarn_cs = DEFAULT_TIMEWARN_CS,
+       .ci_waitwarn_us = DEFAULT_WAITWARN_US
 };
 
index 4f1d6fce58c5e2ff47cadf83de384e788b2f4756..dd0ce24d5a802c83907146db0c7eb32c5dfe6aa3 100644 (file)
@@ -28,6 +28,7 @@ struct dlm_config_info {
        int ci_log_debug;
        int ci_protocol;
        int ci_timewarn_cs;
+       int ci_waitwarn_us;
 };
 
 extern struct dlm_config_info dlm_config;
index b94204913011e088c82a294712d7aa8a64457c73..0262451eb9c6e90cf77d71fb955fff7f60c44668 100644 (file)
@@ -209,6 +209,7 @@ struct dlm_args {
 #define DLM_IFL_WATCH_TIMEWARN 0x00400000
 #define DLM_IFL_TIMEOUT_CANCEL 0x00800000
 #define DLM_IFL_DEADLOCK_CANCEL        0x01000000
+#define DLM_IFL_STUB_MS                0x02000000 /* magic number for m_flags */
 #define DLM_IFL_USER           0x00000001
 #define DLM_IFL_ORPHAN         0x00000002
 
@@ -245,6 +246,7 @@ struct dlm_lkb {
 
        int8_t                  lkb_wait_type;  /* type of reply waiting for */
        int8_t                  lkb_wait_count;
+       int                     lkb_wait_nodeid; /* for debugging */
 
        struct list_head        lkb_idtbl_list; /* lockspace lkbtbl */
        struct list_head        lkb_statequeue; /* rsb g/c/w list */
@@ -254,6 +256,7 @@ struct dlm_lkb {
        struct list_head        lkb_ownqueue;   /* list of locks for a process */
        struct list_head        lkb_time_list;
        ktime_t                 lkb_timestamp;
+       ktime_t                 lkb_wait_time;
        unsigned long           lkb_timeout_cs;
 
        struct dlm_callback     lkb_callbacks[DLM_CALLBACKS_SIZE];
index 56d6bfcc1e48895f2d9523d70376779349b44cfa..f71d0b5abd954db4dee39e5288c7835584f0cc36 100644 (file)
@@ -799,10 +799,84 @@ static int msg_reply_type(int mstype)
        return -1;
 }
 
+static int nodeid_warned(int nodeid, int num_nodes, int *warned)
+{
+       int i;
+
+       for (i = 0; i < num_nodes; i++) {
+               if (!warned[i]) {
+                       warned[i] = nodeid;
+                       return 0;
+               }
+               if (warned[i] == nodeid)
+                       return 1;
+       }
+       return 0;
+}
+
+void dlm_scan_waiters(struct dlm_ls *ls)
+{
+       struct dlm_lkb *lkb;
+       ktime_t zero = ktime_set(0, 0);
+       s64 us;
+       s64 debug_maxus = 0;
+       u32 debug_scanned = 0;
+       u32 debug_expired = 0;
+       int num_nodes = 0;
+       int *warned = NULL;
+
+       if (!dlm_config.ci_waitwarn_us)
+               return;
+
+       mutex_lock(&ls->ls_waiters_mutex);
+
+       list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
+               if (ktime_equal(lkb->lkb_wait_time, zero))
+                       continue;
+
+               debug_scanned++;
+
+               us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_wait_time));
+
+               if (us < dlm_config.ci_waitwarn_us)
+                       continue;
+
+               lkb->lkb_wait_time = zero;
+
+               debug_expired++;
+               if (us > debug_maxus)
+                       debug_maxus = us;
+
+               if (!num_nodes) {
+                       num_nodes = ls->ls_num_nodes;
+                       warned = kmalloc(GFP_KERNEL, num_nodes * sizeof(int));
+                       if (warned)
+                               memset(warned, 0, num_nodes * sizeof(int));
+               }
+               if (!warned)
+                       continue;
+               if (nodeid_warned(lkb->lkb_wait_nodeid, num_nodes, warned))
+                       continue;
+
+               log_error(ls, "waitwarn %x %lld %d us check connection to "
+                         "node %d", lkb->lkb_id, (long long)us,
+                         dlm_config.ci_waitwarn_us, lkb->lkb_wait_nodeid);
+       }
+       mutex_unlock(&ls->ls_waiters_mutex);
+
+       if (warned)
+               kfree(warned);
+
+       if (debug_expired)
+               log_debug(ls, "scan_waiters %u warn %u over %d us max %lld us",
+                         debug_scanned, debug_expired,
+                         dlm_config.ci_waitwarn_us, (long long)debug_maxus);
+}
+
 /* add/remove lkb from global waiters list of lkb's waiting for
    a reply from a remote node */
 
-static int add_to_waiters(struct dlm_lkb *lkb, int mstype)
+static int add_to_waiters(struct dlm_lkb *lkb, int mstype, int to_nodeid)
 {
        struct dlm_ls *ls = lkb->lkb_resource->res_ls;
        int error = 0;
@@ -842,6 +916,8 @@ static int add_to_waiters(struct dlm_lkb *lkb, int mstype)
 
        lkb->lkb_wait_count++;
        lkb->lkb_wait_type = mstype;
+       lkb->lkb_wait_time = ktime_get();
+       lkb->lkb_wait_nodeid = to_nodeid; /* for debugging */
        hold_lkb(lkb);
        list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
  out:
@@ -961,10 +1037,10 @@ static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms)
        struct dlm_ls *ls = lkb->lkb_resource->res_ls;
        int error;
 
-       if (ms != &ls->ls_stub_ms)
+       if (ms->m_flags != DLM_IFL_STUB_MS)
                mutex_lock(&ls->ls_waiters_mutex);
        error = _remove_from_waiters(lkb, ms->m_type, ms);
-       if (ms != &ls->ls_stub_ms)
+       if (ms->m_flags != DLM_IFL_STUB_MS)
                mutex_unlock(&ls->ls_waiters_mutex);
        return error;
 }
@@ -1157,6 +1233,16 @@ void dlm_adjust_timeouts(struct dlm_ls *ls)
        list_for_each_entry(lkb, &ls->ls_timeout, lkb_time_list)
                lkb->lkb_timestamp = ktime_add_us(lkb->lkb_timestamp, adj_us);
        mutex_unlock(&ls->ls_timeout_mutex);
+
+       if (!dlm_config.ci_waitwarn_us)
+               return;
+
+       mutex_lock(&ls->ls_waiters_mutex);
+       list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
+               if (ktime_to_us(lkb->lkb_wait_time))
+                       lkb->lkb_wait_time = ktime_get();
+       }
+       mutex_unlock(&ls->ls_waiters_mutex);
 }
 
 /* lkb is master or local copy */
@@ -1376,14 +1462,8 @@ static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)
    ALTPR/ALTCW: our rqmode may have been changed to PR or CW to become
    compatible with other granted locks */
 
-static void munge_demoted(struct dlm_lkb *lkb, struct dlm_message *ms)
+static void munge_demoted(struct dlm_lkb *lkb)
 {
-       if (ms->m_type != DLM_MSG_CONVERT_REPLY) {
-               log_print("munge_demoted %x invalid reply type %d",
-                         lkb->lkb_id, ms->m_type);
-               return;
-       }
-
        if (lkb->lkb_rqmode == DLM_LOCK_IV || lkb->lkb_grmode == DLM_LOCK_IV) {
                log_print("munge_demoted %x invalid modes gr %d rq %d",
                          lkb->lkb_id, lkb->lkb_grmode, lkb->lkb_rqmode);
@@ -2844,12 +2924,12 @@ static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
        struct dlm_mhandle *mh;
        int to_nodeid, error;
 
-       error = add_to_waiters(lkb, mstype);
+       to_nodeid = r->res_nodeid;
+
+       error = add_to_waiters(lkb, mstype, to_nodeid);
        if (error)
                return error;
 
-       to_nodeid = r->res_nodeid;
-
        error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
        if (error)
                goto fail;
@@ -2880,9 +2960,9 @@ static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
        /* down conversions go without a reply from the master */
        if (!error && down_conversion(lkb)) {
                remove_from_waiters(lkb, DLM_MSG_CONVERT_REPLY);
+               r->res_ls->ls_stub_ms.m_flags = DLM_IFL_STUB_MS;
                r->res_ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;
                r->res_ls->ls_stub_ms.m_result = 0;
-               r->res_ls->ls_stub_ms.m_flags = lkb->lkb_flags;
                __receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms);
        }
 
@@ -2951,12 +3031,12 @@ static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
        struct dlm_mhandle *mh;
        int to_nodeid, error;
 
-       error = add_to_waiters(lkb, DLM_MSG_LOOKUP);
+       to_nodeid = dlm_dir_nodeid(r);
+
+       error = add_to_waiters(lkb, DLM_MSG_LOOKUP, to_nodeid);
        if (error)
                return error;
 
-       to_nodeid = dlm_dir_nodeid(r);
-
        error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh);
        if (error)
                goto fail;
@@ -3070,6 +3150,9 @@ static void receive_flags(struct dlm_lkb *lkb, struct dlm_message *ms)
 
 static void receive_flags_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
 {
+       if (ms->m_flags == DLM_IFL_STUB_MS)
+               return;
+
        lkb->lkb_sbflags = ms->m_sbflags;
        lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
                         (ms->m_flags & 0x0000FFFF);
@@ -3612,7 +3695,7 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
                /* convert was queued on remote master */
                receive_flags_reply(lkb, ms);
                if (is_demoted(lkb))
-                       munge_demoted(lkb, ms);
+                       munge_demoted(lkb);
                del_lkb(r, lkb);
                add_lkb(r, lkb, DLM_LKSTS_CONVERT);
                add_timeout(lkb);
@@ -3622,7 +3705,7 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
                /* convert was granted on remote master */
                receive_flags_reply(lkb, ms);
                if (is_demoted(lkb))
-                       munge_demoted(lkb, ms);
+                       munge_demoted(lkb);
                grant_lock_pc(r, lkb, ms);
                queue_cast(r, lkb, 0);
                break;
@@ -3996,15 +4079,17 @@ void dlm_receive_buffer(union dlm_packet *p, int nodeid)
        dlm_put_lockspace(ls);
 }
 
-static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
+static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb,
+                                  struct dlm_message *ms_stub)
 {
        if (middle_conversion(lkb)) {
                hold_lkb(lkb);
-               ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;
-               ls->ls_stub_ms.m_result = -EINPROGRESS;
-               ls->ls_stub_ms.m_flags = lkb->lkb_flags;
-               ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;
-               _receive_convert_reply(lkb, &ls->ls_stub_ms);
+               memset(ms_stub, 0, sizeof(struct dlm_message));
+               ms_stub->m_flags = DLM_IFL_STUB_MS;
+               ms_stub->m_type = DLM_MSG_CONVERT_REPLY;
+               ms_stub->m_result = -EINPROGRESS;
+               ms_stub->m_header.h_nodeid = lkb->lkb_nodeid;
+               _receive_convert_reply(lkb, ms_stub);
 
                /* Same special case as in receive_rcom_lock_args() */
                lkb->lkb_grmode = DLM_LOCK_IV;
@@ -4045,13 +4130,27 @@ static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)
 void dlm_recover_waiters_pre(struct dlm_ls *ls)
 {
        struct dlm_lkb *lkb, *safe;
+       struct dlm_message *ms_stub;
        int wait_type, stub_unlock_result, stub_cancel_result;
 
+       ms_stub = kmalloc(GFP_KERNEL, sizeof(struct dlm_message));
+       if (!ms_stub) {
+               log_error(ls, "dlm_recover_waiters_pre no mem");
+               return;
+       }
+
        mutex_lock(&ls->ls_waiters_mutex);
 
        list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) {
-               log_debug(ls, "pre recover waiter lkid %x type %d flags %x",
-                         lkb->lkb_id, lkb->lkb_wait_type, lkb->lkb_flags);
+
+               /* exclude debug messages about unlocks because there can be so
+                  many and they aren't very interesting */
+
+               if (lkb->lkb_wait_type != DLM_MSG_UNLOCK) {
+                       log_debug(ls, "recover_waiter %x nodeid %d "
+                                 "msg %d to %d", lkb->lkb_id, lkb->lkb_nodeid,
+                                 lkb->lkb_wait_type, lkb->lkb_wait_nodeid);
+               }
 
                /* all outstanding lookups, regardless of destination  will be
                   resent after recovery is done */
@@ -4097,26 +4196,28 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
                        break;
 
                case DLM_MSG_CONVERT:
-                       recover_convert_waiter(ls, lkb);
+                       recover_convert_waiter(ls, lkb, ms_stub);
                        break;
 
                case DLM_MSG_UNLOCK:
                        hold_lkb(lkb);
-                       ls->ls_stub_ms.m_type = DLM_MSG_UNLOCK_REPLY;
-                       ls->ls_stub_ms.m_result = stub_unlock_result;
-                       ls->ls_stub_ms.m_flags = lkb->lkb_flags;
-                       ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;
-                       _receive_unlock_reply(lkb, &ls->ls_stub_ms);
+                       memset(ms_stub, 0, sizeof(struct dlm_message));
+                       ms_stub->m_flags = DLM_IFL_STUB_MS;
+                       ms_stub->m_type = DLM_MSG_UNLOCK_REPLY;
+                       ms_stub->m_result = stub_unlock_result;
+                       ms_stub->m_header.h_nodeid = lkb->lkb_nodeid;
+                       _receive_unlock_reply(lkb, ms_stub);
                        dlm_put_lkb(lkb);
                        break;
 
                case DLM_MSG_CANCEL:
                        hold_lkb(lkb);
-                       ls->ls_stub_ms.m_type = DLM_MSG_CANCEL_REPLY;
-                       ls->ls_stub_ms.m_result = stub_cancel_result;
-                       ls->ls_stub_ms.m_flags = lkb->lkb_flags;
-                       ls->ls_stub_ms.m_header.h_nodeid = lkb->lkb_nodeid;
-                       _receive_cancel_reply(lkb, &ls->ls_stub_ms);
+                       memset(ms_stub, 0, sizeof(struct dlm_message));
+                       ms_stub->m_flags = DLM_IFL_STUB_MS;
+                       ms_stub->m_type = DLM_MSG_CANCEL_REPLY;
+                       ms_stub->m_result = stub_cancel_result;
+                       ms_stub->m_header.h_nodeid = lkb->lkb_nodeid;
+                       _receive_cancel_reply(lkb, ms_stub);
                        dlm_put_lkb(lkb);
                        break;
 
@@ -4127,6 +4228,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
                schedule();
        }
        mutex_unlock(&ls->ls_waiters_mutex);
+       kfree(ms_stub);
 }
 
 static struct dlm_lkb *find_resend_waiter(struct dlm_ls *ls)
@@ -4191,8 +4293,8 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
                ou = is_overlap_unlock(lkb);
                err = 0;
 
-               log_debug(ls, "recover_waiters_post %x type %d flags %x %s",
-                         lkb->lkb_id, mstype, lkb->lkb_flags, r->res_name);
+               log_debug(ls, "recover_waiter %x nodeid %d msg %d r_nodeid %d",
+                         lkb->lkb_id, lkb->lkb_nodeid, mstype, r->res_nodeid);
 
                /* At this point we assume that we won't get a reply to any
                   previous op or overlap op on this lock.  First, do a big
index 88e93c80cc22491202dcd1843f3931678e324b76..265017a7c3e7a6246f39400566238bddf996507c 100644 (file)
@@ -24,6 +24,7 @@ int dlm_put_lkb(struct dlm_lkb *lkb);
 void dlm_scan_rsbs(struct dlm_ls *ls);
 int dlm_lock_recovery_try(struct dlm_ls *ls);
 void dlm_unlock_recovery(struct dlm_ls *ls);
+void dlm_scan_waiters(struct dlm_ls *ls);
 void dlm_scan_timeout(struct dlm_ls *ls);
 void dlm_adjust_timeouts(struct dlm_ls *ls);
 
index f994a7dfda85c69e9d1d514329add11811bd9278..14cbf409975387ca6b404c8b6ed2600c1ae4954d 100644 (file)
@@ -243,7 +243,6 @@ static struct dlm_ls *find_ls_to_scan(void)
 static int dlm_scand(void *data)
 {
        struct dlm_ls *ls;
-       int timeout_jiffies = dlm_config.ci_scan_secs * HZ;
 
        while (!kthread_should_stop()) {
                ls = find_ls_to_scan();
@@ -252,13 +251,14 @@ static int dlm_scand(void *data)
                                ls->ls_scan_time = jiffies;
                                dlm_scan_rsbs(ls);
                                dlm_scan_timeout(ls);
+                               dlm_scan_waiters(ls);
                                dlm_unlock_recovery(ls);
                        } else {
                                ls->ls_scan_time += HZ;
                        }
-               } else {
-                       schedule_timeout_interruptible(timeout_jiffies);
+                       continue;
                }
+               schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ);
        }
        return 0;
 }
index 30d8b85febbf1eb413333bddac0b365b29b676d3..e2b87800436427ab2783118876ddeacfa2ace9cd 100644 (file)
@@ -71,6 +71,36 @@ static void send_op(struct plock_op *op)
        wake_up(&send_wq);
 }
 
+/* If a process was killed while waiting for the only plock on a file,
+   locks_remove_posix will not see any lock on the file so it won't
+   send an unlock-close to us to pass on to userspace to clean up the
+   abandoned waiter.  So, we have to insert the unlock-close when the
+   lock call is interrupted. */
+
+static void do_unlock_close(struct dlm_ls *ls, u64 number,
+                           struct file *file, struct file_lock *fl)
+{
+       struct plock_op *op;
+
+       op = kzalloc(sizeof(*op), GFP_NOFS);
+       if (!op)
+               return;
+
+       op->info.optype         = DLM_PLOCK_OP_UNLOCK;
+       op->info.pid            = fl->fl_pid;
+       op->info.fsid           = ls->ls_global_id;
+       op->info.number         = number;
+       op->info.start          = 0;
+       op->info.end            = OFFSET_MAX;
+       if (fl->fl_lmops && fl->fl_lmops->fl_grant)
+               op->info.owner  = (__u64) fl->fl_pid;
+       else
+               op->info.owner  = (__u64)(long) fl->fl_owner;
+
+       op->info.flags |= DLM_PLOCK_FL_CLOSE;
+       send_op(op);
+}
+
 int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
                   int cmd, struct file_lock *fl)
 {
@@ -114,9 +144,19 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
 
        send_op(op);
 
-       if (xop->callback == NULL)
-               wait_event(recv_wq, (op->done != 0));
-       else {
+       if (xop->callback == NULL) {
+               rv = wait_event_killable(recv_wq, (op->done != 0));
+               if (rv == -ERESTARTSYS) {
+                       log_debug(ls, "dlm_posix_lock: wait killed %llx",
+                                 (unsigned long long)number);
+                       spin_lock(&ops_lock);
+                       list_del(&op->list);
+                       spin_unlock(&ops_lock);
+                       kfree(xop);
+                       do_unlock_close(ls, number, file, fl);
+                       goto out;
+               }
+       } else {
                rv = FILE_LOCK_DEFERRED;
                goto out;
        }
@@ -233,6 +273,13 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
        else
                op->info.owner  = (__u64)(long) fl->fl_owner;
 
+       if (fl->fl_flags & FL_CLOSE) {
+               op->info.flags |= DLM_PLOCK_FL_CLOSE;
+               send_op(op);
+               rv = 0;
+               goto out;
+       }
+
        send_op(op);
        wait_event(recv_wq, (op->done != 0));
 
@@ -334,7 +381,10 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
        spin_lock(&ops_lock);
        if (!list_empty(&send_list)) {
                op = list_entry(send_list.next, struct plock_op, list);
-               list_move(&op->list, &recv_list);
+               if (op->info.flags & DLM_PLOCK_FL_CLOSE)
+                       list_del(&op->list);
+               else
+                       list_move(&op->list, &recv_list);
                memcpy(&info, &op->info, sizeof(info));
        }
        spin_unlock(&ops_lock);
@@ -342,6 +392,13 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
        if (!op)
                return -EAGAIN;
 
+       /* there is no need to get a reply from userspace for unlocks
+          that were generated by the vfs cleaning up for a close
+          (the process did not make an unlock call). */
+
+       if (op->info.flags & DLM_PLOCK_FL_CLOSE)
+               kfree(op);
+
        if (copy_to_user(u, &info, sizeof(info)))
                return -EFAULT;
        return sizeof(info);
index d5ab3fe7c198ab7da612c0421cb22d4cbeba8568..e96bf3e9be88e566e1095f6960974a5e3fc1340d 100644 (file)
@@ -611,7 +611,6 @@ static ssize_t device_write(struct file *file, const char __user *buf,
 
  out_sig:
        sigprocmask(SIG_SETMASK, &tmpsig, NULL);
-       recalc_sigpending();
  out_free:
        kfree(kbuf);
        return error;
index 0a78dae7e2cbbaea9f76045c7db6fe90426e278e..1dd62ed35b8511efece6cd6733eb960185f9ec28 100644 (file)
@@ -898,7 +898,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
                brelse(bh);
 
                if (!sb_set_blocksize(sb, blocksize)) {
-                       ext2_msg(sb, KERN_ERR, "error: blocksize is too small");
+                       ext2_msg(sb, KERN_ERR,
+                               "error: bad blocksize %d", blocksize);
                        goto failed_sbi;
                }
 
index 32f3b869585927400a035259c0fee27e312b39c8..34b6d9bfc48a511de1a4e52bbb778cdd10a519b6 100644 (file)
@@ -1416,10 +1416,19 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        frame->at = entries;
        frame->bh = bh;
        bh = bh2;
+       /*
+        * Mark buffers dirty here so that if do_split() fails we write a
+        * consistent set of buffers to disk.
+        */
+       ext3_journal_dirty_metadata(handle, frame->bh);
+       ext3_journal_dirty_metadata(handle, bh);
        de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
-       dx_release (frames);
-       if (!(de))
+       if (!de) {
+               ext3_mark_inode_dirty(handle, dir);
+               dx_release(frames);
                return retval;
+       }
+       dx_release(frames);
 
        return add_dirent_to_buf(handle, dentry, inode, de, bh);
 }
@@ -2189,6 +2198,7 @@ static int ext3_symlink (struct inode * dir,
        handle_t *handle;
        struct inode * inode;
        int l, err, retries = 0;
+       int credits;
 
        l = strlen(symname)+1;
        if (l > dir->i_sb->s_blocksize)
@@ -2196,10 +2206,26 @@ static int ext3_symlink (struct inode * dir,
 
        dquot_initialize(dir);
 
+       if (l > EXT3_N_BLOCKS * 4) {
+               /*
+                * For non-fast symlinks, we just allocate inode and put it on
+                * orphan list in the first transaction => we need bitmap,
+                * group descriptor, sb, inode block, quota blocks.
+                */
+               credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+       } else {
+               /*
+                * Fast symlink. We have to add entry to directory
+                * (EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS),
+                * allocate new inode (bitmap, group descriptor, inode block,
+                * quota blocks, sb is already counted in previous macros).
+                */
+               credits = EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
+                         EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+                         EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
+       }
 retry:
-       handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
-                                       EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
-                                       EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
+       handle = ext3_journal_start(dir, credits);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -2211,21 +2237,45 @@ retry:
        if (IS_ERR(inode))
                goto out_stop;
 
-       if (l > sizeof (EXT3_I(inode)->i_data)) {
+       if (l > EXT3_N_BLOCKS * 4) {
                inode->i_op = &ext3_symlink_inode_operations;
                ext3_set_aops(inode);
                /*
-                * page_symlink() calls into ext3_prepare/commit_write.
-                * We have a transaction open.  All is sweetness.  It also sets
-                * i_size in generic_commit_write().
+                * We cannot call page_symlink() with transaction started
+                * because it calls into ext3_write_begin() which acquires page
+                * lock which ranks below transaction start (and it can also
+                * wait for journal commit if we are running out of space). So
+                * we have to stop transaction now and restart it when symlink
+                * contents is written. 
+                *
+                * To keep fs consistent in case of crash, we have to put inode
+                * to orphan list in the mean time.
                 */
+               drop_nlink(inode);
+               err = ext3_orphan_add(handle, inode);
+               ext3_journal_stop(handle);
+               if (err)
+                       goto err_drop_inode;
                err = __page_symlink(inode, symname, l, 1);
+               if (err)
+                       goto err_drop_inode;
+               /*
+                * Now inode is being linked into dir (EXT3_DATA_TRANS_BLOCKS
+                * + EXT3_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified
+                */
+               handle = ext3_journal_start(dir,
+                               EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
+                               EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1);
+               if (IS_ERR(handle)) {
+                       err = PTR_ERR(handle);
+                       goto err_drop_inode;
+               }
+               inc_nlink(inode);
+               err = ext3_orphan_del(handle, inode);
                if (err) {
+                       ext3_journal_stop(handle);
                        drop_nlink(inode);
-                       unlock_new_inode(inode);
-                       ext3_mark_inode_dirty(handle, inode);
-                       iput (inode);
-                       goto out_stop;
+                       goto err_drop_inode;
                }
        } else {
                inode->i_op = &ext3_fast_symlink_inode_operations;
@@ -2239,6 +2289,10 @@ out_stop:
        if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
        return err;
+err_drop_inode:
+       unlock_new_inode(inode);
+       iput(inode);
+       return err;
 }
 
 static int ext3_link (struct dentry * old_dentry,
index 69b18045946330a5a35c54226094ca0dc657a903..72ffa974b0b8d52852e25d7e016f7b4f1fc50b4a 100644 (file)
@@ -302,12 +302,6 @@ void journal_commit_transaction(journal_t *journal)
         * all outstanding updates to complete.
         */
 
-#ifdef COMMIT_STATS
-       spin_lock(&journal->j_list_lock);
-       summarise_journal_usage(journal);
-       spin_unlock(&journal->j_list_lock);
-#endif
-
        /* Do we need to erase the effects of a prior journal_flush? */
        if (journal->j_flags & JFS_FLUSHED) {
                jbd_debug(3, "super block updated\n");
@@ -722,8 +716,13 @@ wait_for_iobuf:
                    required. */
                JBUFFER_TRACE(jh, "file as BJ_Forget");
                journal_file_buffer(jh, commit_transaction, BJ_Forget);
-               /* Wake up any transactions which were waiting for this
-                  IO to complete */
+               /*
+                * Wake up any transactions which were waiting for this
+                * IO to complete. The barrier must be here so that changes
+                * by journal_file_buffer() take effect before wake_up_bit()
+                * does the waitqueue check.
+                */
+               smp_mb();
                wake_up_bit(&bh->b_state, BH_Unshadow);
                JBUFFER_TRACE(jh, "brelse shadowed buffer");
                __brelse(bh);
index b3713afaaa9e698337b40c7e1fecac6afbebc1bf..e2d4285fbe90ebcc511a96574283418bc933634d 100644 (file)
@@ -437,9 +437,12 @@ int __log_space_left(journal_t *journal)
 int __log_start_commit(journal_t *journal, tid_t target)
 {
        /*
-        * Are we already doing a recent enough commit?
+        * The only transaction we can possibly wait upon is the
+        * currently running transaction (if it exists).  Otherwise,
+        * the target tid must be an old one.
         */
-       if (!tid_geq(journal->j_commit_request, target)) {
+       if (journal->j_running_transaction &&
+           journal->j_running_transaction->t_tid == target) {
                /*
                 * We want a new commit: OK, mark the request and wakeup the
                 * commit thread.  We do _not_ do the commit ourselves.
@@ -451,7 +454,14 @@ int __log_start_commit(journal_t *journal, tid_t target)
                          journal->j_commit_sequence);
                wake_up(&journal->j_wait_commit);
                return 1;
-       }
+       } else if (!tid_geq(journal->j_commit_request, target))
+               /* This should never happen, but if it does, preserve
+                  the evidence before kjournald goes into a loop and
+                  increments j_commit_sequence beyond all recognition. */
+               WARN_ONCE(1, "jbd: bad log_start_commit: %u %u %u %u\n",
+                   journal->j_commit_request, journal->j_commit_sequence,
+                   target, journal->j_running_transaction ?
+                   journal->j_running_transaction->t_tid : 0);
        return 0;
 }
 
index 60d2319651b2c2b0f80d346d53a439f3f2513cc6..f7ee81a065dabae13e29501603a8c1726132d05c 100644 (file)
@@ -266,7 +266,8 @@ static handle_t *new_handle(int nblocks)
  * This function is visible to journal users (like ext3fs), so is not
  * called with the journal already locked.
  *
- * Return a pointer to a newly allocated handle, or NULL on failure
+ * Return a pointer to a newly allocated handle, or an ERR_PTR() value
+ * on failure.
  */
 handle_t *journal_start(journal_t *journal, int nblocks)
 {
index 6e28000a4b2168c36d1cee255058ac41b72f34eb..29148a81c783728928cf4ea63d46160cc5c4e85c 100644 (file)
@@ -338,12 +338,6 @@ void jbd2_journal_commit_transaction(journal_t *journal)
         * all outstanding updates to complete.
         */
 
-#ifdef COMMIT_STATS
-       spin_lock(&journal->j_list_lock);
-       summarise_journal_usage(journal);
-       spin_unlock(&journal->j_list_lock);
-#endif
-
        /* Do we need to erase the effects of a prior jbd2_journal_flush? */
        if (journal->j_flags & JBD2_FLUSHED) {
                jbd_debug(3, "super block updated\n");
index 8b3a7da531ebc10c38cad6b73d937e7a29095699..315de66e52b21fc8016f96b5a62b4e94fa41ecd7 100644 (file)
@@ -106,7 +106,7 @@ static long long get_liability(struct ubifs_info *c)
        long long liab;
 
        spin_lock(&c->space_lock);
-       liab = c->budg_idx_growth + c->budg_data_growth + c->budg_dd_growth;
+       liab = c->bi.idx_growth + c->bi.data_growth + c->bi.dd_growth;
        spin_unlock(&c->space_lock);
        return liab;
 }
@@ -180,7 +180,7 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
        int idx_lebs;
        long long idx_size;
 
-       idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx;
+       idx_size = c->bi.old_idx_sz + c->bi.idx_growth + c->bi.uncommitted_idx;
        /* And make sure we have thrice the index size of space reserved */
        idx_size += idx_size << 1;
        /*
@@ -292,13 +292,13 @@ static int can_use_rp(struct ubifs_info *c)
  * budgeted index space to the size of the current index, multiplies this by 3,
  * and makes sure this does not exceed the amount of free LEBs.
  *
- * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables:
+ * Notes about @c->bi.min_idx_lebs and @c->lst.idx_lebs variables:
  * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might
  *    be large, because UBIFS does not do any index consolidation as long as
  *    there is free space. IOW, the index may take a lot of LEBs, but the LEBs
  *    will contain a lot of dirt.
- * o @c->min_idx_lebs is the number of LEBS the index presumably takes. IOW,
- *    the index may be consolidated to take up to @c->min_idx_lebs LEBs.
+ * o @c->bi.min_idx_lebs is the number of LEBS the index presumably takes. IOW,
+ *    the index may be consolidated to take up to @c->bi.min_idx_lebs LEBs.
  *
  * This function returns zero in case of success, and %-ENOSPC in case of
  * failure.
@@ -343,13 +343,13 @@ static int do_budget_space(struct ubifs_info *c)
               c->lst.taken_empty_lebs;
        if (unlikely(rsvd_idx_lebs > lebs)) {
                dbg_budg("out of indexing space: min_idx_lebs %d (old %d), "
-                        "rsvd_idx_lebs %d", min_idx_lebs, c->min_idx_lebs,
+                        "rsvd_idx_lebs %d", min_idx_lebs, c->bi.min_idx_lebs,
                         rsvd_idx_lebs);
                return -ENOSPC;
        }
 
        available = ubifs_calc_available(c, min_idx_lebs);
-       outstanding = c->budg_data_growth + c->budg_dd_growth;
+       outstanding = c->bi.data_growth + c->bi.dd_growth;
 
        if (unlikely(available < outstanding)) {
                dbg_budg("out of data space: available %lld, outstanding %lld",
@@ -360,7 +360,7 @@ static int do_budget_space(struct ubifs_info *c)
        if (available - outstanding <= c->rp_size && !can_use_rp(c))
                return -ENOSPC;
 
-       c->min_idx_lebs = min_idx_lebs;
+       c->bi.min_idx_lebs = min_idx_lebs;
        return 0;
 }
 
@@ -393,11 +393,11 @@ static int calc_data_growth(const struct ubifs_info *c,
 {
        int data_growth;
 
-       data_growth = req->new_ino  ? c->inode_budget : 0;
+       data_growth = req->new_ino  ? c->bi.inode_budget : 0;
        if (req->new_page)
-               data_growth += c->page_budget;
+               data_growth += c->bi.page_budget;
        if (req->new_dent)
-               data_growth += c->dent_budget;
+               data_growth += c->bi.dent_budget;
        data_growth += req->new_ino_d;
        return data_growth;
 }
@@ -413,12 +413,12 @@ static int calc_dd_growth(const struct ubifs_info *c,
 {
        int dd_growth;
 
-       dd_growth = req->dirtied_page ? c->page_budget : 0;
+       dd_growth = req->dirtied_page ? c->bi.page_budget : 0;
 
        if (req->dirtied_ino)
-               dd_growth += c->inode_budget << (req->dirtied_ino - 1);
+               dd_growth += c->bi.inode_budget << (req->dirtied_ino - 1);
        if (req->mod_dent)
-               dd_growth += c->dent_budget;
+               dd_growth += c->bi.dent_budget;
        dd_growth += req->dirtied_ino_d;
        return dd_growth;
 }
@@ -460,19 +460,19 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
 
 again:
        spin_lock(&c->space_lock);
-       ubifs_assert(c->budg_idx_growth >= 0);
-       ubifs_assert(c->budg_data_growth >= 0);
-       ubifs_assert(c->budg_dd_growth >= 0);
+       ubifs_assert(c->bi.idx_growth >= 0);
+       ubifs_assert(c->bi.data_growth >= 0);
+       ubifs_assert(c->bi.dd_growth >= 0);
 
-       if (unlikely(c->nospace) && (c->nospace_rp || !can_use_rp(c))) {
+       if (unlikely(c->bi.nospace) && (c->bi.nospace_rp || !can_use_rp(c))) {
                dbg_budg("no space");
                spin_unlock(&c->space_lock);
                return -ENOSPC;
        }
 
-       c->budg_idx_growth += idx_growth;
-       c->budg_data_growth += data_growth;
-       c->budg_dd_growth += dd_growth;
+       c->bi.idx_growth += idx_growth;
+       c->bi.data_growth += data_growth;
+       c->bi.dd_growth += dd_growth;
 
        err = do_budget_space(c);
        if (likely(!err)) {
@@ -484,9 +484,9 @@ again:
        }
 
        /* Restore the old values */
-       c->budg_idx_growth -= idx_growth;
-       c->budg_data_growth -= data_growth;
-       c->budg_dd_growth -= dd_growth;
+       c->bi.idx_growth -= idx_growth;
+       c->bi.data_growth -= data_growth;
+       c->bi.dd_growth -= dd_growth;
        spin_unlock(&c->space_lock);
 
        if (req->fast) {
@@ -506,9 +506,9 @@ again:
                        goto again;
                }
                dbg_budg("FS is full, -ENOSPC");
-               c->nospace = 1;
+               c->bi.nospace = 1;
                if (can_use_rp(c) || c->rp_size == 0)
-                       c->nospace_rp = 1;
+                       c->bi.nospace_rp = 1;
                smp_wmb();
        } else
                ubifs_err("cannot budget space, error %d", err);
@@ -523,8 +523,8 @@ again:
  * This function releases the space budgeted by 'ubifs_budget_space()'. Note,
  * since the index changes (which were budgeted for in @req->idx_growth) will
  * only be written to the media on commit, this function moves the index budget
- * from @c->budg_idx_growth to @c->budg_uncommitted_idx. The latter will be
- * zeroed by the commit operation.
+ * from @c->bi.idx_growth to @c->bi.uncommitted_idx. The latter will be zeroed
+ * by the commit operation.
  */
 void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
 {
@@ -553,23 +553,23 @@ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
        if (!req->data_growth && !req->dd_growth)
                return;
 
-       c->nospace = c->nospace_rp = 0;
+       c->bi.nospace = c->bi.nospace_rp = 0;
        smp_wmb();
 
        spin_lock(&c->space_lock);
-       c->budg_idx_growth -= req->idx_growth;
-       c->budg_uncommitted_idx += req->idx_growth;
-       c->budg_data_growth -= req->data_growth;
-       c->budg_dd_growth -= req->dd_growth;
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
-
-       ubifs_assert(c->budg_idx_growth >= 0);
-       ubifs_assert(c->budg_data_growth >= 0);
-       ubifs_assert(c->budg_dd_growth >= 0);
-       ubifs_assert(c->min_idx_lebs < c->main_lebs);
-       ubifs_assert(!(c->budg_idx_growth & 7));
-       ubifs_assert(!(c->budg_data_growth & 7));
-       ubifs_assert(!(c->budg_dd_growth & 7));
+       c->bi.idx_growth -= req->idx_growth;
+       c->bi.uncommitted_idx += req->idx_growth;
+       c->bi.data_growth -= req->data_growth;
+       c->bi.dd_growth -= req->dd_growth;
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+
+       ubifs_assert(c->bi.idx_growth >= 0);
+       ubifs_assert(c->bi.data_growth >= 0);
+       ubifs_assert(c->bi.dd_growth >= 0);
+       ubifs_assert(c->bi.min_idx_lebs < c->main_lebs);
+       ubifs_assert(!(c->bi.idx_growth & 7));
+       ubifs_assert(!(c->bi.data_growth & 7));
+       ubifs_assert(!(c->bi.dd_growth & 7));
        spin_unlock(&c->space_lock);
 }
 
@@ -586,13 +586,13 @@ void ubifs_convert_page_budget(struct ubifs_info *c)
 {
        spin_lock(&c->space_lock);
        /* Release the index growth reservation */
-       c->budg_idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
+       c->bi.idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
        /* Release the data growth reservation */
-       c->budg_data_growth -= c->page_budget;
+       c->bi.data_growth -= c->bi.page_budget;
        /* Increase the dirty data growth reservation instead */
-       c->budg_dd_growth += c->page_budget;
+       c->bi.dd_growth += c->bi.page_budget;
        /* And re-calculate the indexing space reservation */
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
        spin_unlock(&c->space_lock);
 }
 
@@ -612,7 +612,7 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
 
        memset(&req, 0, sizeof(struct ubifs_budget_req));
        /* The "no space" flags will be cleared because dd_growth is > 0 */
-       req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8);
+       req.dd_growth = c->bi.inode_budget + ALIGN(ui->data_len, 8);
        ubifs_release_budget(c, &req);
 }
 
@@ -682,9 +682,9 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
        int rsvd_idx_lebs, lebs;
        long long available, outstanding, free;
 
-       ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
-       outstanding = c->budg_data_growth + c->budg_dd_growth;
-       available = ubifs_calc_available(c, c->min_idx_lebs);
+       ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+       outstanding = c->bi.data_growth + c->bi.dd_growth;
+       available = ubifs_calc_available(c, c->bi.min_idx_lebs);
 
        /*
         * When reporting free space to user-space, UBIFS guarantees that it is
@@ -697,8 +697,8 @@ long long ubifs_get_free_space_nolock(struct ubifs_info *c)
         * Note, the calculations below are similar to what we have in
         * 'do_budget_space()', so refer there for comments.
         */
-       if (c->min_idx_lebs > c->lst.idx_lebs)
-               rsvd_idx_lebs = c->min_idx_lebs - c->lst.idx_lebs;
+       if (c->bi.min_idx_lebs > c->lst.idx_lebs)
+               rsvd_idx_lebs = c->bi.min_idx_lebs - c->lst.idx_lebs;
        else
                rsvd_idx_lebs = 0;
        lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
index 1bd01ded7123913f28574261811f73a43a6d4e70..87cd0ead8633f17f9596f1b38adc1f4e48055865 100644 (file)
@@ -182,7 +182,7 @@ static int do_commit(struct ubifs_info *c)
        c->mst_node->root_len    = cpu_to_le32(zroot.len);
        c->mst_node->ihead_lnum  = cpu_to_le32(c->ihead_lnum);
        c->mst_node->ihead_offs  = cpu_to_le32(c->ihead_offs);
-       c->mst_node->index_size  = cpu_to_le64(c->old_idx_sz);
+       c->mst_node->index_size  = cpu_to_le64(c->bi.old_idx_sz);
        c->mst_node->lpt_lnum    = cpu_to_le32(c->lpt_lnum);
        c->mst_node->lpt_offs    = cpu_to_le32(c->lpt_offs);
        c->mst_node->nhead_lnum  = cpu_to_le32(c->nhead_lnum);
index 004d3745dc453a1dcdb6f9eb32cd0a0499d85923..0bb2bcef0de9a8ab8815dfd62103b0bbe601202f 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/moduleparam.h>
 #include <linux/debugfs.h>
 #include <linux/math64.h>
-#include <linux/slab.h>
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
@@ -43,15 +42,12 @@ DEFINE_SPINLOCK(dbg_lock);
 static char dbg_key_buf0[128];
 static char dbg_key_buf1[128];
 
-unsigned int ubifs_msg_flags;
 unsigned int ubifs_chk_flags;
 unsigned int ubifs_tst_flags;
 
-module_param_named(debug_msgs, ubifs_msg_flags, uint, S_IRUGO | S_IWUSR);
 module_param_named(debug_chks, ubifs_chk_flags, uint, S_IRUGO | S_IWUSR);
 module_param_named(debug_tsts, ubifs_tst_flags, uint, S_IRUGO | S_IWUSR);
 
-MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
 MODULE_PARM_DESC(debug_chks, "Debug check flags");
 MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
 
@@ -317,6 +313,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
                printk(KERN_DEBUG "\tflags          %#x\n", sup_flags);
                printk(KERN_DEBUG "\t  big_lpt      %u\n",
                       !!(sup_flags & UBIFS_FLG_BIGLPT));
+               printk(KERN_DEBUG "\t  space_fixup  %u\n",
+                      !!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
                printk(KERN_DEBUG "\tmin_io_size    %u\n",
                       le32_to_cpu(sup->min_io_size));
                printk(KERN_DEBUG "\tleb_size       %u\n",
@@ -602,7 +600,7 @@ void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
        spin_unlock(&dbg_lock);
 }
 
-void dbg_dump_budg(struct ubifs_info *c)
+void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
 {
        int i;
        struct rb_node *rb;
@@ -610,26 +608,42 @@ void dbg_dump_budg(struct ubifs_info *c)
        struct ubifs_gced_idx_leb *idx_gc;
        long long available, outstanding, free;
 
-       ubifs_assert(spin_is_locked(&c->space_lock));
+       spin_lock(&c->space_lock);
        spin_lock(&dbg_lock);
-       printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, "
-              "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid,
-              c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth);
-       printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, "
-              "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth,
-              c->budg_data_growth + c->budg_dd_growth + c->budg_idx_growth,
-              c->freeable_cnt);
-       printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %lld, "
-              "calc_idx_sz %lld, idx_gc_cnt %d\n", c->min_idx_lebs,
-              c->old_idx_sz, c->calc_idx_sz, c->idx_gc_cnt);
+       printk(KERN_DEBUG "(pid %d) Budgeting info: data budget sum %lld, "
+              "total budget sum %lld\n", current->pid,
+              bi->data_growth + bi->dd_growth,
+              bi->data_growth + bi->dd_growth + bi->idx_growth);
+       printk(KERN_DEBUG "\tbudg_data_growth %lld, budg_dd_growth %lld, "
+              "budg_idx_growth %lld\n", bi->data_growth, bi->dd_growth,
+              bi->idx_growth);
+       printk(KERN_DEBUG "\tmin_idx_lebs %d, old_idx_sz %llu, "
+              "uncommitted_idx %lld\n", bi->min_idx_lebs, bi->old_idx_sz,
+              bi->uncommitted_idx);
+       printk(KERN_DEBUG "\tpage_budget %d, inode_budget %d, dent_budget %d\n",
+              bi->page_budget, bi->inode_budget, bi->dent_budget);
+       printk(KERN_DEBUG "\tnospace %u, nospace_rp %u\n",
+              bi->nospace, bi->nospace_rp);
+       printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
+              c->dark_wm, c->dead_wm, c->max_idx_node_sz);
+
+       if (bi != &c->bi)
+               /*
+                * If we are dumping saved budgeting data, do not print
+                * additional information which is about the current state, not
+                * the old one which corresponded to the saved budgeting data.
+                */
+               goto out_unlock;
+
+       printk(KERN_DEBUG "\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
+              c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);
        printk(KERN_DEBUG "\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, "
               "clean_zn_cnt %ld\n", atomic_long_read(&c->dirty_pg_cnt),
               atomic_long_read(&c->dirty_zn_cnt),
               atomic_long_read(&c->clean_zn_cnt));
-       printk(KERN_DEBUG "\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
-              c->dark_wm, c->dead_wm, c->max_idx_node_sz);
        printk(KERN_DEBUG "\tgc_lnum %d, ihead_lnum %d\n",
               c->gc_lnum, c->ihead_lnum);
+
        /* If we are in R/O mode, journal heads do not exist */
        if (c->jheads)
                for (i = 0; i < c->jhead_cnt; i++)
@@ -648,13 +662,15 @@ void dbg_dump_budg(struct ubifs_info *c)
        printk(KERN_DEBUG "\tcommit state %d\n", c->cmt_state);
 
        /* Print budgeting predictions */
-       available = ubifs_calc_available(c, c->min_idx_lebs);
-       outstanding = c->budg_data_growth + c->budg_dd_growth;
+       available = ubifs_calc_available(c, c->bi.min_idx_lebs);
+       outstanding = c->bi.data_growth + c->bi.dd_growth;
        free = ubifs_get_free_space_nolock(c);
        printk(KERN_DEBUG "Budgeting predictions:\n");
        printk(KERN_DEBUG "\tavailable: %lld, outstanding %lld, free %lld\n",
               available, outstanding, free);
+out_unlock:
        spin_unlock(&dbg_lock);
+       spin_unlock(&c->space_lock);
 }
 
 void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
@@ -729,7 +745,13 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
                if (bud->lnum == lp->lnum) {
                        int head = 0;
                        for (i = 0; i < c->jhead_cnt; i++) {
-                               if (lp->lnum == c->jheads[i].wbuf.lnum) {
+                               /*
+                                * Note, if we are in R/O mode or in the middle
+                                * of mounting/re-mounting, the write-buffers do
+                                * not exist.
+                                */
+                               if (c->jheads &&
+                                   lp->lnum == c->jheads[i].wbuf.lnum) {
                                        printk(KERN_CONT ", jhead %s",
                                               dbg_jhead(i));
                                        head = 1;
@@ -976,6 +998,8 @@ void dbg_save_space_info(struct ubifs_info *c)
 
        spin_lock(&c->space_lock);
        memcpy(&d->saved_lst, &c->lst, sizeof(struct ubifs_lp_stats));
+       memcpy(&d->saved_bi, &c->bi, sizeof(struct ubifs_budg_info));
+       d->saved_idx_gc_cnt = c->idx_gc_cnt;
 
        /*
         * We use a dirty hack here and zero out @c->freeable_cnt, because it
@@ -1042,14 +1066,14 @@ int dbg_check_space_info(struct ubifs_info *c)
 out:
        ubifs_msg("saved lprops statistics dump");
        dbg_dump_lstats(&d->saved_lst);
-       ubifs_get_lp_stats(c, &lst);
-
+       ubifs_msg("saved budgeting info dump");
+       dbg_dump_budg(c, &d->saved_bi);
+       ubifs_msg("saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
        ubifs_msg("current lprops statistics dump");
+       ubifs_get_lp_stats(c, &lst);
        dbg_dump_lstats(&lst);
-
-       spin_lock(&c->space_lock);
-       dbg_dump_budg(c);
-       spin_unlock(&c->space_lock);
+       ubifs_msg("current budgeting info dump");
+       dbg_dump_budg(c, &c->bi);
        dump_stack();
        return -EINVAL;
 }
@@ -1793,6 +1817,8 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
        struct rb_node **p, *parent = NULL;
        struct fsck_inode *fscki;
        ino_t inum = key_inum_flash(c, &ino->key);
+       struct inode *inode;
+       struct ubifs_inode *ui;
 
        p = &fsckd->inodes.rb_node;
        while (*p) {
@@ -1816,19 +1842,46 @@ static struct fsck_inode *add_inode(struct ubifs_info *c,
        if (!fscki)
                return ERR_PTR(-ENOMEM);
 
+       inode = ilookup(c->vfs_sb, inum);
+
        fscki->inum = inum;
-       fscki->nlink = le32_to_cpu(ino->nlink);
-       fscki->size = le64_to_cpu(ino->size);
-       fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
-       fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
-       fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
-       fscki->mode = le32_to_cpu(ino->mode);
+       /*
+        * If the inode is present in the VFS inode cache, use it instead of
+        * the on-flash inode which might be out-of-date. E.g., the size might
+        * be out-of-date. If we do not do this, the following may happen, for
+        * example:
+        *   1. A power cut happens
+        *   2. We mount the file-system R/O, the replay process fixes up the
+        *      inode size in the VFS cache, but on on-flash.
+        *   3. 'check_leaf()' fails because it hits a data node beyond inode
+        *      size.
+        */
+       if (!inode) {
+               fscki->nlink = le32_to_cpu(ino->nlink);
+               fscki->size = le64_to_cpu(ino->size);
+               fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
+               fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
+               fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
+               fscki->mode = le32_to_cpu(ino->mode);
+       } else {
+               ui = ubifs_inode(inode);
+               fscki->nlink = inode->i_nlink;
+               fscki->size = inode->i_size;
+               fscki->xattr_cnt = ui->xattr_cnt;
+               fscki->xattr_sz = ui->xattr_size;
+               fscki->xattr_nms = ui->xattr_names;
+               fscki->mode = inode->i_mode;
+               iput(inode);
+       }
+
        if (S_ISDIR(fscki->mode)) {
                fscki->calc_sz = UBIFS_INO_NODE_SZ;
                fscki->calc_cnt = 2;
        }
+
        rb_link_node(&fscki->rb, parent, p);
        rb_insert_color(&fscki->rb, &fsckd->inodes);
+
        return fscki;
 }
 
@@ -2421,7 +2474,8 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
                hashb = key_block(c, &sb->key);
 
                if (hasha > hashb) {
-                       ubifs_err("larger hash %u goes before %u", hasha, hashb);
+                       ubifs_err("larger hash %u goes before %u",
+                                 hasha, hashb);
                        goto error_dump;
                }
        }
@@ -2437,14 +2491,12 @@ error_dump:
        return 0;
 }
 
-static int invocation_cnt;
-
 int dbg_force_in_the_gaps(void)
 {
-       if (!dbg_force_in_the_gaps_enabled)
+       if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
                return 0;
-       /* Force in-the-gaps every 8th commit */
-       return !((invocation_cnt++) & 0x7);
+
+       return !(random32() & 7);
 }
 
 /* Failure mode for recovery testing */
@@ -2632,7 +2684,7 @@ int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
                 int len, int check)
 {
        if (in_failure_mode(desc))
-               return -EIO;
+               return -EROFS;
        return ubi_leb_read(desc, lnum, buf, offset, len, check);
 }
 
@@ -2642,7 +2694,7 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
        int err, failing;
 
        if (in_failure_mode(desc))
-               return -EIO;
+               return -EROFS;
        failing = do_fail(desc, lnum, 1);
        if (failing)
                cut_data(buf, len);
@@ -2650,7 +2702,7 @@ int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
        if (err)
                return err;
        if (failing)
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
@@ -2660,12 +2712,12 @@ int dbg_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
        int err;
 
        if (do_fail(desc, lnum, 1))
-               return -EIO;
+               return -EROFS;
        err = ubi_leb_change(desc, lnum, buf, len, dtype);
        if (err)
                return err;
        if (do_fail(desc, lnum, 1))
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
@@ -2674,12 +2726,12 @@ int dbg_leb_erase(struct ubi_volume_desc *desc, int lnum)
        int err;
 
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        err = ubi_leb_erase(desc, lnum);
        if (err)
                return err;
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
@@ -2688,19 +2740,19 @@ int dbg_leb_unmap(struct ubi_volume_desc *desc, int lnum)
        int err;
 
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        err = ubi_leb_unmap(desc, lnum);
        if (err)
                return err;
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
 int dbg_is_mapped(struct ubi_volume_desc *desc, int lnum)
 {
        if (in_failure_mode(desc))
-               return -EIO;
+               return -EROFS;
        return ubi_is_mapped(desc, lnum);
 }
 
@@ -2709,12 +2761,12 @@ int dbg_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
        int err;
 
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        err = ubi_leb_map(desc, lnum, dtype);
        if (err)
                return err;
        if (do_fail(desc, lnum, 0))
-               return -EIO;
+               return -EROFS;
        return 0;
 }
 
@@ -2784,7 +2836,7 @@ void dbg_debugfs_exit(void)
 static int open_debugfs_file(struct inode *inode, struct file *file)
 {
        file->private_data = inode->i_private;
-       return 0;
+       return nonseekable_open(inode, file);
 }
 
 static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
@@ -2795,18 +2847,15 @@ static ssize_t write_debugfs_file(struct file *file, const char __user *buf,
 
        if (file->f_path.dentry == d->dfs_dump_lprops)
                dbg_dump_lprops(c);
-       else if (file->f_path.dentry == d->dfs_dump_budg) {
-               spin_lock(&c->space_lock);
-               dbg_dump_budg(c);
-               spin_unlock(&c->space_lock);
-       } else if (file->f_path.dentry == d->dfs_dump_tnc) {
+       else if (file->f_path.dentry == d->dfs_dump_budg)
+               dbg_dump_budg(c, &c->bi);
+       else if (file->f_path.dentry == d->dfs_dump_tnc) {
                mutex_lock(&c->tnc_mutex);
                dbg_dump_tnc(c);
                mutex_unlock(&c->tnc_mutex);
        } else
                return -EINVAL;
 
-       *ppos += count;
        return count;
 }
 
@@ -2814,7 +2863,7 @@ static const struct file_operations dfs_fops = {
        .open = open_debugfs_file,
        .write = write_debugfs_file,
        .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .llseek = no_llseek,
 };
 
 /**
index e6493cac193d60d92c6e3e72d743d03f46a5796d..a811ac4a26bb68de36c14756446d1c0de9bcbc7b 100644 (file)
@@ -31,6 +31,8 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
 
 #ifdef CONFIG_UBIFS_FS_DEBUG
 
+#include <linux/random.h>
+
 /**
  * ubifs_debug_info - per-FS debugging information.
  * @old_zroot: old index root - used by 'dbg_check_old_index()'
@@ -50,13 +52,15 @@ typedef int (*dbg_znode_callback)(struct ubifs_info *c,
  * @new_ihead_offs: used by debugging to check @c->ihead_offs
  *
  * @saved_lst: saved lprops statistics (used by 'dbg_save_space_info()')
- * @saved_free: saved free space (used by 'dbg_save_space_info()')
+ * @saved_bi: saved budgeting information
+ * @saved_free: saved amount of free space
+ * @saved_idx_gc_cnt: saved value of @c->idx_gc_cnt
  *
- * dfs_dir_name: name of debugfs directory containing this file-system's files
- * dfs_dir: direntry object of the file-system debugfs directory
- * dfs_dump_lprops: "dump lprops" debugfs knob
- * dfs_dump_budg: "dump budgeting information" debugfs knob
- * dfs_dump_tnc: "dump TNC" debugfs knob
+ * @dfs_dir_name: name of debugfs directory containing this file-system's files
+ * @dfs_dir: direntry object of the file-system debugfs directory
+ * @dfs_dump_lprops: "dump lprops" debugfs knob
+ * @dfs_dump_budg: "dump budgeting information" debugfs knob
+ * @dfs_dump_tnc: "dump TNC" debugfs knob
  */
 struct ubifs_debug_info {
        struct ubifs_zbranch old_zroot;
@@ -76,7 +80,9 @@ struct ubifs_debug_info {
        int new_ihead_offs;
 
        struct ubifs_lp_stats saved_lst;
+       struct ubifs_budg_info saved_bi;
        long long saved_free;
+       int saved_idx_gc_cnt;
 
        char dfs_dir_name[100];
        struct dentry *dfs_dir;
@@ -101,23 +107,7 @@ struct ubifs_debug_info {
        }                                                                      \
 } while (0)
 
-#define dbg_dump_stack() do {                                                  \
-       if (!dbg_failure_mode)                                                 \
-               dump_stack();                                                  \
-} while (0)
-
-/* Generic debugging messages */
-#define dbg_msg(fmt, ...) do {                                                 \
-       spin_lock(&dbg_lock);                                                  \
-       printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid,   \
-              __func__, ##__VA_ARGS__);                                       \
-       spin_unlock(&dbg_lock);                                                \
-} while (0)
-
-#define dbg_do_msg(typ, fmt, ...) do {                                         \
-       if (ubifs_msg_flags & typ)                                             \
-               dbg_msg(fmt, ##__VA_ARGS__);                                   \
-} while (0)
+#define dbg_dump_stack() dump_stack()
 
 #define dbg_err(fmt, ...) do {                                                 \
        spin_lock(&dbg_lock);                                                  \
@@ -137,77 +127,40 @@ const char *dbg_key_str1(const struct ubifs_info *c,
 #define DBGKEY(key) dbg_key_str0(c, (key))
 #define DBGKEY1(key) dbg_key_str1(c, (key))
 
-/* General messages */
-#define dbg_gen(fmt, ...)   dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__)
+#define ubifs_dbg_msg(type, fmt, ...) do {                        \
+       spin_lock(&dbg_lock);                                     \
+       pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \
+       spin_unlock(&dbg_lock);                                   \
+} while (0)
 
+/* Just a debugging messages not related to any specific UBIFS subsystem */
+#define dbg_msg(fmt, ...)   ubifs_dbg_msg("msg", fmt, ##__VA_ARGS__)
+/* General messages */
+#define dbg_gen(fmt, ...)   ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
 /* Additional journal messages */
-#define dbg_jnl(fmt, ...)   dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__)
-
+#define dbg_jnl(fmt, ...)   ubifs_dbg_msg("jnl", fmt, ##__VA_ARGS__)
 /* Additional TNC messages */
-#define dbg_tnc(fmt, ...)   dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__)
-
+#define dbg_tnc(fmt, ...)   ubifs_dbg_msg("tnc", fmt, ##__VA_ARGS__)
 /* Additional lprops messages */
-#define dbg_lp(fmt, ...)    dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__)
-
+#define dbg_lp(fmt, ...)    ubifs_dbg_msg("lp", fmt, ##__VA_ARGS__)
 /* Additional LEB find messages */
-#define dbg_find(fmt, ...)  dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__)
-
+#define dbg_find(fmt, ...)  ubifs_dbg_msg("find", fmt, ##__VA_ARGS__)
 /* Additional mount messages */
-#define dbg_mnt(fmt, ...)   dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__)
-
+#define dbg_mnt(fmt, ...)   ubifs_dbg_msg("mnt", fmt, ##__VA_ARGS__)
 /* Additional I/O messages */
-#define dbg_io(fmt, ...)    dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__)
-
+#define dbg_io(fmt, ...)    ubifs_dbg_msg("io", fmt, ##__VA_ARGS__)
 /* Additional commit messages */
-#define dbg_cmt(fmt, ...)   dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__)
-
+#define dbg_cmt(fmt, ...)   ubifs_dbg_msg("cmt", fmt, ##__VA_ARGS__)
 /* Additional budgeting messages */
-#define dbg_budg(fmt, ...)  dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__)
-
+#define dbg_budg(fmt, ...)  ubifs_dbg_msg("budg", fmt, ##__VA_ARGS__)
 /* Additional log messages */
-#define dbg_log(fmt, ...)   dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__)
-
+#define dbg_log(fmt, ...)   ubifs_dbg_msg("log", fmt, ##__VA_ARGS__)
 /* Additional gc messages */
-#define dbg_gc(fmt, ...)    dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__)
-
+#define dbg_gc(fmt, ...)    ubifs_dbg_msg("gc", fmt, ##__VA_ARGS__)
 /* Additional scan messages */
-#define dbg_scan(fmt, ...)  dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__)
-
+#define dbg_scan(fmt, ...)  ubifs_dbg_msg("scan", fmt, ##__VA_ARGS__)
 /* Additional recovery messages */
-#define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__)
-
-/*
- * Debugging message type flags.
- *
- * UBIFS_MSG_GEN: general messages
- * UBIFS_MSG_JNL: journal messages
- * UBIFS_MSG_MNT: mount messages
- * UBIFS_MSG_CMT: commit messages
- * UBIFS_MSG_FIND: LEB find messages
- * UBIFS_MSG_BUDG: budgeting messages
- * UBIFS_MSG_GC: garbage collection messages
- * UBIFS_MSG_TNC: TNC messages
- * UBIFS_MSG_LP: lprops messages
- * UBIFS_MSG_IO: I/O messages
- * UBIFS_MSG_LOG: log messages
- * UBIFS_MSG_SCAN: scan messages
- * UBIFS_MSG_RCVRY: recovery messages
- */
-enum {
-       UBIFS_MSG_GEN   = 0x1,
-       UBIFS_MSG_JNL   = 0x2,
-       UBIFS_MSG_MNT   = 0x4,
-       UBIFS_MSG_CMT   = 0x8,
-       UBIFS_MSG_FIND  = 0x10,
-       UBIFS_MSG_BUDG  = 0x20,
-       UBIFS_MSG_GC    = 0x40,
-       UBIFS_MSG_TNC   = 0x80,
-       UBIFS_MSG_LP    = 0x100,
-       UBIFS_MSG_IO    = 0x200,
-       UBIFS_MSG_LOG   = 0x400,
-       UBIFS_MSG_SCAN  = 0x800,
-       UBIFS_MSG_RCVRY = 0x1000,
-};
+#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
 
 /*
  * Debugging check flags.
@@ -233,11 +186,9 @@ enum {
 /*
  * Special testing flags.
  *
- * UBIFS_TST_FORCE_IN_THE_GAPS: force the use of in-the-gaps method
  * UBIFS_TST_RCVRY: failure mode for recovery testing
  */
 enum {
-       UBIFS_TST_FORCE_IN_THE_GAPS = 0x2,
        UBIFS_TST_RCVRY             = 0x4,
 };
 
@@ -262,7 +213,7 @@ void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
                       int offs);
 void dbg_dump_budget_req(const struct ubifs_budget_req *req);
 void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
-void dbg_dump_budg(struct ubifs_info *c);
+void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi);
 void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp);
 void dbg_dump_lprops(struct ubifs_info *c);
 void dbg_dump_lpt_info(struct ubifs_info *c);
@@ -304,18 +255,16 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
 int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
 
 /* Force the use of in-the-gaps method for testing */
-
-#define dbg_force_in_the_gaps_enabled \
-       (ubifs_tst_flags & UBIFS_TST_FORCE_IN_THE_GAPS)
-
+static inline int dbg_force_in_the_gaps_enabled(void)
+{
+       return ubifs_chk_flags & UBIFS_CHK_GEN;
+}
 int dbg_force_in_the_gaps(void);
 
 /* Failure mode for recovery testing */
-
 #define dbg_failure_mode (ubifs_tst_flags & UBIFS_TST_RCVRY)
 
 #ifndef UBIFS_DBG_PRESERVE_UBI
-
 #define ubi_leb_read   dbg_leb_read
 #define ubi_leb_write  dbg_leb_write
 #define ubi_leb_change dbg_leb_change
@@ -323,7 +272,6 @@ int dbg_force_in_the_gaps(void);
 #define ubi_leb_unmap  dbg_leb_unmap
 #define ubi_is_mapped  dbg_is_mapped
 #define ubi_leb_map    dbg_leb_map
-
 #endif
 
 int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
@@ -370,33 +318,33 @@ void dbg_debugfs_exit_fs(struct ubifs_info *c);
                       __func__, __LINE__, current->pid);                      \
 } while (0)
 
-#define dbg_err(fmt, ...)   do {                                               \
-       if (0)                                                                 \
-               ubifs_err(fmt, ##__VA_ARGS__);                                 \
+#define dbg_err(fmt, ...)   do {                   \
+       if (0)                                     \
+               ubifs_err(fmt, ##__VA_ARGS__);     \
 } while (0)
 
-#define dbg_msg(fmt, ...) do {                                                 \
-       if (0)                                                                 \
-               printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n",         \
-                      current->pid, __func__, ##__VA_ARGS__);                 \
+#define ubifs_dbg_msg(fmt, ...) do {               \
+       if (0)                                     \
+               pr_debug(fmt "\n", ##__VA_ARGS__); \
 } while (0)
 
 #define dbg_dump_stack()
 #define ubifs_assert_cmt_locked(c)
 
-#define dbg_gen(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_jnl(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_tnc(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_lp(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_find(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_mnt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_io(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_cmt(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_budg(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_log(fmt, ...)   dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gc(fmt, ...)    dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_scan(fmt, ...)  dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_rcvry(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gen(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_jnl(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_tnc(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_lp(fmt, ...)    ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_find(fmt, ...)  ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_mnt(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...)    ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_cmt(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_budg(fmt, ...)  ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_log(fmt, ...)   ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gc(fmt, ...)    ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_scan(fmt, ...)  ubifs_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
 
 #define DBGKEY(key)  ((char *)(key))
 #define DBGKEY1(key) ((char *)(key))
@@ -420,7 +368,9 @@ static inline void
 dbg_dump_budget_req(const struct ubifs_budget_req *req)           { return; }
 static inline void
 dbg_dump_lstats(const struct ubifs_lp_stats *lst)                 { return; }
-static inline void dbg_dump_budg(struct ubifs_info *c)            { return; }
+static inline void
+dbg_dump_budg(struct ubifs_info *c,
+             const struct ubifs_budg_info *bi)                   { return; }
 static inline void dbg_dump_lprop(const struct ubifs_info *c,
                                  const struct ubifs_lprops *lp)  { return; }
 static inline void dbg_dump_lprops(struct ubifs_info *c)          { return; }
@@ -482,8 +432,8 @@ dbg_check_nondata_nodes_order(struct ubifs_info *c,
                              struct list_head *head)             { return 0; }
 
 static inline int dbg_force_in_the_gaps(void)                     { return 0; }
-#define dbg_force_in_the_gaps_enabled 0
-#define dbg_failure_mode              0
+#define dbg_force_in_the_gaps_enabled() 0
+#define dbg_failure_mode                0
 
 static inline int dbg_debugfs_init(void)                          { return 0; }
 static inline void dbg_debugfs_exit(void)                         { return; }
index 7217d67a80a691a8114e4d7f04d2f98037d03997..ef5abd38f0bf32a90f30ef6994c81b6d864f93e8 100644 (file)
@@ -603,7 +603,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
                ubifs_release_budget(c, &req);
        else {
                /* We've deleted something - clean the "no space" flags */
-               c->nospace = c->nospace_rp = 0;
+               c->bi.nospace = c->bi.nospace_rp = 0;
                smp_wmb();
        }
        return 0;
@@ -693,7 +693,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
                ubifs_release_budget(c, &req);
        else {
                /* We've deleted something - clean the "no space" flags */
-               c->nospace = c->nospace_rp = 0;
+               c->bi.nospace = c->bi.nospace_rp = 0;
                smp_wmb();
        }
        return 0;
index b286db79c686597bb593208ff577905d2663f7bf..5e7fccfc4b29d0c7eab7481ff1c89a5213c548df 100644 (file)
@@ -212,7 +212,7 @@ static void release_new_page_budget(struct ubifs_info *c)
  */
 static void release_existing_page_budget(struct ubifs_info *c)
 {
-       struct ubifs_budget_req req = { .dd_growth = c->page_budget};
+       struct ubifs_budget_req req = { .dd_growth = c->bi.page_budget};
 
        ubifs_release_budget(c, &req);
 }
@@ -971,11 +971,11 @@ static int do_writepage(struct page *page, int len)
  * the page locked, and it locks @ui_mutex. However, write-back does take inode
  * @i_mutex, which means other VFS operations may be run on this inode at the
  * same time. And the problematic one is truncation to smaller size, from where
- * we have to call 'truncate_setsize()', which first changes @inode->i_size, then
- * drops the truncated pages. And while dropping the pages, it takes the page
- * lock. This means that 'do_truncation()' cannot call 'truncate_setsize()' with
- * @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This
- * means that @inode->i_size is changed while @ui_mutex is unlocked.
+ * we have to call 'truncate_setsize()', which first changes @inode->i_size,
+ * then drops the truncated pages. And while dropping the pages, it takes the
+ * page lock. This means that 'do_truncation()' cannot call 'truncate_setsize()'
+ * with @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'.
+ * This means that @inode->i_size is changed while @ui_mutex is unlocked.
  *
  * XXX(truncate): with the new truncate sequence this is not true anymore,
  * and the calls to truncate_setsize can be move around freely.  They should
@@ -1189,7 +1189,7 @@ out_budg:
        if (budgeted)
                ubifs_release_budget(c, &req);
        else {
-               c->nospace = c->nospace_rp = 0;
+               c->bi.nospace = c->bi.nospace_rp = 0;
                smp_wmb();
        }
        return err;
@@ -1312,7 +1312,11 @@ int ubifs_fsync(struct file *file, int datasync)
 
        dbg_gen("syncing inode %lu", inode->i_ino);
 
-       if (inode->i_sb->s_flags & MS_RDONLY)
+       if (c->ro_mount)
+               /*
+                * For some really strange reasons VFS does not filter out
+                * 'fsync()' for R/O mounted file-systems as per 2.6.39.
+                */
                return 0;
 
        /*
@@ -1432,10 +1436,11 @@ static int ubifs_releasepage(struct page *page, gfp_t unused_gfp_flags)
 }
 
 /*
- * mmap()d file has taken write protection fault and is being made
- * writable. UBIFS must ensure page is budgeted for.
+ * mmap()d file has taken write protection fault and is being made writable.
+ * UBIFS must ensure page is budgeted for.
  */
-static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma,
+                                struct vm_fault *vmf)
 {
        struct page *page = vmf->page;
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
@@ -1536,7 +1541,6 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        int err;
 
-       /* 'generic_file_mmap()' takes care of NOMMU case */
        err = generic_file_mmap(file, vma);
        if (err)
                return err;
index 1d54383d1269b1df2ecfdc8cb7a8e02c917afc74..2559d174e0040a45578fcc2e7612522a08e99a2f 100644 (file)
@@ -252,8 +252,8 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
                 * But if the index takes fewer LEBs than it is reserved for it,
                 * this function must avoid picking those reserved LEBs.
                 */
-               if (c->min_idx_lebs >= c->lst.idx_lebs) {
-                       rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
+               if (c->bi.min_idx_lebs >= c->lst.idx_lebs) {
+                       rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
                        exclude_index = 1;
                }
                spin_unlock(&c->space_lock);
@@ -276,7 +276,7 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp,
                        pick_free = 0;
        } else {
                spin_lock(&c->space_lock);
-               exclude_index = (c->min_idx_lebs >= c->lst.idx_lebs);
+               exclude_index = (c->bi.min_idx_lebs >= c->lst.idx_lebs);
                spin_unlock(&c->space_lock);
        }
 
@@ -501,8 +501,8 @@ int ubifs_find_free_space(struct ubifs_info *c, int min_space, int *offs,
 
        /* Check if there are enough empty LEBs for commit */
        spin_lock(&c->space_lock);
-       if (c->min_idx_lebs > c->lst.idx_lebs)
-               rsvd_idx_lebs = c->min_idx_lebs -  c->lst.idx_lebs;
+       if (c->bi.min_idx_lebs > c->lst.idx_lebs)
+               rsvd_idx_lebs = c->bi.min_idx_lebs -  c->lst.idx_lebs;
        else
                rsvd_idx_lebs = 0;
        lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
index 151f108828204dc4d88c9d890fbcce051b2d8912..ded29f6224c27155765a366a6ec1e13644b224d6 100644 (file)
@@ -100,6 +100,10 @@ static int switch_gc_head(struct ubifs_info *c)
        if (err)
                return err;
 
+       err = ubifs_wbuf_sync_nolock(wbuf);
+       if (err)
+               return err;
+
        err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
        if (err)
                return err;
@@ -118,7 +122,7 @@ static int switch_gc_head(struct ubifs_info *c)
  * This function compares data nodes @a and @b. Returns %1 if @a has greater
  * inode or block number, and %-1 otherwise.
  */
-int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
 {
        ino_t inuma, inumb;
        struct ubifs_info *c = priv;
@@ -161,7 +165,8 @@ int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
  * first and sorted by length in descending order. Directory entry nodes go
  * after inode nodes and are sorted in ascending hash valuer order.
  */
-int nondata_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
+static int nondata_nodes_cmp(void *priv, struct list_head *a,
+                            struct list_head *b)
 {
        ino_t inuma, inumb;
        struct ubifs_info *c = priv;
@@ -473,6 +478,37 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
        ubifs_assert(c->gc_lnum != lnum);
        ubifs_assert(wbuf->lnum != lnum);
 
+       if (lp->free + lp->dirty == c->leb_size) {
+               /* Special case - a free LEB  */
+               dbg_gc("LEB %d is free, return it", lp->lnum);
+               ubifs_assert(!(lp->flags & LPROPS_INDEX));
+
+               if (lp->free != c->leb_size) {
+                       /*
+                        * Write buffers must be sync'd before unmapping
+                        * freeable LEBs, because one of them may contain data
+                        * which obsoletes something in 'lp->pnum'.
+                        */
+                       err = gc_sync_wbufs(c);
+                       if (err)
+                               return err;
+                       err = ubifs_change_one_lp(c, lp->lnum, c->leb_size,
+                                                 0, 0, 0, 0);
+                       if (err)
+                               return err;
+               }
+               err = ubifs_leb_unmap(c, lp->lnum);
+               if (err)
+                       return err;
+
+               if (c->gc_lnum == -1) {
+                       c->gc_lnum = lnum;
+                       return LEB_RETAINED;
+               }
+
+               return LEB_FREED;
+       }
+
        /*
         * We scan the entire LEB even though we only really need to scan up to
         * (c->leb_size - lp->free).
@@ -682,37 +718,6 @@ int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
                       "(min. space %d)", lp.lnum, lp.free, lp.dirty,
                       lp.free + lp.dirty, min_space);
 
-               if (lp.free + lp.dirty == c->leb_size) {
-                       /* An empty LEB was returned */
-                       dbg_gc("LEB %d is free, return it", lp.lnum);
-                       /*
-                        * ubifs_find_dirty_leb() doesn't return freeable index
-                        * LEBs.
-                        */
-                       ubifs_assert(!(lp.flags & LPROPS_INDEX));
-                       if (lp.free != c->leb_size) {
-                               /*
-                                * Write buffers must be sync'd before
-                                * unmapping freeable LEBs, because one of them
-                                * may contain data which obsoletes something
-                                * in 'lp.pnum'.
-                                */
-                               ret = gc_sync_wbufs(c);
-                               if (ret)
-                                       goto out;
-                               ret = ubifs_change_one_lp(c, lp.lnum,
-                                                         c->leb_size, 0, 0, 0,
-                                                         0);
-                               if (ret)
-                                       goto out;
-                       }
-                       ret = ubifs_leb_unmap(c, lp.lnum);
-                       if (ret)
-                               goto out;
-                       ret = lp.lnum;
-                       break;
-               }
-
                space_before = c->leb_size - wbuf->offs - wbuf->used;
                if (wbuf->lnum == -1)
                        space_before = 0;
index dfd168b7807e179fd450784a6e3a4c0d4b222ebe..166951e0dcd3c7b1dc232102c74bf8b8d61e8c1e 100644 (file)
@@ -393,7 +393,7 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
        ubifs_assert(wbuf->size % c->min_io_size == 0);
        ubifs_assert(!c->ro_media && !c->ro_mount);
        if (c->leb_size - wbuf->offs >= c->max_write_size)
-               ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size ));
+               ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
 
        if (c->ro_error)
                return -EROFS;
@@ -452,8 +452,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
  * @dtype: data type
  *
  * This function targets the write-buffer to logical eraseblock @lnum:@offs.
- * The write-buffer is synchronized if it is not empty. Returns zero in case of
- * success and a negative error code in case of failure.
+ * The write-buffer has to be empty. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
 int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
                           int dtype)
@@ -465,13 +465,7 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
        ubifs_assert(offs >= 0 && offs <= c->leb_size);
        ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
        ubifs_assert(lnum != wbuf->lnum);
-
-       if (wbuf->used > 0) {
-               int err = ubifs_wbuf_sync_nolock(wbuf);
-
-               if (err)
-                       return err;
-       }
+       ubifs_assert(wbuf->used == 0);
 
        spin_lock(&wbuf->lock);
        wbuf->lnum = lnum;
@@ -573,7 +567,7 @@ out_timers:
 int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
 {
        struct ubifs_info *c = wbuf->c;
-       int err, written, n, aligned_len = ALIGN(len, 8), offs;
+       int err, written, n, aligned_len = ALIGN(len, 8);
 
        dbg_io("%d bytes (%s) to jhead %s wbuf at LEB %d:%d", len,
               dbg_ntype(((struct ubifs_ch *)buf)->node_type),
@@ -588,7 +582,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
        ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
        ubifs_assert(!c->ro_media && !c->ro_mount);
        if (c->leb_size - wbuf->offs >= c->max_write_size)
-               ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size ));
+               ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
 
        if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) {
                err = -ENOSPC;
@@ -636,7 +630,6 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                goto exit;
        }
 
-       offs = wbuf->offs;
        written = 0;
 
        if (wbuf->used) {
@@ -653,7 +646,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                if (err)
                        goto out;
 
-               offs += wbuf->size;
+               wbuf->offs += wbuf->size;
                len -= wbuf->avail;
                aligned_len -= wbuf->avail;
                written += wbuf->avail;
@@ -672,7 +665,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                if (err)
                        goto out;
 
-               offs += wbuf->size;
+               wbuf->offs += wbuf->size;
                len -= wbuf->size;
                aligned_len -= wbuf->size;
                written += wbuf->size;
@@ -687,12 +680,13 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
        n = aligned_len >> c->max_write_shift;
        if (n) {
                n <<= c->max_write_shift;
-               dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum, offs);
-               err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written, offs, n,
-                                   wbuf->dtype);
+               dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
+                      wbuf->offs);
+               err = ubi_leb_write(c->ubi, wbuf->lnum, buf + written,
+                                   wbuf->offs, n, wbuf->dtype);
                if (err)
                        goto out;
-               offs += n;
+               wbuf->offs += n;
                aligned_len -= n;
                len -= n;
                written += n;
@@ -707,7 +701,6 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
                 */
                memcpy(wbuf->buf, buf + written, len);
 
-       wbuf->offs = offs;
        if (c->leb_size - wbuf->offs >= c->max_write_size)
                wbuf->size = c->max_write_size;
        else
index aed25e864227d83b1e200021014765a913d16518..34b1679e6e3a671684a1f08be42e155ce4a48ded 100644 (file)
@@ -141,14 +141,8 @@ again:
         * LEB with some empty space.
         */
        lnum = ubifs_find_free_space(c, len, &offs, squeeze);
-       if (lnum >= 0) {
-               /* Found an LEB, add it to the journal head */
-               err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
-               if (err)
-                       goto out_return;
-               /* A new bud was successfully allocated and added to the log */
+       if (lnum >= 0)
                goto out;
-       }
 
        err = lnum;
        if (err != -ENOSPC)
@@ -203,12 +197,23 @@ again:
                return 0;
        }
 
-       err = ubifs_add_bud_to_log(c, jhead, lnum, 0);
-       if (err)
-               goto out_return;
        offs = 0;
 
 out:
+       /*
+        * Make sure we synchronize the write-buffer before we add the new bud
+        * to the log. Otherwise we may have a power cut after the log
+        * reference node for the last bud (@lnum) is written but before the
+        * write-buffer data are written to the next-to-last bud
+        * (@wbuf->lnum). And the effect would be that the recovery would see
+        * that there is corruption in the next-to-last bud.
+        */
+       err = ubifs_wbuf_sync_nolock(wbuf);
+       if (err)
+               goto out_return;
+       err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
+       if (err)
+               goto out_return;
        err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
        if (err)
                goto out_unlock;
@@ -380,10 +385,8 @@ out:
        if (err == -ENOSPC) {
                /* This are some budgeting problems, print useful information */
                down_write(&c->commit_sem);
-               spin_lock(&c->space_lock);
                dbg_dump_stack();
-               dbg_dump_budg(c);
-               spin_unlock(&c->space_lock);
+               dbg_dump_budg(c, &c->bi);
                dbg_dump_lprops(c);
                cmt_retries = dbg_check_lprops(c);
                up_write(&c->commit_sem);
index 40fa780ebea7d6280cc83f30ca4db9b0a0052b98..affea9494ae23551fd34109f009ad6f74cdec276 100644 (file)
@@ -99,20 +99,6 @@ struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum)
        return NULL;
 }
 
-/**
- * next_log_lnum - switch to the next log LEB.
- * @c: UBIFS file-system description object
- * @lnum: current log LEB
- */
-static inline int next_log_lnum(const struct ubifs_info *c, int lnum)
-{
-       lnum += 1;
-       if (lnum > c->log_last)
-               lnum = UBIFS_LOG_LNUM;
-
-       return lnum;
-}
-
 /**
  * empty_log_bytes - calculate amount of empty space in the log.
  * @c: UBIFS file-system description object
@@ -257,7 +243,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
        ref->jhead = cpu_to_le32(jhead);
 
        if (c->lhead_offs > c->leb_size - c->ref_node_alsz) {
-               c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
+               c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
                c->lhead_offs = 0;
        }
 
@@ -425,7 +411,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
 
        /* Switch to the next log LEB */
        if (c->lhead_offs) {
-               c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
+               c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
                c->lhead_offs = 0;
        }
 
@@ -446,7 +432,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
 
        c->lhead_offs += len;
        if (c->lhead_offs == c->leb_size) {
-               c->lhead_lnum = next_log_lnum(c, c->lhead_lnum);
+               c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
                c->lhead_offs = 0;
        }
 
@@ -533,7 +519,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
        }
        mutex_lock(&c->log_mutex);
        for (lnum = old_ltail_lnum; lnum != c->ltail_lnum;
-            lnum = next_log_lnum(c, lnum)) {
+            lnum = ubifs_next_log_lnum(c, lnum)) {
                dbg_log("unmap log LEB %d", lnum);
                err = ubifs_leb_unmap(c, lnum);
                if (err)
@@ -642,7 +628,7 @@ static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
                err = ubifs_leb_change(c, *lnum, buf, sz, UBI_SHORTTERM);
                if (err)
                        return err;
-               *lnum = next_log_lnum(c, *lnum);
+               *lnum = ubifs_next_log_lnum(c, *lnum);
                *offs = 0;
        }
        memcpy(buf + *offs, node, len);
@@ -712,7 +698,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
                ubifs_scan_destroy(sleb);
                if (lnum == c->lhead_lnum)
                        break;
-               lnum = next_log_lnum(c, lnum);
+               lnum = ubifs_next_log_lnum(c, lnum);
        }
        if (offs) {
                int sz = ALIGN(offs, c->min_io_size);
@@ -732,7 +718,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
        /* Unmap remaining LEBs */
        lnum = write_lnum;
        do {
-               lnum = next_log_lnum(c, lnum);
+               lnum = ubifs_next_log_lnum(c, lnum);
                err = ubifs_leb_unmap(c, lnum);
                if (err)
                        return err;
index 0ee0847f24218b0e44cfefeb888dc501b8d159f1..667884f4a61537717adae74d76ba6ebe6a2982ac 100644 (file)
@@ -1006,22 +1006,12 @@ out:
        }
 }
 
-/**
- * struct scan_check_data - data provided to scan callback function.
- * @lst: LEB properties statistics
- * @err: error code
- */
-struct scan_check_data {
-       struct ubifs_lp_stats lst;
-       int err;
-};
-
 /**
  * scan_check_cb - scan callback.
  * @c: the UBIFS file-system description object
  * @lp: LEB properties to scan
  * @in_tree: whether the LEB properties are in main memory
- * @data: information passed to and from the caller of the scan
+ * @lst: lprops statistics to update
  *
  * This function returns a code that indicates whether the scan should continue
  * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
@@ -1030,11 +1020,10 @@ struct scan_check_data {
  */
 static int scan_check_cb(struct ubifs_info *c,
                         const struct ubifs_lprops *lp, int in_tree,
-                        struct scan_check_data *data)
+                        struct ubifs_lp_stats *lst)
 {
        struct ubifs_scan_leb *sleb;
        struct ubifs_scan_node *snod;
-       struct ubifs_lp_stats *lst = &data->lst;
        int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
        void *buf = NULL;
 
@@ -1044,7 +1033,7 @@ static int scan_check_cb(struct ubifs_info *c,
                if (cat != (lp->flags & LPROPS_CAT_MASK)) {
                        ubifs_err("bad LEB category %d expected %d",
                                  (lp->flags & LPROPS_CAT_MASK), cat);
-                       goto out;
+                       return -EINVAL;
                }
        }
 
@@ -1078,7 +1067,7 @@ static int scan_check_cb(struct ubifs_info *c,
                        }
                        if (!found) {
                                ubifs_err("bad LPT list (category %d)", cat);
-                               goto out;
+                               return -EINVAL;
                        }
                }
        }
@@ -1090,45 +1079,40 @@ static int scan_check_cb(struct ubifs_info *c,
                if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
                    lp != heap->arr[lp->hpos]) {
                        ubifs_err("bad LPT heap (category %d)", cat);
-                       goto out;
+                       return -EINVAL;
                }
        }
 
        buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
-       if (!buf) {
-               ubifs_err("cannot allocate memory to scan LEB %d", lnum);
-               goto out;
+       if (!buf)
+               return -ENOMEM;
+
+       /*
+        * After an unclean unmount, empty and freeable LEBs
+        * may contain garbage - do not scan them.
+        */
+       if (lp->free == c->leb_size) {
+               lst->empty_lebs += 1;
+               lst->total_free += c->leb_size;
+               lst->total_dark += ubifs_calc_dark(c, c->leb_size);
+               return LPT_SCAN_CONTINUE;
+       }
+       if (lp->free + lp->dirty == c->leb_size &&
+           !(lp->flags & LPROPS_INDEX)) {
+               lst->total_free  += lp->free;
+               lst->total_dirty += lp->dirty;
+               lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
+               return LPT_SCAN_CONTINUE;
        }
 
        sleb = ubifs_scan(c, lnum, 0, buf, 0);
        if (IS_ERR(sleb)) {
-               /*
-                * After an unclean unmount, empty and freeable LEBs
-                * may contain garbage.
-                */
-               if (lp->free == c->leb_size) {
-                       ubifs_err("scan errors were in empty LEB "
-                                 "- continuing checking");
-                       lst->empty_lebs += 1;
-                       lst->total_free += c->leb_size;
-                       lst->total_dark += ubifs_calc_dark(c, c->leb_size);
-                       ret = LPT_SCAN_CONTINUE;
-                       goto exit;
-               }
-
-               if (lp->free + lp->dirty == c->leb_size &&
-                   !(lp->flags & LPROPS_INDEX)) {
-                       ubifs_err("scan errors were in freeable LEB "
-                                 "- continuing checking");
-                       lst->total_free  += lp->free;
-                       lst->total_dirty += lp->dirty;
-                       lst->total_dark  +=  ubifs_calc_dark(c, c->leb_size);
-                       ret = LPT_SCAN_CONTINUE;
-                       goto exit;
+               ret = PTR_ERR(sleb);
+               if (ret == -EUCLEAN) {
+                       dbg_dump_lprops(c);
+                       dbg_dump_budg(c, &c->bi);
                }
-               data->err = PTR_ERR(sleb);
-               ret = LPT_SCAN_STOP;
-               goto exit;
+               goto out;
        }
 
        is_idx = -1;
@@ -1246,10 +1230,8 @@ static int scan_check_cb(struct ubifs_info *c,
        }
 
        ubifs_scan_destroy(sleb);
-       ret = LPT_SCAN_CONTINUE;
-exit:
        vfree(buf);
-       return ret;
+       return LPT_SCAN_CONTINUE;
 
 out_print:
        ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, "
@@ -1258,10 +1240,10 @@ out_print:
        dbg_dump_leb(c, lnum);
 out_destroy:
        ubifs_scan_destroy(sleb);
+       ret = -EINVAL;
 out:
        vfree(buf);
-       data->err = -EINVAL;
-       return LPT_SCAN_STOP;
+       return ret;
 }
 
 /**
@@ -1278,8 +1260,7 @@ out:
 int dbg_check_lprops(struct ubifs_info *c)
 {
        int i, err;
-       struct scan_check_data data;
-       struct ubifs_lp_stats *lst = &data.lst;
+       struct ubifs_lp_stats lst;
 
        if (!(ubifs_chk_flags & UBIFS_CHK_LPROPS))
                return 0;
@@ -1294,29 +1275,23 @@ int dbg_check_lprops(struct ubifs_info *c)
                        return err;
        }
 
-       memset(lst, 0, sizeof(struct ubifs_lp_stats));
-
-       data.err = 0;
+       memset(&lst, 0, sizeof(struct ubifs_lp_stats));
        err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
                                    (ubifs_lpt_scan_callback)scan_check_cb,
-                                   &data);
+                                   &lst);
        if (err && err != -ENOSPC)
                goto out;
-       if (data.err) {
-               err = data.err;
-               goto out;
-       }
 
-       if (lst->empty_lebs != c->lst.empty_lebs ||
-           lst->idx_lebs != c->lst.idx_lebs ||
-           lst->total_free != c->lst.total_free ||
-           lst->total_dirty != c->lst.total_dirty ||
-           lst->total_used != c->lst.total_used) {
+       if (lst.empty_lebs != c->lst.empty_lebs ||
+           lst.idx_lebs != c->lst.idx_lebs ||
+           lst.total_free != c->lst.total_free ||
+           lst.total_dirty != c->lst.total_dirty ||
+           lst.total_used != c->lst.total_used) {
                ubifs_err("bad overall accounting");
                ubifs_err("calculated: empty_lebs %d, idx_lebs %d, "
                          "total_free %lld, total_dirty %lld, total_used %lld",
-                         lst->empty_lebs, lst->idx_lebs, lst->total_free,
-                         lst->total_dirty, lst->total_used);
+                         lst.empty_lebs, lst.idx_lebs, lst.total_free,
+                         lst.total_dirty, lst.total_used);
                ubifs_err("read from lprops: empty_lebs %d, idx_lebs %d, "
                          "total_free %lld, total_dirty %lld, total_used %lld",
                          c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
@@ -1325,11 +1300,11 @@ int dbg_check_lprops(struct ubifs_info *c)
                goto out;
        }
 
-       if (lst->total_dead != c->lst.total_dead ||
-           lst->total_dark != c->lst.total_dark) {
+       if (lst.total_dead != c->lst.total_dead ||
+           lst.total_dark != c->lst.total_dark) {
                ubifs_err("bad dead/dark space accounting");
                ubifs_err("calculated: total_dead %lld, total_dark %lld",
-                         lst->total_dead, lst->total_dark);
+                         lst.total_dead, lst.total_dark);
                ubifs_err("read from lprops: total_dead %lld, total_dark %lld",
                          c->lst.total_dead, c->lst.total_dark);
                err = -EINVAL;
index 0c9c69bd983a94c0854d90508a15832b99b6fe0f..dfcb5748a7dc14db8695f694e021f4c1a52fefcc 100644 (file)
 #include <linux/slab.h>
 #include "ubifs.h"
 
+#ifdef CONFIG_UBIFS_FS_DEBUG
+static int dbg_populate_lsave(struct ubifs_info *c);
+#else
+#define dbg_populate_lsave(c) 0
+#endif
+
 /**
  * first_dirty_cnode - find first dirty cnode.
  * @c: UBIFS file-system description object
@@ -586,7 +592,7 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
                        if (nnode->nbranch[iip].lnum)
                                break;
                }
-       } while (iip >= UBIFS_LPT_FANOUT);
+       } while (iip >= UBIFS_LPT_FANOUT);
 
        /* Go right */
        nnode = ubifs_get_nnode(c, nnode, iip);
@@ -815,6 +821,10 @@ static void populate_lsave(struct ubifs_info *c)
                c->lpt_drty_flgs |= LSAVE_DIRTY;
                ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);
        }
+
+       if (dbg_populate_lsave(c))
+               return;
+
        list_for_each_entry(lprops, &c->empty_list, list) {
                c->lsave[cnt++] = lprops->lnum;
                if (cnt >= c->lsave_cnt)
@@ -1994,4 +2004,47 @@ void dbg_dump_lpt_lebs(const struct ubifs_info *c)
               current->pid);
 }
 
+/**
+ * dbg_populate_lsave - debugging version of 'populate_lsave()'
+ * @c: UBIFS file-system description object
+ *
+ * This is a debugging version for 'populate_lsave()' which populates lsave
+ * with random LEBs instead of useful LEBs, which is good for test coverage.
+ * Returns zero if lsave has not been populated (this debugging feature is
+ * disabled) an non-zero if lsave has been populated.
+ */
+static int dbg_populate_lsave(struct ubifs_info *c)
+{
+       struct ubifs_lprops *lprops;
+       struct ubifs_lpt_heap *heap;
+       int i;
+
+       if (!(ubifs_chk_flags & UBIFS_CHK_GEN))
+               return 0;
+       if (random32() & 3)
+               return 0;
+
+       for (i = 0; i < c->lsave_cnt; i++)
+               c->lsave[i] = c->main_first;
+
+       list_for_each_entry(lprops, &c->empty_list, list)
+               c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
+       list_for_each_entry(lprops, &c->freeable_list, list)
+               c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
+       list_for_each_entry(lprops, &c->frdi_idx_list, list)
+               c->lsave[random32() % c->lsave_cnt] = lprops->lnum;
+
+       heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
+       for (i = 0; i < heap->cnt; i++)
+               c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
+       heap = &c->lpt_heap[LPROPS_DIRTY - 1];
+       for (i = 0; i < heap->cnt; i++)
+               c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
+       heap = &c->lpt_heap[LPROPS_FREE - 1];
+       for (i = 0; i < heap->cnt; i++)
+               c->lsave[random32() % c->lsave_cnt] = heap->arr[i]->lnum;
+
+       return 1;
+}
+
 #endif /* CONFIG_UBIFS_FS_DEBUG */
index 21f47afdacff170b5241d69e00edbb6fb3e0ae4b..278c2382e8c21a7daafaea11c63caf9663c30d52 100644 (file)
@@ -148,7 +148,7 @@ static int validate_master(const struct ubifs_info *c)
        }
 
        main_sz = (long long)c->main_lebs * c->leb_size;
-       if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) {
+       if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) {
                err = 9;
                goto out;
        }
@@ -218,7 +218,7 @@ static int validate_master(const struct ubifs_info *c)
        }
 
        if (c->lst.total_dead + c->lst.total_dark +
-           c->lst.total_used + c->old_idx_sz > main_sz) {
+           c->lst.total_used + c->bi.old_idx_sz > main_sz) {
                err = 21;
                goto out;
        }
@@ -286,7 +286,7 @@ int ubifs_read_master(struct ubifs_info *c)
        c->gc_lnum         = le32_to_cpu(c->mst_node->gc_lnum);
        c->ihead_lnum      = le32_to_cpu(c->mst_node->ihead_lnum);
        c->ihead_offs      = le32_to_cpu(c->mst_node->ihead_offs);
-       c->old_idx_sz      = le64_to_cpu(c->mst_node->index_size);
+       c->bi.old_idx_sz   = le64_to_cpu(c->mst_node->index_size);
        c->lpt_lnum        = le32_to_cpu(c->mst_node->lpt_lnum);
        c->lpt_offs        = le32_to_cpu(c->mst_node->lpt_offs);
        c->nhead_lnum      = le32_to_cpu(c->mst_node->nhead_lnum);
@@ -305,7 +305,7 @@ int ubifs_read_master(struct ubifs_info *c)
        c->lst.total_dead  = le64_to_cpu(c->mst_node->total_dead);
        c->lst.total_dark  = le64_to_cpu(c->mst_node->total_dark);
 
-       c->calc_idx_sz = c->old_idx_sz;
+       c->calc_idx_sz = c->bi.old_idx_sz;
 
        if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
                c->no_orphs = 1;
index c3de04dc952a5c735428f73ad53c3ad40cf3dc4e..0b5296a9a4c5cc811ab2cc2d7ac50fdadd69f20e 100644 (file)
@@ -340,4 +340,21 @@ static inline void ubifs_release_lprops(struct ubifs_info *c)
        mutex_unlock(&c->lp_mutex);
 }
 
+/**
+ * ubifs_next_log_lnum - switch to the next log LEB.
+ * @c: UBIFS file-system description object
+ * @lnum: current log LEB
+ *
+ * This helper function returns the log LEB number which goes next after LEB
+ * 'lnum'.
+ */
+static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
+{
+       lnum += 1;
+       if (lnum > c->log_last)
+               lnum = UBIFS_LOG_LNUM;
+
+       return lnum;
+}
+
 #endif /* __UBIFS_MISC_H__ */
index 09df318e368f492f3d249f97680c1f9b479393c7..bd644bf587a8a7afbef10b83fdef31f4cb71fdf3 100644 (file)
@@ -673,7 +673,8 @@ static int kill_orphans(struct ubifs_info *c)
                sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
                if (IS_ERR(sleb)) {
                        if (PTR_ERR(sleb) == -EUCLEAN)
-                               sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0);
+                               sleb = ubifs_recover_leb(c, lnum, 0,
+                                                        c->sbuf, 0);
                        if (IS_ERR(sleb)) {
                                err = PTR_ERR(sleb);
                                break;
index 3dbad6fbd1eba528661e458ae56e97c03c43b609..731d9e2e7b50c848bf6088237922c43e0f00ef88 100644 (file)
@@ -564,13 +564,16 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 }
 
 /**
- * drop_incomplete_group - drop nodes from an incomplete group.
+ * drop_last_node - drop the last node or group of nodes.
  * @sleb: scanned LEB information
  * @offs: offset of dropped nodes is returned here
+ * @grouped: non-zero if whole group of nodes have to be dropped
  *
- * This function returns %1 if nodes are dropped and %0 otherwise.
+ * This is a helper function for 'ubifs_recover_leb()' which drops the last
+ * node of the scanned LEB or the last group of nodes if @grouped is not zero.
+ * This function returns %1 if a node was dropped and %0 otherwise.
  */
-static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
+static int drop_last_node(struct ubifs_scan_leb *sleb, int *offs, int grouped)
 {
        int dropped = 0;
 
@@ -589,6 +592,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
                kfree(snod);
                sleb->nodes_cnt -= 1;
                dropped = 1;
+               if (!grouped)
+                       break;
        }
        return dropped;
 }
@@ -609,8 +614,7 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs)
 struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                                         int offs, void *sbuf, int grouped)
 {
-       int err, len = c->leb_size - offs, need_clean = 0, quiet = 1;
-       int empty_chkd = 0, start = offs;
+       int ret = 0, err, len = c->leb_size - offs, start = offs, min_io_unit;
        struct ubifs_scan_leb *sleb;
        void *buf = sbuf + offs;
 
@@ -620,12 +624,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
        if (IS_ERR(sleb))
                return sleb;
 
-       if (sleb->ecc)
-               need_clean = 1;
-
+       ubifs_assert(len >= 8);
        while (len >= 8) {
-               int ret;
-
                dbg_scan("look at LEB %d:%d (%d bytes left)",
                         lnum, offs, len);
 
@@ -635,8 +635,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                 * Scan quietly until there is an error from which we cannot
                 * recover
                 */
-               ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
-
+               ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
                if (ret == SCANNED_A_NODE) {
                        /* A valid node, and not a padding node */
                        struct ubifs_ch *ch = buf;
@@ -649,70 +648,32 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                        offs += node_len;
                        buf += node_len;
                        len -= node_len;
-                       continue;
-               }
-
-               if (ret > 0) {
+               } else if (ret > 0) {
                        /* Padding bytes or a valid padding node */
                        offs += ret;
                        buf += ret;
                        len -= ret;
-                       continue;
-               }
-
-               if (ret == SCANNED_EMPTY_SPACE) {
-                       if (!is_empty(buf, len)) {
-                               if (!is_last_write(c, buf, offs))
-                                       break;
-                               clean_buf(c, &buf, lnum, &offs, &len);
-                               need_clean = 1;
-                       }
-                       empty_chkd = 1;
+               } else if (ret == SCANNED_EMPTY_SPACE ||
+                          ret == SCANNED_GARBAGE     ||
+                          ret == SCANNED_A_BAD_PAD_NODE ||
+                          ret == SCANNED_A_CORRUPT_NODE) {
+                       dbg_rcvry("found corruption - %d", ret);
                        break;
-               }
-
-               if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE)
-                       if (is_last_write(c, buf, offs)) {
-                               clean_buf(c, &buf, lnum, &offs, &len);
-                               need_clean = 1;
-                               empty_chkd = 1;
-                               break;
-                       }
-
-               if (ret == SCANNED_A_CORRUPT_NODE)
-                       if (no_more_nodes(c, buf, len, lnum, offs)) {
-                               clean_buf(c, &buf, lnum, &offs, &len);
-                               need_clean = 1;
-                               empty_chkd = 1;
-                               break;
-                       }
-
-               if (quiet) {
-                       /* Redo the last scan but noisily */
-                       quiet = 0;
-                       continue;
-               }
-
-               switch (ret) {
-               case SCANNED_GARBAGE:
-                       dbg_err("garbage");
-                       goto corrupted;
-               case SCANNED_A_CORRUPT_NODE:
-               case SCANNED_A_BAD_PAD_NODE:
-                       dbg_err("bad node");
-                       goto corrupted;
-               default:
-                       dbg_err("unknown");
+               } else {
+                       dbg_err("unexpected return value %d", ret);
                        err = -EINVAL;
                        goto error;
                }
        }
 
-       if (!empty_chkd && !is_empty(buf, len)) {
-               if (is_last_write(c, buf, offs)) {
-                       clean_buf(c, &buf, lnum, &offs, &len);
-                       need_clean = 1;
-               } else {
+       if (ret == SCANNED_GARBAGE || ret == SCANNED_A_BAD_PAD_NODE) {
+               if (!is_last_write(c, buf, offs))
+                       goto corrupted_rescan;
+       } else if (ret == SCANNED_A_CORRUPT_NODE) {
+               if (!no_more_nodes(c, buf, len, lnum, offs))
+                       goto corrupted_rescan;
+       } else if (!is_empty(buf, len)) {
+               if (!is_last_write(c, buf, offs)) {
                        int corruption = first_non_ff(buf, len);
 
                        /*
@@ -728,29 +689,82 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                }
        }
 
-       /* Drop nodes from incomplete group */
-       if (grouped && drop_incomplete_group(sleb, &offs)) {
-               buf = sbuf + offs;
-               len = c->leb_size - offs;
-               clean_buf(c, &buf, lnum, &offs, &len);
-               need_clean = 1;
-       }
+       min_io_unit = round_down(offs, c->min_io_size);
+       if (grouped)
+               /*
+                * If nodes are grouped, always drop the incomplete group at
+                * the end.
+                */
+               drop_last_node(sleb, &offs, 1);
 
-       if (offs % c->min_io_size) {
-               clean_buf(c, &buf, lnum, &offs, &len);
-               need_clean = 1;
-       }
+       /*
+        * While we are in the middle of the same min. I/O unit keep dropping
+        * nodes. So basically, what we want is to make sure that the last min.
+        * I/O unit where we saw the corruption is dropped completely with all
+        * the uncorrupted node which may possibly sit there.
+        *
+        * In other words, let's name the min. I/O unit where the corruption
+        * starts B, and the previous min. I/O unit A. The below code tries to
+        * deal with a situation when half of B contains valid nodes or the end
+        * of a valid node, and the second half of B contains corrupted data or
+        * garbage. This means that UBIFS had been writing to B just before the
+        * power cut happened. I do not know how realistic is this scenario
+        * that half of the min. I/O unit had been written successfully and the
+        * other half not, but this is possible in our 'failure mode emulation'
+        * infrastructure at least.
+        *
+        * So what is the problem, why we need to drop those nodes? Whey can't
+        * we just clean-up the second half of B by putting a padding node
+        * there? We can, and this works fine with one exception which was
+        * reproduced with power cut emulation testing and happens extremely
+        * rarely. The description follows, but it is worth noting that that is
+        * only about the GC head, so we could do this trick only if the bud
+        * belongs to the GC head, but it does not seem to be worth an
+        * additional "if" statement.
+        *
+        * So, imagine the file-system is full, we run GC which is moving valid
+        * nodes from LEB X to LEB Y (obviously, LEB Y is the current GC head
+        * LEB). The @c->gc_lnum is -1, which means that GC will retain LEB X
+        * and will try to continue. Imagine that LEB X is currently the
+        * dirtiest LEB, and the amount of used space in LEB Y is exactly the
+        * same as amount of free space in LEB X.
+        *
+        * And a power cut happens when nodes are moved from LEB X to LEB Y. We
+        * are here trying to recover LEB Y which is the GC head LEB. We find
+        * the min. I/O unit B as described above. Then we clean-up LEB Y by
+        * padding min. I/O unit. And later 'ubifs_rcvry_gc_commit()' function
+        * fails, because it cannot find a dirty LEB which could be GC'd into
+        * LEB Y! Even LEB X does not match because the amount of valid nodes
+        * there does not fit the free space in LEB Y any more! And this is
+        * because of the padding node which we added to LEB Y. The
+        * user-visible effect of this which I once observed and analysed is
+        * that we cannot mount the file-system with -ENOSPC error.
+        *
+        * So obviously, to make sure that situation does not happen we should
+        * free min. I/O unit B in LEB Y completely and the last used min. I/O
+        * unit in LEB Y should be A. This is basically what the below code
+        * tries to do.
+        */
+       while (min_io_unit == round_down(offs, c->min_io_size) &&
+              min_io_unit != offs &&
+              drop_last_node(sleb, &offs, grouped));
+
+       buf = sbuf + offs;
+       len = c->leb_size - offs;
 
+       clean_buf(c, &buf, lnum, &offs, &len);
        ubifs_end_scan(c, sleb, lnum, offs);
 
-       if (need_clean) {
-               err = fix_unclean_leb(c, sleb, start);
-               if (err)
-                       goto error;
-       }
+       err = fix_unclean_leb(c, sleb, start);
+       if (err)
+               goto error;
 
        return sleb;
 
+corrupted_rescan:
+       /* Re-scan the corrupted data with verbose messages */
+       dbg_err("corruptio %d", ret);
+       ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
 corrupted:
        ubifs_scanned_corruption(c, lnum, offs, buf);
        err = -EUCLEAN;
@@ -1069,6 +1083,53 @@ int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf)
        return 0;
 }
 
+/**
+ * grab_empty_leb - grab an empty LEB to use as GC LEB and run commit.
+ * @c: UBIFS file-system description object
+ *
+ * This is a helper function for 'ubifs_rcvry_gc_commit()' which grabs an empty
+ * LEB to be used as GC LEB (@c->gc_lnum), and then runs the commit. Returns
+ * zero in case of success and a negative error code in case of failure.
+ */
+static int grab_empty_leb(struct ubifs_info *c)
+{
+       int lnum, err;
+
+       /*
+        * Note, it is very important to first search for an empty LEB and then
+        * run the commit, not vice-versa. The reason is that there might be
+        * only one empty LEB at the moment, the one which has been the
+        * @c->gc_lnum just before the power cut happened. During the regular
+        * UBIFS operation (not now) @c->gc_lnum is marked as "taken", so no
+        * one but GC can grab it. But at this moment this single empty LEB is
+        * not marked as taken, so if we run commit - what happens? Right, the
+        * commit will grab it and write the index there. Remember that the
+        * index always expands as long as there is free space, and it only
+        * starts consolidating when we run out of space.
+        *
+        * IOW, if we run commit now, we might not be able to find a free LEB
+        * after this.
+        */
+       lnum = ubifs_find_free_leb_for_idx(c);
+       if (lnum < 0) {
+               dbg_err("could not find an empty LEB");
+               dbg_dump_lprops(c);
+               dbg_dump_budg(c, &c->bi);
+               return lnum;
+       }
+
+       /* Reset the index flag */
+       err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
+                                 LPROPS_INDEX, 0);
+       if (err)
+               return err;
+
+       c->gc_lnum = lnum;
+       dbg_rcvry("found empty LEB %d, run commit", lnum);
+
+       return ubifs_run_commit(c);
+}
+
 /**
  * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit.
  * @c: UBIFS file-system description object
@@ -1091,71 +1152,26 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
 {
        struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
        struct ubifs_lprops lp;
-       int lnum, err;
+       int err;
+
+       dbg_rcvry("GC head LEB %d, offs %d", wbuf->lnum, wbuf->offs);
 
        c->gc_lnum = -1;
-       if (wbuf->lnum == -1) {
-               dbg_rcvry("no GC head LEB");
-               goto find_free;
-       }
-       /*
-        * See whether the used space in the dirtiest LEB fits in the GC head
-        * LEB.
-        */
-       if (wbuf->offs == c->leb_size) {
-               dbg_rcvry("no room in GC head LEB");
-               goto find_free;
-       }
+       if (wbuf->lnum == -1 || wbuf->offs == c->leb_size)
+               return grab_empty_leb(c);
+
        err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
        if (err) {
-               /*
-                * There are no dirty or empty LEBs subject to here being
-                * enough for the index. Try to use
-                * 'ubifs_find_free_leb_for_idx()', which will return any empty
-                * LEBs (ignoring index requirements). If the index then
-                * doesn't have enough LEBs the recovery commit will fail -
-                * which is the  same result anyway i.e. recovery fails. So
-                * there is no problem ignoring index  requirements and just
-                * grabbing a free LEB since we have already established there
-                * is not a dirty LEB we could have used instead.
-                */
-               if (err == -ENOSPC) {
-                       dbg_rcvry("could not find a dirty LEB");
-                       goto find_free;
-               }
-               return err;
-       }
-       ubifs_assert(!(lp.flags & LPROPS_INDEX));
-       lnum = lp.lnum;
-       if (lp.free + lp.dirty == c->leb_size) {
-               /* An empty LEB was returned */
-               if (lp.free != c->leb_size) {
-                       err = ubifs_change_one_lp(c, lnum, c->leb_size,
-                                                 0, 0, 0, 0);
-                       if (err)
-                               return err;
-               }
-               err = ubifs_leb_unmap(c, lnum);
-               if (err)
+               if (err != -ENOSPC)
                        return err;
-               c->gc_lnum = lnum;
-               dbg_rcvry("allocated LEB %d for GC", lnum);
-               /* Run the commit */
-               dbg_rcvry("committing");
-               return ubifs_run_commit(c);
-       }
-       /*
-        * There was no empty LEB so the used space in the dirtiest LEB must fit
-        * in the GC head LEB.
-        */
-       if (lp.free + lp.dirty < wbuf->offs) {
-               dbg_rcvry("LEB %d doesn't fit in GC head LEB %d:%d",
-                         lnum, wbuf->lnum, wbuf->offs);
-               err = ubifs_return_leb(c, lnum);
-               if (err)
-                       return err;
-               goto find_free;
+
+               dbg_rcvry("could not find a dirty LEB");
+               return grab_empty_leb(c);
        }
+
+       ubifs_assert(!(lp.flags & LPROPS_INDEX));
+       ubifs_assert(lp.free + lp.dirty >= wbuf->offs);
+
        /*
         * We run the commit before garbage collection otherwise subsequent
         * mounts will see the GC and orphan deletion in a different order.
@@ -1164,11 +1180,8 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
        err = ubifs_run_commit(c);
        if (err)
                return err;
-       /*
-        * The data in the dirtiest LEB fits in the GC head LEB, so do the GC
-        * - use locking to keep 'ubifs_assert()' happy.
-        */
-       dbg_rcvry("GC'ing LEB %d", lnum);
+
+       dbg_rcvry("GC'ing LEB %d", lp.lnum);
        mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
        err = ubifs_garbage_collect_leb(c, &lp);
        if (err >= 0) {
@@ -1184,37 +1197,17 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
                        err = -EINVAL;
                return err;
        }
-       if (err != LEB_RETAINED) {
-               dbg_err("GC returned %d", err);
+
+       ubifs_assert(err == LEB_RETAINED);
+       if (err != LEB_RETAINED)
                return -EINVAL;
-       }
+
        err = ubifs_leb_unmap(c, c->gc_lnum);
        if (err)
                return err;
-       dbg_rcvry("allocated LEB %d for GC", lnum);
-       return 0;
 
-find_free:
-       /*
-        * There is no GC head LEB or the free space in the GC head LEB is too
-        * small, or there are not dirty LEBs. Allocate gc_lnum by calling
-        * 'ubifs_find_free_leb_for_idx()' so GC is not run.
-        */
-       lnum = ubifs_find_free_leb_for_idx(c);
-       if (lnum < 0) {
-               dbg_err("could not find an empty LEB");
-               return lnum;
-       }
-       /* And reset the index flag */
-       err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
-                                 LPROPS_INDEX, 0);
-       if (err)
-               return err;
-       c->gc_lnum = lnum;
-       dbg_rcvry("allocated LEB %d for GC", lnum);
-       /* Run the commit */
-       dbg_rcvry("committing");
-       return ubifs_run_commit(c);
+       dbg_rcvry("allocated LEB %d for GC", lp.lnum);
+       return 0;
 }
 
 /**
@@ -1456,7 +1449,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
        err = ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
        if (err)
                goto out;
-       dbg_rcvry("inode %lu at %d:%d size %lld -> %lld ",
+       dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
                  (unsigned long)e->inum, lnum, offs, i_size, e->d_size);
        return 0;
 
@@ -1505,20 +1498,27 @@ int ubifs_recover_size(struct ubifs_info *c)
                                e->i_size = le64_to_cpu(ino->size);
                        }
                }
+
                if (e->exists && e->i_size < e->d_size) {
-                       if (!e->inode && c->ro_mount) {
+                       if (c->ro_mount) {
                                /* Fix the inode size and pin it in memory */
                                struct inode *inode;
+                               struct ubifs_inode *ui;
+
+                               ubifs_assert(!e->inode);
 
                                inode = ubifs_iget(c->vfs_sb, e->inum);
                                if (IS_ERR(inode))
                                        return PTR_ERR(inode);
+
+                               ui = ubifs_inode(inode);
                                if (inode->i_size < e->d_size) {
                                        dbg_rcvry("ino %lu size %lld -> %lld",
                                                  (unsigned long)e->inum,
-                                                 e->d_size, inode->i_size);
+                                                 inode->i_size, e->d_size);
                                        inode->i_size = e->d_size;
-                                       ubifs_inode(inode)->ui_size = e->d_size;
+                                       ui->ui_size = e->d_size;
+                                       ui->synced_i_size = e->d_size;
                                        e->inode = inode;
                                        this = rb_next(this);
                                        continue;
@@ -1533,9 +1533,11 @@ int ubifs_recover_size(struct ubifs_info *c)
                                        iput(e->inode);
                        }
                }
+
                this = rb_next(this);
                rb_erase(&e->rb, &c->size_tree);
                kfree(e);
        }
+
        return 0;
 }
index d3d6d365bfc11345d49e3a6bbdc33dd97c476ea9..6617280d167938a7bbf8f925c1af0fe0986c8496 100644 (file)
  */
 
 #include "ubifs.h"
-
-/*
- * Replay flags.
- *
- * REPLAY_DELETION: node was deleted
- * REPLAY_REF: node is a reference node
- */
-enum {
-       REPLAY_DELETION = 1,
-       REPLAY_REF = 2,
-};
+#include <linux/list_sort.h>
 
 /**
- * struct replay_entry - replay tree entry.
+ * struct replay_entry - replay list entry.
  * @lnum: logical eraseblock number of the node
  * @offs: node offset
  * @len: node length
+ * @deletion: non-zero if this entry corresponds to a node deletion
  * @sqnum: node sequence number
- * @flags: replay flags
- * @rb: links the replay tree
+ * @list: links the replay list
  * @key: node key
  * @nm: directory entry name
  * @old_size: truncation old size
  * @new_size: truncation new size
- * @free: amount of free space in a bud
- * @dirty: amount of dirty space in a bud from padding and deletion nodes
- * @jhead: journal head number of the bud
  *
- * UBIFS journal replay must compare node sequence numbers, which means it must
- * build a tree of node information to insert into the TNC.
+ * The replay process first scans all buds and builds the replay list, then
+ * sorts the replay list in nodes sequence number order, and then inserts all
+ * the replay entries to the TNC.
  */
 struct replay_entry {
        int lnum;
        int offs;
        int len;
+       unsigned int deletion:1;
        unsigned long long sqnum;
-       int flags;
-       struct rb_node rb;
+       struct list_head list;
        union ubifs_key key;
        union {
                struct qstr nm;
@@ -78,11 +66,6 @@ struct replay_entry {
                        loff_t old_size;
                        loff_t new_size;
                };
-               struct {
-                       int free;
-                       int dirty;
-                       int jhead;
-               };
        };
 };
 
@@ -90,57 +73,64 @@ struct replay_entry {
  * struct bud_entry - entry in the list of buds to replay.
  * @list: next bud in the list
  * @bud: bud description object
- * @free: free bytes in the bud
  * @sqnum: reference node sequence number
+ * @free: free bytes in the bud
+ * @dirty: dirty bytes in the bud
  */
 struct bud_entry {
        struct list_head list;
        struct ubifs_bud *bud;
-       int free;
        unsigned long long sqnum;
+       int free;
+       int dirty;
 };
 
 /**
  * set_bud_lprops - set free and dirty space used by a bud.
  * @c: UBIFS file-system description object
- * @r: replay entry of bud
+ * @b: bud entry which describes the bud
+ *
+ * This function makes sure the LEB properties of bud @b are set correctly
+ * after the replay. Returns zero in case of success and a negative error code
+ * in case of failure.
  */
-static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
+static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
 {
        const struct ubifs_lprops *lp;
        int err = 0, dirty;
 
        ubifs_get_lprops(c);
 
-       lp = ubifs_lpt_lookup_dirty(c, r->lnum);
+       lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum);
        if (IS_ERR(lp)) {
                err = PTR_ERR(lp);
                goto out;
        }
 
        dirty = lp->dirty;
-       if (r->offs == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
+       if (b->bud->start == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
                /*
                 * The LEB was added to the journal with a starting offset of
                 * zero which means the LEB must have been empty. The LEB
-                * property values should be lp->free == c->leb_size and
-                * lp->dirty == 0, but that is not the case. The reason is that
-                * the LEB was garbage collected. The garbage collector resets
-                * the free and dirty space without recording it anywhere except
-                * lprops, so if there is not a commit then lprops does not have
-                * that information next time the file system is mounted.
+                * property values should be @lp->free == @c->leb_size and
+                * @lp->dirty == 0, but that is not the case. The reason is that
+                * the LEB had been garbage collected before it became the bud,
+                * and there was not commit inbetween. The garbage collector
+                * resets the free and dirty space without recording it
+                * anywhere except lprops, so if there was no commit then
+                * lprops does not have that information.
                 *
                 * We do not need to adjust free space because the scan has told
                 * us the exact value which is recorded in the replay entry as
-                * r->free.
+                * @b->free.
                 *
                 * However we do need to subtract from the dirty space the
                 * amount of space that the garbage collector reclaimed, which
                 * is the whole LEB minus the amount of space that was free.
                 */
-               dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+               dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
                        lp->free, lp->dirty);
-               dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", r->lnum,
+               dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
                        lp->free, lp->dirty);
                dirty -= c->leb_size - lp->free;
                /*
@@ -152,10 +142,10 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
                 */
                if (dirty != 0)
                        dbg_msg("LEB %d lp: %d free %d dirty "
-                               "replay: %d free %d dirty", r->lnum, lp->free,
-                               lp->dirty, r->free, r->dirty);
+                               "replay: %d free %d dirty", b->bud->lnum,
+                               lp->free, lp->dirty, b->free, b->dirty);
        }
-       lp = ubifs_change_lp(c, lp, r->free, dirty + r->dirty,
+       lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty,
                             lp->flags | LPROPS_TAKEN, 0);
        if (IS_ERR(lp)) {
                err = PTR_ERR(lp);
@@ -163,14 +153,36 @@ static int set_bud_lprops(struct ubifs_info *c, struct replay_entry *r)
        }
 
        /* Make sure the journal head points to the latest bud */
-       err = ubifs_wbuf_seek_nolock(&c->jheads[r->jhead].wbuf, r->lnum,
-                                    c->leb_size - r->free, UBI_SHORTTERM);
+       err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
+                                    b->bud->lnum, c->leb_size - b->free,
+                                    UBI_SHORTTERM);
 
 out:
        ubifs_release_lprops(c);
        return err;
 }
 
+/**
+ * set_buds_lprops - set free and dirty space for all replayed buds.
+ * @c: UBIFS file-system description object
+ *
+ * This function sets LEB properties for all replayed buds. Returns zero in
+ * case of success and a negative error code in case of failure.
+ */
+static int set_buds_lprops(struct ubifs_info *c)
+{
+       struct bud_entry *b;
+       int err;
+
+       list_for_each_entry(b, &c->replay_buds, list) {
+               err = set_bud_lprops(c, b);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 /**
  * trun_remove_range - apply a replay entry for a truncation to the TNC.
  * @c: UBIFS file-system description object
@@ -207,24 +219,22 @@ static int trun_remove_range(struct ubifs_info *c, struct replay_entry *r)
  */
 static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 {
-       int err, deletion = ((r->flags & REPLAY_DELETION) != 0);
+       int err;
 
-       dbg_mnt("LEB %d:%d len %d flgs %d sqnum %llu %s", r->lnum,
-               r->offs, r->len, r->flags, r->sqnum, DBGKEY(&r->key));
+       dbg_mnt("LEB %d:%d len %d deletion %d sqnum %llu %s", r->lnum,
+               r->offs, r->len, r->deletion, r->sqnum, DBGKEY(&r->key));
 
        /* Set c->replay_sqnum to help deal with dangling branches. */
        c->replay_sqnum = r->sqnum;
 
-       if (r->flags & REPLAY_REF)
-               err = set_bud_lprops(c, r);
-       else if (is_hash_key(c, &r->key)) {
-               if (deletion)
+       if (is_hash_key(c, &r->key)) {
+               if (r->deletion)
                        err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
                else
                        err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
                                               r->len, &r->nm);
        } else {
-               if (deletion)
+               if (r->deletion)
                        switch (key_type(c, &r->key)) {
                        case UBIFS_INO_KEY:
                        {
@@ -247,7 +257,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
                        return err;
 
                if (c->need_recovery)
-                       err = ubifs_recover_size_accum(c, &r->key, deletion,
+                       err = ubifs_recover_size_accum(c, &r->key, r->deletion,
                                                       r->new_size);
        }
 
@@ -255,68 +265,77 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
 }
 
 /**
- * destroy_replay_tree - destroy the replay.
- * @c: UBIFS file-system description object
+ * replay_entries_cmp - compare 2 replay entries.
+ * @priv: UBIFS file-system description object
+ * @a: first replay entry
+ * @a: second replay entry
  *
- * Destroy the replay tree.
+ * This is a comparios function for 'list_sort()' which compares 2 replay
+ * entries @a and @b by comparing their sequence numer.  Returns %1 if @a has
+ * greater sequence number and %-1 otherwise.
  */
-static void destroy_replay_tree(struct ubifs_info *c)
+static int replay_entries_cmp(void *priv, struct list_head *a,
+                             struct list_head *b)
 {
-       struct rb_node *this = c->replay_tree.rb_node;
-       struct replay_entry *r;
-
-       while (this) {
-               if (this->rb_left) {
-                       this = this->rb_left;
-                       continue;
-               } else if (this->rb_right) {
-                       this = this->rb_right;
-                       continue;
-               }
-               r = rb_entry(this, struct replay_entry, rb);
-               this = rb_parent(this);
-               if (this) {
-                       if (this->rb_left == &r->rb)
-                               this->rb_left = NULL;
-                       else
-                               this->rb_right = NULL;
-               }
-               if (is_hash_key(c, &r->key))
-                       kfree(r->nm.name);
-               kfree(r);
-       }
-       c->replay_tree = RB_ROOT;
+       struct replay_entry *ra, *rb;
+
+       cond_resched();
+       if (a == b)
+               return 0;
+
+       ra = list_entry(a, struct replay_entry, list);
+       rb = list_entry(b, struct replay_entry, list);
+       ubifs_assert(ra->sqnum != rb->sqnum);
+       if (ra->sqnum > rb->sqnum)
+               return 1;
+       return -1;
 }
 
 /**
- * apply_replay_tree - apply the replay tree to the TNC.
+ * apply_replay_list - apply the replay list to the TNC.
  * @c: UBIFS file-system description object
  *
- * Apply the replay tree.
- * Returns zero in case of success and a negative error code in case of
- * failure.
+ * Apply all entries in the replay list to the TNC. Returns zero in case of
+ * success and a negative error code in case of failure.
  */
-static int apply_replay_tree(struct ubifs_info *c)
+static int apply_replay_list(struct ubifs_info *c)
 {
-       struct rb_node *this = rb_first(&c->replay_tree);
+       struct replay_entry *r;
+       int err;
 
-       while (this) {
-               struct replay_entry *r;
-               int err;
+       list_sort(c, &c->replay_list, &replay_entries_cmp);
 
+       list_for_each_entry(r, &c->replay_list, list) {
                cond_resched();
 
-               r = rb_entry(this, struct replay_entry, rb);
                err = apply_replay_entry(c, r);
                if (err)
                        return err;
-               this = rb_next(this);
        }
+
        return 0;
 }
 
 /**
- * insert_node - insert a node to the replay tree.
+ * destroy_replay_list - destroy the replay.
+ * @c: UBIFS file-system description object
+ *
+ * Destroy the replay list.
+ */
+static void destroy_replay_list(struct ubifs_info *c)
+{
+       struct replay_entry *r, *tmp;
+
+       list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
+               if (is_hash_key(c, &r->key))
+                       kfree(r->nm.name);
+               list_del(&r->list);
+               kfree(r);
+       }
+}
+
+/**
+ * insert_node - insert a node to the replay list
  * @c: UBIFS file-system description object
  * @lnum: node logical eraseblock number
  * @offs: node offset
@@ -328,39 +347,25 @@ static int apply_replay_tree(struct ubifs_info *c)
  * @old_size: truncation old size
  * @new_size: truncation new size
  *
- * This function inserts a scanned non-direntry node to the replay tree. The
- * replay tree is an RB-tree containing @struct replay_entry elements which are
- * indexed by the sequence number. The replay tree is applied at the very end
- * of the replay process. Since the tree is sorted in sequence number order,
- * the older modifications are applied first. This function returns zero in
- * case of success and a negative error code in case of failure.
+ * This function inserts a scanned non-direntry node to the replay list. The
+ * replay list contains @struct replay_entry elements, and we sort this list in
+ * sequence number order before applying it. The replay list is applied at the
+ * very end of the replay process. Since the list is sorted in sequence number
+ * order, the older modifications are applied first. This function returns zero
+ * in case of success and a negative error code in case of failure.
  */
 static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
                       union ubifs_key *key, unsigned long long sqnum,
                       int deletion, int *used, loff_t old_size,
                       loff_t new_size)
 {
-       struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
        struct replay_entry *r;
 
+       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
+
        if (key_inum(c, key) >= c->highest_inum)
                c->highest_inum = key_inum(c, key);
 
-       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
-       while (*p) {
-               parent = *p;
-               r = rb_entry(parent, struct replay_entry, rb);
-               if (sqnum < r->sqnum) {
-                       p = &(*p)->rb_left;
-                       continue;
-               } else if (sqnum > r->sqnum) {
-                       p = &(*p)->rb_right;
-                       continue;
-               }
-               ubifs_err("duplicate sqnum in replay");
-               return -EINVAL;
-       }
-
        r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
        if (!r)
                return -ENOMEM;
@@ -370,19 +375,18 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
        r->lnum = lnum;
        r->offs = offs;
        r->len = len;
+       r->deletion = !!deletion;
        r->sqnum = sqnum;
-       r->flags = (deletion ? REPLAY_DELETION : 0);
+       key_copy(c, key, &r->key);
        r->old_size = old_size;
        r->new_size = new_size;
-       key_copy(c, key, &r->key);
 
-       rb_link_node(&r->rb, parent, p);
-       rb_insert_color(&r->rb, &c->replay_tree);
+       list_add_tail(&r->list, &c->replay_list);
        return 0;
 }
 
 /**
- * insert_dent - insert a directory entry node into the replay tree.
+ * insert_dent - insert a directory entry node into the replay list.
  * @c: UBIFS file-system description object
  * @lnum: node logical eraseblock number
  * @offs: node offset
@@ -394,43 +398,25 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
  * @deletion: non-zero if this is a deletion
  * @used: number of bytes in use in a LEB
  *
- * This function inserts a scanned directory entry node to the replay tree.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- *
- * This function is also used for extended attribute entries because they are
- * implemented as directory entry nodes.
+ * This function inserts a scanned directory entry node or an extended
+ * attribute entry to the replay list. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
 static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
                       union ubifs_key *key, const char *name, int nlen,
                       unsigned long long sqnum, int deletion, int *used)
 {
-       struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
        struct replay_entry *r;
        char *nbuf;
 
+       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
        if (key_inum(c, key) >= c->highest_inum)
                c->highest_inum = key_inum(c, key);
 
-       dbg_mnt("add LEB %d:%d, key %s", lnum, offs, DBGKEY(key));
-       while (*p) {
-               parent = *p;
-               r = rb_entry(parent, struct replay_entry, rb);
-               if (sqnum < r->sqnum) {
-                       p = &(*p)->rb_left;
-                       continue;
-               }
-               if (sqnum > r->sqnum) {
-                       p = &(*p)->rb_right;
-                       continue;
-               }
-               ubifs_err("duplicate sqnum in replay");
-               return -EINVAL;
-       }
-
        r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
        if (!r)
                return -ENOMEM;
+
        nbuf = kmalloc(nlen + 1, GFP_KERNEL);
        if (!nbuf) {
                kfree(r);
@@ -442,17 +428,15 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
        r->lnum = lnum;
        r->offs = offs;
        r->len = len;
+       r->deletion = !!deletion;
        r->sqnum = sqnum;
+       key_copy(c, key, &r->key);
        r->nm.len = nlen;
        memcpy(nbuf, name, nlen);
        nbuf[nlen] = '\0';
        r->nm.name = nbuf;
-       r->flags = (deletion ? REPLAY_DELETION : 0);
-       key_copy(c, key, &r->key);
 
-       ubifs_assert(!*p);
-       rb_link_node(&r->rb, parent, p);
-       rb_insert_color(&r->rb, &c->replay_tree);
+       list_add_tail(&r->list, &c->replay_list);
        return 0;
 }
 
@@ -488,30 +472,93 @@ int ubifs_validate_entry(struct ubifs_info *c,
        return 0;
 }
 
+/**
+ * is_last_bud - check if the bud is the last in the journal head.
+ * @c: UBIFS file-system description object
+ * @bud: bud description object
+ *
+ * This function checks if bud @bud is the last bud in its journal head. This
+ * information is then used by 'replay_bud()' to decide whether the bud can
+ * have corruptions or not. Indeed, only last buds can be corrupted by power
+ * cuts. Returns %1 if this is the last bud, and %0 if not.
+ */
+static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
+{
+       struct ubifs_jhead *jh = &c->jheads[bud->jhead];
+       struct ubifs_bud *next;
+       uint32_t data;
+       int err;
+
+       if (list_is_last(&bud->list, &jh->buds_list))
+               return 1;
+
+       /*
+        * The following is a quirk to make sure we work correctly with UBIFS
+        * images used with older UBIFS.
+        *
+        * Normally, the last bud will be the last in the journal head's list
+        * of bud. However, there is one exception if the UBIFS image belongs
+        * to older UBIFS. This is fairly unlikely: one would need to use old
+        * UBIFS, then have a power cut exactly at the right point, and then
+        * try to mount this image with new UBIFS.
+        *
+        * The exception is: it is possible to have 2 buds A and B, A goes
+        * before B, and B is the last, bud B is contains no data, and bud A is
+        * corrupted at the end. The reason is that in older versions when the
+        * journal code switched the next bud (from A to B), it first added a
+        * log reference node for the new bud (B), and only after this it
+        * synchronized the write-buffer of current bud (A). But later this was
+        * changed and UBIFS started to always synchronize the write-buffer of
+        * the bud (A) before writing the log reference for the new bud (B).
+        *
+        * But because older UBIFS always synchronized A's write-buffer before
+        * writing to B, we can recognize this exceptional situation but
+        * checking the contents of bud B - if it is empty, then A can be
+        * treated as the last and we can recover it.
+        *
+        * TODO: remove this piece of code in a couple of years (today it is
+        * 16.05.2011).
+        */
+       next = list_entry(bud->list.next, struct ubifs_bud, list);
+       if (!list_is_last(&next->list, &jh->buds_list))
+               return 0;
+
+       err = ubi_read(c->ubi, next->lnum, (char *)&data,
+                      next->start, 4);
+       if (err)
+               return 0;
+
+       return data == 0xFFFFFFFF;
+}
+
 /**
  * replay_bud - replay a bud logical eraseblock.
  * @c: UBIFS file-system description object
- * @lnum: bud logical eraseblock number to replay
- * @offs: bud start offset
- * @jhead: journal head to which this bud belongs
- * @free: amount of free space in the bud is returned here
- * @dirty: amount of dirty space from padding and deletion nodes is returned
- * here
+ * @b: bud entry which describes the bud
  *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function replays bud @bud, recovers it if needed, and adds all nodes
+ * from this bud to the replay list. Returns zero in case of success and a
+ * negative error code in case of failure.
  */
-static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
-                     int *free, int *dirty)
+static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
 {
-       int err = 0, used = 0;
+       int is_last = is_last_bud(c, b->bud);
+       int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
        struct ubifs_scan_leb *sleb;
        struct ubifs_scan_node *snod;
-       struct ubifs_bud *bud;
 
-       dbg_mnt("replay bud LEB %d, head %d", lnum, jhead);
-       if (c->need_recovery)
-               sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, jhead != GCHD);
+       dbg_mnt("replay bud LEB %d, head %d, offs %d, is_last %d",
+               lnum, b->bud->jhead, offs, is_last);
+
+       if (c->need_recovery && is_last)
+               /*
+                * Recover only last LEBs in the journal heads, because power
+                * cuts may cause corruptions only in these LEBs, because only
+                * these LEBs could possibly be written to at the power cut
+                * time.
+                */
+               sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf,
+                                        b->bud->jhead != GCHD);
        else
                sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0);
        if (IS_ERR(sleb))
@@ -627,15 +674,13 @@ static int replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
                        goto out;
        }
 
-       bud = ubifs_search_bud(c, lnum);
-       if (!bud)
-               BUG();
-
+       ubifs_assert(ubifs_search_bud(c, lnum));
        ubifs_assert(sleb->endpt - offs >= used);
        ubifs_assert(sleb->endpt % c->min_io_size == 0);
 
-       *dirty = sleb->endpt - offs - used;
-       *free = c->leb_size - sleb->endpt;
+       b->dirty = sleb->endpt - offs - used;
+       b->free = c->leb_size - sleb->endpt;
+       dbg_mnt("bud LEB %d replied: dirty %d, free %d", lnum, b->dirty, b->free);
 
 out:
        ubifs_scan_destroy(sleb);
@@ -648,58 +693,6 @@ out_dump:
        return -EINVAL;
 }
 
-/**
- * insert_ref_node - insert a reference node to the replay tree.
- * @c: UBIFS file-system description object
- * @lnum: node logical eraseblock number
- * @offs: node offset
- * @sqnum: sequence number
- * @free: amount of free space in bud
- * @dirty: amount of dirty space from padding and deletion nodes
- * @jhead: journal head number for the bud
- *
- * This function inserts a reference node to the replay tree and returns zero
- * in case of success or a negative error code in case of failure.
- */
-static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
-                          unsigned long long sqnum, int free, int dirty,
-                          int jhead)
-{
-       struct rb_node **p = &c->replay_tree.rb_node, *parent = NULL;
-       struct replay_entry *r;
-
-       dbg_mnt("add ref LEB %d:%d", lnum, offs);
-       while (*p) {
-               parent = *p;
-               r = rb_entry(parent, struct replay_entry, rb);
-               if (sqnum < r->sqnum) {
-                       p = &(*p)->rb_left;
-                       continue;
-               } else if (sqnum > r->sqnum) {
-                       p = &(*p)->rb_right;
-                       continue;
-               }
-               ubifs_err("duplicate sqnum in replay tree");
-               return -EINVAL;
-       }
-
-       r = kzalloc(sizeof(struct replay_entry), GFP_KERNEL);
-       if (!r)
-               return -ENOMEM;
-
-       r->lnum = lnum;
-       r->offs = offs;
-       r->sqnum = sqnum;
-       r->flags = REPLAY_REF;
-       r->free = free;
-       r->dirty = dirty;
-       r->jhead = jhead;
-
-       rb_link_node(&r->rb, parent, p);
-       rb_insert_color(&r->rb, &c->replay_tree);
-       return 0;
-}
-
 /**
  * replay_buds - replay all buds.
  * @c: UBIFS file-system description object
@@ -710,17 +703,16 @@ static int insert_ref_node(struct ubifs_info *c, int lnum, int offs,
 static int replay_buds(struct ubifs_info *c)
 {
        struct bud_entry *b;
-       int err, uninitialized_var(free), uninitialized_var(dirty);
+       int err;
+       unsigned long long prev_sqnum = 0;
 
        list_for_each_entry(b, &c->replay_buds, list) {
-               err = replay_bud(c, b->bud->lnum, b->bud->start, b->bud->jhead,
-                                &free, &dirty);
-               if (err)
-                       return err;
-               err = insert_ref_node(c, b->bud->lnum, b->bud->start, b->sqnum,
-                                     free, dirty, b->bud->jhead);
+               err = replay_bud(c, b);
                if (err)
                        return err;
+
+               ubifs_assert(b->sqnum > prev_sqnum);
+               prev_sqnum = b->sqnum;
        }
 
        return 0;
@@ -1060,25 +1052,29 @@ int ubifs_replay_journal(struct ubifs_info *c)
        if (err)
                goto out;
 
-       err = apply_replay_tree(c);
+       err = apply_replay_list(c);
+       if (err)
+               goto out;
+
+       err = set_buds_lprops(c);
        if (err)
                goto out;
 
        /*
-        * UBIFS budgeting calculations use @c->budg_uncommitted_idx variable
-        * to roughly estimate index growth. Things like @c->min_idx_lebs
+        * UBIFS budgeting calculations use @c->bi.uncommitted_idx variable
+        * to roughly estimate index growth. Things like @c->bi.min_idx_lebs
         * depend on it. This means we have to initialize it to make sure
         * budgeting works properly.
         */
-       c->budg_uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
-       c->budg_uncommitted_idx *= c->max_idx_node_sz;
+       c->bi.uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
+       c->bi.uncommitted_idx *= c->max_idx_node_sz;
 
        ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
        dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, "
                "highest_inum %lu", c->lhead_lnum, c->lhead_offs, c->max_sqnum,
                (unsigned long)c->highest_inum);
 out:
-       destroy_replay_tree(c);
+       destroy_replay_list(c);
        destroy_bud_list(c);
        c->replaying = 0;
        return err;
index bf31b4729e51ce466560777a1e24bad90356311b..c606f010e8df072882d23633c9a58831ca805f86 100644 (file)
@@ -475,7 +475,8 @@ failed:
  * @c: UBIFS file-system description object
  *
  * This function returns a pointer to the superblock node or a negative error
- * code.
+ * code. Note, the user of this function is responsible of kfree()'ing the
+ * returned superblock buffer.
  */
 struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
 {
@@ -616,6 +617,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
        c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran);
        memcpy(&c->uuid, &sup->uuid, 16);
        c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
+       c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
 
        /* Automatically increase file system size to the maximum size */
        c->old_leb_cnt = c->leb_cnt;
@@ -650,3 +652,152 @@ out:
        kfree(sup);
        return err;
 }
+
+/**
+ * fixup_leb - fixup/unmap an LEB containing free space.
+ * @c: UBIFS file-system description object
+ * @lnum: the LEB number to fix up
+ * @len: number of used bytes in LEB (starting at offset 0)
+ *
+ * This function reads the contents of the given LEB number @lnum, then fixes
+ * it up, so that empty min. I/O units in the end of LEB are actually erased on
+ * flash (rather than being just all-0xff real data). If the LEB is completely
+ * empty, it is simply unmapped.
+ */
+static int fixup_leb(struct ubifs_info *c, int lnum, int len)
+{
+       int err;
+
+       ubifs_assert(len >= 0);
+       ubifs_assert(len % c->min_io_size == 0);
+       ubifs_assert(len < c->leb_size);
+
+       if (len == 0) {
+               dbg_mnt("unmap empty LEB %d", lnum);
+               return ubi_leb_unmap(c->ubi, lnum);
+       }
+
+       dbg_mnt("fixup LEB %d, data len %d", lnum, len);
+       err = ubi_read(c->ubi, lnum, c->sbuf, 0, len);
+       if (err)
+               return err;
+
+       return ubi_leb_change(c->ubi, lnum, c->sbuf, len, UBI_UNKNOWN);
+}
+
+/**
+ * fixup_free_space - find & remap all LEBs containing free space.
+ * @c: UBIFS file-system description object
+ *
+ * This function walks through all LEBs in the filesystem and fiexes up those
+ * containing free/empty space.
+ */
+static int fixup_free_space(struct ubifs_info *c)
+{
+       int lnum, err = 0;
+       struct ubifs_lprops *lprops;
+
+       ubifs_get_lprops(c);
+
+       /* Fixup LEBs in the master area */
+       for (lnum = UBIFS_MST_LNUM; lnum < UBIFS_LOG_LNUM; lnum++) {
+               err = fixup_leb(c, lnum, c->mst_offs + c->mst_node_alsz);
+               if (err)
+                       goto out;
+       }
+
+       /* Unmap unused log LEBs */
+       lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
+       while (lnum != c->ltail_lnum) {
+               err = fixup_leb(c, lnum, 0);
+               if (err)
+                       goto out;
+               lnum = ubifs_next_log_lnum(c, lnum);
+       }
+
+       /* Fixup the current log head */
+       err = fixup_leb(c, c->lhead_lnum, c->lhead_offs);
+       if (err)
+               goto out;
+
+       /* Fixup LEBs in the LPT area */
+       for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
+               int free = c->ltab[lnum - c->lpt_first].free;
+
+               if (free > 0) {
+                       err = fixup_leb(c, lnum, c->leb_size - free);
+                       if (err)
+                               goto out;
+               }
+       }
+
+       /* Unmap LEBs in the orphans area */
+       for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
+               err = fixup_leb(c, lnum, 0);
+               if (err)
+                       goto out;
+       }
+
+       /* Fixup LEBs in the main area */
+       for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
+               lprops = ubifs_lpt_lookup(c, lnum);
+               if (IS_ERR(lprops)) {
+                       err = PTR_ERR(lprops);
+                       goto out;
+               }
+
+               if (lprops->free > 0) {
+                       err = fixup_leb(c, lnum, c->leb_size - lprops->free);
+                       if (err)
+                               goto out;
+               }
+       }
+
+out:
+       ubifs_release_lprops(c);
+       return err;
+}
+
+/**
+ * ubifs_fixup_free_space - find & fix all LEBs with free space.
+ * @c: UBIFS file-system description object
+ *
+ * This function fixes up LEBs containing free space on first mount, if the
+ * appropriate flag was set when the FS was created. Each LEB with one or more
+ * empty min. I/O unit (i.e. free-space-count > 0) is re-written, to make sure
+ * the free space is actually erased. E.g., this is necessary for some NAND
+ * chips, since the free space may have been programmed like real "0xff" data
+ * (generating a non-0xff ECC), causing future writes to the not-really-erased
+ * NAND pages to behave badly. After the space is fixed up, the superblock flag
+ * is cleared, so that this is skipped for all future mounts.
+ */
+int ubifs_fixup_free_space(struct ubifs_info *c)
+{
+       int err;
+       struct ubifs_sb_node *sup;
+
+       ubifs_assert(c->space_fixup);
+       ubifs_assert(!c->ro_mount);
+
+       ubifs_msg("start fixing up free space");
+
+       err = fixup_free_space(c);
+       if (err)
+               return err;
+
+       sup = ubifs_read_sb_node(c);
+       if (IS_ERR(sup))
+               return PTR_ERR(sup);
+
+       /* Free-space fixup is no longer required */
+       c->space_fixup = 0;
+       sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
+
+       err = ubifs_write_sb_node(c, sup);
+       kfree(sup);
+       if (err)
+               return err;
+
+       ubifs_msg("free space fixup complete");
+       return err;
+}
index 04ad07f4fcc3da11b05e868442ed6f3bc7ad7729..6db0bdaa9f7429f6cf1661274db5659065157527 100644 (file)
@@ -375,7 +375,7 @@ out:
                ubifs_release_dirty_inode_budget(c, ui);
        else {
                /* We've deleted something - clean the "no space" flags */
-               c->nospace = c->nospace_rp = 0;
+               c->bi.nospace = c->bi.nospace_rp = 0;
                smp_wmb();
        }
 done:
@@ -694,11 +694,11 @@ static int init_constants_sb(struct ubifs_info *c)
         * be compressed and direntries are of the maximum size.
         *
         * Note, data, which may be stored in inodes is budgeted separately, so
-        * it is not included into 'c->inode_budget'.
+        * it is not included into 'c->bi.inode_budget'.
         */
-       c->page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
-       c->inode_budget = UBIFS_INO_NODE_SZ;
-       c->dent_budget = UBIFS_MAX_DENT_NODE_SZ;
+       c->bi.page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE;
+       c->bi.inode_budget = UBIFS_INO_NODE_SZ;
+       c->bi.dent_budget = UBIFS_MAX_DENT_NODE_SZ;
 
        /*
         * When the amount of flash space used by buds becomes
@@ -742,7 +742,7 @@ static void init_constants_master(struct ubifs_info *c)
 {
        long long tmp64;
 
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
        c->report_rp_size = ubifs_reported_space(c, c->rp_size);
 
        /*
@@ -1144,8 +1144,8 @@ static int check_free_space(struct ubifs_info *c)
 {
        ubifs_assert(c->dark_wm > 0);
        if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
-               ubifs_err("insufficient free space to mount in read/write mode");
-               dbg_dump_budg(c);
+               ubifs_err("insufficient free space to mount in R/W mode");
+               dbg_dump_budg(c, &c->bi);
                dbg_dump_lprops(c);
                return -ENOSPC;
        }
@@ -1304,7 +1304,7 @@ static int mount_ubifs(struct ubifs_info *c)
        if (err)
                goto out_lpt;
 
-       err = dbg_check_idx_size(c, c->old_idx_sz);
+       err = dbg_check_idx_size(c, c->bi.old_idx_sz);
        if (err)
                goto out_lpt;
 
@@ -1313,7 +1313,7 @@ static int mount_ubifs(struct ubifs_info *c)
                goto out_journal;
 
        /* Calculate 'min_idx_lebs' after journal replay */
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
 
        err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount);
        if (err)
@@ -1396,6 +1396,12 @@ static int mount_ubifs(struct ubifs_info *c)
        } else
                ubifs_assert(c->lst.taken_empty_lebs > 0);
 
+       if (!c->ro_mount && c->space_fixup) {
+               err = ubifs_fixup_free_space(c);
+               if (err)
+                       goto out_infos;
+       }
+
        err = dbg_check_filesystem(c);
        if (err)
                goto out_infos;
@@ -1442,7 +1448,8 @@ static int mount_ubifs(struct ubifs_info *c)
                c->main_lebs, c->main_first, c->leb_cnt - 1);
        dbg_msg("index LEBs:          %d", c->lst.idx_lebs);
        dbg_msg("total index bytes:   %lld (%lld KiB, %lld MiB)",
-               c->old_idx_sz, c->old_idx_sz >> 10, c->old_idx_sz >> 20);
+               c->bi.old_idx_sz, c->bi.old_idx_sz >> 10,
+               c->bi.old_idx_sz >> 20);
        dbg_msg("key hash type:       %d", c->key_hash_type);
        dbg_msg("tree fanout:         %d", c->fanout);
        dbg_msg("reserved GC LEB:     %d", c->gc_lnum);
@@ -1456,7 +1463,7 @@ static int mount_ubifs(struct ubifs_info *c)
        dbg_msg("node sizes:          ref %zu, cmt. start %zu, orph %zu",
                UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ);
        dbg_msg("max. node sizes:     data %zu, inode %zu dentry %zu, idx %d",
-               UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
+               UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ,
                UBIFS_MAX_DENT_NODE_SZ, ubifs_idx_node_sz(c, c->fanout));
        dbg_msg("dead watermark:      %d", c->dead_wm);
        dbg_msg("dark watermark:      %d", c->dark_wm);
@@ -1584,6 +1591,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                }
                sup->leb_cnt = cpu_to_le32(c->leb_cnt);
                err = ubifs_write_sb_node(c, sup);
+               kfree(sup);
                if (err)
                        goto out;
        }
@@ -1684,6 +1692,13 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                 */
                err = dbg_check_space_info(c);
        }
+
+       if (c->space_fixup) {
+               err = ubifs_fixup_free_space(c);
+               if (err)
+                       goto out;
+       }
+
        mutex_unlock(&c->umount_mutex);
        return err;
 
@@ -1766,10 +1781,9 @@ static void ubifs_put_super(struct super_block *sb)
         * to write them back because of I/O errors.
         */
        if (!c->ro_error) {
-               ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0);
-               ubifs_assert(c->budg_idx_growth == 0);
-               ubifs_assert(c->budg_dd_growth == 0);
-               ubifs_assert(c->budg_data_growth == 0);
+               ubifs_assert(c->bi.idx_growth == 0);
+               ubifs_assert(c->bi.dd_growth == 0);
+               ubifs_assert(c->bi.data_growth == 0);
        }
 
        /*
index de485979ca393eebb7db3fb8c60d382b6857eabe..8119b1fd8d94b9be59320e1c31e1d5b41d050dc1 100644 (file)
@@ -2557,11 +2557,11 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
                if (err) {
                        /* Ensure the znode is dirtied */
                        if (znode->cnext || !ubifs_zn_dirty(znode)) {
-                                   znode = dirty_cow_bottom_up(c, znode);
-                                   if (IS_ERR(znode)) {
-                                           err = PTR_ERR(znode);
-                                           goto out_unlock;
-                                   }
+                               znode = dirty_cow_bottom_up(c, znode);
+                               if (IS_ERR(znode)) {
+                                       err = PTR_ERR(znode);
+                                       goto out_unlock;
+                               }
                        }
                        err = tnc_delete(c, znode, n);
                }
index 53288e5d604e92bd5584b1a3595565261a1c2c81..41920f357bbfc13e49668ef19fd6a0560ca195fc 100644 (file)
@@ -377,15 +377,13 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
                                c->gap_lebs = NULL;
                                return err;
                        }
-                       if (!dbg_force_in_the_gaps_enabled) {
+                       if (dbg_force_in_the_gaps_enabled()) {
                                /*
                                 * Do not print scary warnings if the debugging
                                 * option which forces in-the-gaps is enabled.
                                 */
-                               ubifs_err("out of space");
-                               spin_lock(&c->space_lock);
-                               dbg_dump_budg(c);
-                               spin_unlock(&c->space_lock);
+                               ubifs_warn("out of space");
+                               dbg_dump_budg(c, &c->bi);
                                dbg_dump_lprops(c);
                        }
                        /* Try to commit anyway */
@@ -796,16 +794,16 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
        spin_lock(&c->space_lock);
        /*
         * Although we have not finished committing yet, update size of the
-        * committed index ('c->old_idx_sz') and zero out the index growth
+        * committed index ('c->bi.old_idx_sz') and zero out the index growth
         * budget. It is OK to do this now, because we've reserved all the
         * space which is needed to commit the index, and it is save for the
         * budgeting subsystem to assume the index is already committed,
         * even though it is not.
         */
-       ubifs_assert(c->min_idx_lebs == ubifs_calc_min_idx_lebs(c));
-       c->old_idx_sz = c->calc_idx_sz;
-       c->budg_uncommitted_idx = 0;
-       c->min_idx_lebs = ubifs_calc_min_idx_lebs(c);
+       ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
+       c->bi.old_idx_sz = c->calc_idx_sz;
+       c->bi.uncommitted_idx = 0;
+       c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
        spin_unlock(&c->space_lock);
        mutex_unlock(&c->tnc_mutex);
 
index 191ca7863fe7a94bcca45ab2b2ba2ab6dae74e7b..e24380cf46ed4b0506dcc2f2e9258f04e4367a28 100644 (file)
@@ -408,9 +408,11 @@ enum {
  * Superblock flags.
  *
  * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
+ * UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
  */
 enum {
        UBIFS_FLG_BIGLPT = 0x02,
+       UBIFS_FLG_SPACE_FIXUP = 0x04,
 };
 
 /**
@@ -434,7 +436,7 @@ struct ubifs_ch {
        __u8 node_type;
        __u8 group_type;
        __u8 padding[2];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * union ubifs_dev_desc - device node descriptor.
@@ -448,7 +450,7 @@ struct ubifs_ch {
 union ubifs_dev_desc {
        __le32 new;
        __le64 huge;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_ino_node - inode node.
@@ -509,7 +511,7 @@ struct ubifs_ino_node {
        __le16 compr_type;
        __u8 padding2[26]; /* Watch 'zero_ino_node_unused()' if changing! */
        __u8 data[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_dent_node - directory entry node.
@@ -534,7 +536,7 @@ struct ubifs_dent_node {
        __le16 nlen;
        __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
        __u8 name[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_data_node - data node.
@@ -555,7 +557,7 @@ struct ubifs_data_node {
        __le16 compr_type;
        __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
        __u8 data[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_trun_node - truncation node.
@@ -575,7 +577,7 @@ struct ubifs_trun_node {
        __u8 padding[12]; /* Watch 'zero_trun_node_unused()' if changing! */
        __le64 old_size;
        __le64 new_size;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_pad_node - padding node.
@@ -586,7 +588,7 @@ struct ubifs_trun_node {
 struct ubifs_pad_node {
        struct ubifs_ch ch;
        __le32 pad_len;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_sb_node - superblock node.
@@ -644,7 +646,7 @@ struct ubifs_sb_node {
        __u8 uuid[16];
        __le32 ro_compat_version;
        __u8 padding2[3968];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_mst_node - master node.
@@ -711,7 +713,7 @@ struct ubifs_mst_node {
        __le32 idx_lebs;
        __le32 leb_cnt;
        __u8 padding[344];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_ref_node - logical eraseblock reference node.
@@ -727,7 +729,7 @@ struct ubifs_ref_node {
        __le32 offs;
        __le32 jhead;
        __u8 padding[28];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_branch - key/reference/length branch
@@ -741,7 +743,7 @@ struct ubifs_branch {
        __le32 offs;
        __le32 len;
        __u8 key[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_idx_node - indexing node.
@@ -755,7 +757,7 @@ struct ubifs_idx_node {
        __le16 child_cnt;
        __le16 level;
        __u8 branches[];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_cs_node - commit start node.
@@ -765,7 +767,7 @@ struct ubifs_idx_node {
 struct ubifs_cs_node {
        struct ubifs_ch ch;
        __le64 cmt_no;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubifs_orph_node - orphan node.
@@ -777,6 +779,6 @@ struct ubifs_orph_node {
        struct ubifs_ch ch;
        __le64 cmt_no;
        __le64 inos[];
-} __attribute__ ((packed));
+} __packed;
 
 #endif /* __UBIFS_MEDIA_H__ */
index 8c40ad3c67213375c6d9b99927851f51fabd18d1..93d1412a06f0c736ec3bf5a603d43f541a5a5b79 100644 (file)
@@ -389,9 +389,9 @@ struct ubifs_gced_idx_leb {
  * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
  * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
  * make sure @inode->i_size is always changed under @ui_mutex, because it
- * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would deadlock
- * with 'ubifs_writepage()' (see file.c). All the other inode fields are
- * changed under @ui_mutex, so they do not need "shadow" fields. Note, one
+ * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would
+ * deadlock with 'ubifs_writepage()' (see file.c). All the other inode fields
+ * are changed under @ui_mutex, so they do not need "shadow" fields. Note, one
  * could consider to rework locking and base it on "shadow" fields.
  */
 struct ubifs_inode {
@@ -937,6 +937,40 @@ struct ubifs_mount_opts {
        unsigned int compr_type:2;
 };
 
+/**
+ * struct ubifs_budg_info - UBIFS budgeting information.
+ * @idx_growth: amount of bytes budgeted for index growth
+ * @data_growth: amount of bytes budgeted for cached data
+ * @dd_growth: amount of bytes budgeted for cached data that will make
+ *             other data dirty
+ * @uncommitted_idx: amount of bytes were budgeted for growth of the index, but
+ *                   which still have to be taken into account because the index
+ *                   has not been committed so far
+ * @old_idx_sz: size of index on flash
+ * @min_idx_lebs: minimum number of LEBs required for the index
+ * @nospace: non-zero if the file-system does not have flash space (used as
+ *           optimization)
+ * @nospace_rp: the same as @nospace, but additionally means that even reserved
+ *              pool is full
+ * @page_budget: budget for a page (constant, nenver changed after mount)
+ * @inode_budget: budget for an inode (constant, nenver changed after mount)
+ * @dent_budget: budget for a directory entry (constant, nenver changed after
+ *               mount)
+ */
+struct ubifs_budg_info {
+       long long idx_growth;
+       long long data_growth;
+       long long dd_growth;
+       long long uncommitted_idx;
+       unsigned long long old_idx_sz;
+       int min_idx_lebs;
+       unsigned int nospace:1;
+       unsigned int nospace_rp:1;
+       int page_budget;
+       int inode_budget;
+       int dent_budget;
+};
+
 struct ubifs_debug_info;
 
 /**
@@ -980,6 +1014,7 @@ struct ubifs_debug_info;
  * @cmt_wq: wait queue to sleep on if the log is full and a commit is running
  *
  * @big_lpt: flag that LPT is too big to write whole during commit
+ * @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
  * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
  *                   recovery)
  * @bulk_read: enable bulk-reads
@@ -1057,32 +1092,14 @@ struct ubifs_debug_info;
  * @dirty_zn_cnt: number of dirty znodes
  * @clean_zn_cnt: number of clean znodes
  *
- * @budg_idx_growth: amount of bytes budgeted for index growth
- * @budg_data_growth: amount of bytes budgeted for cached data
- * @budg_dd_growth: amount of bytes budgeted for cached data that will make
- *                  other data dirty
- * @budg_uncommitted_idx: amount of bytes were budgeted for growth of the index,
- *                        but which still have to be taken into account because
- *                        the index has not been committed so far
- * @space_lock: protects @budg_idx_growth, @budg_data_growth, @budg_dd_growth,
- *              @budg_uncommited_idx, @min_idx_lebs, @old_idx_sz, @lst,
- *              @nospace, and @nospace_rp;
- * @min_idx_lebs: minimum number of LEBs required for the index
- * @old_idx_sz: size of index on flash
+ * @space_lock: protects @bi and @lst
+ * @lst: lprops statistics
+ * @bi: budgeting information
  * @calc_idx_sz: temporary variable which is used to calculate new index size
  *               (contains accurate new index size at end of TNC commit start)
- * @lst: lprops statistics
- * @nospace: non-zero if the file-system does not have flash space (used as
- *           optimization)
- * @nospace_rp: the same as @nospace, but additionally means that even reserved
- *              pool is full
- *
- * @page_budget: budget for a page
- * @inode_budget: budget for an inode
- * @dent_budget: budget for a directory entry
  *
  * @ref_node_alsz: size of the LEB reference node aligned to the min. flash
- * I/O unit
+ *                 I/O unit
  * @mst_node_alsz: master node aligned size
  * @min_idx_node_sz: minimum indexing node aligned on 8-bytes boundary
  * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary
@@ -1189,7 +1206,6 @@ struct ubifs_debug_info;
  * @replaying: %1 during journal replay
  * @mounting: %1 while mounting
  * @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
- * @replay_tree: temporary tree used during journal replay
  * @replay_list: temporary list used during journal replay
  * @replay_buds: list of buds to replay
  * @cs_sqnum: sequence number of first node in the log (commit start node)
@@ -1238,6 +1254,7 @@ struct ubifs_info {
        wait_queue_head_t cmt_wq;
 
        unsigned int big_lpt:1;
+       unsigned int space_fixup:1;
        unsigned int no_chk_data_crc:1;
        unsigned int bulk_read:1;
        unsigned int default_compr:2;
@@ -1308,21 +1325,10 @@ struct ubifs_info {
        atomic_long_t dirty_zn_cnt;
        atomic_long_t clean_zn_cnt;
 
-       long long budg_idx_growth;
-       long long budg_data_growth;
-       long long budg_dd_growth;
-       long long budg_uncommitted_idx;
        spinlock_t space_lock;
-       int min_idx_lebs;
-       unsigned long long old_idx_sz;
-       unsigned long long calc_idx_sz;
        struct ubifs_lp_stats lst;
-       unsigned int nospace:1;
-       unsigned int nospace_rp:1;
-
-       int page_budget;
-       int inode_budget;
-       int dent_budget;
+       struct ubifs_budg_info bi;
+       unsigned long long calc_idx_sz;
 
        int ref_node_alsz;
        int mst_node_alsz;
@@ -1430,7 +1436,6 @@ struct ubifs_info {
        unsigned int replaying:1;
        unsigned int mounting:1;
        unsigned int remounting_rw:1;
-       struct rb_root replay_tree;
        struct list_head replay_list;
        struct list_head replay_buds;
        unsigned long long cs_sqnum;
@@ -1628,6 +1633,7 @@ int ubifs_write_master(struct ubifs_info *c);
 int ubifs_read_superblock(struct ubifs_info *c);
 struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
 int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
+int ubifs_fixup_free_space(struct ubifs_info *c);
 
 /* replay.c */
 int ubifs_validate_entry(struct ubifs_info *c,
index 3299f469e7126a004d2b3a37c5c2661b3c6a127d..16f19f55e63fa53e20dcc2cf520794b27b1290a7 100644 (file)
@@ -80,8 +80,8 @@ enum {
        SECURITY_XATTR,
 };
 
-static const struct inode_operations none_inode_operations;
-static const struct file_operations none_file_operations;
+static const struct inode_operations empty_iops;
+static const struct file_operations empty_fops;
 
 /**
  * create_xattr - create an extended attribute.
@@ -131,8 +131,8 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
 
        /* Re-define all operations to be "nothing" */
        inode->i_mapping->a_ops = &empty_aops;
-       inode->i_op = &none_inode_operations;
-       inode->i_fop = &none_file_operations;
+       inode->i_op = &empty_iops;
+       inode->i_fop = &empty_fops;
 
        inode->i_flags |= S_SYNC | S_NOATIME | S_NOCMTIME | S_NOQUOTA;
        ui = ubifs_inode(inode);
index b4bfe338ea0e568258bc66ffffa4b03c6e51ca6d..e9b8e5926befb7b38b03218ffd0f9e6d2d75d454 100644 (file)
@@ -184,22 +184,18 @@ static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 #endif
 
-#ifndef __HAVE_ARCH_PAGE_TEST_DIRTY
-#define page_test_dirty(page)          (0)
+#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
+#define page_test_and_clear_dirty(pfn, mapped) (0)
 #endif
 
-#ifndef __HAVE_ARCH_PAGE_CLEAR_DIRTY
-#define page_clear_dirty(page, mapped) do { } while (0)
-#endif
-
-#ifndef __HAVE_ARCH_PAGE_TEST_DIRTY
+#ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
 #define pte_maybe_dirty(pte)           pte_dirty(pte)
 #else
 #define pte_maybe_dirty(pte)           (1)
 #endif
 
 #ifndef __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
-#define page_test_and_clear_young(page) (0)
+#define page_test_and_clear_young(pfn) (0)
 #endif
 
 #ifndef __HAVE_ARCH_PGD_OFFSET_GATE
index 077c00d94f6e47f63092d6731085e61e12c012db..db22d136ad08bf671266faa87f89de37178187f3 100644 (file)
@@ -15,7 +15,7 @@
  *     HEAD_TEXT_SECTION
  *     INIT_TEXT_SECTION(PAGE_SIZE)
  *     INIT_DATA_SECTION(...)
- *     PERCPU(CACHELINE_SIZE, PAGE_SIZE)
+ *     PERCPU_SECTION(CACHELINE_SIZE)
  *     __init_end = .;
  *
  *     _stext = .;
        *(.discard.*)                                                   \
        }
 
+/**
+ * PERCPU_INPUT - the percpu input sections
+ * @cacheline: cacheline size
+ *
+ * The core percpu section names and core symbols which do not rely
+ * directly upon load addresses.
+ *
+ * @cacheline is used to align subsections to avoid false cacheline
+ * sharing between subsections for different purposes.
+ */
+#define PERCPU_INPUT(cacheline)                                                \
+       VMLINUX_SYMBOL(__per_cpu_start) = .;                            \
+       *(.data..percpu..first)                                         \
+       . = ALIGN(PAGE_SIZE);                                           \
+       *(.data..percpu..page_aligned)                                  \
+       . = ALIGN(cacheline);                                           \
+       *(.data..percpu..readmostly)                                    \
+       . = ALIGN(cacheline);                                           \
+       *(.data..percpu)                                                \
+       *(.data..percpu..shared_aligned)                                \
+       VMLINUX_SYMBOL(__per_cpu_end) = .;
+
 /**
  * PERCPU_VADDR - define output section for percpu area
  * @cacheline: cacheline size
  *
  * Note that this macros defines __per_cpu_load as an absolute symbol.
  * If there is no need to put the percpu section at a predetermined
- * address, use PERCPU().
+ * address, use PERCPU_SECTION.
  */
 #define PERCPU_VADDR(cacheline, vaddr, phdr)                           \
        VMLINUX_SYMBOL(__per_cpu_load) = .;                             \
        .data..percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load)         \
                                - LOAD_OFFSET) {                        \
-               VMLINUX_SYMBOL(__per_cpu_start) = .;                    \
-               *(.data..percpu..first)                                 \
-               . = ALIGN(PAGE_SIZE);                                   \
-               *(.data..percpu..page_aligned)                          \
-               . = ALIGN(cacheline);                                   \
-               *(.data..percpu..readmostly)                            \
-               . = ALIGN(cacheline);                                   \
-               *(.data..percpu)                                        \
-               *(.data..percpu..shared_aligned)                        \
-               VMLINUX_SYMBOL(__per_cpu_end) = .;                      \
+               PERCPU_INPUT(cacheline)                                 \
        } phdr                                                          \
        . = VMLINUX_SYMBOL(__per_cpu_load) + SIZEOF(.data..percpu);
 
 /**
- * PERCPU - define output section for percpu area, simple version
+ * PERCPU_SECTION - define output section for percpu area, simple version
  * @cacheline: cacheline size
- * @align: required alignment
  *
- * Align to @align and outputs output section for percpu area.  This macro
- * doesn't manipulate @vaddr or @phdr and __per_cpu_load and
+ * Align to PAGE_SIZE and outputs output section for percpu area.  This
+ * macro doesn't manipulate @vaddr or @phdr and __per_cpu_load and
  * __per_cpu_start will be identical.
  *
- * This macro is equivalent to ALIGN(@align); PERCPU_VADDR(@cacheline,,)
+ * This macro is equivalent to ALIGN(PAGE_SIZE); PERCPU_VADDR(@cacheline,,)
  * except that __per_cpu_load is defined as a relative symbol against
  * .data..percpu which is required for relocatable x86_32 configuration.
  */
-#define PERCPU(cacheline, align)                                       \
-       . = ALIGN(align);                                               \
+#define PERCPU_SECTION(cacheline)                                      \
+       . = ALIGN(PAGE_SIZE);                                           \
        .data..percpu   : AT(ADDR(.data..percpu) - LOAD_OFFSET) {       \
                VMLINUX_SYMBOL(__per_cpu_load) = .;                     \
-               VMLINUX_SYMBOL(__per_cpu_start) = .;                    \
-               *(.data..percpu..first)                                 \
-               . = ALIGN(PAGE_SIZE);                                   \
-               *(.data..percpu..page_aligned)                          \
-               . = ALIGN(cacheline);                                   \
-               *(.data..percpu..readmostly)                            \
-               . = ALIGN(cacheline);                                   \
-               *(.data..percpu)                                        \
-               *(.data..percpu..shared_aligned)                        \
-               VMLINUX_SYMBOL(__per_cpu_end) = .;                      \
+               PERCPU_INPUT(cacheline)                                 \
        }
 
 
index 202424d17ed7c1924ae5d26936369dc110564e44..738b3a5faa1294215479ddf88e99c2c523dfa72c 100644 (file)
@@ -122,10 +122,14 @@ struct drm_device;
  * using the DRM_DEBUG_KMS and DRM_DEBUG.
  */
 
-extern void drm_ut_debug_printk(unsigned int request_level,
+extern __attribute__((format (printf, 4, 5)))
+void drm_ut_debug_printk(unsigned int request_level,
                                const char *prefix,
                                const char *function_name,
                                const char *format, ...);
+extern __attribute__((format (printf, 2, 3)))
+int drm_err(const char *func, const char *format, ...);
+
 /***********************************************************************/
 /** \name DRM template customization defaults */
 /*@{*/
@@ -181,21 +185,11 @@ extern void drm_ut_debug_printk(unsigned int request_level,
  * \param fmt printf() like format string.
  * \param arg arguments
  */
-#define DRM_ERROR(fmt, arg...) \
-       printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __func__ , ##arg)
-
-/**
- * Memory error output.
- *
- * \param area memory area where the error occurred.
- * \param fmt printf() like format string.
- * \param arg arguments
- */
-#define DRM_MEM_ERROR(area, fmt, arg...) \
-       printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __func__, \
-              drm_mem_stats[area].name , ##arg)
+#define DRM_ERROR(fmt, ...)                            \
+       drm_err(__func__, fmt, ##__VA_ARGS__)
 
-#define DRM_INFO(fmt, arg...)  printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
+#define DRM_INFO(fmt, ...)                             \
+       printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
 
 /**
  * Debug output.
@@ -1000,6 +994,22 @@ struct drm_minor {
        struct drm_mode_group mode_group;
 };
 
+/* mode specified on the command line */
+struct drm_cmdline_mode {
+       bool specified;
+       bool refresh_specified;
+       bool bpp_specified;
+       int xres, yres;
+       int bpp;
+       int refresh;
+       bool rb;
+       bool interlace;
+       bool cvt;
+       bool margins;
+       enum drm_connector_force force;
+};
+
+
 struct drm_pending_vblank_event {
        struct drm_pending_event base;
        int pipe;
@@ -1395,6 +1405,15 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
                                                 struct drm_crtc *refcrtc);
 extern void drm_calc_timestamping_constants(struct drm_crtc *crtc);
 
+extern bool
+drm_mode_parse_command_line_for_connector(const char *mode_option,
+                                         struct drm_connector *connector,
+                                         struct drm_cmdline_mode *mode);
+
+extern struct drm_display_mode *
+drm_mode_create_from_cmdline_mode(struct drm_device *dev,
+                                 struct drm_cmdline_mode *cmd);
+
 /* Modesetting support */
 extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
 extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc);
index d94684b7ba3462ab8e62a0460b3ca06bd3fe9662..9573e0ce312080caf9bcbcb72cd804e2ed200871 100644 (file)
@@ -183,7 +183,9 @@ enum subpixel_order {
        SubPixelNone,
 };
 
-
+#define DRM_COLOR_FORMAT_RGB444                (1<<0)
+#define DRM_COLOR_FORMAT_YCRCB444      (1<<1)
+#define DRM_COLOR_FORMAT_YCRCB422      (1<<2)
 /*
  * Describes a given display (e.g. CRT or flat panel) and its limitations.
  */
@@ -198,8 +200,10 @@ struct drm_display_info {
        unsigned int min_vfreq, max_vfreq;
        unsigned int min_hfreq, max_hfreq;
        unsigned int pixel_clock;
+       unsigned int bpc;
 
        enum subpixel_order subpixel_order;
+       u32 color_formats;
 
        char *raw_edid; /* if any */
 };
index 83a389e44543f19911efe7726ad48d4dd602f967..91567bbdb027c5f36a09923a2d9852c10fe1f07d 100644 (file)
@@ -53,6 +53,7 @@
 
 #define DP_MAX_LANE_COUNT                   0x002
 # define DP_MAX_LANE_COUNT_MASK                    0x1f
+# define DP_TPS3_SUPPORTED                 (1 << 6)
 # define DP_ENHANCED_FRAME_CAP             (1 << 7)
 
 #define DP_MAX_DOWNSPREAD                   0x003
 
 #define DP_MAIN_LINK_CHANNEL_CODING         0x006
 
+#define DP_TRAINING_AUX_RD_INTERVAL         0x00e
+
 /* link configuration */
 #define        DP_LINK_BW_SET                      0x100
 # define DP_LINK_BW_1_62                   0x06
 # define DP_LINK_BW_2_7                            0x0a
+# define DP_LINK_BW_5_4                            0x14
 
 #define DP_LANE_COUNT_SET                  0x101
 # define DP_LANE_COUNT_MASK                0x0f
@@ -84,6 +88,7 @@
 # define DP_TRAINING_PATTERN_DISABLE       0
 # define DP_TRAINING_PATTERN_1             1
 # define DP_TRAINING_PATTERN_2             2
+# define DP_TRAINING_PATTERN_3             3
 # define DP_TRAINING_PATTERN_MASK          0x3
 
 # define DP_LINK_QUAL_PATTERN_DISABLE      (0 << 2)
index 5881fad91faa29ef3d446a75b7e22280ca0dd270..eacb415b309a2c72e20928b4d0faecbff905d132 100644 (file)
@@ -155,12 +155,35 @@ struct detailed_timing {
 #define DRM_EDID_INPUT_SEPARATE_SYNCS  (1 << 3)
 #define DRM_EDID_INPUT_BLANK_TO_BLACK  (1 << 4)
 #define DRM_EDID_INPUT_VIDEO_LEVEL     (3 << 5)
-#define DRM_EDID_INPUT_DIGITAL         (1 << 7) /* bits below must be zero if set */
+#define DRM_EDID_INPUT_DIGITAL         (1 << 7)
+#define DRM_EDID_DIGITAL_DEPTH_MASK    (7 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_UNDEF   (0 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_6       (1 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_8       (2 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_10      (3 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_12      (4 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_14      (5 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_16      (6 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_RSVD    (7 << 4)
+#define DRM_EDID_DIGITAL_TYPE_UNDEF    (0)
+#define DRM_EDID_DIGITAL_TYPE_DVI      (1)
+#define DRM_EDID_DIGITAL_TYPE_HDMI_A   (2)
+#define DRM_EDID_DIGITAL_TYPE_HDMI_B   (3)
+#define DRM_EDID_DIGITAL_TYPE_MDDI     (4)
+#define DRM_EDID_DIGITAL_TYPE_DP       (5)
 
 #define DRM_EDID_FEATURE_DEFAULT_GTF      (1 << 0)
 #define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1)
 #define DRM_EDID_FEATURE_STANDARD_COLOR   (1 << 2)
+/* If analog */
 #define DRM_EDID_FEATURE_DISPLAY_TYPE     (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
+/* If digital */
+#define DRM_EDID_FEATURE_COLOR_MASK      (3 << 3)
+#define DRM_EDID_FEATURE_RGB             (0 << 3)
+#define DRM_EDID_FEATURE_RGB_YCRCB444    (1 << 3)
+#define DRM_EDID_FEATURE_RGB_YCRCB422    (2 << 3)
+#define DRM_EDID_FEATURE_RGB_YCRCB       (3 << 3) /* both 4:4:4 and 4:2:2 */
+
 #define DRM_EDID_FEATURE_PM_ACTIVE_OFF    (1 << 5)
 #define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 6)
 #define DRM_EDID_FEATURE_PM_STANDBY       (1 << 7)
index c99c3d3e78113d8a8596d0696464034c5e20fe8b..6e3076ad646e99debaecdc315affe494b52f2f28 100644 (file)
@@ -40,20 +40,6 @@ struct drm_fb_helper_crtc {
        struct drm_display_mode *desired_mode;
 };
 
-/* mode specified on the command line */
-struct drm_fb_helper_cmdline_mode {
-       bool specified;
-       bool refresh_specified;
-       bool bpp_specified;
-       int xres, yres;
-       int bpp;
-       int refresh;
-       bool rb;
-       bool interlace;
-       bool cvt;
-       bool margins;
-};
-
 struct drm_fb_helper_surface_size {
        u32 fb_width;
        u32 fb_height;
@@ -74,8 +60,8 @@ struct drm_fb_helper_funcs {
 };
 
 struct drm_fb_helper_connector {
-       struct drm_fb_helper_cmdline_mode cmdline_mode;
        struct drm_connector *connector;
+       struct drm_cmdline_mode cmdline_mode;
 };
 
 struct drm_fb_helper {
index 4554db0cde863dab0c454b42e6c032651545bf8f..c42112350003d35bd7890b3a9023fe3161b79f27 100644 (file)
@@ -417,7 +417,6 @@ extern const kernel_cap_t __cap_init_eff_set;
 
 # define CAP_EMPTY_SET    ((kernel_cap_t){{ 0, 0 }})
 # define CAP_FULL_SET     ((kernel_cap_t){{ ~0, ~0 }})
-# define CAP_INIT_EFF_SET ((kernel_cap_t){{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }})
 # define CAP_FS_SET       ((kernel_cap_t){{ CAP_FS_MASK_B0 \
                                    | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
                                    CAP_FS_MASK_B1 } })
@@ -427,11 +426,7 @@ extern const kernel_cap_t __cap_init_eff_set;
 
 #endif /* _KERNEL_CAPABILITY_U32S != 2 */
 
-#define CAP_INIT_INH_SET    CAP_EMPTY_SET
-
 # define cap_clear(c)         do { (c) = __cap_empty_set; } while (0)
-# define cap_set_full(c)      do { (c) = __cap_full_set; } while (0)
-# define cap_set_init_eff(c)  do { (c) = __cap_init_eff_set; } while (0)
 
 #define cap_raise(c, flag)  ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag))
 #define cap_lower(c, flag)  ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag))
index 2dd21243104ffd72dff12fb7cfa70d1b77de0f69..3b1cc1be419f8b13aa31be413360293c7de052a9 100644 (file)
@@ -14,7 +14,7 @@
 #define DLM_PLOCK_MISC_NAME            "dlm_plock"
 
 #define DLM_PLOCK_VERSION_MAJOR        1
-#define DLM_PLOCK_VERSION_MINOR        1
+#define DLM_PLOCK_VERSION_MINOR        2
 #define DLM_PLOCK_VERSION_PATCH        0
 
 enum {
@@ -23,12 +23,14 @@ enum {
        DLM_PLOCK_OP_GET,
 };
 
+#define DLM_PLOCK_FL_CLOSE 1
+
 struct dlm_plock_info {
        __u32 version[3];
        __u8 optype;
        __u8 ex;
        __u8 wait;
-       __u8 pad;
+       __u8 flags;
        __u32 pid;
        __s32 nodeid;
        __s32 rv;
index dd1a56fbe9241235f4baa059394d5d36bd050de7..b5ca4b2c08ecad2fad00c33d48b62466737966b0 100644 (file)
@@ -3,14 +3,15 @@
 
 struct gpio_keys_button {
        /* Configuration parameters */
-       int code;               /* input event code (KEY_*, SW_*) */
+       unsigned int code;      /* input event code (KEY_*, SW_*) */
        int gpio;
        int active_low;
-       char *desc;
-       int type;               /* input event type (EV_KEY, EV_SW) */
+       const char *desc;
+       unsigned int type;      /* input event type (EV_KEY, EV_SW, EV_ABS) */
        int wakeup;             /* configure the button as a wake-up source */
        int debounce_interval;  /* debounce ticks interval in msecs */
        bool can_disable;
+       int value;              /* axis value for EV_ABS */
 };
 
 struct gpio_keys_platform_data {
@@ -21,6 +22,7 @@ struct gpio_keys_platform_data {
        unsigned int rep:1;             /* enable input subsystem auto repeat */
        int (*enable)(struct device *dev);
        void (*disable)(struct device *dev);
+       const char *name;               /* input device name */
 };
 
 #endif
diff --git a/include/linux/i2c/i2c-sh_mobile.h b/include/linux/i2c/i2c-sh_mobile.h
new file mode 100644 (file)
index 0000000..beda708
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __I2C_SH_MOBILE_H__
+#define __I2C_SH_MOBILE_H__
+
+#include <linux/platform_device.h>
+
+struct i2c_sh_mobile_platform_data {
+       unsigned long bus_speed;
+};
+
+#endif /* __I2C_SH_MOBILE_H__ */
diff --git a/include/linux/i2c/mpr121_touchkey.h b/include/linux/i2c/mpr121_touchkey.h
new file mode 100644 (file)
index 0000000..f0bcc38
--- /dev/null
@@ -0,0 +1,20 @@
+/* Header file for Freescale MPR121 Capacitive Touch Sensor */
+
+#ifndef _MPR121_TOUCHKEY_H
+#define _MPR121_TOUCHKEY_H
+
+/**
+ * struct mpr121_platform_data - platform data for mpr121 sensor
+ * @keymap: pointer to array of KEY_* values representing keymap
+ * @keymap_size: size of the keymap
+ * @wakeup: configure the button as a wake-up source
+ * @vdd_uv: VDD voltage in uV
+ */
+struct mpr121_platform_data {
+       const unsigned short *keymap;
+       unsigned int keymap_size;
+       bool wakeup;
+       int vdd_uv;
+};
+
+#endif /* _MPR121_TOUCHKEY_H */
index c6361fbb7bf9e2eb38e087e158910c0b4daf4528..591427a63b062635e991f025222da003915c4911 100644 (file)
@@ -6,6 +6,13 @@
 struct tsc2007_platform_data {
        u16     model;                          /* 2007. */
        u16     x_plate_ohms;
+       u16     max_rt; /* max. resistance above which samples are ignored */
+       unsigned long poll_delay; /* delay (in ms) after pen-down event
+                                    before polling starts */
+       unsigned long poll_period; /* time (in ms) between samples */
+       int     fuzzx; /* fuzz factor for X, Y and pressure axes */
+       int     fuzzy;
+       int     fuzzz;
 
        int     (*get_pendown_state)(void);
        void    (*clear_penirq)(void);          /* If needed, clear 2nd level
index 689496bb6654b60ba37bbc000d982356140f9565..bafc58c00fc32b92fdbdb533c3e43d0e659c44b3 100644 (file)
@@ -83,13 +83,6 @@ extern struct group_info init_groups;
 #define INIT_IDS
 #endif
 
-/*
- * Because of the reduced scope of CAP_SETPCAP when filesystem
- * capabilities are in effect, it is safe to allow CAP_SETPCAP to
- * be available in the default configuration.
- */
-# define CAP_INIT_BSET  CAP_FULL_SET
-
 #ifdef CONFIG_RCU_BOOST
 #define INIT_TASK_RCU_BOOST()                                          \
        .rcu_boost_mutex = NULL,
index 0cbe5e81482eea96046d7e8f219a7e09297d1bf2..d388d857bf14063d15c662bd898d824112f30f02 100644 (file)
@@ -6,7 +6,7 @@
  * The platform_data for the device's "struct device" holds this
  * information.
  *
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
  *
  * Licensed under the GPL-2 or later.
  */
@@ -58,6 +58,7 @@ struct ad714x_platform_data {
        struct ad714x_button_plat *button;
        unsigned short stage_cfg_reg[STAGE_NUM][STAGE_CFGREG_NUM];
        unsigned short sys_cfg_reg[SYS_CFGREG_NUM];
+       unsigned long irqflags;
 };
 
 #endif
diff --git a/include/linux/input/adp5589.h b/include/linux/input/adp5589.h
new file mode 100644 (file)
index 0000000..ef792ec
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Analog Devices ADP5589 I/O Expander and QWERTY Keypad Controller
+ *
+ * Copyright 2010-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef _ADP5589_H
+#define _ADP5589_H
+
+#define ADP5589_ID                     0x00
+#define ADP5589_INT_STATUS             0x01
+#define ADP5589_STATUS                 0x02
+#define ADP5589_FIFO_1                 0x03
+#define ADP5589_FIFO_2                 0x04
+#define ADP5589_FIFO_3                 0x05
+#define ADP5589_FIFO_4                 0x06
+#define ADP5589_FIFO_5                 0x07
+#define ADP5589_FIFO_6                 0x08
+#define ADP5589_FIFO_7                 0x09
+#define ADP5589_FIFO_8                 0x0A
+#define ADP5589_FIFO_9                 0x0B
+#define ADP5589_FIFO_10                        0x0C
+#define ADP5589_FIFO_11                        0x0D
+#define ADP5589_FIFO_12                        0x0E
+#define ADP5589_FIFO_13                        0x0F
+#define ADP5589_FIFO_14                        0x10
+#define ADP5589_FIFO_15                        0x11
+#define ADP5589_FIFO_16                        0x12
+#define ADP5589_GPI_INT_STAT_A         0x13
+#define ADP5589_GPI_INT_STAT_B         0x14
+#define ADP5589_GPI_INT_STAT_C         0x15
+#define ADP5589_GPI_STATUS_A           0x16
+#define ADP5589_GPI_STATUS_B           0x17
+#define ADP5589_GPI_STATUS_C           0x18
+#define ADP5589_RPULL_CONFIG_A         0x19
+#define ADP5589_RPULL_CONFIG_B         0x1A
+#define ADP5589_RPULL_CONFIG_C         0x1B
+#define ADP5589_RPULL_CONFIG_D         0x1C
+#define ADP5589_RPULL_CONFIG_E         0x1D
+#define ADP5589_GPI_INT_LEVEL_A                0x1E
+#define ADP5589_GPI_INT_LEVEL_B                0x1F
+#define ADP5589_GPI_INT_LEVEL_C                0x20
+#define ADP5589_GPI_EVENT_EN_A         0x21
+#define ADP5589_GPI_EVENT_EN_B         0x22
+#define ADP5589_GPI_EVENT_EN_C         0x23
+#define ADP5589_GPI_INTERRUPT_EN_A     0x24
+#define ADP5589_GPI_INTERRUPT_EN_B     0x25
+#define ADP5589_GPI_INTERRUPT_EN_C     0x26
+#define ADP5589_DEBOUNCE_DIS_A         0x27
+#define ADP5589_DEBOUNCE_DIS_B         0x28
+#define ADP5589_DEBOUNCE_DIS_C         0x29
+#define ADP5589_GPO_DATA_OUT_A         0x2A
+#define ADP5589_GPO_DATA_OUT_B         0x2B
+#define ADP5589_GPO_DATA_OUT_C         0x2C
+#define ADP5589_GPO_OUT_MODE_A         0x2D
+#define ADP5589_GPO_OUT_MODE_B         0x2E
+#define ADP5589_GPO_OUT_MODE_C         0x2F
+#define ADP5589_GPIO_DIRECTION_A       0x30
+#define ADP5589_GPIO_DIRECTION_B       0x31
+#define ADP5589_GPIO_DIRECTION_C       0x32
+#define ADP5589_UNLOCK1                        0x33
+#define ADP5589_UNLOCK2                        0x34
+#define ADP5589_EXT_LOCK_EVENT         0x35
+#define ADP5589_UNLOCK_TIMERS          0x36
+#define ADP5589_LOCK_CFG               0x37
+#define ADP5589_RESET1_EVENT_A         0x38
+#define ADP5589_RESET1_EVENT_B         0x39
+#define ADP5589_RESET1_EVENT_C         0x3A
+#define ADP5589_RESET2_EVENT_A         0x3B
+#define ADP5589_RESET2_EVENT_B         0x3C
+#define ADP5589_RESET_CFG              0x3D
+#define ADP5589_PWM_OFFT_LOW           0x3E
+#define ADP5589_PWM_OFFT_HIGH          0x3F
+#define ADP5589_PWM_ONT_LOW            0x40
+#define ADP5589_PWM_ONT_HIGH           0x41
+#define ADP5589_PWM_CFG                        0x42
+#define ADP5589_CLOCK_DIV_CFG          0x43
+#define ADP5589_LOGIC_1_CFG            0x44
+#define ADP5589_LOGIC_2_CFG            0x45
+#define ADP5589_LOGIC_FF_CFG           0x46
+#define ADP5589_LOGIC_INT_EVENT_EN     0x47
+#define ADP5589_POLL_PTIME_CFG         0x48
+#define ADP5589_PIN_CONFIG_A           0x49
+#define ADP5589_PIN_CONFIG_B           0x4A
+#define ADP5589_PIN_CONFIG_C           0x4B
+#define ADP5589_PIN_CONFIG_D           0x4C
+#define ADP5589_GENERAL_CFG            0x4D
+#define ADP5589_INT_EN                 0x4E
+
+#define ADP5589_DEVICE_ID_MASK 0xF
+
+/* Put one of these structures in i2c_board_info platform_data */
+
+#define ADP5589_KEYMAPSIZE     88
+
+#define ADP5589_GPI_PIN_ROW0 97
+#define ADP5589_GPI_PIN_ROW1 98
+#define ADP5589_GPI_PIN_ROW2 99
+#define ADP5589_GPI_PIN_ROW3 100
+#define ADP5589_GPI_PIN_ROW4 101
+#define ADP5589_GPI_PIN_ROW5 102
+#define ADP5589_GPI_PIN_ROW6 103
+#define ADP5589_GPI_PIN_ROW7 104
+#define ADP5589_GPI_PIN_COL0 105
+#define ADP5589_GPI_PIN_COL1 106
+#define ADP5589_GPI_PIN_COL2 107
+#define ADP5589_GPI_PIN_COL3 108
+#define ADP5589_GPI_PIN_COL4 109
+#define ADP5589_GPI_PIN_COL5 110
+#define ADP5589_GPI_PIN_COL6 111
+#define ADP5589_GPI_PIN_COL7 112
+#define ADP5589_GPI_PIN_COL8 113
+#define ADP5589_GPI_PIN_COL9 114
+#define ADP5589_GPI_PIN_COL10 115
+#define GPI_LOGIC1 116
+#define GPI_LOGIC2 117
+
+#define ADP5589_GPI_PIN_ROW_BASE ADP5589_GPI_PIN_ROW0
+#define ADP5589_GPI_PIN_ROW_END ADP5589_GPI_PIN_ROW7
+#define ADP5589_GPI_PIN_COL_BASE ADP5589_GPI_PIN_COL0
+#define ADP5589_GPI_PIN_COL_END ADP5589_GPI_PIN_COL10
+
+#define ADP5589_GPI_PIN_BASE ADP5589_GPI_PIN_ROW_BASE
+#define ADP5589_GPI_PIN_END ADP5589_GPI_PIN_COL_END
+
+#define ADP5589_GPIMAPSIZE_MAX (ADP5589_GPI_PIN_END - ADP5589_GPI_PIN_BASE + 1)
+
+struct adp5589_gpi_map {
+       unsigned short pin;
+       unsigned short sw_evt;
+};
+
+/* scan_cycle_time */
+#define ADP5589_SCAN_CYCLE_10ms                0
+#define ADP5589_SCAN_CYCLE_20ms                1
+#define ADP5589_SCAN_CYCLE_30ms                2
+#define ADP5589_SCAN_CYCLE_40ms                3
+
+/* RESET_CFG */
+#define RESET_PULSE_WIDTH_500us                0
+#define RESET_PULSE_WIDTH_1ms          1
+#define RESET_PULSE_WIDTH_2ms          2
+#define RESET_PULSE_WIDTH_10ms         3
+
+#define RESET_TRIG_TIME_0ms            (0 << 2)
+#define RESET_TRIG_TIME_1000ms         (1 << 2)
+#define RESET_TRIG_TIME_1500ms         (2 << 2)
+#define RESET_TRIG_TIME_2000ms         (3 << 2)
+#define RESET_TRIG_TIME_2500ms         (4 << 2)
+#define RESET_TRIG_TIME_3000ms         (5 << 2)
+#define RESET_TRIG_TIME_3500ms         (6 << 2)
+#define RESET_TRIG_TIME_4000ms         (7 << 2)
+
+#define RESET_PASSTHRU_EN              (1 << 5)
+#define RESET1_POL_HIGH                        (1 << 6)
+#define RESET1_POL_LOW                 (0 << 6)
+#define RESET2_POL_HIGH                        (1 << 7)
+#define RESET2_POL_LOW                 (0 << 7)
+
+/* Mask Bits:
+ * C C C C C C C C C C C | R R R R R R R R
+ * 1 9 8 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0
+ * 0
+ * ---------------- BIT ------------------
+ * 1 1 1 1 1 1 1 1 1 0 0 | 0 0 0 0 0 0 0 0
+ * 8 7 6 5 4 3 2 1 0 9 8 | 7 6 5 4 3 2 1 0
+ */
+
+#define ADP_ROW(x)                     (1 << (x))
+#define ADP_COL(x)                     (1 << (x + 8))
+
+struct adp5589_kpad_platform_data {
+       unsigned keypad_en_mask;        /* Keypad (Rows/Columns) enable mask */
+       const unsigned short *keymap;   /* Pointer to keymap */
+       unsigned short keymapsize;      /* Keymap size */
+       bool repeat;                    /* Enable key repeat */
+       bool en_keylock;                /* Enable key lock feature */
+       unsigned char unlock_key1;      /* Unlock Key 1 */
+       unsigned char unlock_key2;      /* Unlock Key 2 */
+       unsigned char unlock_timer;     /* Time in seconds [0..7] between the two unlock keys 0=disable */
+       unsigned char scan_cycle_time;  /* Time between consecutive scan cycles */
+       unsigned char reset_cfg;        /* Reset config */
+       unsigned short reset1_key_1;    /* Reset Key 1 */
+       unsigned short reset1_key_2;    /* Reset Key 2 */
+       unsigned short reset1_key_3;    /* Reset Key 3 */
+       unsigned short reset2_key_1;    /* Reset Key 1 */
+       unsigned short reset2_key_2;    /* Reset Key 2 */
+       unsigned debounce_dis_mask;     /* Disable debounce mask */
+       unsigned pull_dis_mask;         /* Disable all pull resistors mask */
+       unsigned pullup_en_100k;        /* Pull-Up 100k Enable Mask */
+       unsigned pullup_en_300k;        /* Pull-Up 300k Enable Mask */
+       unsigned pulldown_en_300k;      /* Pull-Down 300k Enable Mask */
+       const struct adp5589_gpi_map *gpimap;
+       unsigned short gpimapsize;
+       const struct adp5589_gpio_platform_data *gpio_data;
+};
+
+struct i2c_client; /* forward declaration */
+
+struct adp5589_gpio_platform_data {
+       int     gpio_start;     /* GPIO Chip base # */
+       int     (*setup)(struct i2c_client *client,
+                               int gpio, unsigned ngpio,
+                               void *context);
+       int     (*teardown)(struct i2c_client *client,
+                               int gpio, unsigned ngpio,
+                               void *context);
+       void    *context;
+};
+
+#endif
index b2bb01719561f0d3de11945a9dba0a78744b8acc..ef19b99aff98d426c8e9b355a31360675daf9669 100644 (file)
@@ -276,6 +276,19 @@ static inline key_serial_t key_serial(struct key *key)
        return key ? key->serial : 0;
 }
 
+/**
+ * key_is_instantiated - Determine if a key has been positively instantiated
+ * @key: The key to check.
+ *
+ * Return true if the specified key has been positively instantiated, false
+ * otherwise.
+ */
+static inline bool key_is_instantiated(const struct key *key)
+{
+       return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
+               !test_bit(KEY_FLAG_NEGATIVE, &key->flags);
+}
+
 #define rcu_dereference_key(KEY)                                       \
        (rcu_dereference_protected((KEY)->payload.rcudata,              \
                                   rwsem_is_locked(&((struct key *)(KEY))->sem)))
index 310231823852026b69bf25cc88868ab86de69975..d4a5c84c503d7307a577474bc0eb4d75cb7265f3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/errno.h>
 #include <linux/compiler.h>
 #include <linux/workqueue.h>
+#include <linux/sysctl.h>
 
 #define KMOD_PATH_LEN 256
 
@@ -109,6 +110,8 @@ call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
                                       NULL, NULL, NULL);
 }
 
+extern struct ctl_table usermodehelper_table[];
+
 extern void usermodehelper_init(void);
 
 extern int usermodehelper_disable(void);
index 7135ebc8428c5273fd62535b985e1fb00e9bfbe0..3f46aedea42fbb5024f8e9896e380d0051c74132 100644 (file)
 #define asmlinkage CPP_ASMLINKAGE
 #endif
 
-#ifndef asmregparm
-# define asmregparm
-#endif
-
 #define __page_aligned_data    __section(.data..page_aligned) __aligned(PAGE_SIZE)
 #define __page_aligned_bss     __section(.bss..page_aligned) __aligned(PAGE_SIZE)
 
index 112a55033352bbaaf79e045f9367edd3f45f5b1e..88e78dedc2e81394f7cbe2e9094782fc2ce32ba5 100644 (file)
@@ -27,7 +27,7 @@
 /* Auxiliary data to use in generating the audit record. */
 struct common_audit_data {
        char type;
-#define LSM_AUDIT_DATA_FS      1
+#define LSM_AUDIT_DATA_PATH    1
 #define LSM_AUDIT_DATA_NET     2
 #define LSM_AUDIT_DATA_CAP     3
 #define LSM_AUDIT_DATA_IPC     4
@@ -35,12 +35,13 @@ struct common_audit_data {
 #define LSM_AUDIT_DATA_KEY     6
 #define LSM_AUDIT_DATA_NONE    7
 #define LSM_AUDIT_DATA_KMOD    8
+#define LSM_AUDIT_DATA_INODE   9
+#define LSM_AUDIT_DATA_DENTRY  10
        struct task_struct *tsk;
        union   {
-               struct {
-                       struct path path;
-                       struct inode *inode;
-               } fs;
+               struct path path;
+               struct dentry *dentry;
+               struct inode *inode;
                struct {
                        int netif;
                        struct sock *sk;
index 84854edf4436f2a62ff7bc956101a6953236726e..15da0e99f48aef0615fafeefb9c3142a0f2bfa5a 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef __LINUX_UBI_H__
 #define __LINUX_UBI_H__
 
-#include <asm/ioctl.h>
+#include <linux/ioctl.h>
 #include <linux/types.h>
 #include <mtd/ubi-user.h>
 
@@ -87,7 +87,7 @@ enum {
  * physical eraseblock size and on how much bytes UBI headers consume. But
  * because of the volume alignment (@alignment), the usable size of logical
  * eraseblocks if a volume may be less. The following equation is true:
- *     @usable_leb_size = LEB size - (LEB size mod @alignment),
+ *     @usable_leb_size = LEB size - (LEB size mod @alignment),
  * where LEB size is the logical eraseblock size defined by the UBI device.
  *
  * The alignment is multiple to the minimal flash input/output unit size or %1
diff --git a/include/linux/mxm-wmi.h b/include/linux/mxm-wmi.h
new file mode 100644 (file)
index 0000000..617a295
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * MXM WMI driver
+ *
+ * Copyright(C) 2010 Red Hat.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef MXM_WMI_H
+#define MXM_WMI_H
+
+/* discrete adapters */
+#define MXM_MXDS_ADAPTER_0 0x0
+#define MXM_MXDS_ADAPTER_1 0x0
+/* integrated adapter */
+#define MXM_MXDS_ADAPTER_IGD 0x10
+int mxm_wmi_call_mxds(int adapter);
+int mxm_wmi_call_mxmx(int adapter);
+bool mxm_wmi_supported(void);
+
+#endif
index 811183de1ef5eb27792b0b272f7e513c6b78d457..79a6700b716263a4f504627aa974f61e755bff9c 100644 (file)
@@ -308,7 +308,7 @@ static inline void SetPageUptodate(struct page *page)
 {
 #ifdef CONFIG_S390
        if (!test_and_set_bit(PG_uptodate, &page->flags))
-               page_clear_dirty(page, 0);
+               page_set_storage_key(page_to_pfn(page), PAGE_DEFAULT_KEY, 0);
 #else
        /*
         * Memory barrier must be issued before setting the PG_uptodate bit,
index 4604d1d5514d9b84bba1eecf8a254a2699fe5575..c446b5ca2d38e0e58b650b217bec0f0f90945dd7 100644 (file)
@@ -941,8 +941,11 @@ int pci_cfg_space_size_ext(struct pci_dev *dev);
 int pci_cfg_space_size(struct pci_dev *dev);
 unsigned char pci_bus_max_busnr(struct pci_bus *bus);
 
+#define PCI_VGA_STATE_CHANGE_BRIDGE (1 << 0)
+#define PCI_VGA_STATE_CHANGE_DECODES (1 << 1)
+
 int pci_set_vga_state(struct pci_dev *pdev, bool decode,
-                     unsigned int command_bits, bool change_bridge);
+                     unsigned int command_bits, u32 flags);
 /* kmem_cache style wrapper around pci_alloc_consistent() */
 
 #include <linux/pci-dma.h>
@@ -1087,7 +1090,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 
 /* some architectures require additional setup to direct VGA traffic */
 typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
-                     unsigned int command_bits, bool change_bridge);
+                     unsigned int command_bits, u32 flags);
 extern void pci_register_set_vga_state(arch_set_vga_state_t func);
 
 #else /* CONFIG_PCI is not enabled */
index 215278b8df2aba5ca56f5eef120ef7b782523da6..3f594dce571650c76253a785e8720490a7c0f80e 100644 (file)
@@ -10,6 +10,7 @@ struct rotary_encoder_platform_data {
        unsigned int inverted_b;
        bool relative_axis;
        bool rollover;
+       bool half_period;
 };
 
 #endif /* __ROTARY_ENCODER_H__ */
index 92bd0839d5b49a414f8cd23fef827403ed965bab..c64de9dd7631bb44232eeca7d8080c62521c5b1e 100644 (file)
@@ -14,7 +14,8 @@ enum ads7846_filter {
 struct ads7846_platform_data {
        u16     model;                  /* 7843, 7845, 7846, 7873. */
        u16     vref_delay_usecs;       /* 0 for external vref; etc */
-       u16     vref_mv;                /* external vref value, milliVolts */
+       u16     vref_mv;                /* external vref value, milliVolts
+                                        * ads7846: if 0, use internal vref */
        bool    keep_vref_on;           /* set to keep vref on for differential
                                         * measurements as well */
        bool    swap_xy;                /* swap x and y axes */
index c0d47ad4b103b5a502cf98230f3d52da3e38d74b..3c4109777afff101c192b880ca1072978eddf3d8 100644 (file)
  * ~~~~~~~~~~~~~~~~~~~~~~~~~
  *
  * To set an UBI volume property the %UBI_IOCSETPROP ioctl command should be
- * used. A pointer to a &struct ubi_set_prop_req object is expected to be
+ * used. A pointer to a &struct ubi_set_vol_prop_req object is expected to be
  * passed. The object describes which property should be set, and to which value
  * it should be set.
  */
 /* Check if LEB is mapped command */
 #define UBI_IOCEBISMAP _IOR(UBI_VOL_IOC_MAGIC, 5, __s32)
 /* Set an UBI volume property */
-#define UBI_IOCSETPROP _IOW(UBI_VOL_IOC_MAGIC, 6, struct ubi_set_prop_req)
+#define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
+                              struct ubi_set_vol_prop_req)
 
 /* Maximum MTD device name length supported by UBI */
 #define MAX_UBI_MTD_NAME_LEN 127
@@ -223,13 +224,14 @@ enum {
 };
 
 /*
- * UBI set property ioctl constants
+ * UBI set volume property ioctl constants.
  *
- * @UBI_PROP_DIRECT_WRITE: allow / disallow user to directly write and
- *                         erase individual eraseblocks on dynamic volumes
+ * @UBI_VOL_PROP_DIRECT_WRITE: allow (any non-zero value) or disallow (value 0)
+ *                             user to directly write and erase individual
+ *                             eraseblocks on dynamic volumes
  */
 enum {
-       UBI_PROP_DIRECT_WRITE = 1,
+       UBI_VOL_PROP_DIRECT_WRITE = 1,
 };
 
 /**
@@ -308,7 +310,7 @@ struct ubi_mkvol_req {
        __s16 name_len;
        __s8 padding2[4];
        char name[UBI_MAX_VOLUME_NAME + 1];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_rsvol_req - a data structure used in volume re-size requests.
@@ -324,7 +326,7 @@ struct ubi_mkvol_req {
 struct ubi_rsvol_req {
        __s64 bytes;
        __s32 vol_id;
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_rnvol_req - volumes re-name request.
@@ -366,7 +368,7 @@ struct ubi_rnvol_req {
                __s8  padding2[2];
                char    name[UBI_MAX_VOLUME_NAME + 1];
        } ents[UBI_MAX_RNVOL];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_leb_change_req - a data structure used in atomic LEB change
@@ -381,7 +383,7 @@ struct ubi_leb_change_req {
        __s32 bytes;
        __s8  dtype;
        __s8  padding[7];
-} __attribute__ ((packed));
+} __packed;
 
 /**
  * struct ubi_map_req - a data structure used in map LEB requests.
@@ -393,20 +395,20 @@ struct ubi_map_req {
        __s32 lnum;
        __s8  dtype;
        __s8  padding[3];
-} __attribute__ ((packed));
+} __packed;
 
 
 /**
- * struct ubi_set_prop_req - a data structure used to set an ubi volume
- *                           property.
- * @property: property to set (%UBI_PROP_DIRECT_WRITE)
+ * struct ubi_set_vol_prop_req - a data structure used to set an UBI volume
+ *                               property.
+ * @property: property to set (%UBI_VOL_PROP_DIRECT_WRITE)
  * @padding: reserved for future, not used, has to be zeroed
  * @value: value to set
  */
-struct ubi_set_prop_req {
-       __u8  property;
-       __u8  padding[7];
-       __u64 value;
-}  __attribute__ ((packed));
+struct ubi_set_vol_prop_req {
+       __u8  property;
+       __u8  padding[7];
+       __u64 value;
+}  __packed;
 
 #endif /* __UBI_USER_H__ */
index 3fd5064dd43a7805c900f28a20a218179836ebbe..7b82080eb02ce325c944341b961545914987a380 100644 (file)
@@ -56,7 +56,7 @@ struct pcmcia_driver {
        int (*resume)           (struct pcmcia_device *dev);
 
        struct module           *owner;
-       struct pcmcia_device_id *id_table;
+       const struct pcmcia_device_id   *id_table;
        struct device_driver    drv;
        struct pcmcia_dynids    dynids;
 };
index c8b172efaa65bf9264ecae76422159214f943b95..332aac6499667658e45b8be17181b81a75618bbb 100644 (file)
@@ -959,24 +959,18 @@ config KALLSYMS_ALL
        bool "Include all symbols in kallsyms"
        depends on DEBUG_KERNEL && KALLSYMS
        help
-          Normally kallsyms only contains the symbols of functions, for nicer
-          OOPS messages.  Some debuggers can use kallsyms for other
-          symbols too: say Y here to include all symbols, if you need them 
-          and you don't care about adding 300k to the size of your kernel.
-
-          Say N.
-
-config KALLSYMS_EXTRA_PASS
-       bool "Do an extra kallsyms pass"
-       depends on KALLSYMS
-       help
-          If kallsyms is not working correctly, the build will fail with
-          inconsistent kallsyms data.  If that occurs, log a bug report and
-          turn on KALLSYMS_EXTRA_PASS which should result in a stable build.
-          Always say N here unless you find a bug in kallsyms, which must be
-          reported.  KALLSYMS_EXTRA_PASS is only a temporary workaround while
-          you wait for kallsyms to be fixed.
-
+          Normally kallsyms only contains the symbols of functions for nicer
+          OOPS messages and backtraces (i.e., symbols from the text and inittext
+          sections). This is sufficient for most cases. And only in very rare
+          cases (e.g., when a debugger is used) all symbols are required (e.g.,
+          names of variables from the data sections, etc).
+
+          This option makes sure that all symbols are loaded into the kernel
+          image (i.e., symbols from all sections) in cost of increased kernel
+          size (depending on the kernel configuration, it may be 300KiB or
+          something like this).
+
+          Say N unless you really need all symbols.
 
 config HOTPLUG
        bool "Support for hot-pluggable devices" if EXPERT
index 32a80e08ff4b8ebf725ebc8d3a526c2dee3f00f4..283c529f8b1cfd2199e90e238aa3d2a67370c414 100644 (file)
  */
 
 const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
-const kernel_cap_t __cap_full_set = CAP_FULL_SET;
-const kernel_cap_t __cap_init_eff_set = CAP_INIT_EFF_SET;
 
 EXPORT_SYMBOL(__cap_empty_set);
-EXPORT_SYMBOL(__cap_full_set);
-EXPORT_SYMBOL(__cap_init_eff_set);
 
 int file_caps_enabled = 1;
 
index 8093c16b84b13d2e9e0714af279b29b0549a0652..e12c8af793f8083c5fcda23a65ec33086b2ca8fb 100644 (file)
@@ -49,10 +49,10 @@ struct cred init_cred = {
        .magic                  = CRED_MAGIC,
 #endif
        .securebits             = SECUREBITS_DEFAULT,
-       .cap_inheritable        = CAP_INIT_INH_SET,
+       .cap_inheritable        = CAP_EMPTY_SET,
        .cap_permitted          = CAP_FULL_SET,
-       .cap_effective          = CAP_INIT_EFF_SET,
-       .cap_bset               = CAP_INIT_BSET,
+       .cap_effective          = CAP_FULL_SET,
+       .cap_bset               = CAP_FULL_SET,
        .user                   = INIT_USER,
        .user_ns                = &init_user_ns,
        .group_info             = &init_groups,
index 5ae0ff38425f7ec6dfd0a794668df7a02d1ff923..ad6a81c58b44e2d5ae57c5dbe866da1cf1008a03 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/kmod.h>
 #include <linux/slab.h>
 #include <linux/completion.h>
+#include <linux/cred.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
 #include <linux/workqueue.h>
@@ -43,6 +44,13 @@ extern int max_threads;
 
 static struct workqueue_struct *khelper_wq;
 
+#define CAP_BSET       (void *)1
+#define CAP_PI         (void *)2
+
+static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
+static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
+static DEFINE_SPINLOCK(umh_sysctl_lock);
+
 #ifdef CONFIG_MODULES
 
 /*
@@ -132,6 +140,7 @@ EXPORT_SYMBOL(__request_module);
 static int ____call_usermodehelper(void *data)
 {
        struct subprocess_info *sub_info = data;
+       struct cred *new;
        int retval;
 
        spin_lock_irq(&current->sighand->siglock);
@@ -153,6 +162,19 @@ static int ____call_usermodehelper(void *data)
                        goto fail;
        }
 
+       retval = -ENOMEM;
+       new = prepare_kernel_cred(current);
+       if (!new)
+               goto fail;
+
+       spin_lock(&umh_sysctl_lock);
+       new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
+       new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
+                                            new->cap_inheritable);
+       spin_unlock(&umh_sysctl_lock);
+
+       commit_creds(new);
+
        retval = kernel_execve(sub_info->path,
                               (const char *const *)sub_info->argv,
                               (const char *const *)sub_info->envp);
@@ -420,6 +442,84 @@ unlock:
 }
 EXPORT_SYMBOL(call_usermodehelper_exec);
 
+static int proc_cap_handler(struct ctl_table *table, int write,
+                        void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct ctl_table t;
+       unsigned long cap_array[_KERNEL_CAPABILITY_U32S];
+       kernel_cap_t new_cap;
+       int err, i;
+
+       if (write && (!capable(CAP_SETPCAP) ||
+                     !capable(CAP_SYS_MODULE)))
+               return -EPERM;
+
+       /*
+        * convert from the global kernel_cap_t to the ulong array to print to
+        * userspace if this is a read.
+        */
+       spin_lock(&umh_sysctl_lock);
+       for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)  {
+               if (table->data == CAP_BSET)
+                       cap_array[i] = usermodehelper_bset.cap[i];
+               else if (table->data == CAP_PI)
+                       cap_array[i] = usermodehelper_inheritable.cap[i];
+               else
+                       BUG();
+       }
+       spin_unlock(&umh_sysctl_lock);
+
+       t = *table;
+       t.data = &cap_array;
+
+       /*
+        * actually read or write and array of ulongs from userspace.  Remember
+        * these are least significant 32 bits first
+        */
+       err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos);
+       if (err < 0)
+               return err;
+
+       /*
+        * convert from the sysctl array of ulongs to the kernel_cap_t
+        * internal representation
+        */
+       for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)
+               new_cap.cap[i] = cap_array[i];
+
+       /*
+        * Drop everything not in the new_cap (but don't add things)
+        */
+       spin_lock(&umh_sysctl_lock);
+       if (write) {
+               if (table->data == CAP_BSET)
+                       usermodehelper_bset = cap_intersect(usermodehelper_bset, new_cap);
+               if (table->data == CAP_PI)
+                       usermodehelper_inheritable = cap_intersect(usermodehelper_inheritable, new_cap);
+       }
+       spin_unlock(&umh_sysctl_lock);
+
+       return 0;
+}
+
+struct ctl_table usermodehelper_table[] = {
+       {
+               .procname       = "bset",
+               .data           = CAP_BSET,
+               .maxlen         = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
+               .mode           = 0600,
+               .proc_handler   = proc_cap_handler,
+       },
+       {
+               .procname       = "inheritable",
+               .data           = CAP_PI,
+               .maxlen         = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
+               .mode           = 0600,
+               .proc_handler   = proc_cap_handler,
+       },
+       { }
+};
+
 void __init usermodehelper_init(void)
 {
        khelper_wq = create_singlethread_workqueue("khelper");
index 3dd0c46fa3bbd68d1d4774e23e0189c54508fd0b..4bffd62c2f13beff38787b8a3e625932492a965f 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/kprobes.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/oom.h>
+#include <linux/kmod.h>
 
 #include <asm/uaccess.h>
 #include <asm/processor.h>
@@ -615,6 +616,11 @@ static struct ctl_table kern_table[] = {
                .mode           = 0555,
                .child          = random_table,
        },
+       {
+               .procname       = "usermodehelper",
+               .mode           = 0555,
+               .child          = usermodehelper_table,
+       },
        {
                .procname       = "overflowuid",
                .data           = &overflowuid,
index e3378e8d3a5ce7e16fbbbb35ebd30a1c51fde650..0400553f0d049807d109e9cc87d7a5dc2c0dcc99 100644 (file)
@@ -2866,9 +2866,7 @@ static int alloc_cwqs(struct workqueue_struct *wq)
                }
        }
 
-       /* just in case, make sure it's actually aligned
-        * - this is affected by PERCPU() alignment in vmlinux.lds.S
-        */
+       /* just in case, make sure it's actually aligned */
        BUG_ON(!IS_ALIGNED(wq->cpu_wq.v, align));
        return wq->cpu_wq.v ? 0 : -ENOMEM;
 }
index 854b57bd7d9d346276fe83599f5cbd306c6e0fe4..cab7621f98aa1130f99de9b9949851e56b4cdc4d 100644 (file)
@@ -88,8 +88,11 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total,
                                        gfp_t flags)
 {
        struct flex_array *ret;
-       int max_size = FLEX_ARRAY_NR_BASE_PTRS *
-                               FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
+       int max_size = 0;
+
+       if (element_size)
+               max_size = FLEX_ARRAY_NR_BASE_PTRS *
+                          FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
 
        /* max_size will end up 0 if element_size > PAGE_SIZE */
        if (total > max_size)
@@ -183,15 +186,18 @@ __fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags)
 int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,
                        gfp_t flags)
 {
-       int part_nr = fa_element_to_part_nr(fa, element_nr);
+       int part_nr;
        struct flex_array_part *part;
        void *dst;
 
        if (element_nr >= fa->total_nr_elements)
                return -ENOSPC;
+       if (!fa->element_size)
+               return 0;
        if (elements_fit_in_base(fa))
                part = (struct flex_array_part *)&fa->parts[0];
        else {
+               part_nr = fa_element_to_part_nr(fa, element_nr);
                part = __fa_get_part(fa, part_nr, flags);
                if (!part)
                        return -ENOMEM;
@@ -211,15 +217,18 @@ EXPORT_SYMBOL(flex_array_put);
  */
 int flex_array_clear(struct flex_array *fa, unsigned int element_nr)
 {
-       int part_nr = fa_element_to_part_nr(fa, element_nr);
+       int part_nr;
        struct flex_array_part *part;
        void *dst;
 
        if (element_nr >= fa->total_nr_elements)
                return -ENOSPC;
+       if (!fa->element_size)
+               return 0;
        if (elements_fit_in_base(fa))
                part = (struct flex_array_part *)&fa->parts[0];
        else {
+               part_nr = fa_element_to_part_nr(fa, element_nr);
                part = fa->parts[part_nr];
                if (!part)
                        return -EINVAL;
@@ -264,6 +273,8 @@ int flex_array_prealloc(struct flex_array *fa, unsigned int start,
 
        if (end >= fa->total_nr_elements)
                return -ENOSPC;
+       if (!fa->element_size)
+               return 0;
        if (elements_fit_in_base(fa))
                return 0;
        start_part = fa_element_to_part_nr(fa, start);
@@ -291,14 +302,17 @@ EXPORT_SYMBOL(flex_array_prealloc);
  */
 void *flex_array_get(struct flex_array *fa, unsigned int element_nr)
 {
-       int part_nr = fa_element_to_part_nr(fa, element_nr);
+       int part_nr;
        struct flex_array_part *part;
 
+       if (!fa->element_size)
+               return NULL;
        if (element_nr >= fa->total_nr_elements)
                return NULL;
        if (elements_fit_in_base(fa))
                part = (struct flex_array_part *)&fa->parts[0];
        else {
+               part_nr = fa_element_to_part_nr(fa, element_nr);
                part = fa->parts[part_nr];
                if (!part)
                        return NULL;
@@ -353,7 +367,7 @@ int flex_array_shrink(struct flex_array *fa)
        int part_nr;
        int ret = 0;
 
-       if (!fa->total_nr_elements)
+       if (!fa->total_nr_elements || !fa->element_size)
                return 0;
        if (elements_fit_in_base(fa))
                return ret;
index a160db39b810d3e7cd5981298b125c807419e964..bf80e55dbed7e66fcd28f6dbc46c86fbd222a008 100644 (file)
@@ -1215,8 +1215,10 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai,
        PCPU_SETUP_BUG_ON(ai->nr_groups <= 0);
 #ifdef CONFIG_SMP
        PCPU_SETUP_BUG_ON(!ai->static_size);
+       PCPU_SETUP_BUG_ON((unsigned long)__per_cpu_start & ~PAGE_MASK);
 #endif
        PCPU_SETUP_BUG_ON(!base_addr);
+       PCPU_SETUP_BUG_ON((unsigned long)base_addr & ~PAGE_MASK);
        PCPU_SETUP_BUG_ON(ai->unit_size < size_sum);
        PCPU_SETUP_BUG_ON(ai->unit_size & ~PAGE_MASK);
        PCPU_SETUP_BUG_ON(ai->unit_size < PCPU_MIN_UNIT_SIZE);
@@ -1645,8 +1647,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
        /* warn if maximum distance is further than 75% of vmalloc space */
        if (max_distance > (VMALLOC_END - VMALLOC_START) * 3 / 4) {
                pr_warning("PERCPU: max_distance=0x%zx too large for vmalloc "
-                          "space 0x%lx\n",
-                          max_distance, VMALLOC_END - VMALLOC_START);
+                          "space 0x%lx\n", max_distance,
+                          (unsigned long)(VMALLOC_END - VMALLOC_START));
 #ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
                /* and fail if we have fallback */
                rc = -EINVAL;
index 8da044a1db0f4db1524f2450cd733e41eb8690ca..522e4a93cadda8d33bcc25025c224dc7acacc9d6 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -719,7 +719,7 @@ int page_referenced(struct page *page,
                        unlock_page(page);
        }
 out:
-       if (page_test_and_clear_young(page))
+       if (page_test_and_clear_young(page_to_pfn(page)))
                referenced++;
 
        return referenced;
@@ -785,10 +785,8 @@ int page_mkclean(struct page *page)
                struct address_space *mapping = page_mapping(page);
                if (mapping) {
                        ret = page_mkclean_file(mapping, page);
-                       if (page_test_dirty(page)) {
-                               page_clear_dirty(page, 1);
+                       if (page_test_and_clear_dirty(page_to_pfn(page), 1))
                                ret = 1;
-                       }
                }
        }
 
@@ -981,10 +979,9 @@ void page_remove_rmap(struct page *page)
         * not if it's in swapcache - there might be another pte slot
         * containing the swap entry, but page not yet written to swap.
         */
-       if ((!PageAnon(page) || PageSwapCache(page)) && page_test_dirty(page)) {
-               page_clear_dirty(page, 1);
+       if ((!PageAnon(page) || PageSwapCache(page)) &&
+           page_test_and_clear_dirty(page_to_pfn(page), 1))
                set_page_dirty(page);
-       }
        /*
         * Hugepages are not counted in NR_ANON_PAGES nor NR_FILE_MAPPED
         * and not charged by memcg for now.
index cfa7a5e1c5c98ca4592e09588a3a80bc1ba24d10..fa000d26dc6097220fe8bf53ed7cfc822afc31a0 100644 (file)
@@ -212,10 +212,12 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m)
        int err = key->type_data.x[0];
 
        seq_puts(m, key->description);
-       if (err)
-               seq_printf(m, ": %d", err);
-       else
-               seq_printf(m, ": %u", key->datalen);
+       if (key_is_instantiated(key)) {
+               if (err)
+                       seq_printf(m, ": %d", err);
+               else
+                       seq_printf(m, ": %u", key->datalen);
+       }
 }
 
 /*
index e2741d23bab8c2343a928e402b063bcc0f251a0d..105b21f0818597e4c881e3f1b7e4f286616cc8d9 100644 (file)
@@ -8,3 +8,4 @@ bin2c
 unifdef
 ihex2fw
 recordmcount
+docproc
index ed2773edfe71bae99adc0a7b64a454912dfd4477..be39cd1c74cff6009eac1120c1eafe18085ed37e 100644 (file)
@@ -118,6 +118,11 @@ cc-option-yn = $(call try-run,\
 cc-option-align = $(subst -functions=0,,\
        $(call cc-option,-falign-functions=0,-malign-functions=0))
 
+# cc-disable-warning
+# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable)
+cc-disable-warning = $(call try-run,\
+       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1)))
+
 # cc-version
 # Usage gcc-ver := $(call cc-version)
 cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
@@ -141,6 +146,11 @@ cc-ldoption = $(call try-run,\
 ld-option = $(call try-run,\
        $(CC) /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2))
 
+# ar-option
+# Usage: KBUILD_ARFLAGS := $(call ar-option,D)
+# Important: no spaces around options
+ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2))
+
 ######
 
 ###
@@ -187,6 +197,8 @@ ifneq ($(KBUILD_NOCMDDEP),1)
 # User may override this check using make KBUILD_NOCMDDEP=1
 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
                     $(filter-out $(cmd_$@),   $(cmd_$(1))) )
+else
+arg-check = $(if $(strip $(cmd_$@)),,1)
 endif
 
 # >'< substitution is for echo to work,
index fcea26168bca718afb07cf4a2a71081b309e906e..df7678febf277b119cbffc4d3b6f230974fb18f0 100644 (file)
@@ -6,6 +6,7 @@
 # pnmttologo:    Convert pnm files to logo files
 # conmakehash:   Create chartable
 # conmakehash:  Create arrays for initializing the kernel console tables
+# docproc:       Used in Documentation/DocBook
 
 hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
@@ -16,12 +17,14 @@ hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
 always         := $(hostprogs-y) $(hostprogs-m)
 
 # The following hostprogs-y programs are only build on demand
-hostprogs-y += unifdef
+hostprogs-y += unifdef docproc
 
-# This target is used internally to avoid "is up to date" messages
+# These targets are used internally to avoid "is up to date" messages
 PHONY += build_unifdef
 build_unifdef: scripts/unifdef FORCE
        @:
+build_docproc: scripts/docproc FORCE
+       @:
 
 subdir-$(CONFIG_MODVERSIONS) += genksyms
 subdir-y                     += mod
diff --git a/scripts/Makefile.asm-generic b/scripts/Makefile.asm-generic
new file mode 100644 (file)
index 0000000..490122c
--- /dev/null
@@ -0,0 +1,23 @@
+# include/asm-generic contains a lot of files that are used
+# verbatim by several architectures.
+#
+# This Makefile reads the file arch/$(SRCARCH)/include/asm/Kbuild
+# and for each file listed in this file with generic-y creates
+# a small wrapper file in $(obj) (arch/$(SRCARCH)/include/generated/asm)
+
+kbuild-file := $(srctree)/arch/$(SRCARCH)/include/asm/Kbuild
+-include $(kbuild-file)
+
+include scripts/Kbuild.include
+
+# Create output directory if not already present
+_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
+
+quiet_cmd_wrap = WRAP    $@
+cmd_wrap = echo "\#include <asm-generic/$*.h>" >$@
+
+all: $(patsubst %, $(obj)/%, $(generic-y))
+
+$(obj)/%.h:
+       $(call cmd,wrap)
+
index 6165622c3e29ae4cb395a1182045a905b603d7f4..a0fd5029cfe78c8d082409b3228a59998b15eaa2 100644 (file)
@@ -51,36 +51,52 @@ ifeq ($(KBUILD_NOPEDANTIC),)
 endif
 
 #
-# make W=1 settings
+# make W=... settings
 #
-# $(call cc-option... ) handles gcc -W.. options which
+# W=1 - warnings that may be relevant and does not occur too often
+# W=2 - warnings that occur quite often but may still be relevant
+# W=3 - the more obscure warnings, can most likely be ignored
+#
+# $(call cc-option, -W...) handles gcc -W.. options which
 # are not supported by all versions of the compiler
 ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS
-KBUILD_EXTRA_WARNINGS := -Wextra
-KBUILD_EXTRA_WARNINGS += -Wunused -Wno-unused-parameter
-KBUILD_EXTRA_WARNINGS += -Waggregate-return
-KBUILD_EXTRA_WARNINGS += -Wbad-function-cast
-KBUILD_EXTRA_WARNINGS += -Wcast-qual
-KBUILD_EXTRA_WARNINGS += -Wcast-align
-KBUILD_EXTRA_WARNINGS += -Wconversion
-KBUILD_EXTRA_WARNINGS += -Wdisabled-optimization
-KBUILD_EXTRA_WARNINGS += -Wlogical-op
-KBUILD_EXTRA_WARNINGS += -Wmissing-declarations
-KBUILD_EXTRA_WARNINGS += -Wmissing-format-attribute
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wmissing-include-dirs,)
-KBUILD_EXTRA_WARNINGS += -Wmissing-prototypes
-KBUILD_EXTRA_WARNINGS += -Wnested-externs
-KBUILD_EXTRA_WARNINGS += -Wold-style-definition
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Woverlength-strings,)
-KBUILD_EXTRA_WARNINGS += -Wpacked
-KBUILD_EXTRA_WARNINGS += -Wpacked-bitfield-compat
-KBUILD_EXTRA_WARNINGS += -Wpadded
-KBUILD_EXTRA_WARNINGS += -Wpointer-arith
-KBUILD_EXTRA_WARNINGS += -Wredundant-decls
-KBUILD_EXTRA_WARNINGS += -Wshadow
-KBUILD_EXTRA_WARNINGS += -Wswitch-default
-KBUILD_EXTRA_WARNINGS += $(call cc-option, -Wvla,)
-KBUILD_CFLAGS += $(KBUILD_EXTRA_WARNINGS)
+warning-  := $(empty)
+
+warning-1 := -Wextra -Wunused -Wno-unused-parameter
+warning-1 += -Wmissing-declarations
+warning-1 += -Wmissing-format-attribute
+warning-1 += -Wmissing-prototypes
+warning-1 += -Wold-style-definition
+warning-1 += $(call cc-option, -Wmissing-include-dirs)
+warning-1 += $(call cc-option, -Wunused-but-set-variable)
+
+warning-2 := -Waggregate-return
+warning-2 += -Wcast-align
+warning-2 += -Wdisabled-optimization
+warning-2 += -Wnested-externs
+warning-2 += -Wshadow
+warning-2 += $(call cc-option, -Wlogical-op)
+
+warning-3 := -Wbad-function-cast
+warning-3 += -Wcast-qual
+warning-3 += -Wconversion
+warning-3 += -Wpacked
+warning-3 += -Wpadded
+warning-3 += -Wpointer-arith
+warning-3 += -Wredundant-decls
+warning-3 += -Wswitch-default
+warning-3 += $(call cc-option, -Wpacked-bitfield-compat)
+warning-3 += $(call cc-option, -Wvla)
+
+warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS)))
+
+ifeq ("$(strip $(warning))","")
+        $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown)
+endif
+
+KBUILD_CFLAGS += $(warning)
 endif
 
 include scripts/Makefile.lib
@@ -351,7 +367,7 @@ quiet_cmd_link_o_target = LD      $@
 cmd_link_o_target = $(if $(strip $(obj-y)),\
                      $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
                      $(cmd_secanalysis),\
-                     rm -f $@; $(AR) rcs $@)
+                     rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@)
 
 $(builtin-target): $(obj-y) FORCE
        $(call if_changed,link_o_target)
@@ -377,7 +393,7 @@ $(modorder-target): $(subdir-ym) FORCE
 #
 ifdef lib-target
 quiet_cmd_link_l_target = AR      $@
-cmd_link_l_target = rm -f $@; $(AR) rcs $@ $(lib-y)
+cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y)
 
 $(lib-target): $(lib-y) FORCE
        $(call if_changed,link_l_target)
index f89cb87f5c018f24b56e13201530df261379c230..a57f5bd5a13d5b8f14a90b03bf23115e925b4a0a 100644 (file)
@@ -27,8 +27,13 @@ header-y      := $(filter-out %/, $(header-y))
 install-file  := $(install)/.install
 check-file    := $(install)/.check
 
+# generic-y list all files an architecture uses from asm-generic
+# Use this to build a list of headers which require a wrapper
+wrapper-files := $(filter $(header-y), $(generic-y))
+
 # all headers files for this dir
-all-files     := $(header-y) $(objhdr-y)
+header-y      := $(filter-out $(generic-y), $(header-y))
+all-files     := $(header-y) $(objhdr-y) $(wrapper-files)
 input-files   := $(addprefix $(srctree)/$(obj)/,$(header-y)) \
                  $(addprefix $(objtree)/$(obj)/,$(objhdr-y))
 output-files  := $(addprefix $(install)/, $(all-files))
@@ -47,6 +52,9 @@ quiet_cmd_install = INSTALL $(printdir) ($(words $(all-files))\
       cmd_install = \
         $(PERL) $< $(srctree)/$(obj) $(install) $(SRCARCH) $(header-y); \
         $(PERL) $< $(objtree)/$(obj) $(install) $(SRCARCH) $(objhdr-y); \
+        for F in $(wrapper-files); do                                   \
+                echo "\#include <asm-generic/$$F>" > $(install)/$$F;    \
+        done;                                                           \
         touch $@
 
 quiet_cmd_remove = REMOVE  $(unwanted)
index 1c702ca8aac81d853ac19c204d126c30dff639cb..93b2b5938a2e9e714590ca9728ec53a39763db06 100644 (file)
@@ -197,7 +197,7 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
 # ---------------------------------------------------------------------------
 
 quiet_cmd_gzip = GZIP    $@
-cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \
+cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \
        (rm -f $@ ; false)
 
 # DTC
index bf8b199ec598d591946f6cf070e3ccfd01ee5a52..a776371a350243330b14dc87b636146ba4ef2b16 100644 (file)
@@ -1,3 +1 @@
-hash
 fixdep
-docproc
index 4c324a1f1e0efb8668b4d64e05b56e8e0f64f25b..4fcef87bb8759894435a395224c7d92cd7a14214 100644 (file)
@@ -7,9 +7,8 @@
 # .config is included by main Makefile.
 # ---------------------------------------------------------------------------
 # fixdep:       Used to generate dependency information during build process
-# docproc:      Used in Documentation/DocBook
 
-hostprogs-y    := fixdep docproc
+hostprogs-y    := fixdep
 always         := $(hostprogs-y)
 
 # fixdep is needed to compile other host programs
similarity index 100%
rename from scripts/basic/docproc.c
rename to scripts/docproc.c
index e12b1a7525cf0b040c10252670cd98ae89566b42..b482f162a18af48e6e83f6097581a317d64b194f 100644 (file)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 # Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
 # Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
 #
@@ -105,9 +105,9 @@ list_parse() {
 # for links, devices etc the format differs. See gen_init_cpio for details
 parse() {
        local location="$1"
-       local name="${location/${srcdir}//}"
+       local name="/${location#${srcdir}}"
        # change '//' into '/'
-       name="${name//\/\///}"
+       name=$(echo "$name" | sed -e 's://*:/:g')
        local mode="$2"
        local uid="$3"
        local gid="$4"
@@ -117,8 +117,8 @@ parse() {
        [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
        local str="${mode} ${uid} ${gid}"
 
-       [ "${ftype}" == "invalid" ] && return 0
-       [ "${location}" == "${srcdir}" ] && return 0
+       [ "${ftype}" = "invalid" ] && return 0
+       [ "${location}" = "${srcdir}" ] && return 0
 
        case "${ftype}" in
                "file")
@@ -192,7 +192,7 @@ input_file() {
        if [ -f "$1" ]; then
                ${dep_list}header "$1"
                is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\?/cpio/')"
-               if [ $2 -eq 0 -a ${is_cpio} == "cpio" ]; then
+               if [ $2 -eq 0 -a ${is_cpio} = "cpio" ]; then
                        cpio_file=$1
                        echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
                        [ ! -z ${dep_list} ] && echo "$1"
@@ -204,7 +204,7 @@ input_file() {
                else
                        echo "$1 \\"
                        cat "$1" | while read type dir file perm ; do
-                               if [ "$type" == "file" ]; then
+                               if [ "$type" = "file" ]; then
                                        echo "$file \\";
                                fi
                        done
@@ -226,7 +226,7 @@ cpio_list=
 output="/dev/stdout"
 output_file=""
 is_cpio_compressed=
-compr="gzip -9 -f"
+compr="gzip -n -9 -f"
 
 arg="$1"
 case "$arg" in
@@ -240,7 +240,7 @@ case "$arg" in
                output_file="$1"
                cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)"
                output=${cpio_list}
-               echo "$output_file" | grep -q "\.gz$" && compr="gzip -9 -f"
+               echo "$output_file" | grep -q "\.gz$" && compr="gzip -n -9 -f"
                echo "$output_file" | grep -q "\.bz2$" && compr="bzip2 -9 -f"
                echo "$output_file" | grep -q "\.lzma$" && compr="lzma -9 -f"
                echo "$output_file" | grep -q "\.xz$" && \
@@ -287,8 +287,15 @@ done
 # we are careful to delete tmp files
 if [ ! -z ${output_file} ]; then
        if [ -z ${cpio_file} ]; then
+               timestamp=
+               if test -n "$KBUILD_BUILD_TIMESTAMP"; then
+                       timestamp="$(date -d"$KBUILD_BUILD_TIMESTAMP" +%s || :)"
+                       if test -n "$timestamp"; then
+                               timestamp="-t $timestamp"
+                       fi
+               fi
                cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)"
-               usr/gen_init_cpio ${cpio_list} > ${cpio_tfile}
+               usr/gen_init_cpio $timestamp ${cpio_list} > ${cpio_tfile}
        else
                cpio_tfile=${cpio_file}
        fi
index 60dd3eb9366e4c5404383285df6cee3886bfa699..487ac6f37ca23ce2d1e832fa177d74d4544386bf 100644 (file)
@@ -500,6 +500,8 @@ static void optimize_result(void)
 
                        /* find the token with the breates profit value */
                        best = find_best_token();
+                       if (token_profit[best] == 0)
+                               break;
 
                        /* place it in the "best" table */
                        best_table_len[i] = 2;
index 50ad317a4bf9b41bc62d074ee8bd19a9864ffda6..f221ddf69080402a60ad612a4ce63f05be671a6e 100755 (executable)
@@ -42,6 +42,16 @@ if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
 else
        TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
 fi
+if test -z "$KBUILD_BUILD_USER"; then
+       LINUX_COMPILE_BY=$(whoami | sed 's/\\/\\\\/')
+else
+       LINUX_COMPILE_BY=$KBUILD_BUILD_USER
+fi
+if test -z "$KBUILD_BUILD_HOST"; then
+       LINUX_COMPILE_HOST=`hostname`
+else
+       LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST
+fi
 
 UTS_VERSION="#$VERSION"
 CONFIG_FLAGS=""
@@ -63,20 +73,8 @@ UTS_TRUNCATE="cut -b -$UTS_LEN"
 
   echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
 
-  echo \#define LINUX_COMPILE_TIME \"`date +%T`\"
-  echo \#define LINUX_COMPILE_BY \"`whoami`\"
-  echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
-
-  domain=`dnsdomainname 2> /dev/null`
-  if [ -z "$domain" ]; then
-    domain=`domainname 2> /dev/null`
-  fi
-
-  if [ -n "$domain" ]; then
-    echo \#define LINUX_COMPILE_DOMAIN \"`echo $domain | $UTS_TRUNCATE`\"
-  else
-    echo \#define LINUX_COMPILE_DOMAIN
-  fi
+  echo \#define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\"
+  echo \#define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\"
 
   echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
 ) > .tmpcompile
@@ -91,8 +89,8 @@ UTS_TRUNCATE="cut -b -$UTS_LEN"
 # first line.
 
 if [ -r $TARGET ] && \
-      grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' $TARGET > .tmpver.1 && \
-      grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' .tmpcompile > .tmpver.2 && \
+      grep -v 'UTS_VERSION' $TARGET > .tmpver.1 && \
+      grep -v 'UTS_VERSION' .tmpcompile > .tmpver.2 && \
       cmp -s .tmpver.1 .tmpver.2; then
    rm -f .tmpcompile
 else
index 95accd442d55eeb5c81f6bcd39b63fc12e5a6f25..e0f08b52e4ab440933c9f72120092b8bcd527b46 100644 (file)
@@ -167,6 +167,7 @@ config INTEL_TXT
 config LSM_MMAP_MIN_ADDR
        int "Low address space for LSM to protect from user allocation"
        depends on SECURITY && SECURITY_SELINUX
+       default 32768 if ARM
        default 65536
        help
          This is the portion of low virtual memory which should be protected
index f20e984ccfb459c141222f51791f4b5a3fcab6a9..a93b3b73307991c69738bc0dab712e56330ba932 100644 (file)
@@ -529,15 +529,10 @@ skip:
        new->suid = new->fsuid = new->euid;
        new->sgid = new->fsgid = new->egid;
 
-       /* For init, we want to retain the capabilities set in the initial
-        * task.  Thus we skip the usual capability rules
-        */
-       if (!is_global_init(current)) {
-               if (effective)
-                       new->cap_effective = new->cap_permitted;
-               else
-                       cap_clear(new->cap_effective);
-       }
+       if (effective)
+               new->cap_effective = new->cap_permitted;
+       else
+               cap_clear(new->cap_effective);
        bprm->cap_effective = effective;
 
        /*
index 07a025f8190233faf66a384816dea03754ee770a..f375152a2500b1d747d7128517430d2401f3a4ce 100644 (file)
@@ -109,11 +109,13 @@ extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                                    const struct cred *cred,
                                    struct key_type *type,
                                    const void *description,
-                                   key_match_func_t match);
+                                   key_match_func_t match,
+                                   bool no_state_check);
 
 extern key_ref_t search_my_process_keyrings(struct key_type *type,
                                            const void *description,
                                            key_match_func_t match,
+                                           bool no_state_check,
                                            const struct cred *cred);
 extern key_ref_t search_process_keyrings(struct key_type *type,
                                         const void *description,
index 427fddcaeb19b78049b3e1028349cb6b731ed8f9..eca51918c951d3a28db16bf0f61c749722b6ac64 100644 (file)
@@ -206,8 +206,14 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
                goto error5;
        }
 
+       /* wait for the key to finish being constructed */
+       ret = wait_for_key_construction(key, 1);
+       if (ret < 0)
+               goto error6;
+
        ret = key->serial;
 
+error6:
        key_put(key);
 error5:
        key_type_put(ktype);
index cdd2f3f88c8879280a7607c1be655d5487d652c4..a06ffab38568809f5187970261888d6a9e673f18 100644 (file)
@@ -176,13 +176,15 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
        else
                seq_puts(m, "[anon]");
 
-       rcu_read_lock();
-       klist = rcu_dereference(keyring->payload.subscriptions);
-       if (klist)
-               seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
-       else
-               seq_puts(m, ": empty");
-       rcu_read_unlock();
+       if (key_is_instantiated(keyring)) {
+               rcu_read_lock();
+               klist = rcu_dereference(keyring->payload.subscriptions);
+               if (klist)
+                       seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
+               else
+                       seq_puts(m, ": empty");
+               rcu_read_unlock();
+       }
 }
 
 /*
@@ -271,6 +273,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
  * @type: The type of key to search for.
  * @description: Parameter for @match.
  * @match: Function to rule on whether or not a key is the one required.
+ * @no_state_check: Don't check if a matching key is bad
  *
  * Search the supplied keyring tree for a key that matches the criteria given.
  * The root keyring and any linked keyrings must grant Search permission to the
@@ -303,7 +306,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
                             const struct cred *cred,
                             struct key_type *type,
                             const void *description,
-                            key_match_func_t match)
+                            key_match_func_t match,
+                            bool no_state_check)
 {
        struct {
                struct keyring_list *keylist;
@@ -345,6 +349,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
        kflags = keyring->flags;
        if (keyring->type == type && match(keyring, description)) {
                key = keyring;
+               if (no_state_check)
+                       goto found;
 
                /* check it isn't negative and hasn't expired or been
                 * revoked */
@@ -384,11 +390,13 @@ descend:
                        continue;
 
                /* skip revoked keys and expired keys */
-               if (kflags & (1 << KEY_FLAG_REVOKED))
-                       continue;
+               if (!no_state_check) {
+                       if (kflags & (1 << KEY_FLAG_REVOKED))
+                               continue;
 
-               if (key->expiry && now.tv_sec >= key->expiry)
-                       continue;
+                       if (key->expiry && now.tv_sec >= key->expiry)
+                               continue;
+               }
 
                /* keys that don't match */
                if (!match(key, description))
@@ -399,6 +407,9 @@ descend:
                                        cred, KEY_SEARCH) < 0)
                        continue;
 
+               if (no_state_check)
+                       goto found;
+
                /* we set a different error code if we pass a negative key */
                if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
                        err = key->type_data.reject_error;
@@ -478,7 +489,7 @@ key_ref_t keyring_search(key_ref_t keyring,
                return ERR_PTR(-ENOKEY);
 
        return keyring_search_aux(keyring, current->cred,
-                                 type, description, type->match);
+                                 type, description, type->match, false);
 }
 EXPORT_SYMBOL(keyring_search);
 
index 525cf8a29cdde86c5c58557fd73ceb49e9c73dec..49bbc97943ad8b804e22ff69150083a0f891ffd5 100644 (file)
@@ -199,7 +199,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
        if (key->perm & KEY_POS_VIEW) {
                skey_ref = search_my_process_keyrings(key->type, key,
                                                      lookup_user_key_possessed,
-                                                     cred);
+                                                     true, cred);
                if (!IS_ERR(skey_ref)) {
                        key_ref_put(skey_ref);
                        key_ref = make_key_ref(key, 1);
index 930634e4514973ac0f79acc7037138acb576a2c3..6c0480db8885b6393b8f4bfea75b8d35ce3015d3 100644 (file)
@@ -331,6 +331,7 @@ void key_fsgid_changed(struct task_struct *tsk)
 key_ref_t search_my_process_keyrings(struct key_type *type,
                                     const void *description,
                                     key_match_func_t match,
+                                    bool no_state_check,
                                     const struct cred *cred)
 {
        key_ref_t key_ref, ret, err;
@@ -350,7 +351,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
        if (cred->thread_keyring) {
                key_ref = keyring_search_aux(
                        make_key_ref(cred->thread_keyring, 1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -371,7 +372,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
        if (cred->tgcred->process_keyring) {
                key_ref = keyring_search_aux(
                        make_key_ref(cred->tgcred->process_keyring, 1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -395,7 +396,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
                        make_key_ref(rcu_dereference(
                                             cred->tgcred->session_keyring),
                                     1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                rcu_read_unlock();
 
                if (!IS_ERR(key_ref))
@@ -417,7 +418,7 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
        else if (cred->user->session_keyring) {
                key_ref = keyring_search_aux(
                        make_key_ref(cred->user->session_keyring, 1),
-                       cred, type, description, match);
+                       cred, type, description, match, no_state_check);
                if (!IS_ERR(key_ref))
                        goto found;
 
@@ -459,7 +460,8 @@ key_ref_t search_process_keyrings(struct key_type *type,
 
        might_sleep();
 
-       key_ref = search_my_process_keyrings(type, description, match, cred);
+       key_ref = search_my_process_keyrings(type, description, match,
+                                            false, cred);
        if (!IS_ERR(key_ref))
                goto found;
        err = key_ref;
index df3c0417ee4062ffebac5cb6f3ad30d84fc66a6b..b18a71745901811120e51e6b33624b9e77a98891 100644 (file)
@@ -530,8 +530,7 @@ struct key *request_key_and_link(struct key_type *type,
               dest_keyring, flags);
 
        /* search all the process keyrings for a key */
-       key_ref = search_process_keyrings(type, description, type->match,
-                                         cred);
+       key_ref = search_process_keyrings(type, description, type->match, cred);
 
        if (!IS_ERR(key_ref)) {
                key = key_ref_to_ptr(key_ref);
index 68164031a74e0bc225844037ceedd45a40fc94cb..f6337c9082ebf6eae8cc0292c6042e5a6350f70f 100644 (file)
@@ -59,7 +59,8 @@ static void request_key_auth_describe(const struct key *key,
 
        seq_puts(m, "key:");
        seq_puts(m, key->description);
-       seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
+       if (key_is_instantiated(key))
+               seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
 }
 
 /*
index f66baf44f32d16344756635321fffb98b34f0034..5b366d7af3c4dc17b595c67af3dbe99d5fd69df1 100644 (file)
@@ -157,8 +157,8 @@ EXPORT_SYMBOL_GPL(user_destroy);
 void user_describe(const struct key *key, struct seq_file *m)
 {
        seq_puts(m, key->description);
-
-       seq_printf(m, ": %u", key->datalen);
+       if (key_is_instantiated(key))
+               seq_printf(m, ": %u", key->datalen);
 }
 
 EXPORT_SYMBOL_GPL(user_describe);
index 908aa712816ac25bcb73fe22e6e704bd669d7566..893af8a2fa1e994c518b7649ddc9d29b61c8681a 100644 (file)
@@ -210,7 +210,6 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
 static void dump_common_audit_data(struct audit_buffer *ab,
                                   struct common_audit_data *a)
 {
-       struct inode *inode = NULL;
        struct task_struct *tsk = current;
 
        if (a->tsk)
@@ -229,33 +228,47 @@ static void dump_common_audit_data(struct audit_buffer *ab,
        case LSM_AUDIT_DATA_CAP:
                audit_log_format(ab, " capability=%d ", a->u.cap);
                break;
-       case LSM_AUDIT_DATA_FS:
-               if (a->u.fs.path.dentry) {
-                       struct dentry *dentry = a->u.fs.path.dentry;
-                       if (a->u.fs.path.mnt) {
-                               audit_log_d_path(ab, "path=", &a->u.fs.path);
-                       } else {
-                               audit_log_format(ab, " name=");
-                               audit_log_untrustedstring(ab,
-                                                dentry->d_name.name);
-                       }
-                       inode = dentry->d_inode;
-               } else if (a->u.fs.inode) {
-                       struct dentry *dentry;
-                       inode = a->u.fs.inode;
-                       dentry = d_find_alias(inode);
-                       if (dentry) {
-                               audit_log_format(ab, " name=");
-                               audit_log_untrustedstring(ab,
-                                                dentry->d_name.name);
-                               dput(dentry);
-                       }
-               }
+       case LSM_AUDIT_DATA_PATH: {
+               struct inode *inode;
+
+               audit_log_d_path(ab, "path=", &a->u.path);
+
+               inode = a->u.path.dentry->d_inode;
                if (inode)
                        audit_log_format(ab, " dev=%s ino=%lu",
                                        inode->i_sb->s_id,
                                        inode->i_ino);
                break;
+       }
+       case LSM_AUDIT_DATA_DENTRY: {
+               struct inode *inode;
+
+               audit_log_format(ab, " name=");
+               audit_log_untrustedstring(ab, a->u.dentry->d_name.name);
+
+               inode = a->u.dentry->d_inode;
+               if (inode)
+                       audit_log_format(ab, " dev=%s ino=%lu",
+                                       inode->i_sb->s_id,
+                                       inode->i_ino);
+               break;
+       }
+       case LSM_AUDIT_DATA_INODE: {
+               struct dentry *dentry;
+               struct inode *inode;
+
+               inode = a->u.inode;
+               dentry = d_find_alias(inode);
+               if (dentry) {
+                       audit_log_format(ab, " name=");
+                       audit_log_untrustedstring(ab,
+                                        dentry->d_name.name);
+                       dput(dentry);
+               }
+               audit_log_format(ab, " dev=%s ino=%lu", inode->i_sb->s_id,
+                                inode->i_ino);
+               break;
+       }
        case LSM_AUDIT_DATA_TASK:
                tsk = a->u.tsk;
                if (tsk && tsk->pid) {
index 3d2715fd35ea4c8dc11b580a7ee1fb946b9c4257..fcb89cb0f2235b5801004eba9ada05738d858f58 100644 (file)
@@ -526,7 +526,7 @@ int avc_audit(u32 ssid, u32 tsid,
         * during retry. However this is logically just as if the operation
         * happened a little later.
         */
-       if ((a->type == LSM_AUDIT_DATA_FS) &&
+       if ((a->type == LSM_AUDIT_DATA_INODE) &&
            (flags & IPERM_FLAG_RCU))
                return -ECHILD;
 
index 8fb248843009de5e6b71a01cae7b884cd597ba36..a0d38459d650af32fe844ca18d4b5ff5ad03be98 100644 (file)
@@ -990,6 +990,7 @@ static void selinux_write_opts(struct seq_file *m,
                        continue;
                default:
                        BUG();
+                       return;
                };
                /* we need a comma before each option */
                seq_putc(m, ',');
@@ -1443,6 +1444,7 @@ static int task_has_capability(struct task_struct *tsk,
                printk(KERN_ERR
                       "SELinux:  out of range capability %d\n", cap);
                BUG();
+               return -EINVAL;
        }
 
        rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
@@ -1487,8 +1489,8 @@ static int inode_has_perm(const struct cred *cred,
 
        if (!adp) {
                adp = &ad;
-               COMMON_AUDIT_DATA_INIT(&ad, FS);
-               ad.u.fs.inode = inode;
+               COMMON_AUDIT_DATA_INIT(&ad, INODE);
+               ad.u.inode = inode;
        }
 
        return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
@@ -1498,16 +1500,29 @@ static int inode_has_perm(const struct cred *cred,
    the dentry to help the auditing code to more easily generate the
    pathname if needed. */
 static inline int dentry_has_perm(const struct cred *cred,
-                                 struct vfsmount *mnt,
                                  struct dentry *dentry,
                                  u32 av)
 {
        struct inode *inode = dentry->d_inode;
        struct common_audit_data ad;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.mnt = mnt;
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
+       return inode_has_perm(cred, inode, av, &ad, 0);
+}
+
+/* Same as inode_has_perm, but pass explicit audit data containing
+   the path to help the auditing code to more easily generate the
+   pathname if needed. */
+static inline int path_has_perm(const struct cred *cred,
+                               struct path *path,
+                               u32 av)
+{
+       struct inode *inode = path->dentry->d_inode;
+       struct common_audit_data ad;
+
+       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.u.path = *path;
        return inode_has_perm(cred, inode, av, &ad, 0);
 }
 
@@ -1529,8 +1544,8 @@ static int file_has_perm(const struct cred *cred,
        u32 sid = cred_sid(cred);
        int rc;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path = file->f_path;
+       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.u.path = file->f_path;
 
        if (sid != fsec->sid) {
                rc = avc_has_perm(sid, fsec->sid,
@@ -1568,8 +1583,8 @@ static int may_create(struct inode *dir,
        sid = tsec->sid;
        newsid = tsec->create_sid;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
 
        rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
                          DIR__ADD_NAME | DIR__SEARCH,
@@ -1621,8 +1636,8 @@ static int may_link(struct inode *dir,
        dsec = dir->i_security;
        isec = dentry->d_inode->i_security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
 
        av = DIR__SEARCH;
        av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
@@ -1667,9 +1682,9 @@ static inline int may_rename(struct inode *old_dir,
        old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
        new_dsec = new_dir->i_security;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
 
-       ad.u.fs.path.dentry = old_dentry;
+       ad.u.dentry = old_dentry;
        rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
                          DIR__REMOVE_NAME | DIR__SEARCH, &ad);
        if (rc)
@@ -1685,7 +1700,7 @@ static inline int may_rename(struct inode *old_dir,
                        return rc;
        }
 
-       ad.u.fs.path.dentry = new_dentry;
+       ad.u.dentry = new_dentry;
        av = DIR__ADD_NAME | DIR__SEARCH;
        if (new_dentry->d_inode)
                av |= DIR__REMOVE_NAME;
@@ -1895,7 +1910,7 @@ static int selinux_quota_on(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
+       return dentry_has_perm(cred, dentry, FILE__QUOTAON);
 }
 
 static int selinux_syslog(int type)
@@ -1992,8 +2007,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
                        return rc;
        }
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path = bprm->file->f_path;
+       COMMON_AUDIT_DATA_INIT(&ad, PATH);
+       ad.u.path = bprm->file->f_path;
 
        if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
                new_tsec->sid = old_tsec->sid;
@@ -2121,7 +2136,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
 
        /* Revalidate access to inherited open files. */
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
+       COMMON_AUDIT_DATA_INIT(&ad, INODE);
 
        spin_lock(&files->file_lock);
        for (;;) {
@@ -2469,8 +2484,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
        if (flags & MS_KERNMOUNT)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = sb->s_root;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = sb->s_root;
        return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
 }
 
@@ -2479,8 +2494,8 @@ static int selinux_sb_statfs(struct dentry *dentry)
        const struct cred *cred = current_cred();
        struct common_audit_data ad;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry->d_sb->s_root;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry->d_sb->s_root;
        return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
 }
 
@@ -2496,8 +2511,7 @@ static int selinux_mount(char *dev_name,
                return superblock_has_perm(cred, path->mnt->mnt_sb,
                                           FILESYSTEM__REMOUNT, NULL);
        else
-               return dentry_has_perm(cred, path->mnt, path->dentry,
-                                      FILE__MOUNTON);
+               return path_has_perm(cred, path, FILE__MOUNTON);
 }
 
 static int selinux_umount(struct vfsmount *mnt, int flags)
@@ -2630,14 +2644,14 @@ static int selinux_inode_readlink(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__READ);
+       return dentry_has_perm(cred, dentry, FILE__READ);
 }
 
 static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__READ);
+       return dentry_has_perm(cred, dentry, FILE__READ);
 }
 
 static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags)
@@ -2654,8 +2668,8 @@ static int selinux_inode_permission(struct inode *inode, int mask, unsigned flag
        if (!mask)
                return 0;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.inode = inode;
+       COMMON_AUDIT_DATA_INIT(&ad, INODE);
+       ad.u.inode = inode;
 
        if (from_access)
                ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
@@ -2680,16 +2694,20 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 
        if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
                        ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
-               return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
+               return dentry_has_perm(cred, dentry, FILE__SETATTR);
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
+       return dentry_has_perm(cred, dentry, FILE__WRITE);
 }
 
 static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
+       struct path path;
+
+       path.dentry = dentry;
+       path.mnt = mnt;
 
-       return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
+       return path_has_perm(cred, &path, FILE__GETATTR);
 }
 
 static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
@@ -2710,7 +2728,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
 
        /* Not an attribute we recognize, so just check the
           ordinary setattr permission. */
-       return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
+       return dentry_has_perm(cred, dentry, FILE__SETATTR);
 }
 
 static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
@@ -2733,8 +2751,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (!inode_owner_or_capable(inode))
                return -EPERM;
 
-       COMMON_AUDIT_DATA_INIT(&ad, FS);
-       ad.u.fs.path.dentry = dentry;
+       COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+       ad.u.dentry = dentry;
 
        rc = avc_has_perm(sid, isec->sid, isec->sclass,
                          FILE__RELABELFROM, &ad);
@@ -2797,14 +2815,14 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
+       return dentry_has_perm(cred, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_listxattr(struct dentry *dentry)
 {
        const struct cred *cred = current_cred();
 
-       return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
+       return dentry_has_perm(cred, dentry, FILE__GETATTR);
 }
 
 static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
index 348eb00cb6685fadfef59c5864157f909b092274..3ba4feba048a0158230620b83ca91d29c2e8ff26 100644 (file)
 #define POLICYDB_VERSION_PERMISSIVE    23
 #define POLICYDB_VERSION_BOUNDARY      24
 #define POLICYDB_VERSION_FILENAME_TRANS        25
+#define POLICYDB_VERSION_ROLETRANS     26
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN   POLICYDB_VERSION_BASE
 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
 #define POLICYDB_VERSION_MAX   CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
 #else
-#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_FILENAME_TRANS
+#define POLICYDB_VERSION_MAX   POLICYDB_VERSION_ROLETRANS
 #endif
 
 /* Mask for just the mount related flags */
@@ -85,7 +86,7 @@ extern int selinux_policycap_openperm;
 int security_mls_enabled(void);
 
 int security_load_policy(void *data, size_t len);
-int security_read_policy(void **data, ssize_t *len);
+int security_read_policy(void **data, size_t *len);
 size_t security_policydb_len(void);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -111,8 +112,8 @@ void security_compute_av_user(u32 ssid, u32 tsid,
 int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
                            const struct qstr *qstr, u32 *out_sid);
 
-int security_transition_sid_user(u32 ssid, u32 tsid,
-                                u16 tclass, u32 *out_sid);
+int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
+                                const char *objname, u32 *out_sid);
 
 int security_member_sid(u32 ssid, u32 tsid,
        u16 tclass, u32 *out_sid);
index 65ebfe954f85395f490ce74d694d73a859b523ac..3618251d0fdb4435dfb96be2c845c0727deca04d 100644 (file)
@@ -141,6 +141,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
                break;
        default:
                BUG();
+               return NULL;
        }
 
        list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)
index 2d3373b2e256b5a8a61e69ddf8f03597eee2baff..77d44138864fd5862a180c5907a81c2a52f1b6ab 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/percpu.h>
 #include <linux/audit.h>
 #include <linux/uaccess.h>
+#include <linux/kobject.h>
 
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
@@ -753,11 +754,13 @@ out:
 static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 {
        char *scon = NULL, *tcon = NULL;
+       char *namebuf = NULL, *objname = NULL;
        u32 ssid, tsid, newsid;
        u16 tclass;
        ssize_t length;
        char *newcon = NULL;
        u32 len;
+       int nargs;
 
        length = task_has_security(current, SECURITY__COMPUTE_CREATE);
        if (length)
@@ -773,9 +776,17 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
        if (!tcon)
                goto out;
 
+       length = -ENOMEM;
+       namebuf = kzalloc(size + 1, GFP_KERNEL);
+       if (!namebuf)
+               goto out;
+
        length = -EINVAL;
-       if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
+       nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
+       if (nargs < 3 || nargs > 4)
                goto out;
+       if (nargs == 4)
+               objname = namebuf;
 
        length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
        if (length)
@@ -785,7 +796,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
        if (length)
                goto out;
 
-       length = security_transition_sid_user(ssid, tsid, tclass, &newsid);
+       length = security_transition_sid_user(ssid, tsid, tclass,
+                                             objname, &newsid);
        if (length)
                goto out;
 
@@ -804,6 +816,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
        length = len;
 out:
        kfree(newcon);
+       kfree(namebuf);
        kfree(tcon);
        kfree(scon);
        return length;
@@ -1901,6 +1914,7 @@ static struct file_system_type sel_fs_type = {
 };
 
 struct vfsmount *selinuxfs_mount;
+static struct kobject *selinuxfs_kobj;
 
 static int __init init_sel_fs(void)
 {
@@ -1908,9 +1922,16 @@ static int __init init_sel_fs(void)
 
        if (!selinux_enabled)
                return 0;
+
+       selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj);
+       if (!selinuxfs_kobj)
+               return -ENOMEM;
+
        err = register_filesystem(&sel_fs_type);
-       if (err)
+       if (err) {
+               kobject_put(selinuxfs_kobj);
                return err;
+       }
 
        selinuxfs_mount = kern_mount(&sel_fs_type);
        if (IS_ERR(selinuxfs_mount)) {
@@ -1927,6 +1948,7 @@ __initcall(init_sel_fs);
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 void exit_sel_fs(void)
 {
+       kobject_put(selinuxfs_kobj);
        unregister_filesystem(&sel_fs_type);
 }
 #endif
index 7102457661d645cd499d770819ad92e3970f6831..102e9ec1b77a327477592b05a8e60933d348d7c1 100644 (file)
@@ -128,6 +128,11 @@ static struct policydb_compat_info policydb_compat[] = {
                .sym_num        = SYM_NUM,
                .ocon_num       = OCON_NUM,
        },
+       {
+               .version        = POLICYDB_VERSION_ROLETRANS,
+               .sym_num        = SYM_NUM,
+               .ocon_num       = OCON_NUM,
+       },
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -179,6 +184,43 @@ out:
        return rc;
 }
 
+static u32 filenametr_hash(struct hashtab *h, const void *k)
+{
+       const struct filename_trans *ft = k;
+       unsigned long hash;
+       unsigned int byte_num;
+       unsigned char focus;
+
+       hash = ft->stype ^ ft->ttype ^ ft->tclass;
+
+       byte_num = 0;
+       while ((focus = ft->name[byte_num++]))
+               hash = partial_name_hash(focus, hash);
+       return hash & (h->size - 1);
+}
+
+static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
+{
+       const struct filename_trans *ft1 = k1;
+       const struct filename_trans *ft2 = k2;
+       int v;
+
+       v = ft1->stype - ft2->stype;
+       if (v)
+               return v;
+
+       v = ft1->ttype - ft2->ttype;
+       if (v)
+               return v;
+
+       v = ft1->tclass - ft2->tclass;
+       if (v)
+               return v;
+
+       return strcmp(ft1->name, ft2->name);
+
+}
+
 static u32 rangetr_hash(struct hashtab *h, const void *k)
 {
        const struct range_trans *key = k;
@@ -231,15 +273,22 @@ static int policydb_init(struct policydb *p)
        if (rc)
                goto out;
 
+       p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
+       if (!p->filename_trans)
+               goto out;
+
        p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
        if (!p->range_tr)
                goto out;
 
+       ebitmap_init(&p->filename_trans_ttypes);
        ebitmap_init(&p->policycaps);
        ebitmap_init(&p->permissive_map);
 
        return 0;
 out:
+       hashtab_destroy(p->filename_trans);
+       hashtab_destroy(p->range_tr);
        for (i = 0; i < SYM_NUM; i++)
                hashtab_destroy(p->symtab[i].table);
        return rc;
@@ -417,32 +466,26 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
 };
 
 #ifdef DEBUG_HASHES
-static void symtab_hash_eval(struct symtab *s)
+static void hash_eval(struct hashtab *h, const char *hash_name)
 {
-       int i;
-
-       for (i = 0; i < SYM_NUM; i++) {
-               struct hashtab *h = s[i].table;
-               struct hashtab_info info;
+       struct hashtab_info info;
 
-               hashtab_stat(h, &info);
-               printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, "
-                      "longest chain length %d\n", symtab_name[i], h->nel,
-                      info.slots_used, h->size, info.max_chain_len);
-       }
+       hashtab_stat(h, &info);
+       printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, "
+              "longest chain length %d\n", hash_name, h->nel,
+              info.slots_used, h->size, info.max_chain_len);
 }
 
-static void rangetr_hash_eval(struct hashtab *h)
+static void symtab_hash_eval(struct symtab *s)
 {
-       struct hashtab_info info;
+       int i;
 
-       hashtab_stat(h, &info);
-       printk(KERN_DEBUG "SELinux: rangetr:  %d entries and %d/%d buckets used, "
-              "longest chain length %d\n", h->nel,
-              info.slots_used, h->size, info.max_chain_len);
+       for (i = 0; i < SYM_NUM; i++)
+               hash_eval(s[i].table, symtab_name[i]);
 }
+
 #else
-static inline void rangetr_hash_eval(struct hashtab *h)
+static inline void hash_eval(struct hashtab *h, char *hash_name)
 {
 }
 #endif
@@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
        cat_destroy,
 };
 
+static int filenametr_destroy(void *key, void *datum, void *p)
+{
+       struct filename_trans *ft = key;
+       kfree(ft->name);
+       kfree(key);
+       kfree(datum);
+       cond_resched();
+       return 0;
+}
+
 static int range_tr_destroy(void *key, void *datum, void *p)
 {
        struct mls_range *rt = datum;
@@ -709,7 +762,6 @@ void policydb_destroy(struct policydb *p)
        int i;
        struct role_allow *ra, *lra = NULL;
        struct role_trans *tr, *ltr = NULL;
-       struct filename_trans *ft, *nft;
 
        for (i = 0; i < SYM_NUM; i++) {
                cond_resched();
@@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p)
        }
        kfree(lra);
 
+       hashtab_map(p->filename_trans, filenametr_destroy, NULL);
+       hashtab_destroy(p->filename_trans);
+
        hashtab_map(p->range_tr, range_tr_destroy, NULL);
        hashtab_destroy(p->range_tr);
 
@@ -788,14 +843,7 @@ void policydb_destroy(struct policydb *p)
                flex_array_free(p->type_attr_map_array);
        }
 
-       ft = p->filename_trans;
-       while (ft) {
-               nft = ft->next;
-               kfree(ft->name);
-               kfree(ft);
-               ft = nft;
-       }
-
+       ebitmap_destroy(&p->filename_trans_ttypes);
        ebitmap_destroy(&p->policycaps);
        ebitmap_destroy(&p->permissive_map);
 
@@ -1795,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp)
                rt = NULL;
                r = NULL;
        }
-       rangetr_hash_eval(p->range_tr);
+       hash_eval(p->range_tr, "rangetr");
        rc = 0;
 out:
        kfree(rt);
@@ -1805,9 +1853,10 @@ out:
 
 static int filename_trans_read(struct policydb *p, void *fp)
 {
-       struct filename_trans *ft, *last;
-       u32 nel, len;
+       struct filename_trans *ft;
+       struct filename_trans_datum *otype;
        char *name;
+       u32 nel, len;
        __le32 buf[4];
        int rc, i;
 
@@ -1816,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp)
 
        rc = next_entry(buf, fp, sizeof(u32));
        if (rc)
-               goto out;
+               return rc;
        nel = le32_to_cpu(buf[0]);
 
-       last = p->filename_trans;
-       while (last && last->next)
-               last = last->next;
-
        for (i = 0; i < nel; i++) {
+               ft = NULL;
+               otype = NULL;
+               name = NULL;
+
                rc = -ENOMEM;
                ft = kzalloc(sizeof(*ft), GFP_KERNEL);
                if (!ft)
                        goto out;
 
-               /* add it to the tail of the list */
-               if (!last)
-                       p->filename_trans = ft;
-               else
-                       last->next = ft;
-               last = ft;
+               rc = -ENOMEM;
+               otype = kmalloc(sizeof(*otype), GFP_KERNEL);
+               if (!otype)
+                       goto out;
 
                /* length of the path component string */
                rc = next_entry(buf, fp, sizeof(u32));
@@ -1862,10 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp)
                ft->stype = le32_to_cpu(buf[0]);
                ft->ttype = le32_to_cpu(buf[1]);
                ft->tclass = le32_to_cpu(buf[2]);
-               ft->otype = le32_to_cpu(buf[3]);
+
+               otype->otype = le32_to_cpu(buf[3]);
+
+               rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
+               if (rc)
+                       goto out;
+
+               hashtab_insert(p->filename_trans, ft, otype);
        }
-       rc = 0;
+       hash_eval(p->filename_trans, "filenametr");
+       return 0;
 out:
+       kfree(ft);
+       kfree(name);
+       kfree(otype);
+
        return rc;
 }
 
@@ -2266,6 +2325,11 @@ int policydb_read(struct policydb *p, void *fp)
                p->symtab[i].nprim = nprim;
        }
 
+       rc = -EINVAL;
+       p->process_class = string_to_security_class(p, "process");
+       if (!p->process_class)
+               goto bad;
+
        rc = avtab_read(&p->te_avtab, fp, p);
        if (rc)
                goto bad;
@@ -2298,8 +2362,17 @@ int policydb_read(struct policydb *p, void *fp)
                tr->role = le32_to_cpu(buf[0]);
                tr->type = le32_to_cpu(buf[1]);
                tr->new_role = le32_to_cpu(buf[2]);
+               if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
+                       rc = next_entry(buf, fp, sizeof(u32));
+                       if (rc)
+                               goto bad;
+                       tr->tclass = le32_to_cpu(buf[0]);
+               } else
+                       tr->tclass = p->process_class;
+
                if (!policydb_role_isvalid(p, tr->role) ||
                    !policydb_type_isvalid(p, tr->type) ||
+                   !policydb_class_isvalid(p, tr->tclass) ||
                    !policydb_role_isvalid(p, tr->new_role))
                        goto bad;
                ltr = tr;
@@ -2340,11 +2413,6 @@ int policydb_read(struct policydb *p, void *fp)
        if (rc)
                goto bad;
 
-       rc = -EINVAL;
-       p->process_class = string_to_security_class(p, "process");
-       if (!p->process_class)
-               goto bad;
-
        rc = -EINVAL;
        p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition");
        p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");
@@ -2517,8 +2585,9 @@ static int cat_write(void *vkey, void *datum, void *ptr)
        return 0;
 }
 
-static int role_trans_write(struct role_trans *r, void *fp)
+static int role_trans_write(struct policydb *p, void *fp)
 {
+       struct role_trans *r = p->role_tr;
        struct role_trans *tr;
        u32 buf[3];
        size_t nel;
@@ -2538,6 +2607,12 @@ static int role_trans_write(struct role_trans *r, void *fp)
                rc = put_entry(buf, sizeof(u32), 3, fp);
                if (rc)
                        return rc;
+               if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
+                       buf[0] = cpu_to_le32(tr->tclass);
+                       rc = put_entry(buf, sizeof(u32), 1, fp);
+                       if (rc)
+                               return rc;
+               }
        }
 
        return 0;
@@ -3045,7 +3120,7 @@ static int genfs_write(struct policydb *p, void *fp)
        return 0;
 }
 
-static int range_count(void *key, void *data, void *ptr)
+static int hashtab_cnt(void *key, void *data, void *ptr)
 {
        int *cnt = ptr;
        *cnt = *cnt + 1;
@@ -3093,7 +3168,7 @@ static int range_write(struct policydb *p, void *fp)
 
        /* count the number of entries in the hashtab */
        nel = 0;
-       rc = hashtab_map(p->range_tr, range_count, &nel);
+       rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);
        if (rc)
                return rc;
 
@@ -3110,43 +3185,60 @@ static int range_write(struct policydb *p, void *fp)
        return 0;
 }
 
-static int filename_trans_write(struct policydb *p, void *fp)
+static int filename_write_helper(void *key, void *data, void *ptr)
 {
-       struct filename_trans *ft;
-       u32 len, nel = 0;
        __le32 buf[4];
+       struct filename_trans *ft = key;
+       struct filename_trans_datum *otype = data;
+       void *fp = ptr;
        int rc;
+       u32 len;
 
-       for (ft = p->filename_trans; ft; ft = ft->next)
-               nel++;
-
-       buf[0] = cpu_to_le32(nel);
+       len = strlen(ft->name);
+       buf[0] = cpu_to_le32(len);
        rc = put_entry(buf, sizeof(u32), 1, fp);
        if (rc)
                return rc;
 
-       for (ft = p->filename_trans; ft; ft = ft->next) {
-               len = strlen(ft->name);
-               buf[0] = cpu_to_le32(len);
-               rc = put_entry(buf, sizeof(u32), 1, fp);
-               if (rc)
-                       return rc;
+       rc = put_entry(ft->name, sizeof(char), len, fp);
+       if (rc)
+               return rc;
 
-               rc = put_entry(ft->name, sizeof(char), len, fp);
-               if (rc)
-                       return rc;
+       buf[0] = ft->stype;
+       buf[1] = ft->ttype;
+       buf[2] = ft->tclass;
+       buf[3] = otype->otype;
 
-               buf[0] = ft->stype;
-               buf[1] = ft->ttype;
-               buf[2] = ft->tclass;
-               buf[3] = ft->otype;
+       rc = put_entry(buf, sizeof(u32), 4, fp);
+       if (rc)
+               return rc;
 
-               rc = put_entry(buf, sizeof(u32), 4, fp);
-               if (rc)
-                       return rc;
-       }
        return 0;
 }
+
+static int filename_trans_write(struct policydb *p, void *fp)
+{
+       u32 nel;
+       __le32 buf[1];
+       int rc;
+
+       nel = 0;
+       rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
+       if (rc)
+               return rc;
+
+       buf[0] = cpu_to_le32(nel);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
 /*
  * Write the configuration data in a policy database
  * structure to a policy database binary representation
@@ -3249,7 +3341,7 @@ int policydb_write(struct policydb *p, void *fp)
        if (rc)
                return rc;
 
-       rc = role_trans_write(p->role_tr, fp);
+       rc = role_trans_write(p, fp);
        if (rc)
                return rc;
 
index 732ea4a686821d048e7b09442b3f7f747c016732..b846c0387180942e2f50d31edc2982594f3dde2e 100644 (file)
@@ -72,17 +72,20 @@ struct role_datum {
 
 struct role_trans {
        u32 role;               /* current role */
-       u32 type;               /* program executable type */
+       u32 type;               /* program executable type, or new object type */
+       u32 tclass;             /* process class, or new object class */
        u32 new_role;           /* new role */
        struct role_trans *next;
 };
 
 struct filename_trans {
-       struct filename_trans *next;
        u32 stype;              /* current process */
        u32 ttype;              /* parent dir context */
        u16 tclass;             /* class of new object */
        const char *name;       /* last path component */
+};
+
+struct filename_trans_datum {
        u32 otype;              /* expected of new object */
 };
 
@@ -227,7 +230,10 @@ struct policydb {
        struct role_trans *role_tr;
 
        /* file transitions with the last path component */
-       struct filename_trans *filename_trans;
+       /* quickly exclude lookups when parent ttype has no rules */
+       struct ebitmap filename_trans_ttypes;
+       /* actual set of filename_trans rules */
+       struct hashtab *filename_trans;
 
        /* bools indexed by (value - 1) */
        struct cond_bool_datum **bool_val_to_struct;
index 6ef4af47dac497be5b8b2cc2ed64aeab4c3ee936..c3e4b52699f4ef6ad8734391c1ef01c53f06a597 100644 (file)
@@ -1359,26 +1359,35 @@ out:
 }
 
 static void filename_compute_type(struct policydb *p, struct context *newcontext,
-                                 u32 scon, u32 tcon, u16 tclass,
-                                 const struct qstr *qstr)
-{
-       struct filename_trans *ft;
-       for (ft = p->filename_trans; ft; ft = ft->next) {
-               if (ft->stype == scon &&
-                   ft->ttype == tcon &&
-                   ft->tclass == tclass &&
-                   !strcmp(ft->name, qstr->name)) {
-                       newcontext->type = ft->otype;
-                       return;
-               }
-       }
+                                 u32 stype, u32 ttype, u16 tclass,
+                                 const char *objname)
+{
+       struct filename_trans ft;
+       struct filename_trans_datum *otype;
+
+       /*
+        * Most filename trans rules are going to live in specific directories
+        * like /dev or /var/run.  This bitmap will quickly skip rule searches
+        * if the ttype does not contain any rules.
+        */
+       if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
+               return;
+
+       ft.stype = stype;
+       ft.ttype = ttype;
+       ft.tclass = tclass;
+       ft.name = objname;
+
+       otype = hashtab_search(p->filename_trans, &ft);
+       if (otype)
+               newcontext->type = otype->otype;
 }
 
 static int security_compute_sid(u32 ssid,
                                u32 tsid,
                                u16 orig_tclass,
                                u32 specified,
-                               const struct qstr *qstr,
+                               const char *objname,
                                u32 *out_sid,
                                bool kern)
 {
@@ -1478,23 +1487,21 @@ static int security_compute_sid(u32 ssid,
                newcontext.type = avdatum->data;
        }
 
-       /* if we have a qstr this is a file trans check so check those rules */
-       if (qstr)
+       /* if we have a objname this is a file trans check so check those rules */
+       if (objname)
                filename_compute_type(&policydb, &newcontext, scontext->type,
-                                     tcontext->type, tclass, qstr);
+                                     tcontext->type, tclass, objname);
 
        /* Check for class-specific changes. */
-       if  (tclass == policydb.process_class) {
-               if (specified & AVTAB_TRANSITION) {
-                       /* Look for a role transition rule. */
-                       for (roletr = policydb.role_tr; roletr;
-                            roletr = roletr->next) {
-                               if (roletr->role == scontext->role &&
-                                   roletr->type == tcontext->type) {
-                                       /* Use the role transition rule. */
-                                       newcontext.role = roletr->new_role;
-                                       break;
-                               }
+       if (specified & AVTAB_TRANSITION) {
+               /* Look for a role transition rule. */
+               for (roletr = policydb.role_tr; roletr; roletr = roletr->next) {
+                       if ((roletr->role == scontext->role) &&
+                           (roletr->type == tcontext->type) &&
+                           (roletr->tclass == tclass)) {
+                               /* Use the role transition rule. */
+                               newcontext.role = roletr->new_role;
+                               break;
                        }
                }
        }
@@ -1541,13 +1548,14 @@ int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
                            const struct qstr *qstr, u32 *out_sid)
 {
        return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
-                                   qstr, out_sid, true);
+                                   qstr ? qstr->name : NULL, out_sid, true);
 }
 
-int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
+int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
+                                const char *objname, u32 *out_sid)
 {
        return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
-                                   NULL, out_sid, false);
+                                   objname, out_sid, false);
 }
 
 /**
@@ -3190,7 +3198,7 @@ out:
  * @len: length of data in bytes
  *
  */
-int security_read_policy(void **data, ssize_t *len)
+int security_read_policy(void **data, size_t *len)
 {
        int rc;
        struct policy_file fp;
index b449cfdad21c2a983ccc4ab2d2c981fe889cde1b..2b6c6a516123d65fea012f83fef9b43feb1b8b6d 100644 (file)
@@ -316,22 +316,17 @@ static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
 static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a,
                                                    struct dentry *d)
 {
-       a->a.u.fs.path.dentry = d;
-}
-static inline void smk_ad_setfield_u_fs_path_mnt(struct smk_audit_info *a,
-                                                struct vfsmount *m)
-{
-       a->a.u.fs.path.mnt = m;
+       a->a.u.dentry = d;
 }
 static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a,
                                              struct inode *i)
 {
-       a->a.u.fs.inode = i;
+       a->a.u.inode = i;
 }
 static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a,
                                             struct path p)
 {
-       a->a.u.fs.path = p;
+       a->a.u.path = p;
 }
 static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a,
                                            struct sock *sk)
index 400a5d5cde6183c9bc3c6d348f58b623e2821b46..9831a39c11f6f5d7196de2a5d154e75cb4bfc7c3 100644 (file)
@@ -383,7 +383,7 @@ static int smack_sb_statfs(struct dentry *dentry)
        int rc;
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);
@@ -407,7 +407,7 @@ static int smack_sb_mount(char *dev_name, struct path *path,
        struct superblock_smack *sbp = path->mnt->mnt_sb->s_security;
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, *path);
 
        return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
@@ -425,10 +425,13 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
 {
        struct superblock_smack *sbp;
        struct smk_audit_info ad;
+       struct path path;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
-       smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_root);
-       smk_ad_setfield_u_fs_path_mnt(&ad, mnt);
+       path.dentry = mnt->mnt_root;
+       path.mnt = mnt;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
+       smk_ad_setfield_u_fs_path(&ad, path);
 
        sbp = mnt->mnt_sb->s_security;
        return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
@@ -563,7 +566,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
        struct smk_audit_info ad;
        int rc;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
 
        isp = smk_of_inode(old_dentry->d_inode);
@@ -592,7 +595,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
        struct smk_audit_info ad;
        int rc;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        /*
@@ -623,7 +626,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
        struct smk_audit_info ad;
        int rc;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        /*
@@ -663,7 +666,7 @@ static int smack_inode_rename(struct inode *old_inode,
        char *isp;
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
 
        isp = smk_of_inode(old_dentry->d_inode);
@@ -700,7 +703,7 @@ static int smack_inode_permission(struct inode *inode, int mask, unsigned flags)
        /* May be droppable after audit */
        if (flags & IPERM_FLAG_RCU)
                return -ECHILD;
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);
        smk_ad_setfield_u_fs_inode(&ad, inode);
        return smk_curacc(smk_of_inode(inode), mask, &ad);
 }
@@ -720,7 +723,7 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
         */
        if (iattr->ia_valid & ATTR_FORCE)
                return 0;
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
@@ -736,10 +739,13 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
 {
        struct smk_audit_info ad;
+       struct path path;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
-       smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
-       smk_ad_setfield_u_fs_path_mnt(&ad, mnt);
+       path.dentry = dentry;
+       path.mnt = mnt;
+
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
+       smk_ad_setfield_u_fs_path(&ad, path);
        return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
 }
 
@@ -784,7 +790,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
        } else
                rc = cap_inode_setxattr(dentry, name, value, size, flags);
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        if (rc == 0)
@@ -845,7 +851,7 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
 {
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
 
        return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
@@ -877,7 +883,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
        } else
                rc = cap_inode_removexattr(dentry, name);
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
        smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
        if (rc == 0)
                rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
@@ -1047,7 +1053,7 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,
        int rc = 0;
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
        if (_IOC_DIR(cmd) & _IOC_WRITE)
@@ -1070,8 +1076,8 @@ static int smack_file_lock(struct file *file, unsigned int cmd)
 {
        struct smk_audit_info ad;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
-       smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
+       smk_ad_setfield_u_fs_path(&ad, file->f_path);
        return smk_curacc(file->f_security, MAY_WRITE, &ad);
 }
 
@@ -1089,7 +1095,7 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,
        struct smk_audit_info ad;
        int rc;
 
-       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
+       smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
        smk_ad_setfield_u_fs_path(&ad, file->f_path);
 
        switch (cmd) {
index 7556315c197823e0baedcf15d0f0930c74345429..a0d09e56874b6a3b7bf23d48631cfede23a105c7 100644 (file)
@@ -108,10 +108,9 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head)
                        head->read_user_buf += len;
                        w += len;
                }
-               if (*w) {
-                       head->r.w[0] = w;
+               head->r.w[0] = w;
+               if (*w)
                        return false;
-               }
                /* Add '\0' for query. */
                if (head->poll) {
                        if (!head->read_user_buf_avail ||
@@ -459,8 +458,16 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
        if (profile == &tomoyo_default_profile)
                return -EINVAL;
        if (!strcmp(data, "COMMENT")) {
-               const struct tomoyo_path_info *old_comment = profile->comment;
-               profile->comment = tomoyo_get_name(cp);
+               static DEFINE_SPINLOCK(lock);
+               const struct tomoyo_path_info *new_comment
+                       = tomoyo_get_name(cp);
+               const struct tomoyo_path_info *old_comment;
+               if (!new_comment)
+                       return -ENOMEM;
+               spin_lock(&lock);
+               old_comment = profile->comment;
+               profile->comment = new_comment;
+               spin_unlock(&lock);
                tomoyo_put_name(old_comment);
                return 0;
        }
index cb09f1fce910959f62dd6d249bc495bf6fa5d432..d64e8ecb6fb3e7cbb923cbf80e8cbb993872279b 100644 (file)
@@ -1011,7 +1011,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
                break;
        case TOMOYO_TYPE_RMDIR:
        case TOMOYO_TYPE_CHROOT:
-       case TOMOYO_TYPE_UMOUNT:
                tomoyo_add_slash(&buf);
                break;
        }
index 297612669c74d244051662d8e1d4bd96d3040a11..42a7b1ba8cbf221ceeaa188c2089fa2a99e01a94 100644 (file)
@@ -75,6 +75,7 @@ void *tomoyo_commit_ok(void *data, const unsigned int size)
                memset(data, 0, size);
                return ptr;
        }
+       kfree(ptr);
        return NULL;
 }
 
index 82bf8c2390bc7c1b0d376ba22817b688447819cc..162a864dba24f51c55156d0733fcae3a88df2da6 100644 (file)
@@ -143,6 +143,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
                        goto out;
                }
                requested_dev_name = tomoyo_realpath_from_path(&path);
+               path_put(&path);
                if (!requested_dev_name) {
                        error = -ENOENT;
                        goto out;
index 9bfc1ee8222ddf6c9edadb48067e5384f0598e8c..6d5393204d951ef0bdd2d7306ff8648bdf141078 100644 (file)
@@ -390,7 +390,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname)
                if (!cp)
                        break;
                if (*domainname != '/' ||
-                   !tomoyo_correct_word2(domainname, cp - domainname - 1))
+                   !tomoyo_correct_word2(domainname, cp - domainname))
                        goto out;
                domainname = cp + 1;
        }
index 8cc4733698a0f02d7de84de2cf4aec3b8c683584..ce33be0e4e9841f5864d95b4e091cdb4cf69df43 100644 (file)
@@ -278,7 +278,7 @@ static int pdacf_resume(struct pcmcia_device *link)
 /*
  * Module entry points
  */
-static struct pcmcia_device_id snd_pdacf_ids[] = {
+static const struct pcmcia_device_id snd_pdacf_ids[] = {
        /* this is too general PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45), */
        PCMCIA_DEVICE_PROD_ID12("Core Sound","PDAudio-CF",0x396d19d2,0x71717b49),
        PCMCIA_DEVICE_NULL
index 80000d631f88366deeeaae70588dec5d3c960830..d9ef21d8fa7321fff082401301adcfc60fb102d1 100644 (file)
@@ -350,7 +350,7 @@ static void vxpocket_detach(struct pcmcia_device *link)
  * Module entry points
  */
 
-static struct pcmcia_device_id vxp_ids[] = {
+static const struct pcmcia_device_id vxp_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100),
        PCMCIA_DEVICE_NULL
 };
index 7f06884ecd41b588d829064a53ac964395b0ae1e..af0f22fb1ef71e6dc94c620873bc3241c2883430 100644 (file)
@@ -22,6 +22,7 @@
 
 static unsigned int offset;
 static unsigned int ino = 721;
+static time_t default_mtime;
 
 struct file_handler {
        const char *type;
@@ -102,7 +103,6 @@ static int cpio_mkslink(const char *name, const char *target,
                         unsigned int mode, uid_t uid, gid_t gid)
 {
        char s[256];
-       time_t mtime = time(NULL);
 
        if (name[0] == '/')
                name++;
@@ -114,7 +114,7 @@ static int cpio_mkslink(const char *name, const char *target,
                (long) uid,             /* uid */
                (long) gid,             /* gid */
                1,                      /* nlink */
-               (long) mtime,           /* mtime */
+               (long) default_mtime,   /* mtime */
                (unsigned)strlen(target)+1, /* filesize */
                3,                      /* major */
                1,                      /* minor */
@@ -152,7 +152,6 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
                       uid_t uid, gid_t gid)
 {
        char s[256];
-       time_t mtime = time(NULL);
 
        if (name[0] == '/')
                name++;
@@ -164,7 +163,7 @@ static int cpio_mkgeneric(const char *name, unsigned int mode,
                (long) uid,             /* uid */
                (long) gid,             /* gid */
                2,                      /* nlink */
-               (long) mtime,           /* mtime */
+               (long) default_mtime,   /* mtime */
                0,                      /* filesize */
                3,                      /* major */
                1,                      /* minor */
@@ -242,7 +241,6 @@ static int cpio_mknod(const char *name, unsigned int mode,
                       unsigned int maj, unsigned int min)
 {
        char s[256];
-       time_t mtime = time(NULL);
 
        if (dev_type == 'b')
                mode |= S_IFBLK;
@@ -259,7 +257,7 @@ static int cpio_mknod(const char *name, unsigned int mode,
                (long) uid,             /* uid */
                (long) gid,             /* gid */
                1,                      /* nlink */
-               (long) mtime,           /* mtime */
+               (long) default_mtime,   /* mtime */
                0,                      /* filesize */
                3,                      /* major */
                1,                      /* minor */
@@ -460,7 +458,7 @@ static int cpio_mkfile_line(const char *line)
 static void usage(const char *prog)
 {
        fprintf(stderr, "Usage:\n"
-               "\t%s <cpio_list>\n"
+               "\t%s [-t <timestamp>] <cpio_list>\n"
                "\n"
                "<cpio_list> is a file containing newline separated entries that\n"
                "describe the files to be included in the initramfs archive:\n"
@@ -491,7 +489,11 @@ static void usage(const char *prog)
                "nod /dev/console 0600 0 0 c 5 1\n"
                "dir /root 0700 0 0\n"
                "dir /sbin 0755 0 0\n"
-               "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n",
+               "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n"
+               "\n"
+               "<timestamp> is time in seconds since Epoch that will be used\n"
+               "as mtime for symlinks, special files and directories. The default\n"
+               "is to use the current time for these entries.\n",
                prog);
 }
 
@@ -529,17 +531,42 @@ int main (int argc, char *argv[])
        char *args, *type;
        int ec = 0;
        int line_nr = 0;
+       const char *filename;
+
+       default_mtime = time(NULL);
+       while (1) {
+               int opt = getopt(argc, argv, "t:h");
+               char *invalid;
 
-       if (2 != argc) {
+               if (opt == -1)
+                       break;
+               switch (opt) {
+               case 't':
+                       default_mtime = strtol(optarg, &invalid, 10);
+                       if (!*optarg || *invalid) {
+                               fprintf(stderr, "Invalid timestamp: %s\n",
+                                               optarg);
+                               usage(argv[0]);
+                               exit(1);
+                       }
+                       break;
+               case 'h':
+               case '?':
+                       usage(argv[0]);
+                       exit(opt == 'h' ? 0 : 1);
+               }
+       }
+
+       if (argc - optind != 1) {
                usage(argv[0]);
                exit(1);
        }
-
-       if (!strcmp(argv[1], "-"))
+       filename = argv[optind];
+       if (!strcmp(filename, "-"))
                cpio_list = stdin;
-       else if (! (cpio_list = fopen(argv[1], "r"))) {
+       else if (!(cpio_list = fopen(filename, "r"))) {
                fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
-                       argv[1], strerror(errno));
+                       filename, strerror(errno));
                usage(argv[0]);
                exit(1);
        }