]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Sat, 21 Jul 2007 01:10:03 +0000 (18:10 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Sat, 21 Jul 2007 01:10:03 +0000 (18:10 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc:
  sdhci: make sure to clear the error interrupt
  mmc: at91_mci: wakeup on card insertion (or removal)
  mmc: add maintainer for at91

523 files changed:
.gitignore
CREDITS
Documentation/kernel-parameters.txt
Documentation/sound/alsa/ALSA-Configuration.txt
Documentation/sound/alsa/Audiophile-Usb.txt
Documentation/sound/alsa/OSS-Emulation.txt
Documentation/time_interpolators.txt [deleted file]
MAINTAINERS
arch/arm/mm/fault.c
arch/i386/boot/compressed/relocs.c
arch/i386/kernel/vsyscall-note.S
arch/i386/xen/events.c
arch/i386/xen/setup.c
arch/i386/xen/vdso.h [new file with mode: 0644]
arch/ia64/Kconfig
arch/ia64/configs/bigsur_defconfig
arch/ia64/configs/gensparse_defconfig
arch/ia64/configs/sim_defconfig
arch/ia64/configs/sn2_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/zx1_defconfig
arch/ia64/defconfig
arch/ia64/kernel/asm-offsets.c
arch/ia64/kernel/cyclone.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/fsys.S
arch/ia64/kernel/fsyscall_gtod_data.h [new file with mode: 0644]
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/time.c
arch/ia64/sn/kernel/sn2/timer.c
arch/m68k/Kconfig
arch/m68k/apollo/config.c
arch/m68k/apollo/dn_ints.c
arch/m68k/atari/atakeyb.c
arch/m68k/bvme6000/config.c
arch/m68k/kernel/head.S
arch/m68k/kernel/setup.c
arch/m68k/kernel/sun3-head.S
arch/m68k/kernel/time.c
arch/m68k/kernel/vmlinux-std.lds
arch/m68k/kernel/vmlinux-sun3.lds
arch/m68k/mac/config.c
arch/m68k/mac/macints.c
arch/m68k/mm/init.c
arch/m68k/mm/sun3kmap.c
arch/m68k/mvme147/config.c
arch/m68k/mvme16x/config.c
arch/m68k/q40/q40ints.c
arch/m68k/sun3/sun3ints.c
arch/m68k/sun3x/prom.c
arch/m68knommu/kernel/setup.c
arch/mips/Kconfig
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/process.c
arch/powerpc/Kconfig
arch/powerpc/configs/cell_defconfig
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/of_device.c
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/time.c
arch/powerpc/oprofile/Kconfig
arch/powerpc/oprofile/Makefile
arch/powerpc/oprofile/cell/pr_util.h [new file with mode: 0644]
arch/powerpc/oprofile/cell/spu_profiler.c [new file with mode: 0644]
arch/powerpc/oprofile/cell/spu_task_sync.c [new file with mode: 0644]
arch/powerpc/oprofile/cell/vma_map.c [new file with mode: 0644]
arch/powerpc/oprofile/common.c
arch/powerpc/oprofile/op_model_7450.c
arch/powerpc/oprofile/op_model_cell.c
arch/powerpc/oprofile/op_model_fsl_booke.c
arch/powerpc/oprofile/op_model_pa6t.c
arch/powerpc/oprofile/op_model_power4.c
arch/powerpc/oprofile/op_model_rs64.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/cell/Kconfig
arch/powerpc/platforms/cell/Makefile
arch/powerpc/platforms/cell/axon_msi.c [new file with mode: 0644]
arch/powerpc/platforms/cell/cbe_cpufreq.c
arch/powerpc/platforms/cell/cbe_cpufreq.h [new file with mode: 0644]
arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c [new file with mode: 0644]
arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c [new file with mode: 0644]
arch/powerpc/platforms/cell/cbe_regs.c
arch/powerpc/platforms/cell/cbe_thermal.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/cell/spu_syscalls.c
arch/powerpc/platforms/cell/spufs/context.c
arch/powerpc/platforms/cell/spufs/coredump.c
arch/powerpc/platforms/cell/spufs/fault.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/gang.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/run.c
arch/powerpc/platforms/cell/spufs/sched.c
arch/powerpc/platforms/cell/spufs/spu_restore.c
arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
arch/powerpc/platforms/cell/spufs/spufs.h
arch/powerpc/platforms/cell/spufs/switch.c
arch/powerpc/platforms/cell/spufs/syscalls.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/axonram.c [new file with mode: 0644]
arch/powerpc/sysdev/pmi.c
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/mpc1211/pci.c
arch/sh/boards/renesas/r7780rp/setup.c
arch/sh/boards/renesas/rts7751r2d/setup.c
arch/sh/boards/se/7722/irq.c
arch/sh/boards/se/7722/setup.c
arch/sh/cchips/hd6446x/Makefile [new file with mode: 0644]
arch/sh/cchips/hd6446x/hd64461.c [moved from arch/sh/cchips/hd6446x/hd64461/setup.c with 98% similarity]
arch/sh/cchips/hd6446x/hd64461/Makefile [deleted file]
arch/sh/cchips/hd6446x/hd64461/io.c [deleted file]
arch/sh/configs/landisk_defconfig
arch/sh/configs/lboxre2_defconfig
arch/sh/configs/r7780mp_defconfig
arch/sh/configs/r7780rp_defconfig
arch/sh/configs/rts7751r2d_defconfig
arch/sh/configs/se7722_defconfig
arch/sh/configs/se7750_defconfig
arch/sh/configs/se7780_defconfig
arch/sh/drivers/dma/Kconfig
arch/sh/drivers/heartbeat.c
arch/sh/drivers/pci/Makefile
arch/sh/drivers/pci/ops-sh4.c
arch/sh/drivers/pci/pci-st40.c
arch/sh/drivers/pci/pci.c
arch/sh/drivers/push-switch.c
arch/sh/kernel/cpu/clock.c
arch/sh/kernel/cpu/irq/Makefile
arch/sh/kernel/cpu/irq/intc.c [new file with mode: 0644]
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh7709.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/clock-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpufreq.c
arch/sh/kernel/head.S
arch/sh/kernel/irq.c
arch/sh/kernel/setup.c
arch/sh/kernel/sh_bios.c
arch/sh/kernel/sh_ksyms.c
arch/sh/kernel/syscalls.S
arch/sh/kernel/vmlinux.lds.S
arch/sh/mm/Kconfig
arch/sh64/configs/cayman_defconfig
arch/sh64/kernel/head.S
arch/sh64/kernel/pci_sh5.c
arch/sh64/kernel/syscalls.S
arch/sh64/kernel/vmlinux.lds.S
arch/sh64/mm/ioremap.c
arch/sparc/Kconfig
arch/sparc/kernel/ebus.c
arch/sparc/kernel/of_device.c
arch/sparc/kernel/process.c
arch/sparc/kernel/prom.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/systbls.S
arch/sparc/kernel/time.c
arch/sparc/prom/console.c
arch/sparc/prom/misc.c
arch/sparc64/Kconfig
arch/sparc64/defconfig
arch/sparc64/kernel/auxio.c
arch/sparc64/kernel/ds.c
arch/sparc64/kernel/ebus.c
arch/sparc64/kernel/head.S
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/isa.c
arch/sparc64/kernel/mdesc.c
arch/sparc64/kernel/of_device.c
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/power.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/prom.c
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/kernel/vio.c
arch/sparc64/prom/console.c
arch/sparc64/prom/misc.c
arch/sparc64/prom/tree.c
block/cfq-iosched.c
crypto/async_tx/async_memcpy.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/processor_idle.c
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata.h
drivers/ata/pata_cs5520.c
drivers/ata/pata_platform.c
drivers/ata/pata_scc.c
drivers/ata/sata_inic162x.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_promise.c
drivers/ata/sata_qstor.c
drivers/ata/sata_sil.c
drivers/ata/sata_sil24.c
drivers/ata/sata_sis.c
drivers/ata/sata_svw.c
drivers/ata/sata_uli.c
drivers/ata/sata_via.c
drivers/ata/sata_vsc.c
drivers/block/sunvdc.c
drivers/char/Kconfig
drivers/char/hpet.c
drivers/char/rtc.c
drivers/char/serial167.c
drivers/char/tpm/tpm_bios.c
drivers/char/vme_scc.c
drivers/char/watchdog/Kconfig
drivers/ide/legacy/falconide.c
drivers/input/input.c
drivers/input/joystick/Kconfig
drivers/input/joystick/xpad.c
drivers/input/mouse/appletouch.c
drivers/input/mouse/lifebook.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/fujitsu_ts.c [new file with mode: 0644]
drivers/kvm/kvm.h
drivers/kvm/kvm_main.c
drivers/kvm/mmu.c
drivers/kvm/paging_tmpl.h
drivers/kvm/x86_emulate.c
drivers/lguest/interrupts_and_traps.c
drivers/lguest/io.c
drivers/lguest/lguest.c
drivers/lguest/lguest_asm.S
drivers/md/raid5.c
drivers/media/common/ir-functions.c
drivers/media/dvb/ttpci/av7110.c
drivers/media/radio/radio-aimslab.c
drivers/media/radio/radio-cadet.c
drivers/media/radio/radio-gemtek-pci.c
drivers/media/video/bt866.c
drivers/media/video/bt8xx/bttv-cards.c
drivers/media/video/bt8xx/bttv-input.c
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/c-qcam.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/ivtv/Kconfig
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-firmware.c
drivers/media/video/ivtv/ivtv-gpio.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-mailbox.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/saa5249.c
drivers/media/video/saa7110.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/tvaudio.c
drivers/media/video/v4l2-common.c
drivers/media/video/vino.c
drivers/media/video/wm8739.c
drivers/media/video/wm8775.c
drivers/net/mac89x0.c
drivers/net/sky2.c
drivers/net/sunvnet.c
drivers/net/sunvnet.h
drivers/of/Kconfig [new file with mode: 0644]
drivers/of/Makefile [new file with mode: 0644]
drivers/of/base.c [new file with mode: 0644]
drivers/of/device.c [new file with mode: 0644]
drivers/of/platform.c [new file with mode: 0644]
drivers/oprofile/buffer_sync.c
drivers/oprofile/event_buffer.h
drivers/oprofile/oprof.c
drivers/parport/Kconfig
drivers/rtc/Kconfig
drivers/sbus/sbus.c
drivers/scsi/Kconfig
drivers/scsi/NCR53C9x.c
drivers/scsi/iscsi_tcp.c
drivers/serial/suncore.c
drivers/serial/suncore.h
drivers/serial/sunhv.c
drivers/serial/sunsab.c
drivers/serial/sunsu.c
drivers/serial/sunzilog.c
drivers/usb/atm/cxacru.c
drivers/usb/atm/speedtch.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/atm/usbatm.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/usblp.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/amd5536udc.c [new file with mode: 0644]
drivers/usb/gadget/amd5536udc.h [new file with mode: 0644]
drivers/usb/gadget/ether.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/m66592-udc.h
drivers/usb/gadget/serial.c
drivers/usb/host/isp116x-hcd.c
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/r8a66597.h
drivers/usb/host/u132-hcd.c
drivers/usb/host/uhci-q.c
drivers/usb/image/mdc800.c
drivers/usb/image/microtek.c
drivers/usb/misc/adutux.c
drivers/usb/misc/appledisplay.c
drivers/usb/misc/auerswald.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/iowarrior.c
drivers/usb/misc/ldusb.c
drivers/usb/misc/legousbtower.c
drivers/usb/misc/phidgetkit.c
drivers/usb/misc/phidgetmotorcontrol.c
drivers/usb/misc/usblcd.c
drivers/usb/misc/usbtest.c
drivers/usb/misc/uss720.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/sierra.c
drivers/usb/storage/dpcm.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/unusual_devs.h
drivers/video/aty/atyfb_base.c
drivers/video/backlight/cr_bllcd.c
drivers/video/igafb.c
fs/afs/rxrpc.c
fs/buffer.c
fs/ecryptfs/mmap.c
fs/ocfs2/mmap.c
fs/splice.c
include/asm-ia64/hw_irq.h
include/asm-ia64/iosapic.h
include/asm-ia64/irq.h
include/asm-ia64/rwsem.h
include/asm-ia64/unistd.h
include/asm-m68k/io.h
include/asm-m68k/raw_io.h
include/asm-mips/atomic.h
include/asm-mips/barrier.h
include/asm-mips/bitops.h
include/asm-mips/ds1216.h [deleted file]
include/asm-mips/futex.h
include/asm-mips/gfx.h [deleted file]
include/asm-mips/mach-cobalt/cpu-feature-overrides.h
include/asm-mips/mach-excite/cpu-feature-overrides.h
include/asm-mips/mach-ip22/cpu-feature-overrides.h
include/asm-mips/mach-ip27/cpu-feature-overrides.h
include/asm-mips/mach-ip32/cpu-feature-overrides.h
include/asm-mips/mach-qemu/cpu-feature-overrides.h
include/asm-mips/mach-rm/cpu-feature-overrides.h
include/asm-mips/mach-sibyte/cpu-feature-overrides.h
include/asm-mips/mach-yosemite/cpu-feature-overrides.h
include/asm-mips/spinlock.h
include/asm-mips/system.h
include/asm-powerpc/of_device.h
include/asm-powerpc/of_platform.h
include/asm-powerpc/oprofile_impl.h
include/asm-powerpc/pmi.h
include/asm-powerpc/prom.h
include/asm-powerpc/spu.h
include/asm-powerpc/spu_csa.h
include/asm-sh/clock.h
include/asm-sh/hw_irq.h
include/asm-sh/se7722.h
include/asm-sh/unistd.h
include/asm-sh64/unistd.h
include/asm-sparc/device.h
include/asm-sparc/fb.h
include/asm-sparc/of_device.h
include/asm-sparc/of_platform.h [new file with mode: 0644]
include/asm-sparc/oplib.h
include/asm-sparc/prom.h
include/asm-sparc/unistd.h
include/asm-sparc64/fb.h
include/asm-sparc64/of_device.h
include/asm-sparc64/of_platform.h [new file with mode: 0644]
include/asm-sparc64/oplib.h
include/asm-sparc64/parport.h
include/asm-sparc64/power.h [deleted file]
include/asm-sparc64/prom.h
include/asm-sparc64/system.h
include/asm-sparc64/unistd.h
include/asm-sparc64/vio.h
include/linux/async_tx.h
include/linux/clocksource.h
include/linux/dcookies.h
include/linux/elf-em.h
include/linux/i2c-id.h
include/linux/input.h
include/linux/ioprio.h
include/linux/libata.h
include/linux/of.h [new file with mode: 0644]
include/linux/of_device.h [new file with mode: 0644]
include/linux/of_platform.h [new file with mode: 0644]
include/linux/oprofile.h
include/linux/serio.h
include/linux/slab.h
include/linux/slub_def.h
include/linux/spi/ads7846.h
include/linux/syscalls.h
include/linux/timex.h
include/linux/videodev2.h
include/sound/ak4xxx-adda.h
include/sound/cs46xx.h
include/sound/cs46xx_dsp_spos.h
include/sound/emu10k1.h
include/sound/sb.h
include/sound/version.h
include/sound/wavefront_fx.h [deleted file]
kernel/ksysfs.c
kernel/time.c
kernel/time/ntp.c
kernel/time/timekeeping.c
kernel/timer.c
mm/page_alloc.c
net/netfilter/nf_conntrack_helper.c
scripts/Lindent
scripts/mod/modpost.c
sound/Kconfig
sound/Makefile
sound/aoa/codecs/snd-aoa-codec-onyx.c
sound/core/pcm_native.c
sound/core/seq/seq_instr.c
sound/core/timer.c
sound/drivers/dummy.c
sound/drivers/mpu401/mpu401.c
sound/drivers/portman2x4.c
sound/drivers/serial-u16550.c
sound/drivers/virmidi.c
sound/i2c/other/ak4xxx-adda.c
sound/isa/Kconfig
sound/isa/ad1848/ad1848_lib.c
sound/isa/opl3sa2.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/isa/sb/Makefile
sound/isa/sb/sb16_main.c
sound/isa/sb/sb_common.c
sound/isa/sb/sb_mixer.c
sound/isa/sscape.c
sound/isa/wavefront/wavefront_synth.c
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/ca0106/ca0106_main.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/cs46xx_lib.h
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs5530.c [new file with mode: 0644]
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/emumixer.c
sound/pci/emu10k1/emupcm.c
sound/pci/ens1370.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_atihdmi.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_si3054.c
sound/pci/hda/patch_sigmatel.c
sound/pci/ice1712/revo.c
sound/pci/nm256/nm256.c
sound/pci/rme9652/rme9652.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/ppc/Kconfig
sound/ppc/Makefile
sound/ppc/snd_ps3.c [new file with mode: 0644]
sound/ppc/snd_ps3.h [new file with mode: 0644]
sound/ppc/snd_ps3_reg.h [new file with mode: 0644]
sound/sh/Kconfig [new file with mode: 0644]
sound/sh/Makefile [new file with mode: 0644]
sound/sh/aica.c [new file with mode: 0644]
sound/sh/aica.h [new file with mode: 0644]
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/s3c24xx/Kconfig
sound/soc/s3c24xx/Makefile
sound/soc/s3c24xx/lm4857.h [new file with mode: 0644]
sound/soc/s3c24xx/neo1973_wm8753.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c2443-ac97.c [new file with mode: 0644]
sound/soc/s3c24xx/s3c24xx-ac97.h [new file with mode: 0644]
sound/soc/s3c24xx/s3c24xx-i2s.c
sound/soc/s3c24xx/smdk2443_wm9710.c [new file with mode: 0644]
sound/soc/sh/Kconfig [new file with mode: 0644]
sound/soc/sh/Makefile [new file with mode: 0644]
sound/soc/sh/dma-sh7760.c [new file with mode: 0644]
sound/soc/sh/hac.c [new file with mode: 0644]
sound/soc/sh/sh7760-ac97.c [new file with mode: 0644]
sound/soc/sh/ssi.c [new file with mode: 0644]
sound/usb/usbaudio.c
sound/usb/usbquirks.h
sound/usb/usx2y/usbusx2yaudio.c

index 8d15830b883d8f715b06aa5f028e5013d637acb3..a232295b99ac87331f375ce17c7e9bba5ea46d58 100644 (file)
@@ -22,6 +22,7 @@
 tags
 TAGS
 vmlinux*
+!vmlinux.lds.S
 System.map
 Module.symvers
 
diff --git a/CREDITS b/CREDITS
index 79fd13dbb8e459924ac584093dc867080811ed9f..10c214dc95e764865c23834e9ff2ea4fa2bcde73 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2212,13 +2212,13 @@ S: 2300 Copenhagen S
 S: Denmark
 
 N: Claudio S. Matsuoka
-E: claudio@conectiva.com
-E: claudio@helllabs.org
+E: cmatsuoka@gmail.com
+E: claudio@mandriva.com
 W: http://helllabs.org/~claudio
-D: V4L, OV511 driver hacks
+D: V4L, OV511 and HDA-codec hacks
 S: Conectiva S.A.
-S: R. Tocantins 89
-S: 80050-430  Curitiba PR
+S: Souza Naves 1250
+S: 80050-040  Curitiba PR
 S: Brazil
 
 N: Heinz Mauelshagen
index 9a541486fb7ee91c227f036071b4bce63f695ebf..5fbe07706ae9eedae14c1582004a0fc52e4daa40 100644 (file)
@@ -1154,6 +1154,8 @@ and is between 256 and 4096 characters. It is defined in the file
 
        nointroute      [IA-64]
 
+       nojitter        [IA64] Disables jitter checking for ITC timers.
+
        nolapic         [IA-32,APIC] Do not enable or use the local APIC.
 
        nolapic_timer   [IA-32,APIC] Do not use the local APIC timer.
@@ -1885,6 +1887,9 @@ and is between 256 and 4096 characters. It is defined in the file
                        vdso=1: enable VDSO (default)
                        vdso=0: disable VDSO mapping
 
+       vector=         [IA-64,SMP]
+                       vector=percpu: enable percpu vector domain
+
        video=          [FB] Frame buffer configuration
                        See Documentation/fb/modedb.txt.
 
index 355ff0a2bb7c5a1cdc9862c4f827e9e49497c165..241e26c4ff926d266b78ecd4f2b7eae706610b5f 100644 (file)
@@ -467,7 +467,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     above explicitly.
 
     The power-management is supported.
-    
+
+  Module snd-cs5530
+  _________________
+
+    Module for Cyrix/NatSemi Geode 5530 chip. 
+  
   Module snd-cs5535audio
   ----------------------
 
@@ -759,6 +764,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 
     model      - force the model name
     position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
+    probe_mask  - Bitmask to probe codecs (default = -1, meaning all slots)
     single_cmd  - Use single immediate commands to communicate with
                codecs (for debugging only)
     enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
@@ -803,6 +809,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          hp-3013       HP machines (3013-variant)
          fujitsu       Fujitsu S7020
          acer          Acer TravelMate
+         will          Will laptops (PB V7900)
+         replacer      Replacer 672V
          basic         fixed pin assignment (old default model)
          auto          auto-config reading BIOS (default)
 
@@ -811,16 +819,31 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          hp-bpc        HP xw4400/6400/8400/9400 laptops
          hp-bpc-d7000  HP BPC D7000
          benq          Benq ED8
+         benq-t31      Benq T31
          hippo         Hippo (ATI) with jack detection, Sony UX-90s
          hippo_1       Hippo (Benq) with jack detection
+         sony-assamd   Sony ASSAMD
          basic         fixed pin assignment w/o SPDIF
          auto          auto-config reading BIOS (default)
 
+       ALC268
+         3stack        3-stack model
+         auto          auto-config reading BIOS (default)
+
+       ALC662
+         3stack-dig    3-stack (2-channel) with SPDIF
+         3stack-6ch     3-stack (6-channel)
+         3stack-6ch-dig 3-stack (6-channel) with SPDIF
+         6stack-dig     6-stack with SPDIF
+         lenovo-101e    Lenovo laptop
+         auto          auto-config reading BIOS (default)
+
        ALC882/885
          3stack-dig    3-jack with SPDIF I/O
          6stack-dig    6-jack digital with SPDIF I/O
          arima         Arima W820Di1
          macpro        MacPro support
+         imac24        iMac 24'' with jack detection
          w2jc          ASUS W2JC
          auto          auto-config reading BIOS (default)
 
@@ -832,9 +855,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          6stack-dig-demo  6-jack digital for Intel demo board
          acer          Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
          medion        Medion Laptops
+         medion-md2    Medion MD2
          targa-dig     Targa/MSI
          targa-2ch-dig Targs/MSI with 2-channel
          laptop-eapd   3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
+         lenovo-101e   Lenovo 101E
+         lenovo-nb0763 Lenovo NB0763
+         lenovo-ms7195-dig Lenovo MS7195
+         6stack-hp     HP machines with 6stack (Nettle boards)
+         3stack-hp     HP machines with 3stack (Lucknow, Samba boards)
          auto          auto-config reading BIOS (default)
 
        ALC861/660
@@ -853,7 +882,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          3stack-dig    3-jack with SPDIF OUT
          6stack-dig    6-jack with SPDIF OUT
          3stack-660    3-jack (for ALC660VD)
+         3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD)
          lenovo        Lenovo 3000 C200
+         dallas        Dallas laptops
          auto          auto-config reading BIOS (default)
 
        CMI9880
@@ -864,12 +895,26 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          allout        5-jack in back, 2-jack in front, SPDIF out
          auto          auto-config reading BIOS (default)
 
+       AD1882
+         3stack        3-stack mode (default)
+         6stack        6-stack mode
+
+       AD1884
+         N/A
+
        AD1981
          basic         3-jack (default)
          hp            HP nx6320
          thinkpad      Lenovo Thinkpad T60/X60/Z60
          toshiba       Toshiba U205
 
+       AD1983
+         N/A
+
+       AD1984
+         basic         default configuration
+         thinkpad      Lenovo Thinkpad T61/X61
+
        AD1986A
          6stack        6-jack, separate surrounds (default)
          3stack        3-stack, shared surrounds
@@ -907,11 +952,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
          ref           Reference board
          3stack        D945 3stack
          5stack        D945 5stack + SPDIF
-         macmini       Intel Mac Mini
-         macbook       Intel Mac Book
-         macbook-pro-v1 Intel Mac Book Pro 1st generation
-         macbook-pro   Intel Mac Book Pro 2nd generation
-         imac-intel    Intel iMac
+         dell          Dell XPS M1210
+         intel-mac-v1  Intel Mac Type 1
+         intel-mac-v2  Intel Mac Type 2
+         intel-mac-v3  Intel Mac Type 3
+         intel-mac-v4  Intel Mac Type 4
+         intel-mac-v5  Intel Mac Type 5
+         macmini       Intel Mac Mini (equivalent with type 3)
+         macbook       Intel Mac Book (eq. type 5)
+         macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
+         macbook-pro   Intel Mac Book Pro 2nd generation (eq. type 3)
+         imac-intel    Intel iMac (eq. type 2)
+         imac-intel-20 Intel iMac (newer version) (eq. type 3)
 
        STAC9202/9250/9251
          ref           Reference board, base config
@@ -956,6 +1008,17 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     from the irq.  Remember this is a last resort, and should be
     avoided as much as possible...
     
+    MORE NOTES ON "azx_get_response timeout" PROBLEMS:
+    On some hardwares, you may need to add a proper probe_mask option
+    to avoid the "azx_get_response timeout" problem above, instead.
+    This occurs when the access to non-existing or non-working codec slot
+    (likely a modem one) causes a stall of the communication via HD-audio
+    bus.  You can see which codec slots are probed by enabling
+    CONFIG_SND_DEBUG_DETECT, or simply from the file name of the codec
+    proc files.  Then limit the slots to probe by probe_mask option.
+    For example, probe_mask=1 means to probe only the first slot, and
+    probe_mask=4 means only the third slot.
+
     The power-management is supported.
 
   Module snd-hdsp
index e40cce83327c4488c38e4541aa5ae5a5877b3f61..2ad5e6306c445bd369bb5346bf18da6156382bca 100644 (file)
@@ -1,4 +1,4 @@
-       Guide to using M-Audio Audiophile USB with ALSA and Jack        v1.3
+       Guide to using M-Audio Audiophile USB with ALSA and Jack        v1.5
        ========================================================
 
            Thibault Le Meur <Thibault.LeMeur@supelec.fr>
@@ -6,8 +6,19 @@
 This document is a guide to using the M-Audio Audiophile USB (tm) device with 
 ALSA and JACK.
 
+History
+=======
+* v1.4 - Thibault Le Meur (2007-07-11)
+ - Added Low Endianness nature of 16bits-modes
+   found by Hakan Lennestal <Hakan.Lennestal@brfsodrahamn.se>
+ - Modifying document structure
+* v1.5 - Thibault Le Meur (2007-07-12)
+ - Added AC3/DTS passthru info
+
+
 1 - Audiophile USB Specs and correct usage
 ==========================================
+
 This part is a reminder of important facts about the functions and limitations 
 of the device.
 
@@ -25,18 +36,18 @@ The device has 4 audio interfaces, and 2 MIDI ports:
 The internal DAC/ADC has the following characteristics:
 * sample depth of 16 or 24 bits
 * sample rate from 8kHz to 96kHz
-* Two ports can't use different sample depths at the same time. Moreover, the 
-Audiophile USB documentation gives the following Warning: "Please exit any 
-audio application running before switching between bit depths"
+* Two interfaces can't use different sample depths at the same time.
+Moreover, the Audiophile USB documentation gives the following Warning:
+"Please exit any audio application running before switching between bit depths"
 
 Due to the USB 1.1 bandwidth limitation, a limited number of interfaces can be 
 activated at the same time depending on the audio mode selected:
- * 16-bit/48kHz ==> 4 channels in/4 channels out
+ * 16-bit/48kHz ==> 4 channels in + 4 channels out
    - Ai+Ao+Di+Do
- * 24-bit/48kHz ==> 4 channels in/2 channels out, 
-                    or 2 channels in/4 channels out
+ * 24-bit/48kHz ==> 4 channels in + 2 channels out, 
+                    or 2 channels in + 4 channels out
    - Ai+Ao+Do or Ai+Di+Ao or Ai+Di+Do or Di+Ao+Do
- * 24-bit/96kHz ==> 2 channels in, or 2 channels out (half duplex only)
+ * 24-bit/96kHz ==> 2 channels in _or_ 2 channels out (half duplex only)
    - Ai or Ao or Di or Do
 
 Important facts about the Digital interface:
@@ -52,44 +63,56 @@ source is connected
 synchronization error (for instance sound played at an odd sample rate)
 
 
-2 - Audiophile USB support in ALSA
-==================================
+2 - Audiophile USB MIDI support in ALSA
+=======================================
 
-2.1 - MIDI ports
-----------------
-The Audiophile USB MIDI ports will be automatically supported once the 
+The Audiophile USB MIDI ports will be automatically supported once the
 following modules have been loaded:
  * snd-usb-audio
  * snd-seq-midi
 
 No additional setting is required.
 
-2.2 - Audio ports
------------------
+
+3 - Audiophile USB Audio support in ALSA
+========================================
 
 Audio functions of the Audiophile USB device are handled by the snd-usb-audio 
 module. This module can work in a default mode (without any device-specific 
 parameter), or in an "advanced" mode with the device-specific parameter called 
 "device_setup".
 
-2.2.1 - Default Alsa driver mode
-
-The default behavior of the snd-usb-audio driver is to parse the device 
-capabilities at startup and enable all functions inside the device (including 
-all ports at any supported sample rates and sample depths). This approach 
-has the advantage to let the driver easily switch from sample rates/depths 
-automatically according to the need of the application claiming the device.
-
-In this case the Audiophile ports are mapped to alsa pcm devices in the 
-following way (I suppose the device's index is 1):
+3.1 - Default Alsa driver mode
+------------------------------
+
+The default behavior of the snd-usb-audio driver is to list the device 
+capabilities at startup and activate the required mode when required 
+by the applications: for instance if the user is recording in a 
+24bit-depth-mode and immediately after wants to switch to a 16bit-depth mode,
+the snd-usb-audio module will reconfigure the device on the fly.
+
+This approach has the advantage to let the driver automatically switch from sample 
+rates/depths automatically according to the user's needs. However, those who 
+are using the device under windows know that this is not how the device is meant to
+work: under windows applications must be closed before using the m-audio control
+panel to switch the device working mode. Thus as we'll see in next section, this 
+Default Alsa driver mode can lead to device misconfigurations.
+
+Let's get back to the Default Alsa driver mode for now.  In this case the 
+Audiophile interfaces are mapped to alsa pcm devices in the following 
+way (I suppose the device's index is 1):
  * hw:1,0 is Ao in playback and Di in capture
  * hw:1,1 is Do in playback and Ai in capture
  * hw:1,2 is Do in AC3/DTS passthrough mode
 
-You must note as well that the device uses Big Endian byte encoding so that 
-supported audio format are S16_BE  for 16-bit depth modes and S24_3BE for 
-24-bits depth mode. One exception is the hw:1,2 port which is Little Endian 
-compliant and thus uses S16_LE.
+In this mode, the device uses Big Endian byte-encoding so that 
+supported audio format are S16_BE for 16-bit depth modes and S24_3BE for 
+24-bits depth mode.
+
+One exception is the hw:1,2 port which was reported to be Little Endian 
+compliant (supposedly supporting S16_LE) but processes in fact only S16_BE streams.
+This has been fixed in kernel 2.6.23 and above and now the hw:1,2 interface 
+is reported to be big endian in this default driver mode.
 
 Examples:
  * playing a S24_3BE encoded raw file to the Ao port
@@ -98,22 +121,26 @@ Examples:
    % arecord -D hw:1,1 -c2  -t raw -r48000 -fS24_3BE test.raw
  * playing a S16_BE encoded raw file to the Do port
    % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test.raw
+ * playing an ac3 sample file to the Do port
+   % aplay -D hw:1,2 --channels=6 ac3_S16_BE_encoded_file.raw
 
-If you're happy with the default Alsa driver setup and don't experience any 
+If you're happy with the default Alsa driver mode and don't experience any 
 issue with this mode, then you can skip the following chapter.
 
-2.2.2 - Advanced module setup
+3.2 - Advanced module setup
+---------------------------
 
 Due to the hardware constraints described above, the device initialization made 
 by the Alsa driver in default mode may result in a corrupted state of the 
 device. For instance, a particularly annoying issue is that the sound captured 
-from the Ai port sounds distorted (as if boosted with an excessive high volume 
-gain).
+from the Ai interface sounds distorted (as if boosted with an excessive high
+volume gain).
 
 For people having this problem, the snd-usb-audio module has a new module 
-parameter called "device_setup".
+parameter called "device_setup" (this parameter was introduced in kernel
+release 2.6.17)
 
-2.2.2.1 - Initializing the working mode of the Audiophile USB
+3.2.1 - Initializing the working mode of the Audiophile USB
 
 As far as the Audiophile USB device is concerned, this value let the user 
 specify:
@@ -121,33 +148,57 @@ specify:
  * the sample rate
  * whether the Di port is used or not 
 
-Here is a list of supported device_setup values for this device:
- * device_setup=0x00 (or omitted)
-   - Alsa driver default mode
-   - maintains backward compatibility with setups that do not use this 
-     parameter by not introducing any change
-   - results sometimes in corrupted sound as described earlier
+When initialized with "device_setup=0x00", the snd-usb-audio module has
+the same behaviour as when the parameter is omitted (see paragraph "Default 
+Alsa driver mode" above)
+
+Others modes are described in the following subsections.
+
+3.2.1.1 - 16-bit modes
+
+The two supported modes are:
+
  * device_setup=0x01
    - 16bits 48kHz mode with Di disabled
    - Ai,Ao,Do can be used at the same time
    - hw:1,0 is not available in capture mode
    - hw:1,2 is not available
+
  * device_setup=0x11
    - 16bits 48kHz mode with Di enabled
    - Ai,Ao,Di,Do can be used at the same time
    - hw:1,0 is available in capture mode
    - hw:1,2 is not available
+
+In this modes the device operates only at 16bits-modes. Before kernel 2.6.23,
+the devices where reported to be Big-Endian when in fact they were Little-Endian
+so that playing a file was a matter of using:
+   % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test_S16_LE.raw
+where "test_S16_LE.raw" was in fact a little-endian sample file.
+
+Thanks to Hakan Lennestal (who discovered the Little-Endiannes of the device in
+these modes) a fix has been committed (expected in kernel 2.6.23) and
+Alsa now reports Little-Endian interfaces. Thus playing a file now is as simple as
+using:
+   % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_LE test_S16_LE.raw
+
+3.2.1.2 - 24-bit modes
+
+The three supported modes are:
+
  * device_setup=0x09
    - 24bits 48kHz mode with Di disabled
    - Ai,Ao,Do can be used at the same time
    - hw:1,0 is not available in capture mode
    - hw:1,2 is not available
+
  * device_setup=0x19
    - 24bits 48kHz mode with Di enabled
    - 3 ports from {Ai,Ao,Di,Do} can be used at the same time
    - hw:1,0 is available in capture mode and an active digital source must be 
      connected to Di
    - hw:1,2 is not available
+
  * device_setup=0x0D or 0x10
    - 24bits 96kHz mode
    - Di is enabled by default for this mode but does not need to be connected 
@@ -155,34 +206,64 @@ Here is a list of supported device_setup values for this device:
    - Only 1 port from {Ai,Ao,Di,Do} can be used at the same time
    - hw:1,0 is available in captured mode
    - hw:1,2 is not available
+
+In these modes the device is only Big-Endian compliant (see "Default Alsa driver 
+mode" above for an aplay command example)
+
+3.2.1.3 - AC3 w/ DTS passthru mode
+
+Thanks to Hakan Lennestal, I now have a report saying that this mode works.
+
  * device_setup=0x03
    - 16bits 48kHz mode with only the Do port enabled 
-   - AC3 with DTS passthru (not tested)
+   - AC3 with DTS passthru
    - Caution with this setup the Do port is mapped to the pcm device hw:1,0
 
-2.2.2.2 - Setting and switching configurations with the device_setup parameter
+The command line used to playback the AC3/DTS encoded .wav-files in this mode:
+   % aplay -D hw:1,0 --channels=6 ac3_S16_LE_encoded_file.raw
+
+3.2.2 - How to use the device_setup parameter
+----------------------------------------------
 
 The parameter can be given:
+
  * By manually probing the device (as root):
    # modprobe -r snd-usb-audio
    # modprobe snd-usb-audio index=1 device_setup=0x09
+
  * Or while configuring the modules options in your modules configuration file
    - For Fedora distributions, edit the /etc/modprobe.conf file:
        alias snd-card-1 snd-usb-audio
        options snd-usb-audio index=1 device_setup=0x09
 
-IMPORTANT NOTE WHEN SWITCHING CONFIGURATION:
--------------------------------------------
- * You may need to _first_ initialize the module with the correct device_setup 
-   parameter and _only_after_ turn on the Audiophile USB device
- * This is especially true when switching the sample depth:
+CAUTION when initializaing the device
+-------------------------------------
+
+ * Correct initialization on the device requires that device_setup is given to
+   the module BEFORE the device is turned on. So, if you use the "manual probing"
+   method described above, take care to power-on the device AFTER this initialization.
+
+ * Failing to respect this will lead in a misconfiguration of the device. In this case
+   turn off the device, unproble the snd-usb-audio module, then probe it again with 
+   correct device_setup parameter and then (and only then) turn on the device again.
+
+ * If you've correctly initialized the device in a valid mode and then want to switch
+   to  another mode (possibly with another sample-depth), please use also the following 
+   procedure:
    - first turn off the device
    - de-register the snd-usb-audio module (modprobe -r)
    - change the device_setup parameter by changing the device_setup
      option in /etc/modprobe.conf 
    - turn on the device
+ * A workaround for this last issue has been applied to kernel 2.6.23, but it may not
+   be enough to ensure the 'stability' of the device initialization.
 
-2.2.2.3 - Audiophile USB's device_setup structure
+3.2.3 - Technical details for hackers
+-------------------------------------
+This section is for hackers, wanting to understand details about the device
+internals and how Alsa supports it.
+
+3.2.3.1 - Audiophile USB's device_setup structure
 
 If you want to understand the device_setup magic numbers for the Audiophile 
 USB, you need some very basic understanding of binary computation. However, 
@@ -228,12 +309,12 @@ Caution:
    - choosing b2 will prepare all interfaces for 24bits/96kHz but you'll
      only be able to use one at the same time
 
-2.2.3 -  USB implementation details for this device
+3.2.3.2 -  USB implementation details for this device
 
 You may safely skip this section if you're not interested in driver 
-development.
+hacking.
 
-This section describes some internal aspects of the device and summarize the 
+This section describes some internal aspects of the device and summarizes the 
 data I got by usb-snooping the windows and Linux drivers.
 
 The M-Audio Audiophile USB has 7 USB Interfaces:
@@ -293,43 +374,45 @@ parse_audio_endpoints function uses a quirk called
 "audiophile_skip_setting_quirk" in order to prevent AltSettings not 
 corresponding to device_setup from being registered in the driver.
 
-3 - Audiophile USB and Jack support
+4 - Audiophile USB and Jack support
 ===================================
 
 This section deals with support of the Audiophile USB device in Jack.
-The main issue regarding this support is that the device is Big Endian 
-compliant.
 
-3.1 - Using the plug alsa plugin
---------------------------------
+There are 2 main potential issues when using Jackd with the device:
+* support for Big-Endian devices in 24-bit modes
+* support for 4-in / 4-out channels
+
+4.1 - Direct support in Jackd
+-----------------------------
 
-Jack doesn't directly support big endian devices. Thus, one way to have support 
-for this device with Alsa is to use the Alsa "plug" converter.
+Jack supports big endian devices only in recent versions (thanks to
+Andreas Steinmetz for his first big-endian patch). I can't remember 
+extacly when this support was released into jackd, let's just say that 
+with jackd version 0.103.0 it's almost ok (just a small bug is affecting 
+16bits Big-Endian devices, but since you've read  carefully the above 
+paragraphs, you're now using kernel >= 2.6.23 and your 16bits devices 
+are now Little Endians ;-) ).
+
+You can run jackd with the following command for playback with Ao and
+record with Ai:
+  % jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
+
+4.2 - Using Alsa plughw
+-----------------------
+If you don't have a recent Jackd installed, you can downgrade to using
+the Alsa "plug" converter.
 
 For instance here is one way to run Jack with 2 playback channels on Ao and 2 
 capture channels from Ai:
   % jackd -R -dalsa -dplughw:1 -r48000 -p256 -n2 -D -Cplughw:1,1
 
-
 However you may see the following warning message:
 "You appear to be using the ALSA software "plug" layer, probably a result of 
 using the "default" ALSA device. This is less efficient than it could be. 
 Consider using a hardware device instead rather than using the plug layer."
 
-3.2 - Patching alsa to use direct pcm device
---------------------------------------------
-A patch for Jack by Andreas Steinmetz adds support for Big Endian devices. 
-However it has not been included in the CVS tree.
-
-You can find it at the following URL:
-http://sourceforge.net/tracker/index.php?func=detail&aid=1289682&group_id=39687&
-atid=425939
-
-After having applied the patch you can run jackd with the following command 
-line:
-  % jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
-
-3.2 - Getting 2 input and/or output interfaces in Jack
+4.3 - Getting 2 input and/or output interfaces in Jack
 ------------------------------------------------------
 
 As you can see, starting the Jack server this way will only enable 1 stereo
@@ -339,6 +422,7 @@ This is due to the following restrictions:
 * Jack can only open one capture device and one playback device at a time
 * The Audiophile USB is seen as 2 (or three) Alsa devices: hw:1,0, hw:1,1
   (and optionally hw:1,2)
+
 If you want to get Ai+Di and/or Ao+Do support with Jack, you would need to
 combine the Alsa devices into one logical "complex" device.
 
@@ -348,13 +432,11 @@ It is related to another device (ice1712) but can be adapted to suit
 the Audiophile USB.
 
 Enabling multiple Audiophile USB interfaces for Jackd will certainly require:
-* patching Jack with the previously mentioned "Big Endian" patch
-* patching Jackd with the MMAP_COMPLEX patch (see the ice1712 page)
-* patching the alsa-lib/src/pcm/pcm_multi.c file (see the ice1712 page)
+* Making sure your Jackd version has the MMAP_COMPLEX patch (see the ice1712 page)
+* (maybe) patching the alsa-lib/src/pcm/pcm_multi.c file (see the ice1712 page)
 * define a multi device (combination of hw:1,0 and hw:1,1) in your .asoundrc
   file 
 * start jackd with this device
 
-I had no success in testing this for now, but this may be due to my OS
-configuration. If you have any success with this kind of setup, please
-drop me an email.
+I had no success in testing this for now, if you have any success with this kind 
+of setup, please drop me an email.
index ec2a02541d5b2a13406eab20e0cd61c4a78ae1f3..bfa0c9aacb4bf17ed6cf8548bab4fea31778b3f3 100644 (file)
@@ -278,6 +278,21 @@ current mixer configuration by reading and writing the whole file
 image.
 
 
+Duplex Streams
+==============
+
+Note that when attempting to use a single device file for playback and
+capture, the OSS API provides no way to set the format, sample rate or
+number of channels different in each direction.  Thus
+       io_handle = open("device", O_RDWR)
+will only function correctly if the values are the same in each direction.
+
+To use different values in the two directions, use both
+       input_handle = open("device", O_RDONLY)
+       output_handle = open("device", O_WRONLY)
+and set the values for the corresponding handle.
+
+
 Unsupported Features
 ====================
 
diff --git a/Documentation/time_interpolators.txt b/Documentation/time_interpolators.txt
deleted file mode 100644 (file)
index e3b6085..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-Time Interpolators
-------------------
-
-Time interpolators are a base of time calculation between timer ticks and
-allow an accurate determination of time down to the accuracy of the time
-source in nanoseconds.
-
-The architecture specific code typically provides gettimeofday and
-settimeofday under Linux. The time interpolator provides both if an arch
-defines CONFIG_TIME_INTERPOLATION. The arch still must set up timer tick
-operations and call the necessary functions to advance the clock.
-
-With the time interpolator a standardized interface exists for time
-interpolation between ticks. The provided logic is highly scalable
-and has been tested in SMP situations of up to 512 CPUs.
-
-If CONFIG_TIME_INTERPOLATION is defined then the architecture specific code
-(or the device drivers - like HPET) may register time interpolators.
-These are typically defined in the following way:
-
-static struct time_interpolator my_interpolator {
-       .frequency = MY_FREQUENCY,
-       .source = TIME_SOURCE_MMIO32,
-       .shift = 8,             /* scaling for higher accuracy */
-       .drift = -1,            /* Unknown drift */
-       .jitter = 0             /* time source is stable */
-};
-
-void time_init(void)
-{
-       ....
-       /* Initialization of the timer *.
-       my_interpolator.address = &my_timer;
-       register_time_interpolator(&my_interpolator);
-       ....
-}
-
-For more details see include/linux/timex.h and kernel/timer.c.
-
-Christoph Lameter <christoph@lameter.com>, October 31, 2004
-
index c9fab2be2c2cceb9572b7a74971d84a711ead74a..773c732b4177d85830e150fb9d4a52acc32dfd1f 100644 (file)
@@ -329,6 +329,12 @@ P: Ivan Kokshaysky
 M:     ink@jurassic.park.msu.ru
 S:     Maintained for 2.4; PCI support for 2.6.
 
+AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
+P:     Thomas Dahlmann
+M:     thomas.dahlmann@amd.com
+L:     info-linux@geode.amd.com
+S:     Supported
+
 AMD GEODE PROCESSOR/CHIPSET SUPPORT
 P:     Jordan Crouse
 M:     info-linux@geode.amd.com
index c04124a095cfb7eb0603471fdd3dd6566592558f..846cce48e2b7fa8e2a012bfab6e76e1431390155 100644 (file)
@@ -145,8 +145,8 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
                __do_kernel_fault(mm, addr, fsr, regs);
 }
 
-#define VM_FAULT_BADMAP                (-20)
-#define VM_FAULT_BADACCESS     (-21)
+#define VM_FAULT_BADMAP                0x010000
+#define VM_FAULT_BADACCESS     0x020000
 
 static int
 __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
@@ -249,7 +249,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        /*
         * Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
         */
-       if (likely(!(fault & VM_FAULT_ERROR)))
+       if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
                return 0;
 
        /*
index b0e21c3cee5c91f01075116b495b676e8023028b..2d77ee728f92188f5ea01b2bc27542857be92a74 100644 (file)
@@ -31,6 +31,7 @@ static const char* safe_abs_relocs[] = {
                "__kernel_rt_sigreturn",
                "__kernel_sigreturn",
                "SYSENTER_RETURN",
+               "VDSO_NOTE_MASK",
                "xen_irq_disable_direct_reloc",
                "xen_save_fl_direct_reloc",
 };
index 271f16a8ca01044bbc8f58058286ba812e2a7dab..07c0daf78237bcb1b80ea1401ada31f0f1065cb2 100644 (file)
@@ -14,7 +14,6 @@ ELFNOTE_START(Linux, 0, "a")
 ELFNOTE_END
 
 #ifdef CONFIG_XEN
-
 /*
  * Add a special note telling glibc's dynamic linker a fake hardware
  * flavor that it will use to choose the search path for libraries in the
@@ -28,15 +27,19 @@ ELFNOTE_END
  * It should contain:
  *     hwcap 1 nosegneg
  * to match the mapping of bit to name that we give here.
+ *
+ * At runtime, the fake hardware feature will be considered to be present
+ * if its bit is set in the mask word.  So, we start with the mask 0, and
+ * at boot time we set VDSO_NOTE_NONEGSEG_BIT if running under Xen.
  */
 
-/* Bit used for the pseudo-hwcap for non-negative segments.  We use
-   bit 1 to avoid bugs in some versions of glibc when bit 0 is
-   used; the choice is otherwise arbitrary. */
-#define VDSO_NOTE_NONEGSEG_BIT 1
+#include "../xen/vdso.h"       /* Defines VDSO_NOTE_NONEGSEG_BIT.  */
 
+       .globl VDSO_NOTE_MASK
 ELFNOTE_START(GNU, 2, "a")
-       .long 1, 1<<VDSO_NOTE_NONEGSEG_BIT              /* ncaps, mask */
+       .long 1                 /* ncaps */
+VDSO_NOTE_MASK:
+       .long 0                 /* mask */
        .byte VDSO_NOTE_NONEGSEG_BIT; .asciz "nosegneg" /* bit, name */
 ELFNOTE_END
 #endif
index 8904acc20f8cd14437b2794f5e13e840640c4bd7..da1b173547a112d9fcf1d3dcc86d2bfd67b5c5ff 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/irq.h>
 #include <asm/sync_bitops.h>
 #include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
 
 #include <xen/events.h>
 #include <xen/interface/xen.h>
index 2fe6eac510f0644c8a9f96358f0cdcf5bd72b16d..f84e772266461aec8a76b4feeb2ba318e21e0547 100644 (file)
@@ -19,6 +19,7 @@
 #include <xen/features.h>
 
 #include "xen-ops.h"
+#include "vdso.h"
 
 /* These are code, but not functions.  Defined in entry.S */
 extern const char xen_hypervisor_callback[];
@@ -55,6 +56,18 @@ static void xen_idle(void)
        }
 }
 
+/*
+ * Set the bit indicating "nosegneg" library variants should be used.
+ */
+static void fiddle_vdso(void)
+{
+       extern u32 VDSO_NOTE_MASK; /* See ../kernel/vsyscall-note.S.  */
+       extern char vsyscall_int80_start;
+       u32 *mask = (u32 *) ((unsigned long) &VDSO_NOTE_MASK - VDSO_PRELINK +
+                            &vsyscall_int80_start);
+       *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT;
+}
+
 void __init xen_arch_setup(void)
 {
        struct physdev_set_iopl set_iopl;
@@ -93,4 +106,6 @@ void __init xen_arch_setup(void)
 #endif
 
        paravirt_disable_iospace();
+
+       fiddle_vdso();
 }
diff --git a/arch/i386/xen/vdso.h b/arch/i386/xen/vdso.h
new file mode 100644 (file)
index 0000000..861fedf
--- /dev/null
@@ -0,0 +1,4 @@
+/* Bit used for the pseudo-hwcap for non-negative segments.  We use
+   bit 1 to avoid bugs in some versions of glibc when bit 0 is
+   used; the choice is otherwise arbitrary. */
+#define VDSO_NOTE_NONEGSEG_BIT 1
index 616c96e734831e4b508009d5b3473b0cff31eb6e..36c7b9682aa6f923a6e47ad364512dcf890f64c7 100644 (file)
@@ -62,7 +62,11 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
-config TIME_INTERPOLATION
+config GENERIC_TIME
+       bool
+       default y
+
+config GENERIC_TIME_VSYSCALL
        bool
        default y
 
index 90e9c2e61bf467d0378b31def6792eb7bfe0082e..9eb48c0927b007baa1d14af8d139df35590ff2c7 100644 (file)
@@ -85,7 +85,7 @@ CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
index 0d29aa2066b309036f42d389d06411da4d9d36dd..3a9ed951db085a77940f7264ca7b2a74b5edab45 100644 (file)
@@ -86,7 +86,7 @@ CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
index d9146c31ea13bb5c8b3fead3f5f3a91087b1e7e4..c420d9f3df98ddccf0e4580e4c93636c36952d0c 100644 (file)
@@ -86,7 +86,7 @@ CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
index 64e951de4e5749b64ca721601f0bddfd4dd7a886..4c9ffc47bc7a3e53f87e00febd4af727109320b0 100644 (file)
@@ -93,7 +93,7 @@ CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
index a1446931b401ef54889bdd0028e37b56cf720bd0..3dbb3987df277cf11a43e4062b86111046c2350c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Thu Mar  8 11:07:09 2007
+# Linux kernel version: 2.6.22
+# Thu Jul 19 13:54:47 2007
 #
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -19,15 +19,15 @@ CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=20
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
@@ -46,18 +46,19 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -65,12 +66,9 @@ CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -91,6 +89,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 CONFIG_IA64=y
 CONFIG_64BIT=y
 CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
 CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -98,7 +97,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
@@ -114,8 +113,8 @@ CONFIG_IA64_DIG=y
 CONFIG_MCKINLEY=y
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_IA64_PAGE_SIZE_16KB is not set
+CONFIG_IA64_PAGE_SIZE_64KB=y
 CONFIG_PGTABLE_3=y
 # CONFIG_PGTABLE_4 is not set
 # CONFIG_HZ_100 is not set
@@ -145,6 +144,9 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -152,11 +154,11 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y
 CONFIG_ARCH_POPULATES_NODE_MAP=y
 CONFIG_VIRTUAL_MEM_MAP=y
 CONFIG_HOLES_IN_ZONE=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_COMPAT=y
+# CONFIG_IA32_SUPPORT is not set
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
+# CONFIG_IA64_MC_ERR_INJECT is not set
 # CONFIG_IA64_ESI is not set
 CONFIG_KEXEC=y
 # CONFIG_CRASH_DUMP is not set
@@ -166,6 +168,7 @@ CONFIG_KEXEC=y
 #
 CONFIG_EFI_VARS=y
 CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 
@@ -175,7 +178,6 @@ CONFIG_BINFMT_MISC=m
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
@@ -205,13 +207,11 @@ CONFIG_ACPI_CONTAINER=m
 #
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
 # CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
 CONFIG_HOTPLUG_PCI=m
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 CONFIG_HOTPLUG_PCI_ACPI=m
@@ -232,7 +232,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -270,20 +269,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -309,7 +296,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -324,25 +321,9 @@ CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -350,10 +331,7 @@ CONFIG_PNP=y
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -370,16 +348,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 CONFIG_IDE=y
 CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
@@ -396,6 +369,7 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_BLK_DEV_IDEACPI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
@@ -404,12 +378,12 @@ CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_BLK_DEV_IDEPNP is not set
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -438,7 +412,6 @@ CONFIG_BLK_DEV_PIIX=y
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -446,6 +419,7 @@ CONFIG_IDEDMA_AUTO=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
@@ -468,6 +442,7 @@ CONFIG_CHR_DEV_SG=m
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -514,15 +489,7 @@ CONFIG_SCSI_QLOGIC_1280=y
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
@@ -539,6 +506,7 @@ CONFIG_DM_SNAPSHOT=m
 CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
 # CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -553,46 +521,25 @@ CONFIG_FUSION_CTL=y
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=m
@@ -623,10 +570,7 @@ CONFIG_E100=m
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
@@ -639,36 +583,36 @@ CONFIG_E1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -678,18 +622,9 @@ CONFIG_TIGON3=y
 # CONFIG_SHAPER is not set
 CONFIG_NETCONSOLE=y
 CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -697,6 +632,7 @@ CONFIG_NET_POLL_CONTROLLER=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -722,9 +658,17 @@ CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -790,19 +734,10 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 CONFIG_AGP=m
@@ -821,15 +756,8 @@ CONFIG_HPET=y
 # CONFIG_HPET_RTC_IRQ is not set
 CONFIG_HPET_MMAP=y
 # CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -837,21 +765,17 @@ CONFIG_HPET_MMAP=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -863,17 +787,20 @@ CONFIG_HWMON=y
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
 # CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
 # CONFIG_FB is not set
 
 #
@@ -887,16 +814,18 @@ CONFIG_DUMMY_CONSOLE=y
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
 #
-# USB support
+# USB Input Devices
 #
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -907,8 +836,10 @@ CONFIG_USB=y
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -918,7 +849,6 @@ CONFIG_USB_EHCI_HCD=m
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -926,6 +856,7 @@ CONFIG_USB_OHCI_HCD=m
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -954,42 +885,11 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_KARMA is not set
 # CONFIG_USB_LIBUSUAL is not set
 
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_GTCO is not set
-
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET_MII is not set
-# CONFIG_USB_USBNET is not set
 # CONFIG_USB_MON is not set
 
 #
@@ -1033,10 +933,6 @@ CONFIG_USB_HID=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
 
 #
@@ -1051,16 +947,8 @@ CONFIG_USB_HID=y
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
 
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
 #
 # Real Time Clock
 #
@@ -1080,12 +968,9 @@ CONFIG_USB_HID=y
 #
 
 #
-# Auxiliary Display support
-#
-
-#
-# Virtualization
+# Userspace I/O
 #
+# CONFIG_UIO is not set
 # CONFIG_MSPEC is not set
 
 #
@@ -1200,7 +1085,8 @@ CONFIG_EXPORTFS=m
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
 CONFIG_SMB_NLS_DEFAULT=y
@@ -1214,7 +1100,6 @@ CONFIG_CIFS=m
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1236,6 +1121,7 @@ CONFIG_SGI_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
 
 #
 # Native Language Support
@@ -1292,11 +1178,14 @@ CONFIG_NLS_UTF8=m
 CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_PENDING_IRQ=y
@@ -1319,8 +1208,8 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=20
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
@@ -1343,17 +1232,12 @@ CONFIG_IA64_GRANULE_16MB=y
 # CONFIG_DISABLE_VHPT is not set
 # CONFIG_IA64_DEBUG_CMPXCHG is not set
 # CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_SYSVIPC_COMPAT=y
 
 #
 # Security options
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=m
@@ -1373,6 +1257,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=m
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
@@ -1390,7 +1275,4 @@ CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
index 1c7955c163588110be1d8d70c584238aac4d7404..4a060fc39934e5bb30166eeb4fde9e15934e07dd 100644 (file)
@@ -96,7 +96,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
index 90bd9601cddef047062a594be3e682b31548fcce..03172dc8c4031fb51e8e1a620617f330076d85e9 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Thu Mar  8 11:01:03 2007
+# Linux kernel version: 2.6.22
+# Thu Jul 19 13:55:32 2007
 #
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -19,15 +19,15 @@ CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=20
 # CONFIG_CPUSETS is not set
 CONFIG_SYSFS_DEPRECATED=y
 # CONFIG_RELAY is not set
@@ -46,18 +46,19 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -65,12 +66,9 @@ CONFIG_MODVERSIONS=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
 CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -91,6 +89,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 CONFIG_IA64=y
 CONFIG_64BIT=y
 CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
 CONFIG_MMU=y
 CONFIG_SWIOTLB=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -98,7 +97,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
 CONFIG_DMI=y
 CONFIG_EFI=y
 CONFIG_GENERIC_IOMAP=y
@@ -114,8 +113,8 @@ CONFIG_IA64_GENERIC=y
 CONFIG_MCKINLEY=y
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_IA64_PAGE_SIZE_16KB is not set
+CONFIG_IA64_PAGE_SIZE_64KB=y
 CONFIG_PGTABLE_3=y
 # CONFIG_PGTABLE_4 is not set
 # CONFIG_HZ_100 is not set
@@ -147,6 +146,9 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_MIGRATION=y
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -164,7 +166,7 @@ CONFIG_COMPAT=y
 CONFIG_IA64_MCA_RECOVERY=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
-# CONFIG_MC_ERR_INJECT is not set
+# CONFIG_IA64_MC_ERR_INJECT is not set
 CONFIG_SGI_SN=y
 # CONFIG_IA64_ESI is not set
 
@@ -180,6 +182,7 @@ CONFIG_CRASH_DUMP=y
 #
 CONFIG_EFI_VARS=y
 CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 
@@ -189,7 +192,6 @@ CONFIG_BINFMT_MISC=m
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
 
 #
 # ACPI (Advanced Configuration and Power Interface) Support
@@ -220,13 +222,11 @@ CONFIG_ACPI_CONTAINER=m
 #
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
 # CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
 # CONFIG_PCI_MSI is not set
 # CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
 CONFIG_HOTPLUG_PCI=m
 # CONFIG_HOTPLUG_PCI_FAKE is not set
 CONFIG_HOTPLUG_PCI_ACPI=m
@@ -248,7 +248,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -286,20 +285,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -325,7 +312,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -340,25 +337,9 @@ CONFIG_FW_LOADER=m
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -366,10 +347,7 @@ CONFIG_PNP=y
 # Protocols
 #
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -386,16 +364,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_SGI_IOC4=y
 # CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 CONFIG_IDE=y
 CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
@@ -412,6 +385,7 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
 CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_BLK_DEV_IDEACPI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
 
 #
 # IDE chipset support/bugfixes
@@ -420,12 +394,12 @@ CONFIG_BLK_DEV_IDESCSI=m
 # CONFIG_BLK_DEV_IDEPNP is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
@@ -455,7 +429,6 @@ CONFIG_BLK_DEV_SGIIOC4=y
 # CONFIG_IDE_ARM is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -463,6 +436,7 @@ CONFIG_IDEDMA_AUTO=y
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 CONFIG_SCSI_NETLINK=y
 CONFIG_SCSI_PROC_FS=y
@@ -485,6 +459,7 @@ CONFIG_CHR_DEV_SG=m
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
 # CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
 
 #
 # SCSI Transports
@@ -492,7 +467,7 @@ CONFIG_CHR_DEV_SG=m
 CONFIG_SCSI_SPI_ATTRS=y
 CONFIG_SCSI_FC_ATTRS=y
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=y
 # CONFIG_SCSI_SAS_LIBSAS is not set
 
 #
@@ -531,15 +506,7 @@ CONFIG_SCSI_QLOGIC_1280=y
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
@@ -557,6 +524,8 @@ CONFIG_DM_MIRROR=m
 CONFIG_DM_ZERO=m
 CONFIG_DM_MULTIPATH=m
 # CONFIG_DM_MULTIPATH_EMC is not set
+# CONFIG_DM_MULTIPATH_RDAC is not set
+# CONFIG_DM_DELAY is not set
 
 #
 # Fusion MPT device support
@@ -564,53 +533,32 @@ CONFIG_DM_MULTIPATH=m
 CONFIG_FUSION=y
 CONFIG_FUSION_SPI=y
 CONFIG_FUSION_FC=m
-# CONFIG_FUSION_SAS is not set
+CONFIG_FUSION_SAS=y
 CONFIG_FUSION_MAX_SGE=128
 # CONFIG_FUSION_CTL is not set
 
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=m
@@ -641,10 +589,7 @@ CONFIG_E100=m
 # CONFIG_SUNDANCE is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
@@ -657,36 +602,36 @@ CONFIG_E1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 CONFIG_TIGON3=y
 # CONFIG_BNX2 is not set
 # CONFIG_QLA3XXX is not set
 # CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# USB Network Adapters
 #
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -696,18 +641,9 @@ CONFIG_TIGON3=y
 # CONFIG_SHAPER is not set
 CONFIG_NETCONSOLE=y
 CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
 # CONFIG_NETPOLL_TRAP is not set
 CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -715,6 +651,7 @@ CONFIG_NET_POLL_CONTROLLER=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -740,9 +677,17 @@ CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -814,19 +759,10 @@ CONFIG_SERIAL_SGI_IOC4=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 CONFIG_AGP=m
@@ -848,15 +784,8 @@ CONFIG_HPET=y
 CONFIG_HPET_MMAP=y
 # CONFIG_HANGCHECK_TIMER is not set
 CONFIG_MMTIMER=y
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -864,21 +793,17 @@ CONFIG_MMTIMER=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
 # CONFIG_SENSORS_F71805F is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -890,17 +815,20 @@ CONFIG_HWMON=y
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
 # CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
 # CONFIG_FB is not set
 
 #
@@ -1014,9 +942,10 @@ CONFIG_SND_FM801=m
 # USB devices
 #
 # CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
 
 #
-# SoC audio support
+# System on Chip audio support
 #
 # CONFIG_SND_SOC is not set
 
@@ -1025,16 +954,24 @@ CONFIG_SND_FM801=m
 #
 # CONFIG_SOUND_PRIME is not set
 CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
 
 #
-# HID Devices
+# USB Input Devices
 #
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
 
 #
-# USB support
+# USB HID Boot Protocol drivers
 #
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1045,8 +982,10 @@ CONFIG_USB=m
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
 # CONFIG_USB_DYNAMIC_MINORS is not set
 # CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -1056,7 +995,6 @@ CONFIG_USB_EHCI_HCD=m
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1064,6 +1002,7 @@ CONFIG_USB_OHCI_HCD=m
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=m
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1092,48 +1031,11 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_KARMA is not set
 # CONFIG_USB_LIBUSUAL is not set
 
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_GTCO is not set
-
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK is not set
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET_MII is not set
-# CONFIG_USB_USBNET is not set
 CONFIG_USB_MON=y
 
 #
@@ -1177,10 +1079,6 @@ CONFIG_USB_MON=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
 
 #
@@ -1195,10 +1093,6 @@ CONFIG_USB_MON=y
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 CONFIG_INFINIBAND=m
 # CONFIG_INFINIBAND_USER_MAD is not set
 # CONFIG_INFINIBAND_USER_ACCESS is not set
@@ -1206,6 +1100,7 @@ CONFIG_INFINIBAND_ADDR_TRANS=y
 CONFIG_INFINIBAND_MTHCA=m
 CONFIG_INFINIBAND_MTHCA_DEBUG=y
 # CONFIG_INFINIBAND_AMSO1100 is not set
+# CONFIG_MLX4_INFINIBAND is not set
 CONFIG_INFINIBAND_IPOIB=m
 # CONFIG_INFINIBAND_IPOIB_CM is not set
 CONFIG_INFINIBAND_IPOIB_DEBUG=y
@@ -1213,10 +1108,6 @@ CONFIG_INFINIBAND_IPOIB_DEBUG=y
 # CONFIG_INFINIBAND_SRP is not set
 # CONFIG_INFINIBAND_ISER is not set
 
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
 #
 # Real Time Clock
 #
@@ -1236,12 +1127,9 @@ CONFIG_INFINIBAND_IPOIB_DEBUG=y
 #
 
 #
-# Auxiliary Display support
-#
-
-#
-# Virtualization
+# Userspace I/O
 #
+# CONFIG_UIO is not set
 # CONFIG_MSPEC is not set
 
 #
@@ -1357,7 +1245,8 @@ CONFIG_EXPORTFS=m
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=m
 CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 CONFIG_SMB_FS=m
 CONFIG_SMB_NLS_DEFAULT=y
@@ -1371,7 +1260,6 @@ CONFIG_CIFS=m
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1393,6 +1281,7 @@ CONFIG_SGI_PARTITION=y
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_KARMA_PARTITION is not set
 CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
 
 #
 # Native Language Support
@@ -1449,11 +1338,14 @@ CONFIG_NLS_UTF8=m
 CONFIG_BITREVERSE=y
 # CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_PENDING_IRQ=y
@@ -1483,8 +1375,8 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_HEADERS_CHECK is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=20
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
@@ -1514,10 +1406,6 @@ CONFIG_SYSVIPC_COMPAT=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=y
 CONFIG_CRYPTO_BLKCIPHER=m
@@ -1537,6 +1425,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=m
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
@@ -1554,7 +1443,4 @@ CONFIG_CRYPTO_DES=m
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
index 2236fabbb3c60fcf6453a8b07a1448b9cb09e6bd..0aebc6f79e95349ce2268b3031a968a1eafebf1f 100644 (file)
@@ -7,6 +7,7 @@
 #define ASM_OFFSETS_C 1
 
 #include <linux/sched.h>
+#include <linux/clocksource.h>
 
 #include <asm-ia64/processor.h>
 #include <asm-ia64/ptrace.h>
@@ -15,6 +16,7 @@
 #include <asm-ia64/mca.h>
 
 #include "../kernel/sigframe.h"
+#include "../kernel/fsyscall_gtod_data.h"
 
 #define DEFINE(sym, val) \
         asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -256,17 +258,24 @@ void foo(void)
        BLANK();
 
        /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
-       DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr));
-       DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source));
-       DEFINE(IA64_TIME_INTERPOLATOR_SHIFT_OFFSET, offsetof (struct time_interpolator, shift));
-       DEFINE(IA64_TIME_INTERPOLATOR_NSEC_OFFSET, offsetof (struct time_interpolator, nsec_per_cyc));
-       DEFINE(IA64_TIME_INTERPOLATOR_OFFSET_OFFSET, offsetof (struct time_interpolator, offset));
-       DEFINE(IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET, offsetof (struct time_interpolator, last_cycle));
-       DEFINE(IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET, offsetof (struct time_interpolator, last_counter));
-       DEFINE(IA64_TIME_INTERPOLATOR_JITTER_OFFSET, offsetof (struct time_interpolator, jitter));
-       DEFINE(IA64_TIME_INTERPOLATOR_MASK_OFFSET, offsetof (struct time_interpolator, mask));
-       DEFINE(IA64_TIME_SOURCE_CPU, TIME_SOURCE_CPU);
-       DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64);
-       DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32);
-       DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec));
+       DEFINE(IA64_GTOD_LOCK_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, lock));
+       DEFINE(IA64_GTOD_WALL_TIME_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, wall_time));
+       DEFINE(IA64_GTOD_MONO_TIME_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, monotonic_time));
+       DEFINE(IA64_CLKSRC_MASK_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_mask));
+       DEFINE(IA64_CLKSRC_MULT_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_mult));
+       DEFINE(IA64_CLKSRC_SHIFT_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_shift));
+       DEFINE(IA64_CLKSRC_MMIO_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_fsys_mmio));
+       DEFINE(IA64_CLKSRC_CYCLE_LAST_OFFSET,
+               offsetof (struct fsyscall_gtod_data_t, clk_cycle_last));
+       DEFINE(IA64_ITC_JITTER_OFFSET,
+               offsetof (struct itc_jitter_data_t, itc_jitter));
+       DEFINE(IA64_ITC_LASTCYCLE_OFFSET,
+               offsetof (struct itc_jitter_data_t, itc_lastcycle));
 }
index e00b21514f7c665e97e1374d41c323ef915c1d57..2fd96d9062a1359b41964c3b4e3d90c8879034a3 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/time.h>
 #include <linux/errno.h>
 #include <linux/timex.h>
+#include <linux/clocksource.h>
 #include <asm/io.h>
 
 /* IBM Summit (EXA) Cyclone counter code*/
@@ -18,13 +19,21 @@ void __init cyclone_setup(void)
        use_cyclone = 1;
 }
 
+static void __iomem *cyclone_mc;
 
-struct time_interpolator cyclone_interpolator = {
-       .source =       TIME_SOURCE_MMIO64,
-       .shift =        16,
-       .frequency =    CYCLONE_TIMER_FREQ,
-       .drift =        -100,
-       .mask =         (1LL << 40) - 1
+static cycle_t read_cyclone(void)
+{
+       return (cycle_t)readq((void __iomem *)cyclone_mc);
+}
+
+static struct clocksource clocksource_cyclone = {
+        .name           = "cyclone",
+        .rating         = 300,
+        .read           = read_cyclone,
+        .mask           = (1LL << 40) - 1,
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 16,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 int __init init_cyclone_clock(void)
@@ -44,13 +53,15 @@ int __init init_cyclone_clock(void)
        offset = (CYCLONE_CBAR_ADDR);
        reg = (u64*)ioremap_nocache(offset, sizeof(u64));
        if(!reg){
-               printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
+                               " register.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
        base = readq(reg);
        if(!base){
-               printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
+                               " value.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
@@ -60,7 +71,8 @@ int __init init_cyclone_clock(void)
        offset = (base + CYCLONE_PMCC_OFFSET);
        reg = (u64*)ioremap_nocache(offset, sizeof(u64));
        if(!reg){
-               printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
+                               " register.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
@@ -71,7 +83,8 @@ int __init init_cyclone_clock(void)
        offset = (base + CYCLONE_MPCS_OFFSET);
        reg = (u64*)ioremap_nocache(offset, sizeof(u64));
        if(!reg){
-               printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
+                               " register.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
@@ -82,7 +95,8 @@ int __init init_cyclone_clock(void)
        offset = (base + CYCLONE_MPMC_OFFSET);
        cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32));
        if(!cyclone_timer){
-               printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+               printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
+                               " register.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
@@ -93,7 +107,8 @@ int __init init_cyclone_clock(void)
                int stall = 100;
                while(stall--) barrier();
                if(readl(cyclone_timer) == old){
-                       printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+                       printk(KERN_ERR "Summit chipset: Counter not counting!"
+                                       " DISABLED\n");
                        iounmap(cyclone_timer);
                        cyclone_timer = 0;
                        use_cyclone = 0;
@@ -101,8 +116,11 @@ int __init init_cyclone_clock(void)
                }
        }
        /* initialize last tick */
-       cyclone_interpolator.addr = cyclone_timer;
-       register_time_interpolator(&cyclone_interpolator);
+       cyclone_mc = cyclone_timer;
+       clocksource_cyclone.fsys_mmio = cyclone_timer;
+       clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
+                                               clocksource_cyclone.shift);
+       clocksource_register(&clocksource_cyclone);
 
        return 0;
 }
index 95f517515235ef1612d35f1eb635c407c0a7dad7..c36f43c9460094cfa72f9f5f73839965481c53fa 100644 (file)
@@ -1581,7 +1581,7 @@ sys_call_table:
        data8 sys_sync_file_range               // 1300
        data8 sys_tee
        data8 sys_vmsplice
-       data8 sys_ni_syscall                    // reserved for move_pages
+       data8 sys_fallocate
        data8 sys_getcpu
        data8 sys_epoll_pwait                   // 1305
        data8 sys_utimensat
index 3f926c2dc708044542a0b34be94f42e0b58912f2..44841971f077bfd812bdc7da38638a6ef99784d5 100644 (file)
@@ -147,12 +147,11 @@ ENTRY(fsys_set_tid_address)
        FSYS_RETURN
 END(fsys_set_tid_address)
 
-/*
- * Ensure that the time interpolator structure is compatible with the asm code
- */
-#if IA64_TIME_INTERPOLATOR_SOURCE_OFFSET !=0 || IA64_TIME_INTERPOLATOR_SHIFT_OFFSET != 2 \
-       || IA64_TIME_INTERPOLATOR_JITTER_OFFSET != 3 || IA64_TIME_INTERPOLATOR_NSEC_OFFSET != 4
-#error fsys_gettimeofday incompatible with changes to struct time_interpolator
+#if IA64_GTOD_LOCK_OFFSET !=0
+#error fsys_gettimeofday incompatible with changes to struct fsyscall_gtod_data_t
+#endif
+#if IA64_ITC_JITTER_OFFSET !=0
+#error fsys_gettimeofday incompatible with changes to struct itc_jitter_data_t
 #endif
 #define CLOCK_REALTIME 0
 #define CLOCK_MONOTONIC 1
@@ -179,126 +178,124 @@ ENTRY(fsys_gettimeofday)
        // r11 = preserved: saved ar.pfs
        // r12 = preserved: memory stack
        // r13 = preserved: thread pointer
-       // r14 = address of mask / mask
+       // r14 = address of mask / mask value
        // r15 = preserved: system call number
        // r16 = preserved: current task pointer
-       // r17 = wall to monotonic use
-       // r18 = time_interpolator->offset
-       // r19 = address of wall_to_monotonic
-       // r20 = pointer to struct time_interpolator / pointer to time_interpolator->address
-       // r21 = shift factor
-       // r22 = address of time interpolator->last_counter
-       // r23 = address of time_interpolator->last_cycle
-       // r24 = adress of time_interpolator->offset
-       // r25 = last_cycle value
-       // r26 = last_counter value
-       // r27 = pointer to xtime
+       // r17 = (not used)
+       // r18 = (not used)
+       // r19 = address of itc_lastcycle
+       // r20 = struct fsyscall_gtod_data (= address of gtod_lock.sequence)
+       // r21 = address of mmio_ptr
+       // r22 = address of wall_time or monotonic_time
+       // r23 = address of shift / value
+       // r24 = address mult factor / cycle_last value
+       // r25 = itc_lastcycle value
+       // r26 = address clocksource cycle_last
+       // r27 = (not used)
        // r28 = sequence number at the beginning of critcal section
-       // r29 = address of seqlock
+       // r29 = address of itc_jitter
        // r30 = time processing flags / memory address
        // r31 = pointer to result
        // Predicates
        // p6,p7 short term use
        // p8 = timesource ar.itc
        // p9 = timesource mmio64
-       // p10 = timesource mmio32
+       // p10 = timesource mmio32 - not used
        // p11 = timesource not to be handled by asm code
-       // p12 = memory time source ( = p9 | p10)
-       // p13 = do cmpxchg with time_interpolator_last_cycle
+       // p12 = memory time source ( = p9 | p10) - not used
+       // p13 = do cmpxchg with itc_lastcycle
        // p14 = Divide by 1000
        // p15 = Add monotonic
        //
-       // Note that instructions are optimized for McKinley. McKinley can process two
-       // bundles simultaneously and therefore we continuously try to feed the CPU
-       // two bundles and then a stop.
-       tnat.nz p6,p0 = r31     // branch deferred since it does not fit into bundle structure
+       // Note that instructions are optimized for McKinley. McKinley can
+       // process two bundles simultaneously and therefore we continuously
+       // try to feed the CPU two bundles and then a stop.
+       //
+       // Additional note that code has changed a lot. Optimization is TBD.
+       // Comments begin with "?" are maybe outdated.
+       tnat.nz p6,p0 = r31     // ? branch deferred to fit later bundle
        mov pr = r30,0xc000     // Set predicates according to function
        add r2 = TI_FLAGS+IA64_TASK_SIZE,r16
-       movl r20 = time_interpolator
+       movl r20 = fsyscall_gtod_data // load fsyscall gettimeofday data address
        ;;
-       ld8 r20 = [r20]         // get pointer to time_interpolator structure
-       movl r29 = xtime_lock
+       movl r29 = itc_jitter_data      // itc_jitter
+       add r22 = IA64_GTOD_WALL_TIME_OFFSET,r20        // wall_time
        ld4 r2 = [r2]           // process work pending flags
-       movl r27 = xtime
-       ;;      // only one bundle here
-       ld8 r21 = [r20]         // first quad with control information
+       ;;
+(p15)  add r22 = IA64_GTOD_MONO_TIME_OFFSET,r20        // monotonic_time
+       add r21 = IA64_CLKSRC_MMIO_OFFSET,r20
+       add r19 = IA64_ITC_LASTCYCLE_OFFSET,r29
        and r2 = TIF_ALLWORK_MASK,r2
-(p6)    br.cond.spnt.few .fail_einval  // deferred branch
+(p6)    br.cond.spnt.few .fail_einval  // deferred branch
        ;;
-       add r10 = IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET,r20
-       extr r3 = r21,32,32     // time_interpolator->nsec_per_cyc
-       extr r8 = r21,0,16      // time_interpolator->source
+       add r26 = IA64_CLKSRC_CYCLE_LAST_OFFSET,r20 // clksrc_cycle_last
        cmp.ne p6, p0 = 0, r2   // Fallback if work is scheduled
 (p6)    br.cond.spnt.many fsys_fallback_syscall
        ;;
-       cmp.eq p8,p12 = 0,r8    // Check for cpu timer
-       cmp.eq p9,p0 = 1,r8     // MMIO64 ?
-       extr r2 = r21,24,8      // time_interpolator->jitter
-       cmp.eq p10,p0 = 2,r8    // MMIO32 ?
-       cmp.ltu p11,p0 = 2,r8   // function or other clock
-(p11)  br.cond.spnt.many fsys_fallback_syscall
+       // Begin critical section
+.time_redo:
+       ld4.acq r28 = [r20]     // gtod_lock.sequence, Must take first
+       ;;
+       and r28 = ~1,r28        // And make sequence even to force retry if odd
        ;;
-       setf.sig f7 = r3        // Setup for scaling of counter
-(p15)  movl r19 = wall_to_monotonic
-(p12)  ld8 r30 = [r10]
-       cmp.ne p13,p0 = r2,r0   // need jitter compensation?
-       extr r21 = r21,16,8     // shift factor
+       ld8 r30 = [r21]         // clocksource->mmio_ptr
+       add r24 = IA64_CLKSRC_MULT_OFFSET,r20
+       ld4 r2 = [r29]          // itc_jitter value
+       add r23 = IA64_CLKSRC_SHIFT_OFFSET,r20
+       add r14 = IA64_CLKSRC_MASK_OFFSET,r20
        ;;
-.time_redo:
-       .pred.rel.mutex p8,p9,p10
-       ld4.acq r28 = [r29]     // xtime_lock.sequence. Must come first for locking purposes
+       ld4 r3 = [r24]          // clocksource mult value
+       ld8 r14 = [r14]         // clocksource mask value
+       cmp.eq p8,p9 = 0,r30    // use cpu timer if no mmio_ptr
        ;;
-       and r28 = ~1,r28        // Make sequence even to force retry if odd
+       setf.sig f7 = r3        // Setup for mult scaling of counter
+(p8)   cmp.ne p13,p0 = r2,r0   // need itc_jitter compensation, set p13
+       ld4 r23 = [r23]         // clocksource shift value
+       ld8 r24 = [r26]         // get clksrc_cycle_last value
+(p9)   cmp.eq p13,p0 = 0,r30   // if mmio_ptr, clear p13 jitter control
        ;;
+       .pred.rel.mutex p8,p9
 (p8)   mov r2 = ar.itc         // CPU_TIMER. 36 clocks latency!!!
-       add r22 = IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET,r20
-(p9)   ld8 r2 = [r30]          // readq(ti->address). Could also have latency issues..
-(p10)  ld4 r2 = [r30]          // readw(ti->address)
-(p13)  add r23 = IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET,r20
-       ;;                      // could be removed by moving the last add upward
-       ld8 r26 = [r22]         // time_interpolator->last_counter
-(p13)  ld8 r25 = [r23]         // time interpolator->last_cycle
-       add r24 = IA64_TIME_INTERPOLATOR_OFFSET_OFFSET,r20
-(p15)  ld8 r17 = [r19],IA64_TIMESPEC_TV_NSEC_OFFSET
-       ld8 r9 = [r27],IA64_TIMESPEC_TV_NSEC_OFFSET
-       add r14 = IA64_TIME_INTERPOLATOR_MASK_OFFSET, r20
-       ;;
-       ld8 r18 = [r24]         // time_interpolator->offset
-       ld8 r8 = [r27],-IA64_TIMESPEC_TV_NSEC_OFFSET    // xtime.tv_nsec
-(p13)  sub r3 = r25,r2 // Diff needed before comparison (thanks davidm)
-       ;;
-       ld8 r14 = [r14]         // time_interpolator->mask
-(p13)  cmp.gt.unc p6,p7 = r3,r0        // check if it is less than last. p6,p7 cleared
-       sub r10 = r2,r26        // current_counter - last_counter
-       ;;
-(p6)   sub r10 = r25,r26       // time we got was less than last_cycle
+(p9)   ld8 r2 = [r30]          // MMIO_TIMER. Could also have latency issues..
+(p13)  ld8 r25 = [r19]         // get itc_lastcycle value
+       ;;              // ? could be removed by moving the last add upward
+       ld8 r9 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET     // tv_sec
+       ;;
+       ld8 r8 = [r22],-IA64_TIMESPEC_TV_NSEC_OFFSET    // tv_nsec
+(p13)  sub r3 = r25,r2         // Diff needed before comparison (thanks davidm)
+       ;;
+(p13)  cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
+       sub r10 = r2,r24        // current_cycle - last_cycle
+       ;;
+(p6)   sub r10 = r25,r24       // time we got was less than last_cycle
 (p7)   mov ar.ccv = r25        // more than last_cycle. Prep for cmpxchg
        ;;
+(p7)   cmpxchg8.rel r3 = [r19],r2,ar.ccv
+       ;;
+(p7)   cmp.ne p7,p0 = r25,r3   // if cmpxchg not successful
+       ;;
+(p7)   sub r10 = r3,r24        // then use new last_cycle instead
+       ;;
        and r10 = r10,r14       // Apply mask
        ;;
        setf.sig f8 = r10
        nop.i 123
        ;;
-(p7)   cmpxchg8.rel r3 = [r23],r2,ar.ccv
-EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have spare time
+       // fault check takes 5 cycles and we have spare time
+EX(.fail_efault, probe.w.fault r31, 3)
        xmpy.l f8 = f8,f7       // nsec_per_cyc*(counter-last_counter)
-(p15)  add r9 = r9,r17         // Add wall to monotonic.secs to result secs
        ;;
-(p15)  ld8 r17 = [r19],-IA64_TIMESPEC_TV_NSEC_OFFSET
-(p7)   cmp.ne p7,p0 = r25,r3   // if cmpxchg not successful redo
-       // simulate tbit.nz.or p7,p0 = r28,0
+       // ? simulate tbit.nz.or p7,p0 = r28,0
        getf.sig r2 = f8
        mf
-       add r8 = r8,r18         // Add time interpolator offset
        ;;
-       ld4 r10 = [r29]         // xtime_lock.sequence
-(p15)  add r8 = r8, r17        // Add monotonic.nsecs to nsecs
-       shr.u r2 = r2,r21
-       ;;              // overloaded 3 bundles!
-       // End critical section.
+       ld4 r10 = [r20]         // gtod_lock.sequence
+       shr.u r2 = r2,r23       // shift by factor
+       ;;              // ? overloaded 3 bundles!
        add r8 = r8,r2          // Add xtime.nsecs
-       cmp4.ne.or p7,p0 = r28,r10
-(p7)   br.cond.dpnt.few .time_redo     // sequence number changed ?
+       cmp4.ne p7,p0 = r28,r10
+(p7)   br.cond.dpnt.few .time_redo     // sequence number changed, redo
+       // End critical section.
        // Now r8=tv->tv_nsec and r9=tv->tv_sec
        mov r10 = r0
        movl r2 = 1000000000
@@ -308,19 +305,19 @@ EX(.fail_efault, probe.w.fault r31, 3)    // This takes 5 cycles and we have spare
 .time_normalize:
        mov r21 = r8
        cmp.ge p6,p0 = r8,r2
-(p14)  shr.u r20 = r8, 3               // We can repeat this if necessary just wasting some time
+(p14)  shr.u r20 = r8, 3 // We can repeat this if necessary just wasting time
        ;;
 (p14)  setf.sig f8 = r20
 (p6)   sub r8 = r8,r2
-(p6)   add r9 = 1,r9                   // two nops before the branch.
-(p14)  setf.sig f7 = r3                // Chances for repeats are 1 in 10000 for gettod
+(p6)   add r9 = 1,r9           // two nops before the branch.
+(p14)  setf.sig f7 = r3        // Chances for repeats are 1 in 10000 for gettod
 (p6)   br.cond.dpnt.few .time_normalize
        ;;
        // Divided by 8 though shift. Now divide by 125
        // The compiler was able to do that with a multiply
        // and a shift and we do the same
-EX(.fail_efault, probe.w.fault r23, 3)         // This also costs 5 cycles
-(p14)  xmpy.hu f8 = f8, f7                     // xmpy has 5 cycles latency so use it...
+EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles
+(p14)  xmpy.hu f8 = f8, f7             // xmpy has 5 cycles latency so use it
        ;;
        mov r8 = r0
 (p14)  getf.sig r2 = f8
diff --git a/arch/ia64/kernel/fsyscall_gtod_data.h b/arch/ia64/kernel/fsyscall_gtod_data.h
new file mode 100644 (file)
index 0000000..490dab5
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ *        Contributed by Peter Keilty <peter.keilty@hp.com>
+ *
+ * fsyscall gettimeofday data
+ */
+
+struct fsyscall_gtod_data_t {
+       seqlock_t       lock;
+       struct timespec wall_time;
+       struct timespec monotonic_time;
+       cycle_t         clk_mask;
+       u32             clk_mult;
+       u32             clk_shift;
+       void            *clk_fsys_mmio;
+       cycle_t         clk_cycle_last;
+} __attribute__ ((aligned (L1_CACHE_BYTES)));
+
+struct itc_jitter_data_t {
+       int             itc_jitter;
+       cycle_t         itc_lastcycle;
+} __attribute__ ((aligned (L1_CACHE_BYTES)));
+
index 37f46527d233eef451ead5c8b6adcc2b24e33ca9..91e6dc1e7baf8d37ddd91c340c0b8c753cfed16d 100644 (file)
@@ -118,15 +118,25 @@ static DEFINE_SPINLOCK(iosapic_lock);
  * vector.
  */
 
-struct iosapic_rte_info {
-       struct list_head rte_list;      /* node in list of RTEs sharing the
-                                        * same vector */
+#define NO_REF_RTE     0
+
+static struct iosapic {
        char __iomem    *addr;          /* base address of IOSAPIC */
-       unsigned int    gsi_base;       /* first GSI assigned to this
-                                        * IOSAPIC */
+       unsigned int    gsi_base;       /* GSI base */
+       unsigned short  num_rte;        /* # of RTEs on this IOSAPIC */
+       int             rtes_inuse;     /* # of RTEs in use on this IOSAPIC */
+#ifdef CONFIG_NUMA
+       unsigned short  node;           /* numa node association via pxm */
+#endif
+       spinlock_t      lock;           /* lock for indirect reg access */
+} iosapic_lists[NR_IOSAPICS];
+
+struct iosapic_rte_info {
+       struct list_head rte_list;      /* RTEs sharing the same vector */
        char            rte_index;      /* IOSAPIC RTE index */
        int             refcnt;         /* reference counter */
        unsigned int    flags;          /* flags */
+       struct iosapic  *iosapic;
 } ____cacheline_aligned;
 
 static struct iosapic_intr_info {
@@ -140,24 +150,23 @@ static struct iosapic_intr_info {
        unsigned char   polarity: 1;    /* interrupt polarity
                                         * (see iosapic.h) */
        unsigned char   trigger : 1;    /* trigger mode (see iosapic.h) */
-} iosapic_intr_info[IA64_NUM_VECTORS];
-
-static struct iosapic {
-       char __iomem    *addr;          /* base address of IOSAPIC */
-       unsigned int    gsi_base;       /* first GSI assigned to this
-                                        * IOSAPIC */
-       unsigned short  num_rte;        /* # of RTEs on this IOSAPIC */
-       int             rtes_inuse;     /* # of RTEs in use on this IOSAPIC */
-#ifdef CONFIG_NUMA
-       unsigned short  node;           /* numa node association via pxm */
-#endif
-} iosapic_lists[NR_IOSAPICS];
+} iosapic_intr_info[NR_IRQS];
 
 static unsigned char pcat_compat __devinitdata;        /* 8259 compatibility flag */
 
 static int iosapic_kmalloc_ok;
 static LIST_HEAD(free_rte_list);
 
+static inline void
+iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&iosapic->lock, flags);
+       __iosapic_write(iosapic->addr, reg, val);
+       spin_unlock_irqrestore(&iosapic->lock, flags);
+}
+
 /*
  * Find an IOSAPIC associated with a GSI
  */
@@ -175,17 +184,18 @@ find_iosapic (unsigned int gsi)
        return -1;
 }
 
-static inline int
-_gsi_to_vector (unsigned int gsi)
+static inline int __gsi_to_irq(unsigned int gsi)
 {
+       int irq;
        struct iosapic_intr_info *info;
        struct iosapic_rte_info *rte;
 
-       for (info = iosapic_intr_info; info <
-                    iosapic_intr_info + IA64_NUM_VECTORS; ++info)
+       for (irq = 0; irq < NR_IRQS; irq++) {
+               info = &iosapic_intr_info[irq];
                list_for_each_entry(rte, &info->rtes, rte_list)
-                       if (rte->gsi_base + rte->rte_index == gsi)
-                               return info - iosapic_intr_info;
+                       if (rte->iosapic->gsi_base + rte->rte_index == gsi)
+                               return irq;
+       }
        return -1;
 }
 
@@ -196,7 +206,10 @@ _gsi_to_vector (unsigned int gsi)
 inline int
 gsi_to_vector (unsigned int gsi)
 {
-       return _gsi_to_vector(gsi);
+       int irq = __gsi_to_irq(gsi);
+       if (check_irq_used(irq) < 0)
+               return -1;
+       return irq_to_vector(irq);
 }
 
 int
@@ -204,66 +217,48 @@ gsi_to_irq (unsigned int gsi)
 {
        unsigned long flags;
        int irq;
-       /*
-        * XXX fix me: this assumes an identity mapping between IA-64 vector
-        * and Linux irq numbers...
-        */
+
        spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               irq = _gsi_to_vector(gsi);
-       }
+       irq = __gsi_to_irq(gsi);
        spin_unlock_irqrestore(&iosapic_lock, flags);
-
        return irq;
 }
 
-static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi,
-                                                 unsigned int vec)
+static struct iosapic_rte_info *find_rte(unsigned int irq, unsigned int gsi)
 {
        struct iosapic_rte_info *rte;
 
-       list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
-               if (rte->gsi_base + rte->rte_index == gsi)
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
+               if (rte->iosapic->gsi_base + rte->rte_index == gsi)
                        return rte;
        return NULL;
 }
 
 static void
-set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
+set_rte (unsigned int gsi, unsigned int irq, unsigned int dest, int mask)
 {
        unsigned long pol, trigger, dmode;
        u32 low32, high32;
-       char __iomem *addr;
        int rte_index;
        char redir;
        struct iosapic_rte_info *rte;
+       ia64_vector vector = irq_to_vector(irq);
 
        DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
 
-       rte = gsi_vector_to_rte(gsi, vector);
+       rte = find_rte(irq, gsi);
        if (!rte)
                return;         /* not an IOSAPIC interrupt */
 
        rte_index = rte->rte_index;
-       addr    = rte->addr;
-       pol     = iosapic_intr_info[vector].polarity;
-       trigger = iosapic_intr_info[vector].trigger;
-       dmode   = iosapic_intr_info[vector].dmode;
+       pol     = iosapic_intr_info[irq].polarity;
+       trigger = iosapic_intr_info[irq].trigger;
+       dmode   = iosapic_intr_info[irq].dmode;
 
        redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
 
 #ifdef CONFIG_SMP
-       {
-               unsigned int irq;
-
-               for (irq = 0; irq < NR_IRQS; ++irq)
-                       if (irq_to_vector(irq) == vector) {
-                               set_irq_affinity_info(irq,
-                                                     (int)(dest & 0xffff),
-                                                     redir);
-                               break;
-                       }
-       }
+       set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
 #endif
 
        low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
@@ -275,10 +270,10 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
        /* dest contains both id and eid */
        high32 = (dest << IOSAPIC_DEST_SHIFT);
 
-       iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
-       iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-       iosapic_intr_info[vector].low32 = low32;
-       iosapic_intr_info[vector].dest = dest;
+       iosapic_write(rte->iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
+       iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
+       iosapic_intr_info[irq].low32 = low32;
+       iosapic_intr_info[irq].dest = dest;
 }
 
 static void
@@ -294,15 +289,18 @@ kexec_disable_iosapic(void)
 {
        struct iosapic_intr_info *info;
        struct iosapic_rte_info *rte;
-       u8 vec = 0;
-       for (info = iosapic_intr_info; info <
-                       iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) {
+       ia64_vector vec;
+       int irq;
+
+       for (irq = 0; irq < NR_IRQS; irq++) {
+               info = &iosapic_intr_info[irq];
+               vec = irq_to_vector(irq);
                list_for_each_entry(rte, &info->rtes,
                                rte_list) {
-                       iosapic_write(rte->addr,
+                       iosapic_write(rte->iosapic,
                                        IOSAPIC_RTE_LOW(rte->rte_index),
                                        IOSAPIC_MASK|vec);
-                       iosapic_eoi(rte->addr, vec);
+                       iosapic_eoi(rte->iosapic->addr, vec);
                }
        }
 }
@@ -311,54 +309,36 @@ kexec_disable_iosapic(void)
 static void
 mask_irq (unsigned int irq)
 {
-       unsigned long flags;
-       char __iomem *addr;
        u32 low32;
        int rte_index;
-       ia64_vector vec = irq_to_vector(irq);
        struct iosapic_rte_info *rte;
 
-       if (list_empty(&iosapic_intr_info[vec].rtes))
+       if (list_empty(&iosapic_intr_info[irq].rtes))
                return;                 /* not an IOSAPIC interrupt! */
 
-       spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               /* set only the mask bit */
-               low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
-               list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
-                                   rte_list) {
-                       addr = rte->addr;
-                       rte_index = rte->rte_index;
-                       iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-               }
+       /* set only the mask bit */
+       low32 = iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+               rte_index = rte->rte_index;
+               iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
        }
-       spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
 static void
 unmask_irq (unsigned int irq)
 {
-       unsigned long flags;
-       char __iomem *addr;
        u32 low32;
        int rte_index;
-       ia64_vector vec = irq_to_vector(irq);
        struct iosapic_rte_info *rte;
 
-       if (list_empty(&iosapic_intr_info[vec].rtes))
+       if (list_empty(&iosapic_intr_info[irq].rtes))
                return;                 /* not an IOSAPIC interrupt! */
 
-       spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
-               list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
-                                   rte_list) {
-                       addr = rte->addr;
-                       rte_index = rte->rte_index;
-                       iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-               }
+       low32 = iosapic_intr_info[irq].low32 &= ~IOSAPIC_MASK;
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+               rte_index = rte->rte_index;
+               iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
        }
-       spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
 
@@ -366,23 +346,24 @@ static void
 iosapic_set_affinity (unsigned int irq, cpumask_t mask)
 {
 #ifdef CONFIG_SMP
-       unsigned long flags;
        u32 high32, low32;
        int dest, rte_index;
-       char __iomem *addr;
        int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
-       ia64_vector vec;
        struct iosapic_rte_info *rte;
+       struct iosapic *iosapic;
 
        irq &= (~IA64_IRQ_REDIRECTED);
-       vec = irq_to_vector(irq);
 
+       cpus_and(mask, mask, cpu_online_map);
        if (cpus_empty(mask))
                return;
 
+       if (reassign_irq_vector(irq, first_cpu(mask)))
+               return;
+
        dest = cpu_physical_id(first_cpu(mask));
 
-       if (list_empty(&iosapic_intr_info[vec].rtes))
+       if (list_empty(&iosapic_intr_info[irq].rtes))
                return;                 /* not an IOSAPIC interrupt */
 
        set_irq_affinity_info(irq, dest, redir);
@@ -390,31 +371,24 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
        /* dest contains both id and eid */
        high32 = dest << IOSAPIC_DEST_SHIFT;
 
-       spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               low32 = iosapic_intr_info[vec].low32 &
-                       ~(7 << IOSAPIC_DELIVERY_SHIFT);
-
-               if (redir)
-                       /* change delivery mode to lowest priority */
-                       low32 |= (IOSAPIC_LOWEST_PRIORITY <<
-                                 IOSAPIC_DELIVERY_SHIFT);
-               else
-                       /* change delivery mode to fixed */
-                       low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
-
-               iosapic_intr_info[vec].low32 = low32;
-               iosapic_intr_info[vec].dest = dest;
-               list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
-                                   rte_list) {
-                       addr = rte->addr;
-                       rte_index = rte->rte_index;
-                       iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index),
-                                     high32);
-                       iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
-               }
+       low32 = iosapic_intr_info[irq].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
+       if (redir)
+               /* change delivery mode to lowest priority */
+               low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+       else
+               /* change delivery mode to fixed */
+               low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
+       low32 &= IOSAPIC_VECTOR_MASK;
+       low32 |= irq_to_vector(irq);
+
+       iosapic_intr_info[irq].low32 = low32;
+       iosapic_intr_info[irq].dest = dest;
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+               iosapic = rte->iosapic;
+               rte_index = rte->rte_index;
+               iosapic_write(iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
+               iosapic_write(iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
        }
-       spin_unlock_irqrestore(&iosapic_lock, flags);
 #endif
 }
 
@@ -434,10 +408,20 @@ iosapic_end_level_irq (unsigned int irq)
 {
        ia64_vector vec = irq_to_vector(irq);
        struct iosapic_rte_info *rte;
+       int do_unmask_irq = 0;
 
-       move_native_irq(irq);
-       list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
-               iosapic_eoi(rte->addr, vec);
+       if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
+               do_unmask_irq = 1;
+               mask_irq(irq);
+       }
+
+       list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
+               iosapic_eoi(rte->iosapic->addr, vec);
+
+       if (unlikely(do_unmask_irq)) {
+               move_masked_irq(irq);
+               unmask_irq(irq);
+       }
 }
 
 #define iosapic_shutdown_level_irq     mask_irq
@@ -519,13 +503,12 @@ iosapic_version (char __iomem *addr)
         *      unsigned int reserved2 : 8;
         * }
         */
-       return iosapic_read(addr, IOSAPIC_VERSION);
+       return __iosapic_read(addr, IOSAPIC_VERSION);
 }
 
-static int iosapic_find_sharable_vector (unsigned long trigger,
-                                        unsigned long pol)
+static int iosapic_find_sharable_irq(unsigned long trigger, unsigned long pol)
 {
-       int i, vector = -1, min_count = -1;
+       int i, irq = -ENOSPC, min_count = -1;
        struct iosapic_intr_info *info;
 
        /*
@@ -533,21 +516,21 @@ static int iosapic_find_sharable_vector (unsigned long trigger,
         * supported yet
         */
        if (trigger == IOSAPIC_EDGE)
-               return -1;
+               return -EINVAL;
 
-       for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
+       for (i = 0; i <= NR_IRQS; i++) {
                info = &iosapic_intr_info[i];
                if (info->trigger == trigger && info->polarity == pol &&
-                   (info->dmode == IOSAPIC_FIXED || info->dmode ==
-                    IOSAPIC_LOWEST_PRIORITY)) {
+                   (info->dmode == IOSAPIC_FIXED ||
+                    info->dmode == IOSAPIC_LOWEST_PRIORITY) &&
+                   can_request_irq(i, IRQF_SHARED)) {
                        if (min_count == -1 || info->count < min_count) {
-                               vector = i;
+                               irq = i;
                                min_count = info->count;
                        }
                }
        }
-
-       return vector;
+       return irq;
 }
 
 /*
@@ -555,25 +538,25 @@ static int iosapic_find_sharable_vector (unsigned long trigger,
  *  assign a new vector for the other and make the vector available
  */
 static void __init
-iosapic_reassign_vector (int vector)
+iosapic_reassign_vector (int irq)
 {
-       int new_vector;
+       int new_irq;
 
-       if (!list_empty(&iosapic_intr_info[vector].rtes)) {
-               new_vector = assign_irq_vector(AUTO_ASSIGN);
-               if (new_vector < 0)
+       if (!list_empty(&iosapic_intr_info[irq].rtes)) {
+               new_irq = create_irq();
+               if (new_irq < 0)
                        panic("%s: out of interrupt vectors!\n", __FUNCTION__);
                printk(KERN_INFO "Reassigning vector %d to %d\n",
-                      vector, new_vector);
-               memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
+                      irq_to_vector(irq), irq_to_vector(new_irq));
+               memcpy(&iosapic_intr_info[new_irq], &iosapic_intr_info[irq],
                       sizeof(struct iosapic_intr_info));
-               INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
-               list_move(iosapic_intr_info[vector].rtes.next,
-                         &iosapic_intr_info[new_vector].rtes);
-               memset(&iosapic_intr_info[vector], 0,
+               INIT_LIST_HEAD(&iosapic_intr_info[new_irq].rtes);
+               list_move(iosapic_intr_info[irq].rtes.next,
+                         &iosapic_intr_info[new_irq].rtes);
+               memset(&iosapic_intr_info[irq], 0,
                       sizeof(struct iosapic_intr_info));
-               iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
-               INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+               iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
+               INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
        }
 }
 
@@ -610,29 +593,18 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void)
        return rte;
 }
 
-static void iosapic_free_rte (struct iosapic_rte_info *rte)
+static inline int irq_is_shared (int irq)
 {
-       if (rte->flags & RTE_PREALLOCATED)
-               list_add_tail(&rte->rte_list, &free_rte_list);
-       else
-               kfree(rte);
-}
-
-static inline int vector_is_shared (int vector)
-{
-       return (iosapic_intr_info[vector].count > 1);
+       return (iosapic_intr_info[irq].count > 1);
 }
 
 static int
-register_intr (unsigned int gsi, int vector, unsigned char delivery,
+register_intr (unsigned int gsi, int irq, unsigned char delivery,
               unsigned long polarity, unsigned long trigger)
 {
        irq_desc_t *idesc;
        struct hw_interrupt_type *irq_type;
-       int rte_index;
        int index;
-       unsigned long gsi_base;
-       void __iomem *iosapic_address;
        struct iosapic_rte_info *rte;
 
        index = find_iosapic(gsi);
@@ -642,10 +614,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
                return -ENODEV;
        }
 
-       iosapic_address = iosapic_lists[index].addr;
-       gsi_base = iosapic_lists[index].gsi_base;
-
-       rte = gsi_vector_to_rte(gsi, vector);
+       rte = find_rte(irq, gsi);
        if (!rte) {
                rte = iosapic_alloc_rte();
                if (!rte) {
@@ -654,40 +623,42 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
                        return -ENOMEM;
                }
 
-               rte_index = gsi - gsi_base;
-               rte->rte_index  = rte_index;
-               rte->addr       = iosapic_address;
-               rte->gsi_base   = gsi_base;
+               rte->iosapic    = &iosapic_lists[index];
+               rte->rte_index  = gsi - rte->iosapic->gsi_base;
                rte->refcnt++;
-               list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
-               iosapic_intr_info[vector].count++;
+               list_add_tail(&rte->rte_list, &iosapic_intr_info[irq].rtes);
+               iosapic_intr_info[irq].count++;
                iosapic_lists[index].rtes_inuse++;
        }
-       else if (vector_is_shared(vector)) {
-               struct iosapic_intr_info *info = &iosapic_intr_info[vector];
-               if (info->trigger != trigger || info->polarity != polarity) {
+       else if (rte->refcnt == NO_REF_RTE) {
+               struct iosapic_intr_info *info = &iosapic_intr_info[irq];
+               if (info->count > 0 &&
+                   (info->trigger != trigger || info->polarity != polarity)){
                        printk (KERN_WARNING
                                "%s: cannot override the interrupt\n",
                                __FUNCTION__);
                        return -EINVAL;
                }
+               rte->refcnt++;
+               iosapic_intr_info[irq].count++;
+               iosapic_lists[index].rtes_inuse++;
        }
 
-       iosapic_intr_info[vector].polarity = polarity;
-       iosapic_intr_info[vector].dmode    = delivery;
-       iosapic_intr_info[vector].trigger  = trigger;
+       iosapic_intr_info[irq].polarity = polarity;
+       iosapic_intr_info[irq].dmode    = delivery;
+       iosapic_intr_info[irq].trigger  = trigger;
 
        if (trigger == IOSAPIC_EDGE)
                irq_type = &irq_type_iosapic_edge;
        else
                irq_type = &irq_type_iosapic_level;
 
-       idesc = irq_desc + vector;
+       idesc = irq_desc + irq;
        if (idesc->chip != irq_type) {
                if (idesc->chip != &no_irq_type)
                        printk(KERN_WARNING
                               "%s: changing vector %d from %s to %s\n",
-                              __FUNCTION__, vector,
+                              __FUNCTION__, irq_to_vector(irq),
                               idesc->chip->name, irq_type->name);
                idesc->chip = irq_type;
        }
@@ -695,18 +666,19 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
 }
 
 static unsigned int
-get_target_cpu (unsigned int gsi, int vector)
+get_target_cpu (unsigned int gsi, int irq)
 {
 #ifdef CONFIG_SMP
        static int cpu = -1;
        extern int cpe_vector;
+       cpumask_t domain = irq_to_domain(irq);
 
        /*
         * In case of vector shared by multiple RTEs, all RTEs that
         * share the vector need to use the same destination CPU.
         */
-       if (!list_empty(&iosapic_intr_info[vector].rtes))
-               return iosapic_intr_info[vector].dest;
+       if (!list_empty(&iosapic_intr_info[irq].rtes))
+               return iosapic_intr_info[irq].dest;
 
        /*
         * If the platform supports redirection via XTP, let it
@@ -723,7 +695,7 @@ get_target_cpu (unsigned int gsi, int vector)
                return cpu_physical_id(smp_processor_id());
 
 #ifdef CONFIG_ACPI
-       if (cpe_vector > 0 && vector == IA64_CPEP_VECTOR)
+       if (cpe_vector > 0 && irq_to_vector(irq) == IA64_CPEP_VECTOR)
                return get_cpei_target_cpu();
 #endif
 
@@ -738,7 +710,7 @@ get_target_cpu (unsigned int gsi, int vector)
                        goto skip_numa_setup;
 
                cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node);
-
+               cpus_and(cpu_mask, cpu_mask, domain);
                for_each_cpu_mask(numa_cpu, cpu_mask) {
                        if (!cpu_online(numa_cpu))
                                cpu_clear(numa_cpu, cpu_mask);
@@ -749,8 +721,8 @@ get_target_cpu (unsigned int gsi, int vector)
                if (!num_cpus)
                        goto skip_numa_setup;
 
-               /* Use vector assignment to distribute across cpus in node */
-               cpu_index = vector % num_cpus;
+               /* Use irq assignment to distribute across cpus in node */
+               cpu_index = irq % num_cpus;
 
                for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
                        numa_cpu = next_cpu(numa_cpu, cpu_mask);
@@ -768,7 +740,7 @@ skip_numa_setup:
        do {
                if (++cpu >= NR_CPUS)
                        cpu = 0;
-       } while (!cpu_online(cpu));
+       } while (!cpu_online(cpu) || !cpu_isset(cpu, domain));
 
        return cpu_physical_id(cpu);
 #else  /* CONFIG_SMP */
@@ -785,84 +757,72 @@ int
 iosapic_register_intr (unsigned int gsi,
                       unsigned long polarity, unsigned long trigger)
 {
-       int vector, mask = 1, err;
+       int irq, mask = 1, err;
        unsigned int dest;
        unsigned long flags;
        struct iosapic_rte_info *rte;
        u32 low32;
-again:
+
        /*
         * If this GSI has already been registered (i.e., it's a
         * shared interrupt, or we lost a race to register it),
         * don't touch the RTE.
         */
        spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               vector = gsi_to_vector(gsi);
-               if (vector > 0) {
-                       rte = gsi_vector_to_rte(gsi, vector);
+       irq = __gsi_to_irq(gsi);
+       if (irq > 0) {
+               rte = find_rte(irq, gsi);
+               if(iosapic_intr_info[irq].count == 0) {
+                       assign_irq_vector(irq);
+                       dynamic_irq_init(irq);
+               } else if (rte->refcnt != NO_REF_RTE) {
                        rte->refcnt++;
-                       spin_unlock_irqrestore(&iosapic_lock, flags);
-                       return vector;
+                       goto unlock_iosapic_lock;
                }
-       }
-       spin_unlock_irqrestore(&iosapic_lock, flags);
+       } else
+               irq = create_irq();
 
        /* If vector is running out, we try to find a sharable vector */
-       vector = assign_irq_vector(AUTO_ASSIGN);
-       if (vector < 0) {
-               vector = iosapic_find_sharable_vector(trigger, polarity);
-               if (vector < 0)
-                       return -ENOSPC;
+       if (irq < 0) {
+               irq = iosapic_find_sharable_irq(trigger, polarity);
+               if (irq < 0)
+                       goto unlock_iosapic_lock;
        }
 
-       spin_lock_irqsave(&irq_desc[vector].lock, flags);
-       spin_lock(&iosapic_lock);
-       {
-               if (gsi_to_vector(gsi) > 0) {
-                       if (list_empty(&iosapic_intr_info[vector].rtes))
-                               free_irq_vector(vector);
-                       spin_unlock(&iosapic_lock);
-                       spin_unlock_irqrestore(&irq_desc[vector].lock,
-                                              flags);
-                       goto again;
-               }
-
-               dest = get_target_cpu(gsi, vector);
-               err = register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
-                             polarity, trigger);
-               if (err < 0) {
-                       spin_unlock(&iosapic_lock);
-                       spin_unlock_irqrestore(&irq_desc[vector].lock,
-                                              flags);
-                       return err;
-               }
-
-               /*
-                * If the vector is shared and already unmasked for
-                * other interrupt sources, don't mask it.
-                */
-               low32 = iosapic_intr_info[vector].low32;
-               if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
-                       mask = 0;
-               set_rte(gsi, vector, dest, mask);
+       spin_lock(&irq_desc[irq].lock);
+       dest = get_target_cpu(gsi, irq);
+       err = register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY,
+                           polarity, trigger);
+       if (err < 0) {
+               irq = err;
+               goto unlock_all;
        }
-       spin_unlock(&iosapic_lock);
-       spin_unlock_irqrestore(&irq_desc[vector].lock, flags);
+
+       /*
+        * If the vector is shared and already unmasked for other
+        * interrupt sources, don't mask it.
+        */
+       low32 = iosapic_intr_info[irq].low32;
+       if (irq_is_shared(irq) && !(low32 & IOSAPIC_MASK))
+               mask = 0;
+       set_rte(gsi, irq, dest, mask);
 
        printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
               gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
               (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-              cpu_logical_id(dest), dest, vector);
-
-       return vector;
+              cpu_logical_id(dest), dest, irq_to_vector(irq));
+ unlock_all:
+       spin_unlock(&irq_desc[irq].lock);
+ unlock_iosapic_lock:
+       spin_unlock_irqrestore(&iosapic_lock, flags);
+       return irq;
 }
 
 void
 iosapic_unregister_intr (unsigned int gsi)
 {
        unsigned long flags;
-       int irq, vector, index;
+       int irq, index;
        irq_desc_t *idesc;
        u32 low32;
        unsigned long trigger, polarity;
@@ -881,78 +841,56 @@ iosapic_unregister_intr (unsigned int gsi)
                WARN_ON(1);
                return;
        }
-       vector = irq_to_vector(irq);
 
-       idesc = irq_desc + irq;
-       spin_lock_irqsave(&idesc->lock, flags);
-       spin_lock(&iosapic_lock);
-       {
-               if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
-                       printk(KERN_ERR
-                              "iosapic_unregister_intr(%u) unbalanced\n",
-                              gsi);
-                       WARN_ON(1);
-                       goto out;
-               }
+       spin_lock_irqsave(&iosapic_lock, flags);
+       if ((rte = find_rte(irq, gsi)) == NULL) {
+               printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",
+                      gsi);
+               WARN_ON(1);
+               goto out;
+       }
 
-               if (--rte->refcnt > 0)
-                       goto out;
+       if (--rte->refcnt > 0)
+               goto out;
 
-               /* Mask the interrupt */
-               low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
-               iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index),
-                             low32);
+       idesc = irq_desc + irq;
+       rte->refcnt = NO_REF_RTE;
 
-               /* Remove the rte entry from the list */
-               list_del(&rte->rte_list);
-               iosapic_intr_info[vector].count--;
-               iosapic_free_rte(rte);
-               index = find_iosapic(gsi);
-               iosapic_lists[index].rtes_inuse--;
-               WARN_ON(iosapic_lists[index].rtes_inuse < 0);
-
-               trigger  = iosapic_intr_info[vector].trigger;
-               polarity = iosapic_intr_info[vector].polarity;
-               dest     = iosapic_intr_info[vector].dest;
-               printk(KERN_INFO
-                      "GSI %u (%s, %s) -> CPU %d (0x%04x)"
-                      " vector %d unregistered\n",
-                      gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
-                      (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-                      cpu_logical_id(dest), dest, vector);
+       /* Mask the interrupt */
+       low32 = iosapic_intr_info[irq].low32 | IOSAPIC_MASK;
+       iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32);
 
-               if (list_empty(&iosapic_intr_info[vector].rtes)) {
-                       /* Sanity check */
-                       BUG_ON(iosapic_intr_info[vector].count);
+       iosapic_intr_info[irq].count--;
+       index = find_iosapic(gsi);
+       iosapic_lists[index].rtes_inuse--;
+       WARN_ON(iosapic_lists[index].rtes_inuse < 0);
 
-                       /* Clear the interrupt controller descriptor */
-                       idesc->chip = &no_irq_type;
+       trigger  = iosapic_intr_info[irq].trigger;
+       polarity = iosapic_intr_info[irq].polarity;
+       dest     = iosapic_intr_info[irq].dest;
+       printk(KERN_INFO
+              "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
+              gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+              (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+              cpu_logical_id(dest), dest, irq_to_vector(irq));
 
+       if (iosapic_intr_info[irq].count == 0) {
 #ifdef CONFIG_SMP
-                       /* Clear affinity */
-                       cpus_setall(idesc->affinity);
+               /* Clear affinity */
+               cpus_setall(idesc->affinity);
 #endif
-
-                       /* Clear the interrupt information */
-                       memset(&iosapic_intr_info[vector], 0,
-                              sizeof(struct iosapic_intr_info));
-                       iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
-                       INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
-
-                       if (idesc->action) {
-                               printk(KERN_ERR
-                                      "interrupt handlers still exist on"
-                                      "IRQ %u\n", irq);
-                               WARN_ON(1);
-                       }
-
-                       /* Free the interrupt vector */
-                       free_irq_vector(vector);
-               }
+               /* Clear the interrupt information */
+               iosapic_intr_info[irq].dest = 0;
+               iosapic_intr_info[irq].dmode = 0;
+               iosapic_intr_info[irq].polarity = 0;
+               iosapic_intr_info[irq].trigger = 0;
+               iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
+
+               /* Destroy and reserve IRQ */
+               destroy_and_reserve_irq(irq);
        }
  out:
-       spin_unlock(&iosapic_lock);
-       spin_unlock_irqrestore(&idesc->lock, flags);
+       spin_unlock_irqrestore(&iosapic_lock, flags);
 }
 
 /*
@@ -965,27 +903,30 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
 {
        static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
        unsigned char delivery;
-       int vector, mask = 0;
+       int irq, vector, mask = 0;
        unsigned int dest = ((id << 8) | eid) & 0xffff;
 
        switch (int_type) {
              case ACPI_INTERRUPT_PMI:
-               vector = iosapic_vector;
+               irq = vector = iosapic_vector;
+               bind_irq_vector(irq, vector, CPU_MASK_ALL);
                /*
                 * since PMI vector is alloc'd by FW(ACPI) not by kernel,
                 * we need to make sure the vector is available
                 */
-               iosapic_reassign_vector(vector);
+               iosapic_reassign_vector(irq);
                delivery = IOSAPIC_PMI;
                break;
              case ACPI_INTERRUPT_INIT:
-               vector = assign_irq_vector(AUTO_ASSIGN);
-               if (vector < 0)
+               irq = create_irq();
+               if (irq < 0)
                        panic("%s: out of interrupt vectors!\n", __FUNCTION__);
+               vector = irq_to_vector(irq);
                delivery = IOSAPIC_INIT;
                break;
              case ACPI_INTERRUPT_CPEI:
-               vector = IA64_CPE_VECTOR;
+               irq = vector = IA64_CPE_VECTOR;
+               BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));
                delivery = IOSAPIC_LOWEST_PRIORITY;
                mask = 1;
                break;
@@ -995,7 +936,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
                return -1;
        }
 
-       register_intr(gsi, vector, delivery, polarity, trigger);
+       register_intr(gsi, irq, delivery, polarity, trigger);
 
        printk(KERN_INFO
               "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)"
@@ -1005,7 +946,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
               (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
               cpu_logical_id(dest), dest, vector);
 
-       set_rte(gsi, vector, dest, mask);
+       set_rte(gsi, irq, dest, mask);
        return vector;
 }
 
@@ -1017,30 +958,32 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
                          unsigned long polarity,
                          unsigned long trigger)
 {
-       int vector;
+       int vector, irq;
        unsigned int dest = cpu_physical_id(smp_processor_id());
 
-       vector = isa_irq_to_vector(isa_irq);
-
-       register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
+       irq = vector = isa_irq_to_vector(isa_irq);
+       BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));
+       register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
 
        DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
            isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
            polarity == IOSAPIC_POL_HIGH ? "high" : "low",
            cpu_logical_id(dest), dest, vector);
 
-       set_rte(gsi, vector, dest, 1);
+       set_rte(gsi, irq, dest, 1);
 }
 
 void __init
 iosapic_system_init (int system_pcat_compat)
 {
-       int vector;
+       int irq;
 
-       for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
-               iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
+       for (irq = 0; irq < NR_IRQS; ++irq) {
+               iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
                /* mark as unused */
-               INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+               INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
+
+               iosapic_intr_info[irq].count = 0;
        }
 
        pcat_compat = system_pcat_compat;
@@ -1108,31 +1051,35 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
        unsigned long flags;
 
        spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               addr = ioremap(phys_addr, 0);
-               ver = iosapic_version(addr);
+       index = find_iosapic(gsi_base);
+       if (index >= 0) {
+               spin_unlock_irqrestore(&iosapic_lock, flags);
+               return -EBUSY;
+       }
 
-               if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
-                       iounmap(addr);
-                       spin_unlock_irqrestore(&iosapic_lock, flags);
-                       return err;
-               }
+       addr = ioremap(phys_addr, 0);
+       ver = iosapic_version(addr);
+       if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
+               iounmap(addr);
+               spin_unlock_irqrestore(&iosapic_lock, flags);
+               return err;
+       }
 
-               /*
-                * The MAX_REDIR register holds the highest input pin
-                * number (starting from 0).
-                * We add 1 so that we can use it for number of pins (= RTEs)
-                */
-               num_rte = ((ver >> 16) & 0xff) + 1;
+       /*
+        * The MAX_REDIR register holds the highest input pin number
+        * (starting from 0).  We add 1 so that we can use it for
+        * number of pins (= RTEs)
+        */
+       num_rte = ((ver >> 16) & 0xff) + 1;
 
-               index = iosapic_alloc();
-               iosapic_lists[index].addr = addr;
-               iosapic_lists[index].gsi_base = gsi_base;
-               iosapic_lists[index].num_rte = num_rte;
+       index = iosapic_alloc();
+       iosapic_lists[index].addr = addr;
+       iosapic_lists[index].gsi_base = gsi_base;
+       iosapic_lists[index].num_rte = num_rte;
 #ifdef CONFIG_NUMA
-               iosapic_lists[index].node = MAX_NUMNODES;
+       iosapic_lists[index].node = MAX_NUMNODES;
 #endif
-       }
+       spin_lock_init(&iosapic_lists[index].lock);
        spin_unlock_irqrestore(&iosapic_lock, flags);
 
        if ((gsi_base == 0) && pcat_compat) {
@@ -1157,25 +1104,22 @@ iosapic_remove (unsigned int gsi_base)
        unsigned long flags;
 
        spin_lock_irqsave(&iosapic_lock, flags);
-       {
-               index = find_iosapic(gsi_base);
-               if (index < 0) {
-                       printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
-                              __FUNCTION__, gsi_base);
-                       goto out;
-               }
-
-               if (iosapic_lists[index].rtes_inuse) {
-                       err = -EBUSY;
-                       printk(KERN_WARNING
-                              "%s: IOSAPIC for GSI base %u is busy\n",
-                              __FUNCTION__, gsi_base);
-                       goto out;
-               }
+       index = find_iosapic(gsi_base);
+       if (index < 0) {
+               printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
+                      __FUNCTION__, gsi_base);
+               goto out;
+       }
 
-               iounmap(iosapic_lists[index].addr);
-               iosapic_free(index);
+       if (iosapic_lists[index].rtes_inuse) {
+               err = -EBUSY;
+               printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
+                      __FUNCTION__, gsi_base);
+               goto out;
        }
+
+       iounmap(iosapic_lists[index].addr);
+       iosapic_free(index);
  out:
        spin_unlock_irqrestore(&iosapic_lock, flags);
        return err;
index 407b45870489ebb6cb5024dde6eefa00809c9596..cc3ee4ef37afb1bbfed332481f8b9e787b91ae38 100644 (file)
@@ -35,7 +35,7 @@ void ack_bad_irq(unsigned int irq)
 #ifdef CONFIG_IA64_GENERIC
 unsigned int __ia64_local_vector_to_irq (ia64_vector vec)
 {
-       return (unsigned int) vec;
+       return __get_cpu_var(vector_irq)[vec];
 }
 #endif
 
index bc47049f060f6348e5bb0a19874d89da86b131f6..91797c11116218a254fdfe5496bbb19561ee9320 100644 (file)
 
 #define IRQ_DEBUG      0
 
+#define IRQ_VECTOR_UNASSIGNED  (0)
+
+#define IRQ_UNUSED             (0)
+#define IRQ_USED               (1)
+#define IRQ_RSVD               (2)
+
 /* These can be overridden in platform_irq_init */
 int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
 int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
@@ -54,6 +60,8 @@ int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
 void __iomem *ipi_base_addr = ((void __iomem *)
                               (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
 
+static cpumask_t vector_allocation_domain(int cpu);
+
 /*
  * Legacy IRQ to IA-64 vector translation table.
  */
@@ -64,46 +72,269 @@ __u8 isa_irq_to_vector_map[16] = {
 };
 EXPORT_SYMBOL(isa_irq_to_vector_map);
 
-static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];
+DEFINE_SPINLOCK(vector_lock);
+
+struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
+       [0 ... NR_IRQS - 1] = {
+               .vector = IRQ_VECTOR_UNASSIGNED,
+               .domain = CPU_MASK_NONE
+       }
+};
+
+DEFINE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq) = {
+       [0 ... IA64_NUM_VECTORS - 1] = IA64_SPURIOUS_INT_VECTOR
+};
+
+static cpumask_t vector_table[IA64_MAX_DEVICE_VECTORS] = {
+       [0 ... IA64_MAX_DEVICE_VECTORS - 1] = CPU_MASK_NONE
+};
+
+static int irq_status[NR_IRQS] = {
+       [0 ... NR_IRQS -1] = IRQ_UNUSED
+};
+
+int check_irq_used(int irq)
+{
+       if (irq_status[irq] == IRQ_USED)
+               return 1;
+
+       return -1;
+}
+
+static void reserve_irq(unsigned int irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       irq_status[irq] = IRQ_RSVD;
+       spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+static inline int find_unassigned_irq(void)
+{
+       int irq;
+
+       for (irq = IA64_FIRST_DEVICE_VECTOR; irq < NR_IRQS; irq++)
+               if (irq_status[irq] == IRQ_UNUSED)
+                       return irq;
+       return -ENOSPC;
+}
+
+static inline int find_unassigned_vector(cpumask_t domain)
+{
+       cpumask_t mask;
+       int pos;
+
+       cpus_and(mask, domain, cpu_online_map);
+       if (cpus_empty(mask))
+               return -EINVAL;
+
+       for (pos = 0; pos < IA64_NUM_DEVICE_VECTORS; pos++) {
+               cpus_and(mask, domain, vector_table[pos]);
+               if (!cpus_empty(mask))
+                       continue;
+               return IA64_FIRST_DEVICE_VECTOR + pos;
+       }
+       return -ENOSPC;
+}
+
+static int __bind_irq_vector(int irq, int vector, cpumask_t domain)
+{
+       cpumask_t mask;
+       int cpu, pos;
+       struct irq_cfg *cfg = &irq_cfg[irq];
+
+       cpus_and(mask, domain, cpu_online_map);
+       if (cpus_empty(mask))
+               return -EINVAL;
+       if ((cfg->vector == vector) && cpus_equal(cfg->domain, domain))
+               return 0;
+       if (cfg->vector != IRQ_VECTOR_UNASSIGNED)
+               return -EBUSY;
+       for_each_cpu_mask(cpu, mask)
+               per_cpu(vector_irq, cpu)[vector] = irq;
+       cfg->vector = vector;
+       cfg->domain = domain;
+       irq_status[irq] = IRQ_USED;
+       pos = vector - IA64_FIRST_DEVICE_VECTOR;
+       cpus_or(vector_table[pos], vector_table[pos], domain);
+       return 0;
+}
+
+int bind_irq_vector(int irq, int vector, cpumask_t domain)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       ret = __bind_irq_vector(irq, vector, domain);
+       spin_unlock_irqrestore(&vector_lock, flags);
+       return ret;
+}
+
+static void __clear_irq_vector(int irq)
+{
+       int vector, cpu, pos;
+       cpumask_t mask;
+       cpumask_t domain;
+       struct irq_cfg *cfg = &irq_cfg[irq];
+
+       BUG_ON((unsigned)irq >= NR_IRQS);
+       BUG_ON(cfg->vector == IRQ_VECTOR_UNASSIGNED);
+       vector = cfg->vector;
+       domain = cfg->domain;
+       cpus_and(mask, cfg->domain, cpu_online_map);
+       for_each_cpu_mask(cpu, mask)
+               per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
+       cfg->vector = IRQ_VECTOR_UNASSIGNED;
+       cfg->domain = CPU_MASK_NONE;
+       irq_status[irq] = IRQ_UNUSED;
+       pos = vector - IA64_FIRST_DEVICE_VECTOR;
+       cpus_andnot(vector_table[pos], vector_table[pos], domain);
+}
+
+static void clear_irq_vector(int irq)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       __clear_irq_vector(irq);
+       spin_unlock_irqrestore(&vector_lock, flags);
+}
 
 int
 assign_irq_vector (int irq)
 {
-       int pos, vector;
- again:
-       pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
-       vector = IA64_FIRST_DEVICE_VECTOR + pos;
-       if (vector > IA64_LAST_DEVICE_VECTOR)
-               return -ENOSPC;
-       if (test_and_set_bit(pos, ia64_vector_mask))
-               goto again;
+       unsigned long flags;
+       int vector, cpu;
+       cpumask_t domain;
+
+       vector = -ENOSPC;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       if (irq < 0) {
+               goto out;
+       }
+       for_each_online_cpu(cpu) {
+               domain = vector_allocation_domain(cpu);
+               vector = find_unassigned_vector(domain);
+               if (vector >= 0)
+                       break;
+       }
+       if (vector < 0)
+               goto out;
+       BUG_ON(__bind_irq_vector(irq, vector, domain));
+ out:
+       spin_unlock_irqrestore(&vector_lock, flags);
        return vector;
 }
 
 void
 free_irq_vector (int vector)
 {
-       int pos;
-
-       if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
+       if (vector < IA64_FIRST_DEVICE_VECTOR ||
+           vector > IA64_LAST_DEVICE_VECTOR)
                return;
-
-       pos = vector - IA64_FIRST_DEVICE_VECTOR;
-       if (!test_and_clear_bit(pos, ia64_vector_mask))
-               printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
+       clear_irq_vector(vector);
 }
 
 int
 reserve_irq_vector (int vector)
 {
-       int pos;
-
        if (vector < IA64_FIRST_DEVICE_VECTOR ||
            vector > IA64_LAST_DEVICE_VECTOR)
                return -EINVAL;
+       return !!bind_irq_vector(vector, vector, CPU_MASK_ALL);
+}
 
-       pos = vector - IA64_FIRST_DEVICE_VECTOR;
-       return test_and_set_bit(pos, ia64_vector_mask);
+/*
+ * Initialize vector_irq on a new cpu. This function must be called
+ * with vector_lock held.
+ */
+void __setup_vector_irq(int cpu)
+{
+       int irq, vector;
+
+       /* Clear vector_irq */
+       for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
+               per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
+       /* Mark the inuse vectors */
+       for (irq = 0; irq < NR_IRQS; ++irq) {
+               if (!cpu_isset(cpu, irq_cfg[irq].domain))
+                       continue;
+               vector = irq_to_vector(irq);
+               per_cpu(vector_irq, cpu)[vector] = irq;
+       }
+}
+
+#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG))
+static enum vector_domain_type {
+       VECTOR_DOMAIN_NONE,
+       VECTOR_DOMAIN_PERCPU
+} vector_domain_type = VECTOR_DOMAIN_NONE;
+
+static cpumask_t vector_allocation_domain(int cpu)
+{
+       if (vector_domain_type == VECTOR_DOMAIN_PERCPU)
+               return cpumask_of_cpu(cpu);
+       return CPU_MASK_ALL;
+}
+
+static int __init parse_vector_domain(char *arg)
+{
+       if (!arg)
+               return -EINVAL;
+       if (!strcmp(arg, "percpu")) {
+               vector_domain_type = VECTOR_DOMAIN_PERCPU;
+               no_int_routing = 1;
+       }
+       return 1;
+}
+early_param("vector", parse_vector_domain);
+#else
+static cpumask_t vector_allocation_domain(int cpu)
+{
+       return CPU_MASK_ALL;
+}
+#endif
+
+
+void destroy_and_reserve_irq(unsigned int irq)
+{
+       dynamic_irq_cleanup(irq);
+
+       clear_irq_vector(irq);
+       reserve_irq(irq);
+}
+
+static int __reassign_irq_vector(int irq, int cpu)
+{
+       struct irq_cfg *cfg = &irq_cfg[irq];
+       int vector;
+       cpumask_t domain;
+
+       if (cfg->vector == IRQ_VECTOR_UNASSIGNED || !cpu_online(cpu))
+               return -EINVAL;
+       if (cpu_isset(cpu, cfg->domain))
+               return 0;
+       domain = vector_allocation_domain(cpu);
+       vector = find_unassigned_vector(domain);
+       if (vector < 0)
+               return -ENOSPC;
+       __clear_irq_vector(irq);
+       BUG_ON(__bind_irq_vector(irq, vector, domain));
+       return 0;
+}
+
+int reassign_irq_vector(int irq, int cpu)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&vector_lock, flags);
+       ret = __reassign_irq_vector(irq, cpu);
+       spin_unlock_irqrestore(&vector_lock, flags);
+       return ret;
 }
 
 /*
@@ -111,18 +342,35 @@ reserve_irq_vector (int vector)
  */
 int create_irq(void)
 {
-       int vector = assign_irq_vector(AUTO_ASSIGN);
-
-       if (vector >= 0)
-               dynamic_irq_init(vector);
-
-       return vector;
+       unsigned long flags;
+       int irq, vector, cpu;
+       cpumask_t domain;
+
+       irq = vector = -ENOSPC;
+       spin_lock_irqsave(&vector_lock, flags);
+       for_each_online_cpu(cpu) {
+               domain = vector_allocation_domain(cpu);
+               vector = find_unassigned_vector(domain);
+               if (vector >= 0)
+                       break;
+       }
+       if (vector < 0)
+               goto out;
+       irq = find_unassigned_irq();
+       if (irq < 0)
+               goto out;
+       BUG_ON(__bind_irq_vector(irq, vector, domain));
+ out:
+       spin_unlock_irqrestore(&vector_lock, flags);
+       if (irq >= 0)
+               dynamic_irq_init(irq);
+       return irq;
 }
 
 void destroy_irq(unsigned int irq)
 {
        dynamic_irq_cleanup(irq);
-       free_irq_vector(irq);
+       clear_irq_vector(irq);
 }
 
 #ifdef CONFIG_SMP
@@ -301,14 +549,13 @@ register_percpu_irq (ia64_vector vec, struct irqaction *action)
        irq_desc_t *desc;
        unsigned int irq;
 
-       for (irq = 0; irq < NR_IRQS; ++irq)
-               if (irq_to_vector(irq) == vec) {
-                       desc = irq_desc + irq;
-                       desc->status |= IRQ_PER_CPU;
-                       desc->chip = &irq_type_ia64_lsapic;
-                       if (action)
-                               setup_irq(irq, action);
-               }
+       irq = vec;
+       BUG_ON(bind_irq_vector(irq, vec, CPU_MASK_ALL));
+       desc = irq_desc + irq;
+       desc->status |= IRQ_PER_CPU;
+       desc->chip = &irq_type_ia64_lsapic;
+       if (action)
+               setup_irq(irq, action);
 }
 
 void __init
index c81080df70df47244579c1edeebef9969b6769bd..2fdbd5c3f21342beb82046bc4ca6c4c3d08b50b5 100644 (file)
@@ -13,6 +13,7 @@
 
 #define MSI_DATA_VECTOR_SHIFT          0
 #define            MSI_DATA_VECTOR(v)          (((u8)v) << MSI_DATA_VECTOR_SHIFT)
+#define MSI_DATA_VECTOR_MASK           0xffffff00
 
 #define MSI_DATA_DELIVERY_SHIFT                8
 #define     MSI_DATA_DELIVERY_FIXED    (0 << MSI_DATA_DELIVERY_SHIFT)
@@ -50,17 +51,29 @@ static struct irq_chip      ia64_msi_chip;
 static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
 {
        struct msi_msg msg;
-       u32 addr;
+       u32 addr, data;
+       int cpu = first_cpu(cpu_mask);
+
+       if (!cpu_online(cpu))
+               return;
+
+       if (reassign_irq_vector(irq, cpu))
+               return;
 
        read_msi_msg(irq, &msg);
 
        addr = msg.address_lo;
        addr &= MSI_ADDR_DESTID_MASK;
-       addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
+       addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(cpu));
        msg.address_lo = addr;
 
+       data = msg.data;
+       data &= MSI_DATA_VECTOR_MASK;
+       data |= MSI_DATA_VECTOR(irq_to_vector(irq));
+       msg.data = data;
+
        write_msi_msg(irq, &msg);
-       irq_desc[irq].affinity = cpu_mask;
+       irq_desc[irq].affinity = cpumask_of_cpu(cpu);
 }
 #endif /* CONFIG_SMP */
 
@@ -69,13 +82,15 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
        struct msi_msg  msg;
        unsigned long   dest_phys_id;
        int     irq, vector;
+       cpumask_t mask;
 
        irq = create_irq();
        if (irq < 0)
                return irq;
 
        set_irq_msi(irq, desc);
-       dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+       cpus_and(mask, irq_to_domain(irq), cpu_online_map);
+       dest_phys_id = cpu_physical_id(first_cpu(mask));
        vector = irq_to_vector(irq);
 
        msg.address_hi = 0;
index 3c9d8e6089cf9b5134bca8e86610dfe810891415..9f5c90b594b9361bf839c15b99a41d89bf9f28ce 100644 (file)
@@ -395,9 +395,13 @@ smp_callin (void)
        fix_b0_for_bsp();
 
        lock_ipi_calllock();
+       spin_lock(&vector_lock);
+       /* Setup the per cpu irq handling data structures */
+       __setup_vector_irq(cpuid);
        cpu_set(cpuid, cpu_online_map);
        unlock_ipi_calllock();
        per_cpu(cpu_state, cpuid) = CPU_ONLINE;
+       spin_unlock(&vector_lock);
 
        smp_setup_percpu_timer();
 
index 3486fe7d6e65df00db95a4b93ff442cc2b14090d..627785c48ea95e495389653b5bfdc320967247df 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/efi.h>
 #include <linux/timex.h>
+#include <linux/clocksource.h>
 
 #include <asm/machvec.h>
 #include <asm/delay.h>
 #include <asm/sections.h>
 #include <asm/system.h>
 
+#include "fsyscall_gtod_data.h"
+
+static cycle_t itc_get_cycles(void);
+
+struct fsyscall_gtod_data_t fsyscall_gtod_data = {
+       .lock = SEQLOCK_UNLOCKED,
+};
+
+struct itc_jitter_data_t itc_jitter_data;
+
 volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
 
 #ifdef CONFIG_IA64_DEBUG_IRQ
@@ -37,11 +48,16 @@ EXPORT_SYMBOL(last_cli_ip);
 
 #endif
 
-static struct time_interpolator itc_interpolator = {
-       .shift = 16,
-       .mask = 0xffffffffffffffffLL,
-       .source = TIME_SOURCE_CPU
+static struct clocksource clocksource_itc = {
+        .name           = "itc",
+        .rating         = 350,
+        .read           = itc_get_cycles,
+        .mask           = 0xffffffffffffffff,
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 16,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
+static struct clocksource *itc_clocksource;
 
 static irqreturn_t
 timer_interrupt (int irq, void *dev_id)
@@ -210,8 +226,6 @@ ia64_init_itm (void)
                                        + itc_freq/2)/itc_freq;
 
        if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
-               itc_interpolator.frequency = local_cpu_data->itc_freq;
-               itc_interpolator.drift = itc_drift;
 #ifdef CONFIG_SMP
                /* On IA64 in an SMP configuration ITCs are never accurately synchronized.
                 * Jitter compensation requires a cmpxchg which may limit
@@ -223,15 +237,50 @@ ia64_init_itm (void)
                 * even going backward) if the ITC offsets between the individual CPUs
                 * are too large.
                 */
-               if (!nojitter) itc_interpolator.jitter = 1;
+               if (!nojitter)
+                       itc_jitter_data.itc_jitter = 1;
 #endif
-               register_time_interpolator(&itc_interpolator);
        }
 
        /* Setup the CPU local timer tick */
        ia64_cpu_local_tick();
+
+       if (!itc_clocksource) {
+               /* Sort out mult/shift values: */
+               clocksource_itc.mult =
+                       clocksource_hz2mult(local_cpu_data->itc_freq,
+                                               clocksource_itc.shift);
+               clocksource_register(&clocksource_itc);
+               itc_clocksource = &clocksource_itc;
+       }
 }
 
+static cycle_t itc_get_cycles()
+{
+       u64 lcycle, now, ret;
+
+       if (!itc_jitter_data.itc_jitter)
+               return get_cycles();
+
+       lcycle = itc_jitter_data.itc_lastcycle;
+       now = get_cycles();
+       if (lcycle && time_after(lcycle, now))
+               return lcycle;
+
+       /*
+        * Keep track of the last timer value returned.
+        * In an SMP environment, you could lose out in contention of
+        * cmpxchg. If so, your cmpxchg returns new value which the
+        * winner of contention updated to. Use the new value instead.
+        */
+       ret = cmpxchg(&itc_jitter_data.itc_lastcycle, lcycle, now);
+       if (unlikely(ret != lcycle))
+               return ret;
+
+       return now;
+}
+
+
 static struct irqaction timer_irqaction = {
        .handler =      timer_interrupt,
        .flags =        IRQF_DISABLED | IRQF_IRQPOLL,
@@ -307,3 +356,34 @@ ia64_setup_printk_clock(void)
        if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
                ia64_printk_clock = ia64_itc_printk_clock;
 }
+
+void update_vsyscall(struct timespec *wall, struct clocksource *c)
+{
+        unsigned long flags;
+
+        write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags);
+
+        /* copy fsyscall clock data */
+        fsyscall_gtod_data.clk_mask = c->mask;
+        fsyscall_gtod_data.clk_mult = c->mult;
+        fsyscall_gtod_data.clk_shift = c->shift;
+        fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio;
+        fsyscall_gtod_data.clk_cycle_last = c->cycle_last;
+
+       /* copy kernel time structures */
+        fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec;
+        fsyscall_gtod_data.wall_time.tv_nsec = wall->tv_nsec;
+        fsyscall_gtod_data.monotonic_time.tv_sec = wall_to_monotonic.tv_sec
+                                                       + wall->tv_sec;
+        fsyscall_gtod_data.monotonic_time.tv_nsec = wall_to_monotonic.tv_nsec
+                                                       + wall->tv_nsec;
+
+       /* normalize */
+       while (fsyscall_gtod_data.monotonic_time.tv_nsec >= NSEC_PER_SEC) {
+               fsyscall_gtod_data.monotonic_time.tv_nsec -= NSEC_PER_SEC;
+               fsyscall_gtod_data.monotonic_time.tv_sec++;
+       }
+
+        write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags);
+}
+
index 56a88b6df4b41fbca0df635ab5fc23988b0298b4..19e25d2b64fcabdd003c7e239cf8938cc8200383 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
+#include <linux/clocksource.h>
 
 #include <asm/hw_irq.h>
 #include <asm/system.h>
 
 extern unsigned long sn_rtc_cycles_per_second;
 
-static struct time_interpolator sn2_interpolator = {
-       .drift = -1,
-       .shift = 10,
-       .mask = (1LL << 55) - 1,
-       .source = TIME_SOURCE_MMIO64
+static void __iomem *sn2_mc;
+
+static cycle_t read_sn2(void)
+{
+       return (cycle_t)readq(sn2_mc);
+}
+
+static struct clocksource clocksource_sn2 = {
+        .name           = "sn2_rtc",
+        .rating         = 300,
+        .read           = read_sn2,
+        .mask           = (1LL << 55) - 1,
+        .mult           = 0,
+        .shift          = 10,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 /*
@@ -47,9 +58,11 @@ ia64_sn_udelay (unsigned long usecs)
 
 void __init sn_timer_init(void)
 {
-       sn2_interpolator.frequency = sn_rtc_cycles_per_second;
-       sn2_interpolator.addr = RTC_COUNTER_ADDR;
-       register_time_interpolator(&sn2_interpolator);
+       sn2_mc = RTC_COUNTER_ADDR;
+       clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR;
+       clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
+                                                       clocksource_sn2.shift);
+       clocksource_register(&clocksource_sn2);
 
        ia64_udelay = &ia64_sn_udelay;
 }
index a86e2e9a639fff5c20a9378cf9f27c52158a4623..20a9c08e59c34ee34b21adb100b33014c99a39ff 100644 (file)
@@ -37,6 +37,10 @@ config TIME_LOW_RES
        bool
        default y
 
+config GENERIC_IOMAP
+       bool
+       default y
+
 config ARCH_MAY_HAVE_PC_FDC
        bool
        depends on Q40 || (BROKEN && SUN3X)
@@ -45,6 +49,9 @@ config ARCH_MAY_HAVE_PC_FDC
 config NO_IOPORT
        def_bool y
 
+config NO_DMA
+       def_bool SUN3
+
 mainmenu "Linux/68k Kernel Configuration"
 
 source "init/Kconfig"
index cb8e7609df4c1308ef105864d88030a318ff0634..78df98f2029af9e5556f33973c71949da070a8fc 100644 (file)
@@ -148,8 +148,8 @@ void dn_serial_print (const char *str)
     }
 }
 
-void config_apollo(void) {
-
+void __init config_apollo(void)
+{
        int i;
 
        dn_setup_model();
index 13bd41bed28e52d600ef76e6d0beaa4abee33b62..5d47f3aa3810fb0d5af3abab09a01156fa6b2a7f 100644 (file)
@@ -37,7 +37,7 @@ static struct irq_controller apollo_irq_controller = {
 };
 
 
-void dn_init_IRQ(void)
+void __init dn_init_IRQ(void)
 {
        m68k_setup_user_interrupt(VEC_USER + 96, 16, dn_process_int);
        m68k_setup_irq_controller(&apollo_irq_controller, IRQ_APOLLO, 16);
index 1c29603b16b31058cd47c6e644b1921d24859a84..2b5f64726a2e88ff851c4c02119f5729e7947d80 100644 (file)
@@ -13,6 +13,7 @@
  * enhanced by Bjoern Brauel and Roman Hodek
  */
 
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
@@ -42,6 +43,9 @@ void (*atari_mouse_interrupt_hook) (char *);
 void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
 /* Hook for mouse inputdev  driver */
 void (*atari_input_mouse_interrupt_hook) (char *);
+EXPORT_SYMBOL(atari_mouse_interrupt_hook);
+EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook);
+EXPORT_SYMBOL(atari_input_mouse_interrupt_hook);
 
 /* variables for IKBD self test: */
 
@@ -429,6 +433,7 @@ void ikbd_mouse_rel_pos(void)
 
        ikbd_write(cmd, 1);
 }
+EXPORT_SYMBOL(ikbd_mouse_rel_pos);
 
 /* Set absolute mouse position reporting */
 void ikbd_mouse_abs_pos(int xmax, int ymax)
@@ -453,6 +458,7 @@ void ikbd_mouse_thresh(int x, int y)
 
        ikbd_write(cmd, 3);
 }
+EXPORT_SYMBOL(ikbd_mouse_thresh);
 
 /* Set mouse scale */
 void ikbd_mouse_scale(int x, int y)
@@ -495,6 +501,7 @@ void ikbd_mouse_y0_top(void)
 
        ikbd_write(cmd, 1);
 }
+EXPORT_SYMBOL(ikbd_mouse_y0_top);
 
 /* Resume */
 void ikbd_resume(void)
@@ -511,6 +518,7 @@ void ikbd_mouse_disable(void)
 
        ikbd_write(cmd, 1);
 }
+EXPORT_SYMBOL(ikbd_mouse_disable);
 
 /* Pause output */
 void ikbd_pause(void)
@@ -696,7 +704,6 @@ int __init atari_keyb_init(void)
        return 0;
 }
 
-
 int atari_kbdrate(struct kbd_repeat *k)
 {
        if (k->delay > 0) {
index 896ae3d3d91905bcb40b71636e778155345a298b..9433a88a33c4093866e6ea603182f0975e6b0e54 100644 (file)
@@ -97,7 +97,7 @@ static int bvme6000_get_hardware_list(char *buffer)
  * This function is called during kernel startup to initialize
  * the bvme6000 IRQ handling routines.
  */
-static void bvme6000_init_IRQ(void)
+static void __init bvme6000_init_IRQ(void)
 {
        m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 }
index 05741f23356720aef7c7c2ebcb015720ea8dec03..faa6764f1d13617c0b9580d0aef9c8641a325691 100644 (file)
@@ -577,7 +577,7 @@ func_define putn,1
 #endif
 .endm
 
-.text
+.section ".text.head","ax"
 ENTRY(_stext)
 /*
  * Version numbers of the bootinfo interface
index 215c7bd43924f43a21ce8b55d90ef3acc54e6da2..7e6d5fb75390e7a92b5c438c6b0059e03e2e432e 100644 (file)
@@ -58,6 +58,7 @@ extern int end;
 extern unsigned long availmem;
 
 int m68k_num_memory;
+EXPORT_SYMBOL(m68k_num_memory);
 int m68k_realnum_memory;
 EXPORT_SYMBOL(m68k_realnum_memory);
 unsigned long m68k_memoffset;
index 4b5f050204e860ca7f2991e487d83602517b916f..aad01592dbbcd12304674fdfff0ff8ef1903bbdc 100644 (file)
@@ -29,7 +29,7 @@ kernel_pmd_table:              .skip 0x2000
 .globl kernel_pg_dir
 .equ    kernel_pg_dir,kernel_pmd_table
 
-       .section .head
+       .section .text.head
 ENTRY(_stext)
 ENTRY(_start)
 
index 4c065f9ceffcd5ab7fcfe6e8de09b3e6d2adacc9..7db41594d7b6b92d4beed91da8a6d847e16128af 100644 (file)
@@ -72,7 +72,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy)
        return IRQ_HANDLED;
 }
 
-void time_init(void)
+void __init time_init(void)
 {
        struct rtc_time time;
 
index 40f02b128f22bb3a62ebce9d66349f3f78dc7fdc..c42245775a4db9d520df660424c6c7e690480beb 100644 (file)
@@ -11,6 +11,7 @@ SECTIONS
   . = 0x1000;
   _text = .;                   /* Text and read-only data */
   .text : {
+       *(.text.head)
        TEXT_TEXT
        SCHED_TEXT
        LOCK_TEXT
index f06425b6d20643a9fc32d74bfdc5af6c3487a394..4adffefb5c48c673b5f349a6c0142b4a10a26ada 100644 (file)
@@ -11,7 +11,7 @@ SECTIONS
   . = 0xE002000;
   _text = .;                   /* Text and read-only data */
   .text : {
-       *(.head)
+       *(.text.head)
        TEXT_TEXT
        SCHED_TEXT
        LOCK_TEXT
index 5fd413246f89d923f858b28ca33ec4558679df98..8547dbc5e8d73335a9b78a2bb37a1e416ac37b8f 100644 (file)
@@ -49,6 +49,7 @@ struct mac_booter_data mac_bi_data;
 int mac_bisize = sizeof mac_bi_data;
 
 struct mac_hw_present mac_hw_present;
+EXPORT_SYMBOL(mac_hw_present);
 
 /* New m68k bootinfo stuff and videobase */
 
@@ -84,7 +85,7 @@ extern void nubus_sweep_video(void);
 
 static void mac_get_model(char *str);
 
-static void mac_sched_init(irq_handler_t vector)
+static void __init mac_sched_init(irq_handler_t vector)
 {
        via_init_clock(vector);
 }
@@ -769,7 +770,7 @@ static struct mac_model mac_data_table[] = {
        }
 };
 
-void mac_identify(void)
+void __init mac_identify(void)
 {
        struct mac_model *m;
 
@@ -846,7 +847,7 @@ void mac_identify(void)
        baboon_init();
 }
 
-void mac_report_hardware(void)
+void __init mac_report_hardware(void)
 {
        printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
 }
index 0fc72d8f786e1ee3f271f1ab088190519a233af5..ecddac4a02b95abc11f80dbff860d2bdaea32fbd 100644 (file)
  *
  */
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -224,7 +225,7 @@ static struct irq_controller mac_irq_controller = {
        .disable        = mac_disable_irq,
 };
 
-void mac_init_IRQ(void)
+void __init mac_init_IRQ(void)
 {
 #ifdef DEBUG_MACINTS
        printk("mac_init_IRQ(): Setting things up...\n");
@@ -391,6 +392,7 @@ int mac_irq_pending(unsigned int irq)
        }
        return 0;
 }
+EXPORT_SYMBOL(mac_irq_pending);
 
 static int num_debug[8];
 
index f1de19e1dde66f50317db6f7a40992fdba481f2f..f42caa79e4e89f9fadf73041d33ab81077e7d11f 100644 (file)
@@ -44,7 +44,7 @@ pg_data_t *pg_data_table[65];
 EXPORT_SYMBOL(pg_data_table);
 #endif
 
-void m68k_setup_node(int node)
+void __init m68k_setup_node(int node)
 {
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
        struct mem_info *info = m68k_memory + node;
index 1af24cb5bfe136b4f8e18337ad72d8609bc4e755..3dc41158c05e973af1a57d9eb43b48fa1db87677 100644 (file)
@@ -105,6 +105,7 @@ void __iomem *sun3_ioremap(unsigned long phys, unsigned long size,
        return (void __iomem *)ret;
 
 }
+EXPORT_SYMBOL(sun3_ioremap);
 
 
 void __iomem *__ioremap(unsigned long phys, unsigned long size, int cache)
@@ -157,3 +158,4 @@ int sun3_map_test(unsigned long addr, char *val)
 
        return ret;
 }
+EXPORT_SYMBOL(sun3_map_test);
index 4a7df9c3f85a533339350dd48669e09e80be6e9f..92fe507141126fd566973e9598c86dd31e9eb389 100644 (file)
@@ -89,7 +89,7 @@ static int mvme147_get_hardware_list(char *buffer)
  * the mvme147 IRQ handling routines.
  */
 
-void mvme147_init_IRQ(void)
+void __init mvme147_init_IRQ(void)
 {
        m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 }
index c829ebb6b1af8510f380801138d6207f2d52c904..daa7851614013c385b7c9f4660120f716849d39b 100644 (file)
@@ -119,7 +119,7 @@ static int mvme16x_get_hardware_list(char *buffer)
  * that the base vectors for the VMEChip2 and PCCChip2 are valid.
  */
 
-static void mvme16x_init_IRQ (void)
+static void __init mvme16x_init_IRQ (void)
 {
        m68k_setup_user_interrupt(VEC_USER, 192, NULL);
 }
index 2fb25ae46a8a2249fc610a9d9fd5e7edb215da79..ad3ed1fb88793e066aca96628a8ecb505f038d05 100644 (file)
@@ -79,7 +79,7 @@ static struct irq_controller q40_irq_controller = {
 
 static int disabled;
 
-void q40_init_IRQ(void)
+void __init q40_init_IRQ(void)
 {
        m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX);
 
index 50df34bf80e320d24342c42a982591a1bee3786a..cf93481adb1d7f3bd074d719338f4072456deaf0 100644 (file)
@@ -97,7 +97,7 @@ static struct irq_controller sun3_irq_controller = {
        .disable        = sun3_disable_irq,
 };
 
-void sun3_init_IRQ(void)
+void __init sun3_init_IRQ(void)
 {
        *sun3_intreg = 1;
 
index 48f8eb7b15653efdb5f66f154801ea63b7b20f10..a7b7e818d6279450119f4a8da5e76cf1c6746466 100644 (file)
@@ -92,7 +92,7 @@ static struct console sun3x_debug = {
        .index  = -1,
 };
 
-void sun3x_prom_init(void)
+void __init sun3x_prom_init(void)
 {
        /* Read the vector table */
 
index 80f4e9d74ac17c7ca55b72fa06ec21e05fe1f29c..2203f694f26bb303ec057debe68bd3746891d4a3 100644 (file)
@@ -231,32 +231,33 @@ void setup_arch(char **cmdline_p)
 /*
  *     Get CPU information for use by the procfs.
  */
-
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
-    char *cpu, *mmu, *fpu;
-    u_long clockfreq;
+       char *cpu, *mmu, *fpu;
+       u_long clockfreq;
 
-    cpu = CPU;
-    mmu = "none";
-    fpu = "none";
+       cpu = CPU;
+       mmu = "none";
+       fpu = "none";
 
 #ifdef CONFIG_COLDFIRE
-    clockfreq = (loops_per_jiffy*HZ)*3;
+       clockfreq = (loops_per_jiffy * HZ) * 3;
 #else
-    clockfreq = (loops_per_jiffy*HZ)*16;
-#endif
-
-    seq_printf(m, "CPU:\t\t%s\n"
-                  "MMU:\t\t%s\n"
-                  "FPU:\t\t%s\n"
-                  "Clocking:\t%lu.%1luMHz\n"
-                  "BogoMips:\t%lu.%02lu\n"
-                  "Calibration:\t%lu loops\n",
-                  cpu, mmu, fpu,
-                  clockfreq/1000000,(clockfreq/100000)%10,
-                  (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100,
-                  (loops_per_jiffy*HZ));
+       clockfreq = (loops_per_jiffy * HZ) * 16;
+#endif
+
+       seq_printf(m, "CPU:\t\t%s\n"
+                     "MMU:\t\t%s\n"
+                     "FPU:\t\t%s\n"
+                     "Clocking:\t%lu.%1luMHz\n"
+                     "BogoMips:\t%lu.%02lu\n"
+                     "Calibration:\t%lu loops\n",
+                     cpu, mmu, fpu,
+                     clockfreq / 1000000,
+                     (clockfreq / 100000) % 10,
+                     (loops_per_jiffy * HZ) / 500000,
+                     ((loops_per_jiffy * HZ) / 5000) % 100,
+                     (loops_per_jiffy * HZ));
 
        return 0;
 }
index 5c863bcd5614e4076d4417e294458e4bbd5cae8f..1e3aeccd7322cfdc06067c46dea49950687a22f0 100644 (file)
@@ -1190,8 +1190,19 @@ config SYS_HAS_CPU_RM9000
 config SYS_HAS_CPU_SB1
        bool
 
+#
+# CPU may reorder R->R, R->W, W->R, W->W
+# Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
+#
 config WEAK_ORDERING
        bool
+
+#
+# CPU may reorder reads and writes beyond LL/SC
+# CPU may reorder R->LL, R->LL, W->LL, W->LL, R->SC, R->SC, W->SC, W->SC
+#
+config WEAK_REORDERING_BEYOND_LLSC
+       bool
 endmenu
 
 #
index c6b8b074a81aa65fad1fa9d0ce3aede09bff8ef5..06448a9656dce69f5920de6b21cdca5e05c98498 100644 (file)
@@ -75,6 +75,27 @@ static void r4k_wait_irqoff(void)
        local_irq_enable();
 }
 
+/*
+ * The RM7000 variant has to handle erratum 38.  The workaround is to not
+ * have any pending stores when the WAIT instruction is executed.
+ */
+static void rm7k_wait_irqoff(void)
+{
+       local_irq_disable();
+       if (!need_resched())
+               __asm__(
+               "       .set    push                                    \n"
+               "       .set    mips3                                   \n"
+               "       .set    noat                                    \n"
+               "       mfc0    $1, $12                                 \n"
+               "       sync                                            \n"
+               "       mtc0    $1, $12         # stalls until W stage  \n"
+               "       wait                                            \n"
+               "       mtc0    $1, $12         # stalls until W stage  \n"
+               "       .set    pop                                     \n");
+       local_irq_enable();
+}
+
 /* The Au1xxx wait is available only if using 32khz counter or
  * external timer source, but specifically not CP0 Counter. */
 int allow_au1k_wait;
@@ -132,7 +153,6 @@ static inline void check_wait(void)
        case CPU_R4700:
        case CPU_R5000:
        case CPU_NEVADA:
-       case CPU_RM7000:
        case CPU_4KC:
        case CPU_4KEC:
        case CPU_4KSC:
@@ -142,6 +162,10 @@ static inline void check_wait(void)
                cpu_wait = r4k_wait;
                break;
 
+       case CPU_RM7000:
+               cpu_wait = rm7k_wait_irqoff;
+               break;
+
        case CPU_24K:
        case CPU_34K:
                cpu_wait = r4k_wait;
index 8f4cf27c7157e634cd7b4b226410868352a81862..bd05f5a927eaac4c7983f19100353876cc34aed9 100644 (file)
@@ -25,7 +25,9 @@
 #include <linux/init.h>
 #include <linux/completion.h>
 #include <linux/kallsyms.h>
+#include <linux/random.h>
 
+#include <asm/asm.h>
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
 #include <asm/dsp.h>
@@ -460,3 +462,15 @@ unsigned long get_wchan(struct task_struct *task)
 out:
        return pc;
 }
+
+/*
+ * Don't forget that the stack pointer must be aligned on a 8 bytes
+ * boundary for 32-bits ABI and 16 bytes for 64-bits ABI.
+ */
+unsigned long arch_align_stack(unsigned long sp)
+{
+       if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+               sp -= get_random_int() & ~PAGE_MASK;
+
+       return sp & ALMASK;
+}
index d860b640a1405572285413efb922b8253046b835..853c282da22eadb59032f50983295d48f28f90e0 100644 (file)
@@ -92,6 +92,9 @@ config ARCH_MAY_HAVE_PC_FDC
 config PPC_OF
        def_bool y
 
+config OF
+       def_bool y
+
 config PPC_UDBG_16550
        bool
        default n
index 74f83f4a4e5e8cefb1c57ed7efb077c38ef2e903..d9ac24e8de1660812f740119820eb758fac97f5a 100644 (file)
@@ -1455,7 +1455,8 @@ CONFIG_HAS_DMA=y
 # Instrumentation Support
 #
 CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+CONFIG_OPROFILE=m
+CONFIG_OPROFILE_CELL=y
 # CONFIG_KPROBES is not set
 
 #
index d3f2080d2eeeb3719778352b7f39c4bb2ce7b637..37658ea417fa923b280ef92858209a303b85bb73 100644 (file)
@@ -219,6 +219,72 @@ void crash_kexec_secondary(struct pt_regs *regs)
        cpus_in_sr = CPU_MASK_NONE;
 }
 #endif
+#ifdef CONFIG_SPU_BASE
+
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+
+struct crash_spu_info {
+       struct spu *spu;
+       u32 saved_spu_runcntl_RW;
+       u32 saved_spu_status_R;
+       u32 saved_spu_npc_RW;
+       u64 saved_mfc_sr1_RW;
+       u64 saved_mfc_dar;
+       u64 saved_mfc_dsisr;
+};
+
+#define CRASH_NUM_SPUS 16      /* Enough for current hardware */
+static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS];
+
+static void crash_kexec_stop_spus(void)
+{
+       struct spu *spu;
+       int i;
+       u64 tmp;
+
+       for (i = 0; i < CRASH_NUM_SPUS; i++) {
+               if (!crash_spu_info[i].spu)
+                       continue;
+
+               spu = crash_spu_info[i].spu;
+
+               crash_spu_info[i].saved_spu_runcntl_RW =
+                       in_be32(&spu->problem->spu_runcntl_RW);
+               crash_spu_info[i].saved_spu_status_R =
+                       in_be32(&spu->problem->spu_status_R);
+               crash_spu_info[i].saved_spu_npc_RW =
+                       in_be32(&spu->problem->spu_npc_RW);
+
+               crash_spu_info[i].saved_mfc_dar    = spu_mfc_dar_get(spu);
+               crash_spu_info[i].saved_mfc_dsisr  = spu_mfc_dsisr_get(spu);
+               tmp = spu_mfc_sr1_get(spu);
+               crash_spu_info[i].saved_mfc_sr1_RW = tmp;
+
+               tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+               spu_mfc_sr1_set(spu, tmp);
+
+               __delay(200);
+       }
+}
+
+void crash_register_spus(struct list_head *list)
+{
+       struct spu *spu;
+
+       list_for_each_entry(spu, list, full_list) {
+               if (WARN_ON(spu->number >= CRASH_NUM_SPUS))
+                       continue;
+
+               crash_spu_info[spu->number].spu = spu;
+       }
+}
+
+#else
+static inline void crash_kexec_stop_spus(void)
+{
+}
+#endif /* CONFIG_SPU_BASE */
 
 void default_machine_crash_shutdown(struct pt_regs *regs)
 {
@@ -254,6 +320,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
        crash_save_cpu(regs, crashing_cpu);
        crash_kexec_prepare_cpus(crashing_cpu);
        cpu_set(crashing_cpu, cpus_in_crash);
+       crash_kexec_stop_spus();
        if (ppc_md.kexec_cpu_down)
                ppc_md.kexec_cpu_down(1, 0);
 }
index a464d67248dfd1c7f754095fa386aabf7cd33178..89b911e83c0453cfe3824db2ac514faa62e39cea 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
@@ -8,118 +9,6 @@
 #include <asm/errno.h>
 #include <asm/of_device.h>
 
-/**
- * of_match_node - Tell if an device_node has a matching of_match structure
- * @ids: array of of device match structures to search in
- * @node: the of device structure to match against
- *
- * Low level utility function used by device matching.
- */
-const struct of_device_id *of_match_node(const struct of_device_id *matches,
-                                        const struct device_node *node)
-{
-       while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-               int match = 1;
-               if (matches->name[0])
-                       match &= node->name
-                               && !strcmp(matches->name, node->name);
-               if (matches->type[0])
-                       match &= node->type
-                               && !strcmp(matches->type, node->type);
-               if (matches->compatible[0])
-                       match &= of_device_is_compatible(node,
-                                                     matches->compatible);
-               if (match)
-                       return matches;
-               matches++;
-       }
-       return NULL;
-}
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-                                       const struct of_device *dev)
-{
-       if (!dev->node)
-               return NULL;
-       return of_match_node(matches, dev->node);
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
-       struct device *tmp;
-
-       if (!dev)
-               return NULL;
-       tmp = get_device(&dev->dev);
-       if (tmp)
-               return to_of_device(tmp);
-       else
-               return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
-       if (dev)
-               put_device(&dev->dev);
-}
-
-static ssize_t dev_show_devspec(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct of_device *ofdev;
-
-       ofdev = to_of_device(dev);
-       return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-       struct of_device *ofdev;
-
-        ofdev = to_of_device(dev);
-       of_node_put(ofdev->node);
-       kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
-       int rc;
-
-       BUG_ON(ofdev->node == NULL);
-
-       rc = device_register(&ofdev->dev);
-       if (rc)
-               return rc;
-
-       return device_create_file(&ofdev->dev, &dev_attr_devspec);
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
-       device_remove_file(&ofdev->dev, &dev_attr_devspec);
-
-       device_unregister(&ofdev->dev);
-}
-
-
 ssize_t of_device_get_modalias(struct of_device *ofdev,
                                char *str, ssize_t len)
 {
@@ -229,14 +118,5 @@ int of_device_uevent(struct device *dev,
 
        return 0;
 }
-
-
-EXPORT_SYMBOL(of_match_node);
-EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
-EXPORT_SYMBOL(of_release_dev);
 EXPORT_SYMBOL(of_device_uevent);
 EXPORT_SYMBOL(of_device_get_modalias);
index 8ded4e7dc87e750db5bcfb2a1ccfe0cd66ce9254..f70e787d556fc6d6b08ce662e8b7fec35272d920 100644 (file)
@@ -55,94 +55,14 @@ static struct of_device_id of_default_bus_ids[] = {
 
 static atomic_t bus_no_reg_magic;
 
-/*
- *
- * OF platform device type definition & base infrastructure
- *
- */
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-       const struct of_device_id * matches = of_drv->match_table;
-
-       if (!matches)
-               return 0;
-
-       return of_match_device(matches, of_dev) != NULL;
-}
-
-static int of_platform_device_probe(struct device *dev)
-{
-       int error = -ENODEV;
-       struct of_platform_driver *drv;
-       struct of_device *of_dev;
-       const struct of_device_id *match;
-
-       drv = to_of_platform_driver(dev->driver);
-       of_dev = to_of_device(dev);
-
-       if (!drv->probe)
-               return error;
-
-       of_dev_get(of_dev);
-
-       match = of_match_device(drv->match_table, of_dev);
-       if (match)
-               error = drv->probe(of_dev, match);
-       if (error)
-               of_dev_put(of_dev);
-
-       return error;
-}
-
-static int of_platform_device_remove(struct device *dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-       if (dev->driver && drv->remove)
-               drv->remove(of_dev);
-       return 0;
-}
-
-static int of_platform_device_suspend(struct device *dev, pm_message_t state)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->suspend)
-               error = drv->suspend(of_dev, state);
-       return error;
-}
-
-static int of_platform_device_resume(struct device * dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->resume)
-               error = drv->resume(of_dev);
-       return error;
-}
-
 struct bus_type of_platform_bus_type = {
-       .name   = "of_platform",
-       .match  = of_platform_bus_match,
        .uevent = of_device_uevent,
-       .probe  = of_platform_device_probe,
-       .remove = of_platform_device_remove,
-       .suspend        = of_platform_device_suspend,
-       .resume = of_platform_device_resume,
 };
 EXPORT_SYMBOL(of_platform_bus_type);
 
 static int __init of_bus_driver_init(void)
 {
-       return bus_register(&of_platform_bus_type);
+       return of_bus_type_init(&of_platform_bus_type, "of_platform");
 }
 
 postcore_initcall(of_bus_driver_init);
index 37ff99bd98b45ac892cab67a839b4110d68e26dd..bdcd23d8d8b99f8648b61a63aa4ece60f66c375a 100644 (file)
@@ -78,12 +78,9 @@ static struct boot_param_header *initial_boot_params __initdata;
 struct boot_param_header *initial_boot_params;
 #endif
 
-static struct device_node *allnodes = NULL;
+extern struct device_node *allnodes;   /* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
+extern rwlock_t devtree_lock;  /* temporary while merging */
 
 /* export that to outside world */
 struct device_node *of_chosen;
@@ -1056,60 +1053,6 @@ void __init early_init_devtree(void *params)
        DBG(" <- early_init_devtree()\n");
 }
 
-int of_n_addr_cells(struct device_node* np)
-{
-       const int *ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#address-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #address-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node* np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#size-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #size-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
-/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
- */
-int of_device_is_compatible(const struct device_node *device,
-               const char *compat)
-{
-       const char* cp;
-       int cplen, l;
-
-       cp = of_get_property(device, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncasecmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
 
 /**
  * Indicates whether the root node has a given value in its
@@ -1140,119 +1083,6 @@ EXPORT_SYMBOL(machine_is_compatible);
  *
  *******/
 
-/**
- *     of_find_node_by_name - Find a node by its "name" property
- *     @from:  The node to start searching from or NULL, the node
- *             you pass will not be searched, only the next one
- *             will; typically, you pass what the previous call
- *             returned. of_node_put() will be called on it
- *     @name:  The name string to match against
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       np = from ? from->allnext : allnodes;
-       for (; np != NULL; np = np->allnext)
-               if (np->name != NULL && strcasecmp(np->name, name) == 0
-                   && of_node_get(np))
-                       break;
-       of_node_put(from);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-/**
- *     of_find_node_by_type - Find a node by its "device_type" property
- *     @from:  The node to start searching from, or NULL to start searching
- *             the entire device tree. The node you pass will not be
- *             searched, only the next one will; typically, you pass
- *             what the previous call returned. of_node_put() will be
- *             called on from for you.
- *     @type:  The type string to match against
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext)
-               if (np->type != 0 && strcasecmp(np->type, type) == 0
-                   && of_node_get(np))
-                       break;
-       of_node_put(from);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-/**
- *     of_find_compatible_node - Find a node based on type and one of the
- *                                tokens in its "compatible" property
- *     @from:          The node to start searching from or NULL, the node
- *                     you pass will not be searched, only the next one
- *                     will; typically, you pass what the previous call
- *                     returned. of_node_put() will be called on it
- *     @type:          The type string to match "device_type" or NULL to ignore
- *     @compatible:    The string to match to one of the tokens in the device
- *                     "compatible" list.
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compatible)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext) {
-               if (type != NULL
-                   && !(np->type != 0 && strcasecmp(np->type, type) == 0))
-                       continue;
-               if (of_device_is_compatible(np, compatible) && of_node_get(np))
-                       break;
-       }
-       of_node_put(from);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-/**
- *     of_find_node_by_path - Find a node matching a full OF path
- *     @path:  The full path to match
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_path(const char *path)
-{
-       struct device_node *np = allnodes;
-
-       read_lock(&devtree_lock);
-       for (; np != 0; np = np->allnext) {
-               if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
-                   && of_node_get(np))
-                       break;
-       }
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
-
 /**
  *     of_find_node_by_phandle - Find a node given a phandle
  *     @handle:        phandle of the node to find
@@ -1297,51 +1127,6 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
 }
 EXPORT_SYMBOL(of_find_all_nodes);
 
-/**
- *     of_get_parent - Get a node's parent if any
- *     @node:  Node to get parent
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_get_parent(const struct device_node *node)
-{
-       struct device_node *np;
-
-       if (!node)
-               return NULL;
-
-       read_lock(&devtree_lock);
-       np = of_node_get(node->parent);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-/**
- *     of_get_next_child - Iterate a node childs
- *     @node:  parent node
- *     @prev:  previous child of the parent node, or NULL to get first
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_get_next_child(const struct device_node *node,
-       struct device_node *prev)
-{
-       struct device_node *next;
-
-       read_lock(&devtree_lock);
-       next = prev ? prev->sibling : node->child;
-       for (; next != 0; next = next->sibling)
-               if (of_node_get(next))
-                       break;
-       of_node_put(prev);
-       read_unlock(&devtree_lock);
-       return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
 /**
  *     of_node_get - Increment refcount of a node
  *     @node:  Node to inc refcount, NULL is supported to
@@ -1543,37 +1328,6 @@ static int __init prom_reconfig_setup(void)
 __initcall(prom_reconfig_setup);
 #endif
 
-struct property *of_find_property(const struct device_node *np,
-                                 const char *name,
-                                 int *lenp)
-{
-       struct property *pp;
-
-       read_lock(&devtree_lock);
-       for (pp = np->properties; pp != 0; pp = pp->next)
-               if (strcmp(pp->name, name) == 0) {
-                       if (lenp != 0)
-                               *lenp = pp->length;
-                       break;
-               }
-       read_unlock(&devtree_lock);
-
-       return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
-                        int *lenp)
-{
-       struct property *pp = of_find_property(np,name,lenp);
-       return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 /*
  * Add a property to a node
  */
index e5df167f7824dfc648984f2fd21d154c3f9cbea1..727a6699f2f41c36ffaac9a205a1aaf3405ec554 100644 (file)
@@ -122,6 +122,7 @@ extern struct timezone sys_tz;
 static long timezone_offset;
 
 unsigned long ppc_proc_freq;
+EXPORT_SYMBOL(ppc_proc_freq);
 unsigned long ppc_tb_freq;
 
 static u64 tb_last_jiffy __cacheline_aligned_in_smp;
index eb2dece76a540626fc3fe6c0f90e4330f9c84a59..7089e79689b90310860f9ff5819266abf29494f8 100644 (file)
@@ -15,3 +15,10 @@ config OPROFILE
 
          If unsure, say N.
 
+config OPROFILE_CELL
+       bool "OProfile for Cell Broadband Engine"
+       depends on (SPU_FS = y && OPROFILE = m) || (SPU_FS = y && OPROFILE = y) || (SPU_FS = m && OPROFILE = m)
+       default y
+       help
+         Profiling of Cell BE SPUs requires special support enabled
+         by this option.
index 4b5f9528218ccd14c7af13ac48209b7c7e0add2b..c5f64c3bd668a21615dcc714c96a144a272bbcfe 100644 (file)
@@ -11,7 +11,9 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
                timer_int.o )
 
 oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
-oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o
+oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
+               cell/spu_profiler.o cell/vma_map.o \
+               cell/spu_task_sync.o
 oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
 oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
 oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/cell/pr_util.h b/arch/powerpc/oprofile/cell/pr_util.h
new file mode 100644 (file)
index 0000000..e5704f0
--- /dev/null
@@ -0,0 +1,97 @@
+ /*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef PR_UTIL_H
+#define PR_UTIL_H
+
+#include <linux/cpumask.h>
+#include <linux/oprofile.h>
+#include <asm/cell-pmu.h>
+#include <asm/spu.h>
+
+#include "../../platforms/cell/cbe_regs.h"
+
+/* Defines used for sync_start */
+#define SKIP_GENERIC_SYNC 0
+#define SYNC_START_ERROR -1
+#define DO_GENERIC_SYNC 1
+
+struct spu_overlay_info {      /* map of sections within an SPU overlay */
+       unsigned int vma;       /* SPU virtual memory address from elf */
+       unsigned int size;      /* size of section from elf */
+       unsigned int offset;    /* offset of section into elf file */
+       unsigned int buf;
+};
+
+struct vma_to_fileoffset_map { /* map of sections within an SPU program */
+       struct vma_to_fileoffset_map *next;     /* list pointer */
+       unsigned int vma;       /* SPU virtual memory address from elf */
+       unsigned int size;      /* size of section from elf */
+       unsigned int offset;    /* offset of section into elf file */
+       unsigned int guard_ptr;
+       unsigned int guard_val;
+        /*
+        * The guard pointer is an entry in the _ovly_buf_table,
+        * computed using ovly.buf as the index into the table.  Since
+        * ovly.buf values begin at '1' to reference the first (or 0th)
+        * entry in the _ovly_buf_table, the computation subtracts 1
+        * from ovly.buf.
+        * The guard value is stored in the _ovly_buf_table entry and
+        * is an index (starting at 1) back to the _ovly_table entry
+        * that is pointing at this _ovly_buf_table entry.  So, for
+        * example, for an overlay scenario with one overlay segment
+        * and two overlay sections:
+        *      - Section 1 points to the first entry of the
+        *        _ovly_buf_table, which contains a guard value
+        *        of '1', referencing the first (index=0) entry of
+        *        _ovly_table.
+        *      - Section 2 points to the second entry of the
+        *        _ovly_buf_table, which contains a guard value
+        *        of '2', referencing the second (index=1) entry of
+        *        _ovly_table.
+        */
+
+};
+
+/* The three functions below are for maintaining and accessing
+ * the vma-to-fileoffset map.
+ */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *spu,
+                                            u64 objectid);
+unsigned int vma_map_lookup(struct vma_to_fileoffset_map *map,
+                           unsigned int vma, const struct spu *aSpu,
+                           int *grd_val);
+void vma_map_free(struct vma_to_fileoffset_map *map);
+
+/*
+ * Entry point for SPU profiling.
+ * cycles_reset is the SPU_CYCLES count value specified by the user.
+ */
+int start_spu_profiling(unsigned int cycles_reset);
+
+void stop_spu_profiling(void);
+
+
+/* add the necessary profiling hooks */
+int spu_sync_start(void);
+
+/* remove the hooks */
+int spu_sync_stop(void);
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+                    int num_samples);
+
+void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset);
+
+#endif   /* PR_UTIL_H */
diff --git a/arch/powerpc/oprofile/cell/spu_profiler.c b/arch/powerpc/oprofile/cell/spu_profiler.c
new file mode 100644 (file)
index 0000000..380d7e2
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Authors: Maynard Johnson <maynardj@us.ibm.com>
+ *         Carl Love <carll@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/hrtimer.h>
+#include <linux/smp.h>
+#include <linux/slab.h>
+#include <asm/cell-pmu.h>
+#include "pr_util.h"
+
+#define TRACE_ARRAY_SIZE 1024
+#define SCALE_SHIFT 14
+
+static u32 *samples;
+
+static int spu_prof_running;
+static unsigned int profiling_interval;
+
+#define NUM_SPU_BITS_TRBUF 16
+#define SPUS_PER_TB_ENTRY   4
+#define SPUS_PER_NODE       8
+
+#define SPU_PC_MASK         0xFFFF
+
+static DEFINE_SPINLOCK(sample_array_lock);
+unsigned long sample_array_lock_flags;
+
+void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset)
+{
+       unsigned long ns_per_cyc;
+
+       if (!freq_khz)
+               freq_khz = ppc_proc_freq/1000;
+
+       /* To calculate a timeout in nanoseconds, the basic
+        * formula is ns = cycles_reset * (NSEC_PER_SEC / cpu frequency).
+        * To avoid floating point math, we use the scale math
+        * technique as described in linux/jiffies.h.  We use
+        * a scale factor of SCALE_SHIFT, which provides 4 decimal places
+        * of precision.  This is close enough for the purpose at hand.
+        *
+        * The value of the timeout should be small enough that the hw
+        * trace buffer will not get more then about 1/3 full for the
+        * maximum user specified (the LFSR value) hw sampling frequency.
+        * This is to ensure the trace buffer will never fill even if the
+        * kernel thread scheduling varies under a heavy system load.
+        */
+
+       ns_per_cyc = (USEC_PER_SEC << SCALE_SHIFT)/freq_khz;
+       profiling_interval = (ns_per_cyc * cycles_reset) >> SCALE_SHIFT;
+
+}
+
+/*
+ * Extract SPU PC from trace buffer entry
+ */
+static void spu_pc_extract(int cpu, int entry)
+{
+       /* the trace buffer is 128 bits */
+       u64 trace_buffer[2];
+       u64 spu_mask;
+       int spu;
+
+       spu_mask = SPU_PC_MASK;
+
+       /* Each SPU PC is 16 bits; hence, four spus in each of
+        * the two 64-bit buffer entries that make up the
+        * 128-bit trace_buffer entry.  Process two 64-bit values
+        * simultaneously.
+        * trace[0] SPU PC contents are: 0 1 2 3
+        * trace[1] SPU PC contents are: 4 5 6 7
+        */
+
+       cbe_read_trace_buffer(cpu, trace_buffer);
+
+       for (spu = SPUS_PER_TB_ENTRY-1; spu >= 0; spu--) {
+               /* spu PC trace entry is upper 16 bits of the
+                * 18 bit SPU program counter
+                */
+               samples[spu * TRACE_ARRAY_SIZE + entry]
+                       = (spu_mask & trace_buffer[0]) << 2;
+               samples[(spu + SPUS_PER_TB_ENTRY) * TRACE_ARRAY_SIZE + entry]
+                       = (spu_mask & trace_buffer[1]) << 2;
+
+               trace_buffer[0] = trace_buffer[0] >> NUM_SPU_BITS_TRBUF;
+               trace_buffer[1] = trace_buffer[1] >> NUM_SPU_BITS_TRBUF;
+       }
+}
+
+static int cell_spu_pc_collection(int cpu)
+{
+       u32 trace_addr;
+       int entry;
+
+       /* process the collected SPU PC for the node */
+
+       entry = 0;
+
+       trace_addr = cbe_read_pm(cpu, trace_address);
+       while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY)) {
+               /* there is data in the trace buffer to process */
+               spu_pc_extract(cpu, entry);
+
+               entry++;
+
+               if (entry >= TRACE_ARRAY_SIZE)
+                       /* spu_samples is full */
+                       break;
+
+               trace_addr = cbe_read_pm(cpu, trace_address);
+       }
+
+       return entry;
+}
+
+
+static enum hrtimer_restart profile_spus(struct hrtimer *timer)
+{
+       ktime_t kt;
+       int cpu, node, k, num_samples, spu_num;
+
+       if (!spu_prof_running)
+               goto stop;
+
+       for_each_online_cpu(cpu) {
+               if (cbe_get_hw_thread_id(cpu))
+                       continue;
+
+               node = cbe_cpu_to_node(cpu);
+
+               /* There should only be one kernel thread at a time processing
+                * the samples.  In the very unlikely case that the processing
+                * is taking a very long time and multiple kernel threads are
+                * started to process the samples.  Make sure only one kernel
+                * thread is working on the samples array at a time.  The
+                * sample array must be loaded and then processed for a given
+                * cpu.  The sample array is not per cpu.
+                */
+               spin_lock_irqsave(&sample_array_lock,
+                                 sample_array_lock_flags);
+               num_samples = cell_spu_pc_collection(cpu);
+
+               if (num_samples == 0) {
+                       spin_unlock_irqrestore(&sample_array_lock,
+                                              sample_array_lock_flags);
+                       continue;
+               }
+
+               for (k = 0; k < SPUS_PER_NODE; k++) {
+                       spu_num = k + (node * SPUS_PER_NODE);
+                       spu_sync_buffer(spu_num,
+                                       samples + (k * TRACE_ARRAY_SIZE),
+                                       num_samples);
+               }
+
+               spin_unlock_irqrestore(&sample_array_lock,
+                                      sample_array_lock_flags);
+
+       }
+       smp_wmb();      /* insure spu event buffer updates are written */
+                       /* don't want events intermingled... */
+
+       kt = ktime_set(0, profiling_interval);
+       if (!spu_prof_running)
+               goto stop;
+       hrtimer_forward(timer, timer->base->get_time(), kt);
+       return HRTIMER_RESTART;
+
+ stop:
+       printk(KERN_INFO "SPU_PROF: spu-prof timer ending\n");
+       return HRTIMER_NORESTART;
+}
+
+static struct hrtimer timer;
+/*
+ * Entry point for SPU profiling.
+ * NOTE:  SPU profiling is done system-wide, not per-CPU.
+ *
+ * cycles_reset is the count value specified by the user when
+ * setting up OProfile to count SPU_CYCLES.
+ */
+int start_spu_profiling(unsigned int cycles_reset)
+{
+       ktime_t kt;
+
+       pr_debug("timer resolution: %lu\n", TICK_NSEC);
+       kt = ktime_set(0, profiling_interval);
+       hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       timer.expires = kt;
+       timer.function = profile_spus;
+
+       /* Allocate arrays for collecting SPU PC samples */
+       samples = kzalloc(SPUS_PER_NODE *
+                         TRACE_ARRAY_SIZE * sizeof(u32), GFP_KERNEL);
+
+       if (!samples)
+               return -ENOMEM;
+
+       spu_prof_running = 1;
+       hrtimer_start(&timer, kt, HRTIMER_MODE_REL);
+
+       return 0;
+}
+
+void stop_spu_profiling(void)
+{
+       spu_prof_running = 0;
+       hrtimer_cancel(&timer);
+       kfree(samples);
+       pr_debug("SPU_PROF: stop_spu_profiling issued\n");
+}
diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c
new file mode 100644 (file)
index 0000000..1336657
--- /dev/null
@@ -0,0 +1,484 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The purpose of this file is to handle SPU event task switching
+ * and to record SPU context information into the OProfile
+ * event buffer.
+ *
+ * Additionally, the spu_sync_buffer function is provided as a helper
+ * for recoding actual SPU program counter samples to the event buffer.
+ */
+#include <linux/dcookies.h>
+#include <linux/kref.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/numa.h>
+#include <linux/oprofile.h>
+#include <linux/spinlock.h>
+#include "pr_util.h"
+
+#define RELEASE_ALL 9999
+
+static DEFINE_SPINLOCK(buffer_lock);
+static DEFINE_SPINLOCK(cache_lock);
+static int num_spu_nodes;
+int spu_prof_num_nodes;
+int last_guard_val[MAX_NUMNODES * 8];
+
+/* Container for caching information about an active SPU task. */
+struct cached_info {
+       struct vma_to_fileoffset_map *map;
+       struct spu *the_spu;    /* needed to access pointer to local_store */
+       struct kref cache_ref;
+};
+
+static struct cached_info *spu_info[MAX_NUMNODES * 8];
+
+static void destroy_cached_info(struct kref *kref)
+{
+       struct cached_info *info;
+
+       info = container_of(kref, struct cached_info, cache_ref);
+       vma_map_free(info->map);
+       kfree(info);
+       module_put(THIS_MODULE);
+}
+
+/* Return the cached_info for the passed SPU number.
+ * ATTENTION:  Callers are responsible for obtaining the
+ *            cache_lock if needed prior to invoking this function.
+ */
+static struct cached_info *get_cached_info(struct spu *the_spu, int spu_num)
+{
+       struct kref *ref;
+       struct cached_info *ret_info;
+
+       if (spu_num >= num_spu_nodes) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Invalid index %d into spu info cache\n",
+                      __FUNCTION__, __LINE__, spu_num);
+               ret_info = NULL;
+               goto out;
+       }
+       if (!spu_info[spu_num] && the_spu) {
+               ref = spu_get_profile_private_kref(the_spu->ctx);
+               if (ref) {
+                       spu_info[spu_num] = container_of(ref, struct cached_info, cache_ref);
+                       kref_get(&spu_info[spu_num]->cache_ref);
+               }
+       }
+
+       ret_info = spu_info[spu_num];
+ out:
+       return ret_info;
+}
+
+
+/* Looks for cached info for the passed spu.  If not found, the
+ * cached info is created for the passed spu.
+ * Returns 0 for success; otherwise, -1 for error.
+ */
+static int
+prepare_cached_spu_info(struct spu *spu, unsigned long objectId)
+{
+       unsigned long flags;
+       struct vma_to_fileoffset_map *new_map;
+       int retval = 0;
+       struct cached_info *info;
+
+       /* We won't bother getting cache_lock here since
+        * don't do anything with the cached_info that's returned.
+        */
+       info = get_cached_info(spu, spu->number);
+
+       if (info) {
+               pr_debug("Found cached SPU info.\n");
+               goto out;
+       }
+
+       /* Create cached_info and set spu_info[spu->number] to point to it.
+        * spu->number is a system-wide value, not a per-node value.
+        */
+       info = kzalloc(sizeof(struct cached_info), GFP_KERNEL);
+       if (!info) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: create vma_map failed\n",
+                      __FUNCTION__, __LINE__);
+               retval = -ENOMEM;
+               goto err_alloc;
+       }
+       new_map = create_vma_map(spu, objectId);
+       if (!new_map) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: create vma_map failed\n",
+                      __FUNCTION__, __LINE__);
+               retval = -ENOMEM;
+               goto err_alloc;
+       }
+
+       pr_debug("Created vma_map\n");
+       info->map = new_map;
+       info->the_spu = spu;
+       kref_init(&info->cache_ref);
+       spin_lock_irqsave(&cache_lock, flags);
+       spu_info[spu->number] = info;
+       /* Increment count before passing off ref to SPUFS. */
+       kref_get(&info->cache_ref);
+
+       /* We increment the module refcount here since SPUFS is
+        * responsible for the final destruction of the cached_info,
+        * and it must be able to access the destroy_cached_info()
+        * function defined in the OProfile module.  We decrement
+        * the module refcount in destroy_cached_info.
+        */
+       try_module_get(THIS_MODULE);
+       spu_set_profile_private_kref(spu->ctx, &info->cache_ref,
+                               destroy_cached_info);
+       spin_unlock_irqrestore(&cache_lock, flags);
+       goto out;
+
+err_alloc:
+       kfree(info);
+out:
+       return retval;
+}
+
+/*
+ * NOTE:  The caller is responsible for locking the
+ *       cache_lock prior to calling this function.
+ */
+static int release_cached_info(int spu_index)
+{
+       int index, end;
+
+       if (spu_index == RELEASE_ALL) {
+               end = num_spu_nodes;
+               index = 0;
+       } else {
+               if (spu_index >= num_spu_nodes) {
+                       printk(KERN_ERR "SPU_PROF: "
+                               "%s, line %d: "
+                               "Invalid index %d into spu info cache\n",
+                               __FUNCTION__, __LINE__, spu_index);
+                       goto out;
+               }
+               end = spu_index + 1;
+               index = spu_index;
+       }
+       for (; index < end; index++) {
+               if (spu_info[index]) {
+                       kref_put(&spu_info[index]->cache_ref,
+                                destroy_cached_info);
+                       spu_info[index] = NULL;
+               }
+       }
+
+out:
+       return 0;
+}
+
+/* The source code for fast_get_dcookie was "borrowed"
+ * from drivers/oprofile/buffer_sync.c.
+ */
+
+/* Optimisation. We can manage without taking the dcookie sem
+ * because we cannot reach this code without at least one
+ * dcookie user still being registered (namely, the reader
+ * of the event buffer).
+ */
+static inline unsigned long fast_get_dcookie(struct dentry *dentry,
+                                            struct vfsmount *vfsmnt)
+{
+       unsigned long cookie;
+
+       if (dentry->d_cookie)
+               return (unsigned long)dentry;
+       get_dcookie(dentry, vfsmnt, &cookie);
+       return cookie;
+}
+
+/* Look up the dcookie for the task's first VM_EXECUTABLE mapping,
+ * which corresponds loosely to "application name". Also, determine
+ * the offset for the SPU ELF object.  If computed offset is
+ * non-zero, it implies an embedded SPU object; otherwise, it's a
+ * separate SPU binary, in which case we retrieve it's dcookie.
+ * For the embedded case, we must determine if SPU ELF is embedded
+ * in the executable application or another file (i.e., shared lib).
+ * If embedded in a shared lib, we must get the dcookie and return
+ * that to the caller.
+ */
+static unsigned long
+get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
+                           unsigned long *spu_bin_dcookie,
+                           unsigned long spu_ref)
+{
+       unsigned long app_cookie = 0;
+       unsigned int my_offset = 0;
+       struct file *app = NULL;
+       struct vm_area_struct *vma;
+       struct mm_struct *mm = spu->mm;
+
+       if (!mm)
+               goto out;
+
+       down_read(&mm->mmap_sem);
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if (!vma->vm_file)
+                       continue;
+               if (!(vma->vm_flags & VM_EXECUTABLE))
+                       continue;
+               app_cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+                                         vma->vm_file->f_vfsmnt);
+               pr_debug("got dcookie for %s\n",
+                        vma->vm_file->f_dentry->d_name.name);
+               app = vma->vm_file;
+               break;
+       }
+
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               if (vma->vm_start > spu_ref || vma->vm_end <= spu_ref)
+                       continue;
+               my_offset = spu_ref - vma->vm_start;
+               if (!vma->vm_file)
+                       goto fail_no_image_cookie;
+
+               pr_debug("Found spu ELF at %X(object-id:%lx) for file %s\n",
+                        my_offset, spu_ref,
+                        vma->vm_file->f_dentry->d_name.name);
+               *offsetp = my_offset;
+               break;
+       }
+
+       *spu_bin_dcookie = fast_get_dcookie(vma->vm_file->f_dentry,
+                                                vma->vm_file->f_vfsmnt);
+       pr_debug("got dcookie for %s\n", vma->vm_file->f_dentry->d_name.name);
+
+       up_read(&mm->mmap_sem);
+
+out:
+       return app_cookie;
+
+fail_no_image_cookie:
+       up_read(&mm->mmap_sem);
+
+       printk(KERN_ERR "SPU_PROF: "
+               "%s, line %d: Cannot find dcookie for SPU binary\n",
+               __FUNCTION__, __LINE__);
+       goto out;
+}
+
+
+
+/* This function finds or creates cached context information for the
+ * passed SPU and records SPU context information into the OProfile
+ * event buffer.
+ */
+static int process_context_switch(struct spu *spu, unsigned long objectId)
+{
+       unsigned long flags;
+       int retval;
+       unsigned int offset = 0;
+       unsigned long spu_cookie = 0, app_dcookie;
+
+       retval = prepare_cached_spu_info(spu, objectId);
+       if (retval)
+               goto out;
+
+       /* Get dcookie first because a mutex_lock is taken in that
+        * code path, so interrupts must not be disabled.
+        */
+       app_dcookie = get_exec_dcookie_and_offset(spu, &offset, &spu_cookie, objectId);
+       if (!app_dcookie || !spu_cookie) {
+               retval  = -ENOENT;
+               goto out;
+       }
+
+       /* Record context info in event buffer */
+       spin_lock_irqsave(&buffer_lock, flags);
+       add_event_entry(ESCAPE_CODE);
+       add_event_entry(SPU_CTX_SWITCH_CODE);
+       add_event_entry(spu->number);
+       add_event_entry(spu->pid);
+       add_event_entry(spu->tgid);
+       add_event_entry(app_dcookie);
+       add_event_entry(spu_cookie);
+       add_event_entry(offset);
+       spin_unlock_irqrestore(&buffer_lock, flags);
+       smp_wmb();      /* insure spu event buffer updates are written */
+                       /* don't want entries intermingled... */
+out:
+       return retval;
+}
+
+/*
+ * This function is invoked on either a bind_context or unbind_context.
+ * If called for an unbind_context, the val arg is 0; otherwise,
+ * it is the object-id value for the spu context.
+ * The data arg is of type 'struct spu *'.
+ */
+static int spu_active_notify(struct notifier_block *self, unsigned long val,
+                               void *data)
+{
+       int retval;
+       unsigned long flags;
+       struct spu *the_spu = data;
+
+       pr_debug("SPU event notification arrived\n");
+       if (!val) {
+               spin_lock_irqsave(&cache_lock, flags);
+               retval = release_cached_info(the_spu->number);
+               spin_unlock_irqrestore(&cache_lock, flags);
+       } else {
+               retval = process_context_switch(the_spu, val);
+       }
+       return retval;
+}
+
+static struct notifier_block spu_active = {
+       .notifier_call = spu_active_notify,
+};
+
+static int number_of_online_nodes(void)
+{
+        u32 cpu; u32 tmp;
+        int nodes = 0;
+        for_each_online_cpu(cpu) {
+                tmp = cbe_cpu_to_node(cpu) + 1;
+                if (tmp > nodes)
+                        nodes++;
+        }
+        return nodes;
+}
+
+/* The main purpose of this function is to synchronize
+ * OProfile with SPUFS by registering to be notified of
+ * SPU task switches.
+ *
+ * NOTE: When profiling SPUs, we must ensure that only
+ * spu_sync_start is invoked and not the generic sync_start
+ * in drivers/oprofile/oprof.c.         A return value of
+ * SKIP_GENERIC_SYNC or SYNC_START_ERROR will
+ * accomplish this.
+ */
+int spu_sync_start(void)
+{
+       int k;
+       int ret = SKIP_GENERIC_SYNC;
+       int register_ret;
+       unsigned long flags = 0;
+
+       spu_prof_num_nodes = number_of_online_nodes();
+       num_spu_nodes = spu_prof_num_nodes * 8;
+
+       spin_lock_irqsave(&buffer_lock, flags);
+       add_event_entry(ESCAPE_CODE);
+       add_event_entry(SPU_PROFILING_CODE);
+       add_event_entry(num_spu_nodes);
+       spin_unlock_irqrestore(&buffer_lock, flags);
+
+       /* Register for SPU events  */
+       register_ret = spu_switch_event_register(&spu_active);
+       if (register_ret) {
+               ret = SYNC_START_ERROR;
+               goto out;
+       }
+
+       for (k = 0; k < (MAX_NUMNODES * 8); k++)
+               last_guard_val[k] = 0;
+       pr_debug("spu_sync_start -- running.\n");
+out:
+       return ret;
+}
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+                    int num_samples)
+{
+       unsigned long long file_offset;
+       unsigned long flags;
+       int i;
+       struct vma_to_fileoffset_map *map;
+       struct spu *the_spu;
+       unsigned long long spu_num_ll = spu_num;
+       unsigned long long spu_num_shifted = spu_num_ll << 32;
+       struct cached_info *c_info;
+
+       /* We need to obtain the cache_lock here because it's
+        * possible that after getting the cached_info, the SPU job
+        * corresponding to this cached_info may end, thus resulting
+        * in the destruction of the cached_info.
+        */
+       spin_lock_irqsave(&cache_lock, flags);
+       c_info = get_cached_info(NULL, spu_num);
+       if (!c_info) {
+               /* This legitimately happens when the SPU task ends before all
+                * samples are recorded.
+                * No big deal -- so we just drop a few samples.
+                */
+               pr_debug("SPU_PROF: No cached SPU contex "
+                         "for SPU #%d. Dropping samples.\n", spu_num);
+               goto out;
+       }
+
+       map = c_info->map;
+       the_spu = c_info->the_spu;
+       spin_lock(&buffer_lock);
+       for (i = 0; i < num_samples; i++) {
+               unsigned int sample = *(samples+i);
+               int grd_val = 0;
+               file_offset = 0;
+               if (sample == 0)
+                       continue;
+               file_offset = vma_map_lookup( map, sample, the_spu, &grd_val);
+
+               /* If overlays are used by this SPU application, the guard
+                * value is non-zero, indicating which overlay section is in
+                * use.  We need to discard samples taken during the time
+                * period which an overlay occurs (i.e., guard value changes).
+                */
+               if (grd_val && grd_val != last_guard_val[spu_num]) {
+                       last_guard_val[spu_num] = grd_val;
+                       /* Drop the rest of the samples. */
+                       break;
+               }
+
+               add_event_entry(file_offset | spu_num_shifted);
+       }
+       spin_unlock(&buffer_lock);
+out:
+       spin_unlock_irqrestore(&cache_lock, flags);
+}
+
+
+int spu_sync_stop(void)
+{
+       unsigned long flags = 0;
+       int ret = spu_switch_event_unregister(&spu_active);
+       if (ret) {
+               printk(KERN_ERR "SPU_PROF: "
+                       "%s, line %d: spu_switch_event_unregister returned %d\n",
+                       __FUNCTION__, __LINE__, ret);
+               goto out;
+       }
+
+       spin_lock_irqsave(&cache_lock, flags);
+       ret = release_cached_info(RELEASE_ALL);
+       spin_unlock_irqrestore(&cache_lock, flags);
+out:
+       pr_debug("spu_sync_stop -- done.\n");
+       return ret;
+}
+
+
diff --git a/arch/powerpc/oprofile/cell/vma_map.c b/arch/powerpc/oprofile/cell/vma_map.c
new file mode 100644 (file)
index 0000000..76ec1d1
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The code in this source file is responsible for generating
+ * vma-to-fileOffset maps for both overlay and non-overlay SPU
+ * applications.
+ */
+
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/elf.h>
+#include "pr_util.h"
+
+
+void vma_map_free(struct vma_to_fileoffset_map *map)
+{
+       while (map) {
+               struct vma_to_fileoffset_map *next = map->next;
+               kfree(map);
+               map = next;
+       }
+}
+
+unsigned int
+vma_map_lookup(struct vma_to_fileoffset_map *map, unsigned int vma,
+              const struct spu *aSpu, int *grd_val)
+{
+       /*
+        * Default the offset to the physical address + a flag value.
+        * Addresses of dynamically generated code can't be found in the vma
+        * map.  For those addresses the flagged value will be sent on to
+        * the user space tools so they can be reported rather than just
+        * thrown away.
+        */
+       u32 offset = 0x10000000 + vma;
+       u32 ovly_grd;
+
+       for (; map; map = map->next) {
+               if (vma < map->vma || vma >= map->vma + map->size)
+                       continue;
+
+               if (map->guard_ptr) {
+                       ovly_grd = *(u32 *)(aSpu->local_store + map->guard_ptr);
+                       if (ovly_grd != map->guard_val)
+                               continue;
+                       *grd_val = ovly_grd;
+               }
+               offset = vma - map->vma + map->offset;
+               break;
+       }
+
+       return offset;
+}
+
+static struct vma_to_fileoffset_map *
+vma_map_add(struct vma_to_fileoffset_map *map, unsigned int vma,
+           unsigned int size, unsigned int offset, unsigned int guard_ptr,
+           unsigned int guard_val)
+{
+       struct vma_to_fileoffset_map *new =
+               kzalloc(sizeof(struct vma_to_fileoffset_map), GFP_KERNEL);
+       if (!new) {
+               printk(KERN_ERR "SPU_PROF: %s, line %d: malloc failed\n",
+                      __FUNCTION__, __LINE__);
+               vma_map_free(map);
+               return NULL;
+       }
+
+       new->next = map;
+       new->vma = vma;
+       new->size = size;
+       new->offset = offset;
+       new->guard_ptr = guard_ptr;
+       new->guard_val = guard_val;
+
+       return new;
+}
+
+
+/* Parse SPE ELF header and generate a list of vma_maps.
+ * A pointer to the first vma_map in the generated list
+ * of vma_maps is returned.  */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu,
+                                            unsigned long spu_elf_start)
+{
+       static const unsigned char expected[EI_PAD] = {
+               [EI_MAG0] = ELFMAG0,
+               [EI_MAG1] = ELFMAG1,
+               [EI_MAG2] = ELFMAG2,
+               [EI_MAG3] = ELFMAG3,
+               [EI_CLASS] = ELFCLASS32,
+               [EI_DATA] = ELFDATA2MSB,
+               [EI_VERSION] = EV_CURRENT,
+               [EI_OSABI] = ELFOSABI_NONE
+       };
+
+       int grd_val;
+       struct vma_to_fileoffset_map *map = NULL;
+       struct spu_overlay_info ovly;
+       unsigned int overlay_tbl_offset = -1;
+       unsigned long phdr_start, shdr_start;
+       Elf32_Ehdr ehdr;
+       Elf32_Phdr phdr;
+       Elf32_Shdr shdr, shdr_str;
+       Elf32_Sym sym;
+       int i, j;
+       char name[32];
+
+       unsigned int ovly_table_sym = 0;
+       unsigned int ovly_buf_table_sym = 0;
+       unsigned int ovly_table_end_sym = 0;
+       unsigned int ovly_buf_table_end_sym = 0;
+       unsigned long ovly_table;
+       unsigned int n_ovlys;
+
+       /* Get and validate ELF header.  */
+
+       if (copy_from_user(&ehdr, (void *) spu_elf_start, sizeof (ehdr)))
+               goto fail;
+
+       if (memcmp(ehdr.e_ident, expected, EI_PAD) != 0) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Unexpected e_ident parsing SPU ELF\n",
+                      __FUNCTION__, __LINE__);
+               goto fail;
+       }
+       if (ehdr.e_machine != EM_SPU) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Unexpected e_machine parsing SPU ELF\n",
+                      __FUNCTION__,  __LINE__);
+               goto fail;
+       }
+       if (ehdr.e_type != ET_EXEC) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Unexpected e_type parsing SPU ELF\n",
+                      __FUNCTION__, __LINE__);
+               goto fail;
+       }
+       phdr_start = spu_elf_start + ehdr.e_phoff;
+       shdr_start = spu_elf_start + ehdr.e_shoff;
+
+       /* Traverse program headers.  */
+       for (i = 0; i < ehdr.e_phnum; i++) {
+               if (copy_from_user(&phdr,
+                                  (void *) (phdr_start + i * sizeof(phdr)),
+                                  sizeof(phdr)))
+                       goto fail;
+
+               if (phdr.p_type != PT_LOAD)
+                       continue;
+               if (phdr.p_flags & (1 << 27))
+                       continue;
+
+               map = vma_map_add(map, phdr.p_vaddr, phdr.p_memsz,
+                                 phdr.p_offset, 0, 0);
+               if (!map)
+                       goto fail;
+       }
+
+       pr_debug("SPU_PROF: Created non-overlay maps\n");
+       /* Traverse section table and search for overlay-related symbols.  */
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               if (copy_from_user(&shdr,
+                                  (void *) (shdr_start + i * sizeof(shdr)),
+                                  sizeof(shdr)))
+                       goto fail;
+
+               if (shdr.sh_type != SHT_SYMTAB)
+                       continue;
+               if (shdr.sh_entsize != sizeof (sym))
+                       continue;
+
+               if (copy_from_user(&shdr_str,
+                                  (void *) (shdr_start + shdr.sh_link *
+                                            sizeof(shdr)),
+                                  sizeof(shdr)))
+                       goto fail;
+
+               if (shdr_str.sh_type != SHT_STRTAB)
+                       goto fail;;
+
+               for (j = 0; j < shdr.sh_size / sizeof (sym); j++) {
+                       if (copy_from_user(&sym, (void *) (spu_elf_start +
+                                                      shdr.sh_offset + j *
+                                                          sizeof (sym)),
+                                          sizeof (sym)))
+                               goto fail;
+
+                       if (copy_from_user(name, (void *)
+                                          (spu_elf_start + shdr_str.sh_offset +
+                                           sym.st_name),
+                                          20))
+                               goto fail;
+
+                       if (memcmp(name, "_ovly_table", 12) == 0)
+                               ovly_table_sym = sym.st_value;
+                       if (memcmp(name, "_ovly_buf_table", 16) == 0)
+                               ovly_buf_table_sym = sym.st_value;
+                       if (memcmp(name, "_ovly_table_end", 16) == 0)
+                               ovly_table_end_sym = sym.st_value;
+                       if (memcmp(name, "_ovly_buf_table_end", 20) == 0)
+                               ovly_buf_table_end_sym = sym.st_value;
+               }
+       }
+
+       /* If we don't have overlays, we're done.  */
+       if (ovly_table_sym == 0 || ovly_buf_table_sym == 0
+           || ovly_table_end_sym == 0 || ovly_buf_table_end_sym == 0) {
+               pr_debug("SPU_PROF: No overlay table found\n");
+               goto out;
+       } else {
+               pr_debug("SPU_PROF: Overlay table found\n");
+       }
+
+       /* The _ovly_table symbol represents a table with one entry
+        * per overlay section.  The _ovly_buf_table symbol represents
+        * a table with one entry per overlay region.
+        * The struct spu_overlay_info gives the structure of the _ovly_table
+        * entries.  The structure of _ovly_table_buf is simply one
+        * u32 word per entry.
+        */
+       overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym,
+                                           aSpu, &grd_val);
+       if (overlay_tbl_offset < 0) {
+               printk(KERN_ERR "SPU_PROF: "
+                      "%s, line %d: Error finding SPU overlay table\n",
+                      __FUNCTION__, __LINE__);
+               goto fail;
+       }
+       ovly_table = spu_elf_start + overlay_tbl_offset;
+
+       n_ovlys = (ovly_table_end_sym -
+                  ovly_table_sym) / sizeof (ovly);
+
+       /* Traverse overlay table.  */
+       for (i = 0; i < n_ovlys; i++) {
+               if (copy_from_user(&ovly, (void *)
+                                  (ovly_table + i * sizeof (ovly)),
+                                  sizeof (ovly)))
+                       goto fail;
+
+               /* The ovly.vma/size/offset arguments are analogous to the same
+                * arguments used above for non-overlay maps.  The final two
+                * args are referred to as the guard pointer and the guard
+                * value.
+                * The guard pointer is an entry in the _ovly_buf_table,
+                * computed using ovly.buf as the index into the table.  Since
+                * ovly.buf values begin at '1' to reference the first (or 0th)
+                * entry in the _ovly_buf_table, the computation subtracts 1
+                * from ovly.buf.
+                * The guard value is stored in the _ovly_buf_table entry and
+                * is an index (starting at 1) back to the _ovly_table entry
+                * that is pointing at this _ovly_buf_table entry.  So, for
+                * example, for an overlay scenario with one overlay segment
+                * and two overlay sections:
+                *      - Section 1 points to the first entry of the
+                *        _ovly_buf_table, which contains a guard value
+                *        of '1', referencing the first (index=0) entry of
+                *        _ovly_table.
+                *      - Section 2 points to the second entry of the
+                *        _ovly_buf_table, which contains a guard value
+                *        of '2', referencing the second (index=1) entry of
+                *        _ovly_table.
+                */
+               map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset,
+                                 ovly_buf_table_sym + (ovly.buf-1) * 4, i+1);
+               if (!map)
+                       goto fail;
+       }
+       goto out;
+
+ fail:
+       map = NULL;
+ out:
+       return map;
+}
index 1a7ef7e246d2bb0c069c396ee63ccc23dd2aa92a..a28cce1d6c24628b82a5e01eb40677557b0bf23f 100644 (file)
@@ -29,6 +29,8 @@ static struct op_powerpc_model *model;
 static struct op_counter_config ctr[OP_MAX_COUNTER];
 static struct op_system_config sys;
 
+static int op_per_cpu_rc;
+
 static void op_handle_interrupt(struct pt_regs *regs)
 {
        model->handle_interrupt(regs, ctr);
@@ -36,25 +38,41 @@ static void op_handle_interrupt(struct pt_regs *regs)
 
 static void op_powerpc_cpu_setup(void *dummy)
 {
-       model->cpu_setup(ctr);
+       int ret;
+
+       ret = model->cpu_setup(ctr);
+
+       if (ret != 0)
+               op_per_cpu_rc = ret;
 }
 
 static int op_powerpc_setup(void)
 {
        int err;
 
+       op_per_cpu_rc = 0;
+
        /* Grab the hardware */
        err = reserve_pmc_hardware(op_handle_interrupt);
        if (err)
                return err;
 
        /* Pre-compute the values to stuff in the hardware registers.  */
-       model->reg_setup(ctr, &sys, model->num_counters);
+       op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
 
-       /* Configure the registers on all cpus.  */
+       if (op_per_cpu_rc)
+               goto out;
+
+       /* Configure the registers on all cpus.  If an error occurs on one
+        * of the cpus, op_per_cpu_rc will be set to the error */
        on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1);
 
-       return 0;
+out:   if (op_per_cpu_rc) {
+               /* error on setup release the performance counter hardware */
+               release_pmc_hardware();
+       }
+
+       return op_per_cpu_rc;
 }
 
 static void op_powerpc_shutdown(void)
@@ -64,16 +82,29 @@ static void op_powerpc_shutdown(void)
 
 static void op_powerpc_cpu_start(void *dummy)
 {
-       model->start(ctr);
+       /* If any of the cpus have return an error, set the
+        * global flag to the error so it can be returned
+        * to the generic OProfile caller.
+        */
+       int ret;
+
+       ret = model->start(ctr);
+       if (ret != 0)
+               op_per_cpu_rc = ret;
 }
 
 static int op_powerpc_start(void)
 {
+       op_per_cpu_rc = 0;
+
        if (model->global_start)
-               model->global_start(ctr);
-       if (model->start)
+               return model->global_start(ctr);
+       if (model->start) {
                on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
-       return 0;
+               return op_per_cpu_rc;
+       }
+       return -EIO; /* No start function is defined for this
+                       power architecture */
 }
 
 static inline void op_powerpc_cpu_stop(void *dummy)
@@ -147,11 +178,13 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
 
        switch (cur_cpu_spec->oprofile_type) {
 #ifdef CONFIG_PPC64
-#ifdef CONFIG_PPC_CELL_NATIVE
+#ifdef CONFIG_OPROFILE_CELL
                case PPC_OPROFILE_CELL:
                        if (firmware_has_feature(FW_FEATURE_LPAR))
                                return -ENODEV;
                        model = &op_model_cell;
+                       ops->sync_start = model->sync_start;
+                       ops->sync_stop = model->sync_stop;
                        break;
 #endif
                case PPC_OPROFILE_RS64:
index 5d1bbaf35ccbe3db836aba30934fb4b5dd6adc14..cc599eb8768b3eac6bbbe1a1ad862d1d80db2283 100644 (file)
@@ -81,7 +81,7 @@ static void pmc_stop_ctrs(void)
 
 /* Configures the counters on this CPU based on the global
  * settings */
-static void fsl7450_cpu_setup(struct op_counter_config *ctr)
+static int fsl7450_cpu_setup(struct op_counter_config *ctr)
 {
        /* freeze all counters */
        pmc_stop_ctrs();
@@ -89,12 +89,14 @@ static void fsl7450_cpu_setup(struct op_counter_config *ctr)
        mtspr(SPRN_MMCR0, mmcr0_val);
        mtspr(SPRN_MMCR1, mmcr1_val);
        mtspr(SPRN_MMCR2, mmcr2_val);
+
+       return 0;
 }
 
 #define NUM_CTRS 6
 
 /* Configures the global settings for the countes on all CPUs. */
-static void fsl7450_reg_setup(struct op_counter_config *ctr,
+static int fsl7450_reg_setup(struct op_counter_config *ctr,
                             struct op_system_config *sys,
                             int num_ctrs)
 {
@@ -126,10 +128,12 @@ static void fsl7450_reg_setup(struct op_counter_config *ctr,
                | mmcr1_event6(ctr[5].event);
 
        mmcr2_val = 0;
+
+       return 0;
 }
 
 /* Sets the counters on this CPU to the chosen values, and starts them */
-static void fsl7450_start(struct op_counter_config *ctr)
+static int fsl7450_start(struct op_counter_config *ctr)
 {
        int i;
 
@@ -148,6 +152,8 @@ static void fsl7450_start(struct op_counter_config *ctr)
        pmc_start_ctrs();
 
        oprofile_running = 1;
+
+       return 0;
 }
 
 /* Stop the counters on this CPU */
@@ -193,7 +199,7 @@ static void fsl7450_handle_interrupt(struct pt_regs *regs,
        /* The freeze bit was set by the interrupt. */
        /* Clear the freeze bit, and reenable the interrupt.
         * The counters won't actually start until the rfi clears
-        * the PMM bit */
+        * the PM/M bit */
        pmc_start_ctrs();
 }
 
index c29293befba9b69c0e0f673c82869e4343802230..d928b54f3a0fb9df3b03bc475b05d0f643e19429 100644 (file)
@@ -5,8 +5,8 @@
  *
  * Author: David Erb (djerb@us.ibm.com)
  * Modifications:
- *         Carl Love <carll@us.ibm.com>
- *         Maynard Johnson <maynardj@us.ibm.com>
+ *        Carl Love <carll@us.ibm.com>
+ *        Maynard Johnson <maynardj@us.ibm.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 
 #include "../platforms/cell/interrupt.h"
 #include "../platforms/cell/cbe_regs.h"
+#include "cell/pr_util.h"
+
+static void cell_global_stop_spu(void);
+
+/*
+ * spu_cycle_reset is the number of cycles between samples.
+ * This variable is used for SPU profiling and should ONLY be set
+ * at the beginning of cell_reg_setup; otherwise, it's read-only.
+ */
+static unsigned int spu_cycle_reset;
+
+#define NUM_SPUS_PER_NODE    8
+#define SPU_CYCLES_EVENT_NUM 2 /*  event number for SPU_CYCLES */
 
 #define PPU_CYCLES_EVENT_NUM 1 /*  event number for CYCLES */
-#define PPU_CYCLES_GRP_NUM   1  /* special group number for identifying
-                                 * PPU_CYCLES event
-                                 */
-#define CBE_COUNT_ALL_CYCLES 0x42800000        /* PPU cycle event specifier */
+#define PPU_CYCLES_GRP_NUM   1 /* special group number for identifying
+                                * PPU_CYCLES event
+                                */
+#define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */
 
 #define NUM_THREADS 2         /* number of physical threads in
                               * physical processor
@@ -51,6 +64,7 @@
 #define NUM_TRACE_BUS_WORDS 4
 #define NUM_INPUT_BUS_WORDS 2
 
+#define MAX_SPU_COUNT 0xFFFFFF /* maximum 24 bit LFSR value */
 
 struct pmc_cntrl_data {
        unsigned long vcntr;
@@ -62,11 +76,10 @@ struct pmc_cntrl_data {
 /*
  * ibm,cbe-perftools rtas parameters
  */
-
 struct pm_signal {
        u16 cpu;                /* Processor to modify */
-       u16 sub_unit;           /* hw subunit this applies to (if applicable) */
-       short int signal_group; /* Signal Group to Enable/Disable */
+       u16 sub_unit;           /* hw subunit this applies to (if applicable)*/
+       short int signal_group; /* Signal Group to Enable/Disable */
        u8 bus_word;            /* Enable/Disable on this Trace/Trigger/Event
                                 * Bus Word(s) (bitmask)
                                 */
@@ -112,21 +125,42 @@ static DEFINE_PER_CPU(unsigned long[NR_PHYS_CTRS], pmc_values);
 
 static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS];
 
-/* Interpetation of hdw_thread:
+/*
+ * The CELL profiling code makes rtas calls to setup the debug bus to
+ * route the performance signals.  Additionally, SPU profiling requires
+ * a second rtas call to setup the hardware to capture the SPU PCs.
+ * The EIO error value is returned if the token lookups or the rtas
+ * call fail.  The EIO error number is the best choice of the existing
+ * error numbers.  The probability of rtas related error is very low.  But
+ * by returning EIO and printing additional information to dmsg the user
+ * will know that OProfile did not start and dmesg will tell them why.
+ * OProfile does not support returning errors on Stop. Not a huge issue
+ * since failure to reset the debug bus or stop the SPU PC collection is
+ * not a fatel issue.  Chances are if the Stop failed, Start doesn't work
+ * either.
+ */
+
+/*
+ * Interpetation of hdw_thread:
  * 0 - even virtual cpus 0, 2, 4,...
  * 1 - odd virtual cpus 1, 3, 5, ...
+ *
+ * FIXME: this is strictly wrong, we need to clean this up in a number
+ * of places. It works for now. -arnd
  */
 static u32 hdw_thread;
 
 static u32 virt_cntr_inter_mask;
 static struct timer_list timer_virt_cntr;
 
-/* pm_signal needs to be global since it is initialized in
+/*
+ * pm_signal needs to be global since it is initialized in
  * cell_reg_setup at the time when the necessary information
  * is available.
  */
 static struct pm_signal pm_signal[NR_PHYS_CTRS];
-static int pm_rtas_token;
+static int pm_rtas_token;    /* token for debug bus setup call */
+static int spu_rtas_token;   /* token for SPU cycle profiling */
 
 static u32 reset_value[NR_PHYS_CTRS];
 static int num_counters;
@@ -147,8 +181,8 @@ rtas_ibm_cbe_perftools(int subfunc, int passthru,
 {
        u64 paddr = __pa(address);
 
-       return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, passthru,
-                        paddr >> 32, paddr & 0xffffffff, length);
+       return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc,
+                        passthru, paddr >> 32, paddr & 0xffffffff, length);
 }
 
 static void pm_rtas_reset_signals(u32 node)
@@ -156,12 +190,13 @@ static void pm_rtas_reset_signals(u32 node)
        int ret;
        struct pm_signal pm_signal_local;
 
-       /*  The debug bus is being set to the passthru disable state.
-        *  However, the FW still expects atleast one legal signal routing
-        *  entry or it will return an error on the arguments.  If we don't
-        *  supply a valid entry, we must ignore all return values.  Ignoring
-        *  all return values means we might miss an error we should be
-        *  concerned about.
+       /*
+        * The debug bus is being set to the passthru disable state.
+        * However, the FW still expects atleast one legal signal routing
+        * entry or it will return an error on the arguments.   If we don't
+        * supply a valid entry, we must ignore all return values.  Ignoring
+        * all return values means we might miss an error we should be
+        * concerned about.
         */
 
        /*  fw expects physical cpu #. */
@@ -175,18 +210,24 @@ static void pm_rtas_reset_signals(u32 node)
                                     &pm_signal_local,
                                     sizeof(struct pm_signal));
 
-       if (ret)
+       if (unlikely(ret))
+               /*
+                * Not a fatal error. For Oprofile stop, the oprofile
+                * functions do not support returning an error for
+                * failure to stop OProfile.
+                */
                printk(KERN_WARNING "%s: rtas returned: %d\n",
                       __FUNCTION__, ret);
 }
 
-static void pm_rtas_activate_signals(u32 node, u32 count)
+static int pm_rtas_activate_signals(u32 node, u32 count)
 {
        int ret;
        int i, j;
        struct pm_signal pm_signal_local[NR_PHYS_CTRS];
 
-       /* There is no debug setup required for the cycles event.
+       /*
+        * There is no debug setup required for the cycles event.
         * Note that only events in the same group can be used.
         * Otherwise, there will be conflicts in correctly routing
         * the signals on the debug bus.  It is the responsiblity
@@ -213,10 +254,14 @@ static void pm_rtas_activate_signals(u32 node, u32 count)
                                             pm_signal_local,
                                             i * sizeof(struct pm_signal));
 
-               if (ret)
+               if (unlikely(ret)) {
                        printk(KERN_WARNING "%s: rtas returned: %d\n",
                               __FUNCTION__, ret);
+                       return -EIO;
+               }
        }
+
+       return 0;
 }
 
 /*
@@ -260,11 +305,12 @@ static void set_pm_event(u32 ctr, int event, u32 unit_mask)
        pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity);
        pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control);
 
-       /* Some of the islands signal selection is based on 64 bit words.
+       /*
+        * Some of the islands signal selection is based on 64 bit words.
         * The debug bus words are 32 bits, the input words to the performance
         * counters are defined as 32 bits.  Need to convert the 64 bit island
         * specification to the appropriate 32 input bit and bus word for the
-        * performance counter event selection.  See the CELL Performance
+        * performance counter event selection.  See the CELL Performance
         * monitoring signals manual and the Perf cntr hardware descriptions
         * for the details.
         */
@@ -298,6 +344,7 @@ static void set_pm_event(u32 ctr, int event, u32 unit_mask)
                                        input_bus[j] = i;
                                        pm_regs.group_control |=
                                            (i << (31 - i));
+
                                        break;
                                }
                        }
@@ -309,7 +356,8 @@ out:
 
 static void write_pm_cntrl(int cpu)
 {
-       /* Oprofile will use 32 bit counters, set bits 7:10 to 0
+       /*
+        * Oprofile will use 32 bit counters, set bits 7:10 to 0
         * pmregs.pm_cntrl is a global
         */
 
@@ -326,7 +374,8 @@ static void write_pm_cntrl(int cpu)
        if (pm_regs.pm_cntrl.freeze == 1)
                val |= CBE_PM_FREEZE_ALL_CTRS;
 
-       /* Routine set_count_mode must be called previously to set
+       /*
+        * Routine set_count_mode must be called previously to set
         * the count mode based on the user selection of user and kernel.
         */
        val |= CBE_PM_COUNT_MODE_SET(pm_regs.pm_cntrl.count_mode);
@@ -336,7 +385,8 @@ static void write_pm_cntrl(int cpu)
 static inline void
 set_count_mode(u32 kernel, u32 user)
 {
-       /* The user must specify user and kernel if they want them. If
+       /*
+        * The user must specify user and kernel if they want them. If
         *  neither is specified, OProfile will count in hypervisor mode.
         *  pm_regs.pm_cntrl is a global
         */
@@ -364,7 +414,7 @@ static inline void enable_ctr(u32 cpu, u32 ctr, u32 * pm07_cntrl)
 
 /*
  * Oprofile is expected to collect data on all CPUs simultaneously.
- * However, there is one set of performance counters per node.  There are
+ * However, there is one set of performance counters per node. There are
  * two hardware threads or virtual CPUs on each node.  Hence, OProfile must
  * multiplex in time the performance counter collection on the two virtual
  * CPUs.  The multiplexing of the performance counters is done by this
@@ -377,19 +427,19 @@ static inline void enable_ctr(u32 cpu, u32 ctr, u32 * pm07_cntrl)
  * pair of per-cpu arrays is used for storing the previous and next
  * pmc values for a given node.
  * NOTE: We use the per-cpu variable to improve cache performance.
+ *
+ * This routine will alternate loading the virtual counters for
+ * virtual CPUs
  */
 static void cell_virtual_cntr(unsigned long data)
 {
-       /* This routine will alternate loading the virtual counters for
-        * virtual CPUs
-        */
        int i, prev_hdw_thread, next_hdw_thread;
        u32 cpu;
        unsigned long flags;
 
-       /* Make sure that the interrupt_hander and
-        * the virt counter are not both playing with
-        * the counters on the same node.
+       /*
+        * Make sure that the interrupt_hander and the virt counter are
+        * not both playing with the counters on the same node.
         */
 
        spin_lock_irqsave(&virt_cntr_lock, flags);
@@ -400,22 +450,25 @@ static void cell_virtual_cntr(unsigned long data)
        hdw_thread = 1 ^ hdw_thread;
        next_hdw_thread = hdw_thread;
 
-       for (i = 0; i < num_counters; i++)
-       /* There are some per thread events.  Must do the
+       /*
+        * There are some per thread events.  Must do the
         * set event, for the thread that is being started
         */
+       for (i = 0; i < num_counters; i++)
                set_pm_event(i,
                        pmc_cntrl[next_hdw_thread][i].evnts,
                        pmc_cntrl[next_hdw_thread][i].masks);
 
-       /* The following is done only once per each node, but
+       /*
+        * The following is done only once per each node, but
         * we need cpu #, not node #, to pass to the cbe_xxx functions.
         */
        for_each_online_cpu(cpu) {
                if (cbe_get_hw_thread_id(cpu))
                        continue;
 
-               /* stop counters, save counter values, restore counts
+               /*
+                * stop counters, save counter values, restore counts
                 * for previous thread
                 */
                cbe_disable_pm(cpu);
@@ -428,7 +481,7 @@ static void cell_virtual_cntr(unsigned long data)
                            == 0xFFFFFFFF)
                                /* If the cntr value is 0xffffffff, we must
                                 * reset that to 0xfffffff0 when the current
-                                * thread is restarted.  This will generate a
+                                * thread is restarted.  This will generate a
                                 * new interrupt and make sure that we never
                                 * restore the counters to the max value.  If
                                 * the counters were restored to the max value,
@@ -444,13 +497,15 @@ static void cell_virtual_cntr(unsigned long data)
                                                      next_hdw_thread)[i]);
                }
 
-               /* Switch to the other thread. Change the interrupt
+               /*
+                * Switch to the other thread. Change the interrupt
                 * and control regs to be scheduled on the CPU
                 * corresponding to the thread to execute.
                 */
                for (i = 0; i < num_counters; i++) {
                        if (pmc_cntrl[next_hdw_thread][i].enabled) {
-                               /* There are some per thread events.
+                               /*
+                                * There are some per thread events.
                                 * Must do the set event, enable_cntr
                                 * for each cpu.
                                 */
@@ -482,17 +537,42 @@ static void start_virt_cntrs(void)
 }
 
 /* This function is called once for all cpus combined */
-static void
-cell_reg_setup(struct op_counter_config *ctr,
-              struct op_system_config *sys, int num_ctrs)
+static int cell_reg_setup(struct op_counter_config *ctr,
+                       struct op_system_config *sys, int num_ctrs)
 {
        int i, j, cpu;
+       spu_cycle_reset = 0;
+
+       if (ctr[0].event == SPU_CYCLES_EVENT_NUM) {
+               spu_cycle_reset = ctr[0].count;
+
+               /*
+                * Each node will need to make the rtas call to start
+                * and stop SPU profiling.  Get the token once and store it.
+                */
+               spu_rtas_token = rtas_token("ibm,cbe-spu-perftools");
+
+               if (unlikely(spu_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+                       printk(KERN_ERR
+                              "%s: rtas token ibm,cbe-spu-perftools unknown\n",
+                              __FUNCTION__);
+                       return -EIO;
+               }
+       }
 
        pm_rtas_token = rtas_token("ibm,cbe-perftools");
-       if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
-               printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
+
+       /*
+        * For all events excetp PPU CYCLEs, each node will need to make
+        * the rtas cbe-perftools call to setup and reset the debug bus.
+        * Make the token lookup call once and store it in the global
+        * variable pm_rtas_token.
+        */
+       if (unlikely(pm_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+               printk(KERN_ERR
+                      "%s: rtas token ibm,cbe-perftools unknown\n",
                       __FUNCTION__);
-               goto out;
+               return -EIO;
        }
 
        num_counters = num_ctrs;
@@ -520,7 +600,8 @@ cell_reg_setup(struct op_counter_config *ctr,
                        per_cpu(pmc_values, j)[i] = 0;
        }
 
-       /* Setup the thread 1 events, map the thread 0 event to the
+       /*
+        * Setup the thread 1 events, map the thread 0 event to the
         * equivalent thread 1 event.
         */
        for (i = 0; i < num_ctrs; ++i) {
@@ -544,9 +625,10 @@ cell_reg_setup(struct op_counter_config *ctr,
        for (i = 0; i < NUM_INPUT_BUS_WORDS; i++)
                input_bus[i] = 0xff;
 
-       /* Our counters count up, and "count" refers to
+       /*
+        * Our counters count up, and "count" refers to
         * how much before the next interrupt, and we interrupt
-        * on overflow.  So we calculate the starting value
+        * on overflow.  So we calculate the starting value
         * which will give us "count" until overflow.
         * Then we set the events on the enabled counters.
         */
@@ -569,28 +651,27 @@ cell_reg_setup(struct op_counter_config *ctr,
                for (i = 0; i < num_counters; ++i) {
                        per_cpu(pmc_values, cpu)[i] = reset_value[i];
                }
-out:
-       ;
+
+       return 0;
 }
 
+
+
 /* This function is called once for each cpu */
-static void cell_cpu_setup(struct op_counter_config *cntr)
+static int cell_cpu_setup(struct op_counter_config *cntr)
 {
        u32 cpu = smp_processor_id();
        u32 num_enabled = 0;
        int i;
 
+       if (spu_cycle_reset)
+               return 0;
+
        /* There is one performance monitor per processor chip (i.e. node),
         * so we only need to perform this function once per node.
         */
        if (cbe_get_hw_thread_id(cpu))
-               goto out;
-
-       if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
-               printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
-                      __FUNCTION__);
-               goto out;
-       }
+               return 0;
 
        /* Stop all counters */
        cbe_disable_pm(cpu);
@@ -609,16 +690,286 @@ static void cell_cpu_setup(struct op_counter_config *cntr)
                }
        }
 
-       pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
+       /*
+        * The pm_rtas_activate_signals will return -EIO if the FW
+        * call failed.
+        */
+       return pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
+}
+
+#define ENTRIES         303
+#define MAXLFSR         0xFFFFFF
+
+/* precomputed table of 24 bit LFSR values */
+static int initial_lfsr[] = {
+ 8221349, 12579195, 5379618, 10097839, 7512963, 7519310, 3955098, 10753424,
+ 15507573, 7458917, 285419, 2641121, 9780088, 3915503, 6668768, 1548716,
+ 4885000, 8774424, 9650099, 2044357, 2304411, 9326253, 10332526, 4421547,
+ 3440748, 10179459, 13332843, 10375561, 1313462, 8375100, 5198480, 6071392,
+ 9341783, 1526887, 3985002, 1439429, 13923762, 7010104, 11969769, 4547026,
+ 2040072, 4025602, 3437678, 7939992, 11444177, 4496094, 9803157, 10745556,
+ 3671780, 4257846, 5662259, 13196905, 3237343, 12077182, 16222879, 7587769,
+ 14706824, 2184640, 12591135, 10420257, 7406075, 3648978, 11042541, 15906893,
+ 11914928, 4732944, 10695697, 12928164, 11980531, 4430912, 11939291, 2917017,
+ 6119256, 4172004, 9373765, 8410071, 14788383, 5047459, 5474428, 1737756,
+ 15967514, 13351758, 6691285, 8034329, 2856544, 14394753, 11310160, 12149558,
+ 7487528, 7542781, 15668898, 12525138, 12790975, 3707933, 9106617, 1965401,
+ 16219109, 12801644, 2443203, 4909502, 8762329, 3120803, 6360315, 9309720,
+ 15164599, 10844842, 4456529, 6667610, 14924259, 884312, 6234963, 3326042,
+ 15973422, 13919464, 5272099, 6414643, 3909029, 2764324, 5237926, 4774955,
+ 10445906, 4955302, 5203726, 10798229, 11443419, 2303395, 333836, 9646934,
+ 3464726, 4159182, 568492, 995747, 10318756, 13299332, 4836017, 8237783,
+ 3878992, 2581665, 11394667, 5672745, 14412947, 3159169, 9094251, 16467278,
+ 8671392, 15230076, 4843545, 7009238, 15504095, 1494895, 9627886, 14485051,
+ 8304291, 252817, 12421642, 16085736, 4774072, 2456177, 4160695, 15409741,
+ 4902868, 5793091, 13162925, 16039714, 782255, 11347835, 14884586, 366972,
+ 16308990, 11913488, 13390465, 2958444, 10340278, 1177858, 1319431, 10426302,
+ 2868597, 126119, 5784857, 5245324, 10903900, 16436004, 3389013, 1742384,
+ 14674502, 10279218, 8536112, 10364279, 6877778, 14051163, 1025130, 6072469,
+ 1988305, 8354440, 8216060, 16342977, 13112639, 3976679, 5913576, 8816697,
+ 6879995, 14043764, 3339515, 9364420, 15808858, 12261651, 2141560, 5636398,
+ 10345425, 10414756, 781725, 6155650, 4746914, 5078683, 7469001, 6799140,
+ 10156444, 9667150, 10116470, 4133858, 2121972, 1124204, 1003577, 1611214,
+ 14304602, 16221850, 13878465, 13577744, 3629235, 8772583, 10881308, 2410386,
+ 7300044, 5378855, 9301235, 12755149, 4977682, 8083074, 10327581, 6395087,
+ 9155434, 15501696, 7514362, 14520507, 15808945, 3244584, 4741962, 9658130,
+ 14336147, 8654727, 7969093, 15759799, 14029445, 5038459, 9894848, 8659300,
+ 13699287, 8834306, 10712885, 14753895, 10410465, 3373251, 309501, 9561475,
+ 5526688, 14647426, 14209836, 5339224, 207299, 14069911, 8722990, 2290950,
+ 3258216, 12505185, 6007317, 9218111, 14661019, 10537428, 11731949, 9027003,
+ 6641507, 9490160, 200241, 9720425, 16277895, 10816638, 1554761, 10431375,
+ 7467528, 6790302, 3429078, 14633753, 14428997, 11463204, 3576212, 2003426,
+ 6123687, 820520, 9992513, 15784513, 5778891, 6428165, 8388607
+};
+
+/*
+ * The hardware uses an LFSR counting sequence to determine when to capture
+ * the SPU PCs.         An LFSR sequence is like a puesdo random number sequence
+ * where each number occurs once in the sequence but the sequence is not in
+ * numerical order. The SPU PC capture is done when the LFSR sequence reaches
+ * the last value in the sequence.  Hence the user specified value N
+ * corresponds to the LFSR number that is N from the end of the sequence.
+ *
+ * To avoid the time to compute the LFSR, a lookup table is used.  The 24 bit
+ * LFSR sequence is broken into four ranges.  The spacing of the precomputed
+ * values is adjusted in each range so the error between the user specifed
+ * number (N) of events between samples and the actual number of events based
+ * on the precomputed value will be les then about 6.2%.  Note, if the user
+ * specifies N < 2^16, the LFSR value that is 2^16 from the end will be used.
+ * This is to prevent the loss of samples because the trace buffer is full.
+ *
+ *        User specified N                  Step between          Index in
+ *                                      precomputed values      precomputed
+ *                                                                 table
+ * 0               to  2^16-1                  ----                  0
+ * 2^16            to  2^16+2^19-1             2^12                1 to 128
+ * 2^16+2^19       to  2^16+2^19+2^22-1        2^15              129 to 256
+ * 2^16+2^19+2^22  to  2^24-1                  2^18              257 to 302
+ *
+ *
+ * For example, the LFSR values in the second range are computed for 2^16,
+ * 2^16+2^12, ... , 2^19-2^16, 2^19 and stored in the table at indicies
+ * 1, 2,..., 127, 128.
+ *
+ * The 24 bit LFSR value for the nth number in the sequence can be
+ * calculated using the following code:
+ *
+ * #define size 24
+ * int calculate_lfsr(int n)
+ * {
+ *     int i;
+ *     unsigned int newlfsr0;
+ *     unsigned int lfsr = 0xFFFFFF;
+ *     unsigned int howmany = n;
+ *
+ *     for (i = 2; i < howmany + 2; i++) {
+ *             newlfsr0 = (((lfsr >> (size - 1 - 0)) & 1) ^
+ *             ((lfsr >> (size - 1 - 1)) & 1) ^
+ *             (((lfsr >> (size - 1 - 6)) & 1) ^
+ *             ((lfsr >> (size - 1 - 23)) & 1)));
+ *
+ *             lfsr >>= 1;
+ *             lfsr = lfsr | (newlfsr0 << (size - 1));
+ *     }
+ *     return lfsr;
+ * }
+ */
+
+#define V2_16  (0x1 << 16)
+#define V2_19  (0x1 << 19)
+#define V2_22  (0x1 << 22)
+
+static int calculate_lfsr(int n)
+{
+       /*
+        * The ranges and steps are in powers of 2 so the calculations
+        * can be done using shifts rather then divide.
+        */
+       int index;
+
+       if ((n >> 16) == 0)
+               index = 0;
+       else if (((n - V2_16) >> 19) == 0)
+               index = ((n - V2_16) >> 12) + 1;
+       else if (((n - V2_16 - V2_19) >> 22) == 0)
+               index = ((n - V2_16 - V2_19) >> 15 ) + 1 + 128;
+       else if (((n - V2_16 - V2_19 - V2_22) >> 24) == 0)
+               index = ((n - V2_16 - V2_19 - V2_22) >> 18 ) + 1 + 256;
+       else
+               index = ENTRIES-1;
+
+       /* make sure index is valid */
+       if ((index > ENTRIES) || (index < 0))
+               index = ENTRIES-1;
+
+       return initial_lfsr[index];
+}
+
+static int pm_rtas_activate_spu_profiling(u32 node)
+{
+       int ret, i;
+       struct pm_signal pm_signal_local[NR_PHYS_CTRS];
+
+       /*
+        * Set up the rtas call to configure the debug bus to
+        * route the SPU PCs.  Setup the pm_signal for each SPU
+        */
+       for (i = 0; i < NUM_SPUS_PER_NODE; i++) {
+               pm_signal_local[i].cpu = node;
+               pm_signal_local[i].signal_group = 41;
+               /* spu i on word (i/2) */
+               pm_signal_local[i].bus_word = 1 << i / 2;
+               /* spu i */
+               pm_signal_local[i].sub_unit = i;
+               pm_signal_local[i].bit = 63;
+       }
+
+       ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE,
+                                    PASSTHRU_ENABLE, pm_signal_local,
+                                    (NUM_SPUS_PER_NODE
+                                     * sizeof(struct pm_signal)));
+
+       if (unlikely(ret)) {
+               printk(KERN_WARNING "%s: rtas returned: %d\n",
+                      __FUNCTION__, ret);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int
+oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void *data)
+{
+       int ret = 0;
+       struct cpufreq_freqs *frq = data;
+       if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) ||
+           (val == CPUFREQ_POSTCHANGE && frq->old > frq->new) ||
+           (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE))
+               set_spu_profiling_frequency(frq->new, spu_cycle_reset);
+       return ret;
+}
+
+static struct notifier_block cpu_freq_notifier_block = {
+       .notifier_call  = oprof_cpufreq_notify
+};
+#endif
+
+static int cell_global_start_spu(struct op_counter_config *ctr)
+{
+       int subfunc;
+       unsigned int lfsr_value;
+       int cpu;
+       int ret;
+       int rtas_error;
+       unsigned int cpu_khzfreq = 0;
+
+       /* The SPU profiling uses time-based profiling based on
+        * cpu frequency, so if configured with the CPU_FREQ
+        * option, we should detect frequency changes and react
+        * accordingly.
+        */
+#ifdef CONFIG_CPU_FREQ
+       ret = cpufreq_register_notifier(&cpu_freq_notifier_block,
+                                       CPUFREQ_TRANSITION_NOTIFIER);
+       if (ret < 0)
+               /* this is not a fatal error */
+               printk(KERN_ERR "CPU freq change registration failed: %d\n",
+                      ret);
+
+       else
+               cpu_khzfreq = cpufreq_quick_get(smp_processor_id());
+#endif
+
+       set_spu_profiling_frequency(cpu_khzfreq, spu_cycle_reset);
+
+       for_each_online_cpu(cpu) {
+               if (cbe_get_hw_thread_id(cpu))
+                       continue;
+
+               /*
+                * Setup SPU cycle-based profiling.
+                * Set perf_mon_control bit 0 to a zero before
+                * enabling spu collection hardware.
+                */
+               cbe_write_pm(cpu, pm_control, 0);
+
+               if (spu_cycle_reset > MAX_SPU_COUNT)
+                       /* use largest possible value */
+                       lfsr_value = calculate_lfsr(MAX_SPU_COUNT-1);
+               else
+                       lfsr_value = calculate_lfsr(spu_cycle_reset);
+
+               /* must use a non zero value. Zero disables data collection. */
+               if (lfsr_value == 0)
+                       lfsr_value = calculate_lfsr(1);
+
+               lfsr_value = lfsr_value << 8; /* shift lfsr to correct
+                                               * register location
+                                               */
+
+               /* debug bus setup */
+               ret = pm_rtas_activate_spu_profiling(cbe_cpu_to_node(cpu));
+
+               if (unlikely(ret)) {
+                       rtas_error = ret;
+                       goto out;
+               }
+
+
+               subfunc = 2;    /* 2 - activate SPU tracing, 3 - deactivate */
+
+               /* start profiling */
+               ret = rtas_call(spu_rtas_token, 3, 1, NULL, subfunc,
+                 cbe_cpu_to_node(cpu), lfsr_value);
+
+               if (unlikely(ret != 0)) {
+                       printk(KERN_ERR
+                              "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+                              __FUNCTION__, ret);
+                       rtas_error = -EIO;
+                       goto out;
+               }
+       }
+
+       rtas_error = start_spu_profiling(spu_cycle_reset);
+       if (rtas_error)
+               goto out_stop;
+
+       oprofile_running = 1;
+       return 0;
+
+out_stop:
+       cell_global_stop_spu();         /* clean up the PMU/debug bus */
 out:
-       ;
+       return rtas_error;
 }
 
-static void cell_global_start(struct op_counter_config *ctr)
+static int cell_global_start_ppu(struct op_counter_config *ctr)
 {
-       u32 cpu;
+       u32 cpu, i;
        u32 interrupt_mask = 0;
-       u32 i;
 
        /* This routine gets called once for the system.
         * There is one performance monitor per node, so we
@@ -651,19 +1002,79 @@ static void cell_global_start(struct op_counter_config *ctr)
        oprofile_running = 1;
        smp_wmb();
 
-       /* NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
-        * executed which manipulates the PMU.  We start the "virtual counter"
+       /*
+        * NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
+        * executed which manipulates the PMU.  We start the "virtual counter"
         * here so that we do not need to synchronize access to the PMU in
         * the above for-loop.
         */
        start_virt_cntrs();
+
+       return 0;
 }
 
-static void cell_global_stop(void)
+static int cell_global_start(struct op_counter_config *ctr)
+{
+       if (spu_cycle_reset)
+               return cell_global_start_spu(ctr);
+       else
+               return cell_global_start_ppu(ctr);
+}
+
+/*
+ * Note the generic OProfile stop calls do not support returning
+ * an error on stop.  Hence, will not return an error if the FW
+ * calls fail on stop. Failure to reset the debug bus is not an issue.
+ * Failure to disable the SPU profiling is not an issue.  The FW calls
+ * to enable the performance counters and debug bus will work even if
+ * the hardware was not cleanly reset.
+ */
+static void cell_global_stop_spu(void)
+{
+       int subfunc, rtn_value;
+       unsigned int lfsr_value;
+       int cpu;
+
+       oprofile_running = 0;
+
+#ifdef CONFIG_CPU_FREQ
+       cpufreq_unregister_notifier(&cpu_freq_notifier_block,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
+       for_each_online_cpu(cpu) {
+               if (cbe_get_hw_thread_id(cpu))
+                       continue;
+
+               subfunc = 3;    /*
+                                * 2 - activate SPU tracing,
+                                * 3 - deactivate
+                                */
+               lfsr_value = 0x8f100000;
+
+               rtn_value = rtas_call(spu_rtas_token, 3, 1, NULL,
+                                     subfunc, cbe_cpu_to_node(cpu),
+                                     lfsr_value);
+
+               if (unlikely(rtn_value != 0)) {
+                       printk(KERN_ERR
+                              "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+                              __FUNCTION__, rtn_value);
+               }
+
+               /* Deactivate the signals */
+               pm_rtas_reset_signals(cbe_cpu_to_node(cpu));
+       }
+
+       stop_spu_profiling();
+}
+
+static void cell_global_stop_ppu(void)
 {
        int cpu;
 
-       /* This routine will be called once for the system.
+       /*
+        * This routine will be called once for the system.
         * There is one performance monitor per node, so we
         * only need to perform this function once per node.
         */
@@ -687,8 +1098,16 @@ static void cell_global_stop(void)
        }
 }
 
-static void
-cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
+static void cell_global_stop(void)
+{
+       if (spu_cycle_reset)
+               cell_global_stop_spu();
+       else
+               cell_global_stop_ppu();
+}
+
+static void cell_handle_interrupt(struct pt_regs *regs,
+                               struct op_counter_config *ctr)
 {
        u32 cpu;
        u64 pc;
@@ -699,13 +1118,15 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
 
        cpu = smp_processor_id();
 
-       /* Need to make sure the interrupt handler and the virt counter
+       /*
+        * Need to make sure the interrupt handler and the virt counter
         * routine are not running at the same time. See the
         * cell_virtual_cntr() routine for additional comments.
         */
        spin_lock_irqsave(&virt_cntr_lock, flags);
 
-       /* Need to disable and reenable the performance counters
+       /*
+        * Need to disable and reenable the performance counters
         * to get the desired behavior from the hardware.  This
         * is hardware specific.
         */
@@ -714,7 +1135,8 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
 
        interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu);
 
-       /* If the interrupt mask has been cleared, then the virt cntr
+       /*
+        * If the interrupt mask has been cleared, then the virt cntr
         * has cleared the interrupt.  When the thread that generated
         * the interrupt is restored, the data count will be restored to
         * 0xffffff0 to cause the interrupt to be regenerated.
@@ -732,18 +1154,20 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
                        }
                }
 
-               /* The counters were frozen by the interrupt.
+               /*
+                * The counters were frozen by the interrupt.
                 * Reenable the interrupt and restart the counters.
                 * If there was a race between the interrupt handler and
-                * the virtual counter routine.  The virutal counter
+                * the virtual counter routine.  The virutal counter
                 * routine may have cleared the interrupts.  Hence must
                 * use the virt_cntr_inter_mask to re-enable the interrupts.
                 */
                cbe_enable_pm_interrupts(cpu, hdw_thread,
                                         virt_cntr_inter_mask);
 
-               /* The writes to the various performance counters only writes
-                * to a latch.  The new values (interrupt setting bits, reset
+               /*
+                * The writes to the various performance counters only writes
+                * to a latch.  The new values (interrupt setting bits, reset
                 * counter value etc.) are not copied to the actual registers
                 * until the performance monitor is enabled.  In order to get
                 * this to work as desired, the permormance monitor needs to
@@ -755,10 +1179,33 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
        spin_unlock_irqrestore(&virt_cntr_lock, flags);
 }
 
+/*
+ * This function is called from the generic OProfile
+ * driver.  When profiling PPUs, we need to do the
+ * generic sync start; otherwise, do spu_sync_start.
+ */
+static int cell_sync_start(void)
+{
+       if (spu_cycle_reset)
+               return spu_sync_start();
+       else
+               return DO_GENERIC_SYNC;
+}
+
+static int cell_sync_stop(void)
+{
+       if (spu_cycle_reset)
+               return spu_sync_stop();
+       else
+               return 1;
+}
+
 struct op_powerpc_model op_model_cell = {
        .reg_setup = cell_reg_setup,
        .cpu_setup = cell_cpu_setup,
        .global_start = cell_global_start,
        .global_stop = cell_global_stop,
+       .sync_start = cell_sync_start,
+       .sync_stop = cell_sync_stop,
        .handle_interrupt = cell_handle_interrupt,
 };
index 2267eb8c661b4bdd3d97581464cd5df234dc9a31..183a28bb1812e7b57f503acc1abbb0d18ec64d8d 100644 (file)
@@ -244,7 +244,7 @@ static void dump_pmcs(void)
                        mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
 }
 
-static void fsl_booke_cpu_setup(struct op_counter_config *ctr)
+static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
 {
        int i;
 
@@ -258,9 +258,11 @@ static void fsl_booke_cpu_setup(struct op_counter_config *ctr)
 
                set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
        }
+
+       return 0;
 }
 
-static void fsl_booke_reg_setup(struct op_counter_config *ctr,
+static int fsl_booke_reg_setup(struct op_counter_config *ctr,
                             struct op_system_config *sys,
                             int num_ctrs)
 {
@@ -276,9 +278,10 @@ static void fsl_booke_reg_setup(struct op_counter_config *ctr,
        for (i = 0; i < num_counters; ++i)
                reset_value[i] = 0x80000000UL - ctr[i].count;
 
+       return 0;
 }
 
-static void fsl_booke_start(struct op_counter_config *ctr)
+static int fsl_booke_start(struct op_counter_config *ctr)
 {
        int i;
 
@@ -308,6 +311,8 @@ static void fsl_booke_start(struct op_counter_config *ctr)
 
        pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
                        mfpmr(PMRN_PMGC0));
+
+       return 0;
 }
 
 static void fsl_booke_stop(void)
index e8a56b0adadcebd6952aa8ee2350f7922eb23e04..c40de461fd4eac5aab53ccbfdb9f705eb43ae554 100644 (file)
@@ -89,7 +89,7 @@ static inline void ctr_write(unsigned int i, u64 val)
 
 
 /* precompute the values to stuff in the hardware registers */
-static void pa6t_reg_setup(struct op_counter_config *ctr,
+static int pa6t_reg_setup(struct op_counter_config *ctr,
                           struct op_system_config *sys,
                           int num_ctrs)
 {
@@ -135,10 +135,12 @@ static void pa6t_reg_setup(struct op_counter_config *ctr,
                pr_debug("reset_value for pmc%u inited to 0x%lx\n",
                                 pmc, reset_value[pmc]);
        }
+
+       return 0;
 }
 
 /* configure registers on this cpu */
-static void pa6t_cpu_setup(struct op_counter_config *ctr)
+static int pa6t_cpu_setup(struct op_counter_config *ctr)
 {
        u64 mmcr0 = mmcr0_val;
        u64 mmcr1 = mmcr1_val;
@@ -154,9 +156,11 @@ static void pa6t_cpu_setup(struct op_counter_config *ctr)
                mfspr(SPRN_PA6T_MMCR0));
        pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
                mfspr(SPRN_PA6T_MMCR1));
+
+       return 0;
 }
 
-static void pa6t_start(struct op_counter_config *ctr)
+static int pa6t_start(struct op_counter_config *ctr)
 {
        int i;
 
@@ -174,6 +178,8 @@ static void pa6t_start(struct op_counter_config *ctr)
        oprofile_running = 1;
 
        pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+
+       return 0;
 }
 
 static void pa6t_stop(void)
index a7c206b665afe4ec0dfb485eb2307b343ddd0cdf..cddc250a6a5cf13325556175cbbed3473c61ec02 100644 (file)
@@ -32,7 +32,7 @@ static u32 mmcr0_val;
 static u64 mmcr1_val;
 static u64 mmcra_val;
 
-static void power4_reg_setup(struct op_counter_config *ctr,
+static int power4_reg_setup(struct op_counter_config *ctr,
                             struct op_system_config *sys,
                             int num_ctrs)
 {
@@ -60,6 +60,8 @@ static void power4_reg_setup(struct op_counter_config *ctr,
                mmcr0_val &= ~MMCR0_PROBLEM_DISABLE;
        else
                mmcr0_val |= MMCR0_PROBLEM_DISABLE;
+
+       return 0;
 }
 
 extern void ppc64_enable_pmcs(void);
@@ -84,7 +86,7 @@ static inline int mmcra_must_set_sample(void)
        return 0;
 }
 
-static void power4_cpu_setup(struct op_counter_config *ctr)
+static int power4_cpu_setup(struct op_counter_config *ctr)
 {
        unsigned int mmcr0 = mmcr0_val;
        unsigned long mmcra = mmcra_val;
@@ -111,9 +113,11 @@ static void power4_cpu_setup(struct op_counter_config *ctr)
            mfspr(SPRN_MMCR1));
        dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(),
            mfspr(SPRN_MMCRA));
+
+       return 0;
 }
 
-static void power4_start(struct op_counter_config *ctr)
+static int power4_start(struct op_counter_config *ctr)
 {
        int i;
        unsigned int mmcr0;
@@ -148,6 +152,7 @@ static void power4_start(struct op_counter_config *ctr)
        oprofile_running = 1;
 
        dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+       return 0;
 }
 
 static void power4_stop(void)
index c731acbfb2a5f6deb431a5f89bec06401fb081f6..a20afe45d936639fc2061a02b948e016cae8ba92 100644 (file)
@@ -88,7 +88,7 @@ static unsigned long reset_value[OP_MAX_COUNTER];
 
 static int num_counters;
 
-static void rs64_reg_setup(struct op_counter_config *ctr,
+static int rs64_reg_setup(struct op_counter_config *ctr,
                           struct op_system_config *sys,
                           int num_ctrs)
 {
@@ -100,9 +100,10 @@ static void rs64_reg_setup(struct op_counter_config *ctr,
                reset_value[i] = 0x80000000UL - ctr[i].count;
 
        /* XXX setup user and kernel profiling */
+       return 0;
 }
 
-static void rs64_cpu_setup(struct op_counter_config *ctr)
+static int rs64_cpu_setup(struct op_counter_config *ctr)
 {
        unsigned int mmcr0;
 
@@ -125,9 +126,11 @@ static void rs64_cpu_setup(struct op_counter_config *ctr)
            mfspr(SPRN_MMCR0));
        dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
            mfspr(SPRN_MMCR1));
+
+       return 0;
 }
 
-static void rs64_start(struct op_counter_config *ctr)
+static int rs64_start(struct op_counter_config *ctr)
 {
        int i;
        unsigned int mmcr0;
@@ -155,6 +158,7 @@ static void rs64_start(struct op_counter_config *ctr)
        mtspr(SPRN_MMCR0, mmcr0);
 
        dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+       return 0;
 }
 
 static void rs64_stop(void)
index 33545d352e9234af9d2d08e0820450bb31aef5be..932538a93c2bb63c9b31ed677cddd5c4364a97e6 100644 (file)
@@ -272,4 +272,14 @@ config CPM2
          you wish to build a kernel for a machine with a CPM2 coprocessor
          on it (826x, 827x, 8560).
 
+config AXON_RAM
+       tristate "Axon DDR2 memory device driver"
+       depends on PPC_IBM_CELL_BLADE
+       default m
+       help
+         It registers one block device per Axon's DDR2 memory bank found
+         on a system. Block devices are called axonram?, their major and
+         minor numbers are available in /proc/devices, /proc/partitions or
+         in /sys/block/axonram?/dev.
+
 endmenu
index 9b2b386ccf48aa2f6ed0650aeca471a2dad29ea3..ac8032034fb8725026ebdf39f7e93790c8fbae38 100644 (file)
@@ -73,4 +73,14 @@ config CBE_CPUFREQ
          For details, take a look at <file:Documentation/cpu-freq/>.
          If you don't have such processor, say N
 
+config CBE_CPUFREQ_PMI
+       tristate "CBE frequency scaling using PMI interface"
+       depends on CBE_CPUFREQ && PPC_PMI && EXPERIMENTAL
+       default n
+       help
+         Select this, if you want to use the PMI interface
+         to switch frequencies. Using PMI, the
+         processor will not only be able to run at lower speed,
+         but also at lower core voltage.
+
 endmenu
index 869af89df6ffe0daaee14ed9f4bda25eecb3247d..f88a7c76f2964f08e8771f7670f58fd14f726496 100644 (file)
@@ -4,7 +4,9 @@ obj-$(CONFIG_PPC_CELL_NATIVE)           += interrupt.o iommu.o setup.o \
 obj-$(CONFIG_CBE_RAS)                  += ras.o
 
 obj-$(CONFIG_CBE_THERM)                        += cbe_thermal.o
-obj-$(CONFIG_CBE_CPUFREQ)              += cbe_cpufreq.o
+obj-$(CONFIG_CBE_CPUFREQ_PMI)          += cbe_cpufreq_pmi.o
+obj-$(CONFIG_CBE_CPUFREQ)              += cbe-cpufreq.o
+cbe-cpufreq-y                          += cbe_cpufreq_pervasive.o cbe_cpufreq.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_CELL_NATIVE)          += smp.o
@@ -23,3 +25,5 @@ obj-$(CONFIG_SPU_BASE)                        += spu_callbacks.o spu_base.o \
                                           $(spu-priv1-y) \
                                           $(spu-manage-y) \
                                           spufs/
+
+obj-$(CONFIG_PCI_MSI)                  += axon_msi.o
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
new file mode 100644 (file)
index 0000000..4c9ab5b
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/reboot.h>
+
+#include <asm/dcr.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+
+
+/*
+ * MSIC registers, specified as offsets from dcr_base
+ */
+#define MSIC_CTRL_REG  0x0
+
+/* Base Address registers specify FIFO location in BE memory */
+#define MSIC_BASE_ADDR_HI_REG  0x3
+#define MSIC_BASE_ADDR_LO_REG  0x4
+
+/* Hold the read/write offsets into the FIFO */
+#define MSIC_READ_OFFSET_REG   0x5
+#define MSIC_WRITE_OFFSET_REG  0x6
+
+
+/* MSIC control register flags */
+#define MSIC_CTRL_ENABLE               0x0001
+#define MSIC_CTRL_FIFO_FULL_ENABLE     0x0002
+#define MSIC_CTRL_IRQ_ENABLE           0x0008
+#define MSIC_CTRL_FULL_STOP_ENABLE     0x0010
+
+/*
+ * The MSIC can be configured to use a FIFO of 32KB, 64KB, 128KB or 256KB.
+ * Currently we're using a 64KB FIFO size.
+ */
+#define MSIC_FIFO_SIZE_SHIFT   16
+#define MSIC_FIFO_SIZE_BYTES   (1 << MSIC_FIFO_SIZE_SHIFT)
+
+/*
+ * To configure the FIFO size as (1 << n) bytes, we write (n - 15) into bits
+ * 8-9 of the MSIC control reg.
+ */
+#define MSIC_CTRL_FIFO_SIZE    (((MSIC_FIFO_SIZE_SHIFT - 15) << 8) & 0x300)
+
+/*
+ * We need to mask the read/write offsets to make sure they stay within
+ * the bounds of the FIFO. Also they should always be 16-byte aligned.
+ */
+#define MSIC_FIFO_SIZE_MASK    ((MSIC_FIFO_SIZE_BYTES - 1) & ~0xFu)
+
+/* Each entry in the FIFO is 16 bytes, the first 4 bytes hold the irq # */
+#define MSIC_FIFO_ENTRY_SIZE   0x10
+
+
+struct axon_msic {
+       struct device_node *dn;
+       struct irq_host *irq_host;
+       __le32 *fifo;
+       dcr_host_t dcr_host;
+       struct list_head list;
+       u32 read_offset;
+       u32 dcr_base;
+};
+
+static LIST_HEAD(axon_msic_list);
+
+static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
+{
+       pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
+
+       dcr_write(msic->dcr_host, msic->dcr_base + dcr_n, val);
+}
+
+static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n)
+{
+       return dcr_read(msic->dcr_host, msic->dcr_base + dcr_n);
+}
+
+static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       struct axon_msic *msic = get_irq_data(irq);
+       u32 write_offset, msi;
+       int idx;
+
+       write_offset = msic_dcr_read(msic, MSIC_WRITE_OFFSET_REG);
+       pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
+
+       /* write_offset doesn't wrap properly, so we have to mask it */
+       write_offset &= MSIC_FIFO_SIZE_MASK;
+
+       while (msic->read_offset != write_offset) {
+               idx  = msic->read_offset / sizeof(__le32);
+               msi  = le32_to_cpu(msic->fifo[idx]);
+               msi &= 0xFFFF;
+
+               pr_debug("axon_msi: woff %x roff %x msi %x\n",
+                         write_offset, msic->read_offset, msi);
+
+               msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
+               msic->read_offset &= MSIC_FIFO_SIZE_MASK;
+
+               if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host)
+                       generic_handle_irq(msi);
+               else
+                       pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
+       }
+
+       desc->chip->eoi(irq);
+}
+
+static struct axon_msic *find_msi_translator(struct pci_dev *dev)
+{
+       struct irq_host *irq_host;
+       struct device_node *dn, *tmp;
+       const phandle *ph;
+       struct axon_msic *msic = NULL;
+
+       dn = pci_device_to_OF_node(dev);
+       if (!dn) {
+               dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
+               return NULL;
+       }
+
+       for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+               ph = of_get_property(dn, "msi-translator", NULL);
+               if (ph)
+                       break;
+       }
+
+       if (!ph) {
+               dev_dbg(&dev->dev,
+                       "axon_msi: no msi-translator property found\n");
+               goto out_error;
+       }
+
+       tmp = dn;
+       dn = of_find_node_by_phandle(*ph);
+       if (!dn) {
+               dev_dbg(&dev->dev,
+                       "axon_msi: msi-translator doesn't point to a node\n");
+               goto out_error;
+       }
+
+       irq_host = irq_find_host(dn);
+       if (!irq_host) {
+               dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n",
+                       dn->full_name);
+               goto out_error;
+       }
+
+       msic = irq_host->host_data;
+
+out_error:
+       of_node_put(dn);
+       of_node_put(tmp);
+
+       return msic;
+}
+
+static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type)
+{
+       if (!find_msi_translator(dev))
+               return -ENODEV;
+
+       return 0;
+}
+
+static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
+{
+       struct device_node *dn, *tmp;
+       struct msi_desc *entry;
+       int len;
+       const u32 *prop;
+
+       dn = pci_device_to_OF_node(dev);
+       if (!dn) {
+               dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
+               return -ENODEV;
+       }
+
+       entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
+
+       for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+               if (entry->msi_attrib.is_64) {
+                       prop = of_get_property(dn, "msi-address-64", &len);
+                       if (prop)
+                               break;
+               }
+
+               prop = of_get_property(dn, "msi-address-32", &len);
+               if (prop)
+                       break;
+       }
+
+       if (!prop) {
+               dev_dbg(&dev->dev,
+                       "axon_msi: no msi-address-(32|64) properties found\n");
+               return -ENOENT;
+       }
+
+       switch (len) {
+       case 8:
+               msg->address_hi = prop[0];
+               msg->address_lo = prop[1];
+               break;
+       case 4:
+               msg->address_hi = 0;
+               msg->address_lo = prop[0];
+               break;
+       default:
+               dev_dbg(&dev->dev,
+                       "axon_msi: malformed msi-address-(32|64) property\n");
+               of_node_put(dn);
+               return -EINVAL;
+       }
+
+       of_node_put(dn);
+
+       return 0;
+}
+
+static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+       unsigned int virq, rc;
+       struct msi_desc *entry;
+       struct msi_msg msg;
+       struct axon_msic *msic;
+
+       msic = find_msi_translator(dev);
+       if (!msic)
+               return -ENODEV;
+
+       rc = setup_msi_msg_address(dev, &msg);
+       if (rc)
+               return rc;
+
+       /* We rely on being able to stash a virq in a u16 */
+       BUILD_BUG_ON(NR_IRQS > 65536);
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               virq = irq_create_direct_mapping(msic->irq_host);
+               if (virq == NO_IRQ) {
+                       dev_warn(&dev->dev,
+                                "axon_msi: virq allocation failed!\n");
+                       return -1;
+               }
+               dev_dbg(&dev->dev, "axon_msi: allocated virq 0x%x\n", virq);
+
+               set_irq_msi(virq, entry);
+               msg.data = virq;
+               write_msi_msg(virq, &msg);
+       }
+
+       return 0;
+}
+
+static void axon_msi_teardown_msi_irqs(struct pci_dev *dev)
+{
+       struct msi_desc *entry;
+
+       dev_dbg(&dev->dev, "axon_msi: tearing down msi irqs\n");
+
+       list_for_each_entry(entry, &dev->msi_list, list) {
+               if (entry->irq == NO_IRQ)
+                       continue;
+
+               set_irq_msi(entry->irq, NULL);
+               irq_dispose_mapping(entry->irq);
+       }
+}
+
+static struct irq_chip msic_irq_chip = {
+       .mask           = mask_msi_irq,
+       .unmask         = unmask_msi_irq,
+       .shutdown       = unmask_msi_irq,
+       .typename       = "AXON-MSI",
+};
+
+static int msic_host_map(struct irq_host *h, unsigned int virq,
+                        irq_hw_number_t hw)
+{
+       set_irq_chip_and_handler(virq, &msic_irq_chip, handle_simple_irq);
+
+       return 0;
+}
+
+static int msic_host_match(struct irq_host *host, struct device_node *dn)
+{
+       struct axon_msic *msic = host->host_data;
+
+       return msic->dn == dn;
+}
+
+static struct irq_host_ops msic_host_ops = {
+       .match  = msic_host_match,
+       .map    = msic_host_map,
+};
+
+static int axon_msi_notify_reboot(struct notifier_block *nb,
+                                 unsigned long code, void *data)
+{
+       struct axon_msic *msic;
+       u32 tmp;
+
+       list_for_each_entry(msic, &axon_msic_list, list) {
+               pr_debug("axon_msi: disabling %s\n", msic->dn->full_name);
+               tmp  = msic_dcr_read(msic, MSIC_CTRL_REG);
+               tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
+               msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
+       }
+
+       return 0;
+}
+
+static struct notifier_block axon_msi_reboot_notifier = {
+       .notifier_call = axon_msi_notify_reboot
+};
+
+static int axon_msi_setup_one(struct device_node *dn)
+{
+       struct page *page;
+       struct axon_msic *msic;
+       unsigned int virq;
+       int dcr_len;
+
+       pr_debug("axon_msi: setting up dn %s\n", dn->full_name);
+
+       msic = kzalloc(sizeof(struct axon_msic), GFP_KERNEL);
+       if (!msic) {
+               printk(KERN_ERR "axon_msi: couldn't allocate msic for %s\n",
+                      dn->full_name);
+               goto out;
+       }
+
+       msic->dcr_base = dcr_resource_start(dn, 0);
+       dcr_len = dcr_resource_len(dn, 0);
+
+       if (msic->dcr_base == 0 || dcr_len == 0) {
+               printk(KERN_ERR
+                      "axon_msi: couldn't parse dcr properties on %s\n",
+                       dn->full_name);
+               goto out;
+       }
+
+       msic->dcr_host = dcr_map(dn, msic->dcr_base, dcr_len);
+       if (!DCR_MAP_OK(msic->dcr_host)) {
+               printk(KERN_ERR "axon_msi: dcr_map failed for %s\n",
+                      dn->full_name);
+               goto out_free_msic;
+       }
+
+       page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
+                               get_order(MSIC_FIFO_SIZE_BYTES));
+       if (!page) {
+               printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
+                      dn->full_name);
+               goto out_free_msic;
+       }
+
+       msic->fifo = page_address(page);
+
+       msic->irq_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, NR_IRQS,
+                                       &msic_host_ops, 0);
+       if (!msic->irq_host) {
+               printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n",
+                      dn->full_name);
+               goto out_free_fifo;
+       }
+
+       msic->irq_host->host_data = msic;
+
+       virq = irq_of_parse_and_map(dn, 0);
+       if (virq == NO_IRQ) {
+               printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n",
+                      dn->full_name);
+               goto out_free_host;
+       }
+
+       msic->dn = of_node_get(dn);
+
+       set_irq_data(virq, msic);
+       set_irq_chained_handler(virq, axon_msi_cascade);
+       pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
+
+       /* Enable the MSIC hardware */
+       msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
+       msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
+                                 (u64)msic->fifo & 0xFFFFFFFF);
+       msic_dcr_write(msic, MSIC_CTRL_REG,
+                       MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
+                       MSIC_CTRL_FIFO_SIZE);
+
+       list_add(&msic->list, &axon_msic_list);
+
+       printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
+
+       return 0;
+
+out_free_host:
+       kfree(msic->irq_host);
+out_free_fifo:
+       __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
+out_free_msic:
+       kfree(msic);
+out:
+
+       return -1;
+}
+
+static int axon_msi_init(void)
+{
+       struct device_node *dn;
+       int found = 0;
+
+       pr_debug("axon_msi: initialising ...\n");
+
+       for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
+               if (axon_msi_setup_one(dn) == 0)
+                       found++;
+       }
+
+       if (found) {
+               ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
+               ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
+               ppc_md.msi_check_device = axon_msi_check_device;
+
+               register_reboot_notifier(&axon_msi_reboot_notifier);
+
+               pr_debug("axon_msi: registered callbacks!\n");
+       }
+
+       return 0;
+}
+arch_initcall(axon_msi_init);
index ab511d5b65a449a567698a787b73036d21f7c414..0b6e8ee85ab10be1faf5f9d985d3e750deff46bf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cpufreq driver for the cell processor
  *
- * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
  *
  * Author: Christian Krafft <krafft@de.ibm.com>
  *
  */
 
 #include <linux/cpufreq.h>
-#include <linux/timer.h>
-
-#include <asm/hw_irq.h>
-#include <asm/io.h>
 #include <asm/machdep.h>
-#include <asm/processor.h>
-#include <asm/prom.h>
-#include <asm/time.h>
-#include <asm/pmi.h>
 #include <asm/of_platform.h>
-
+#include <asm/prom.h>
 #include "cbe_regs.h"
+#include "cbe_cpufreq.h"
 
 static DEFINE_MUTEX(cbe_switch_mutex);
 
@@ -50,159 +43,24 @@ static struct cpufreq_frequency_table cbe_freqs[] = {
        {0,     CPUFREQ_TABLE_END},
 };
 
-/* to write to MIC register */
-static u64 MIC_Slow_Fast_Timer_table[] = {
-       [0 ... 7] = 0x007fc00000000000ull,
-};
-
-/* more values for the MIC */
-static u64 MIC_Slow_Next_Timer_table[] = {
-       0x0000240000000000ull,
-       0x0000268000000000ull,
-       0x000029C000000000ull,
-       0x00002D0000000000ull,
-       0x0000300000000000ull,
-       0x0000334000000000ull,
-       0x000039C000000000ull,
-       0x00003FC000000000ull,
-};
-
-static unsigned int pmi_frequency_limit = 0;
 /*
  * hardware specific functions
  */
 
-static struct of_device *pmi_dev;
-
-#ifdef CONFIG_PPC_PMI
-static int set_pmode_pmi(int cpu, unsigned int pmode)
-{
-       int ret;
-       pmi_message_t pmi_msg;
-#ifdef DEBUG
-       u64 time;
-#endif
-
-       pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
-       pmi_msg.data1 = cbe_cpu_to_node(cpu);
-       pmi_msg.data2 = pmode;
-
-#ifdef DEBUG
-       time = (u64) get_cycles();
-#endif
-
-       pmi_send_message(pmi_dev, pmi_msg);
-       ret = pmi_msg.data2;
-
-       pr_debug("PMI returned slow mode %d\n", ret);
-
-#ifdef DEBUG
-       time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
-       time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
-       pr_debug("had to wait %lu ns for a transition\n", time);
-#endif
-       return ret;
-}
-#endif
-
-static int get_pmode(int cpu)
+static int set_pmode(unsigned int cpu, unsigned int slow_mode)
 {
-       int ret;
-       struct cbe_pmd_regs __iomem *pmd_regs;
-
-       pmd_regs = cbe_get_cpu_pmd_regs(cpu);
-       ret = in_be64(&pmd_regs->pmsr) & 0x07;
-
-       return ret;
-}
-
-static int set_pmode_reg(int cpu, unsigned int pmode)
-{
-       struct cbe_pmd_regs __iomem *pmd_regs;
-       struct cbe_mic_tm_regs __iomem *mic_tm_regs;
-       u64 flags;
-       u64 value;
-
-       local_irq_save(flags);
-
-       mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
-       pmd_regs = cbe_get_cpu_pmd_regs(cpu);
-
-       pr_debug("pm register is mapped at %p\n", &pmd_regs->pmcr);
-       pr_debug("mic register is mapped at %p\n", &mic_tm_regs->slow_fast_timer_0);
-
-       out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
-       out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
-
-       out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
-       out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
-
-       value = in_be64(&pmd_regs->pmcr);
-       /* set bits to zero */
-       value &= 0xFFFFFFFFFFFFFFF8ull;
-       /* set bits to next pmode */
-       value |= pmode;
-
-       out_be64(&pmd_regs->pmcr, value);
-
-       /* wait until new pmode appears in status register */
-       value = in_be64(&pmd_regs->pmsr) & 0x07;
-       while(value != pmode) {
-               cpu_relax();
-               value = in_be64(&pmd_regs->pmsr) & 0x07;
-       }
-
-       local_irq_restore(flags);
-
-       return 0;
-}
+       int rc;
 
-static int set_pmode(int cpu, unsigned int slow_mode) {
-#ifdef CONFIG_PPC_PMI
-       if (pmi_dev)
-               return set_pmode_pmi(cpu, slow_mode);
+       if (cbe_cpufreq_has_pmi)
+               rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
        else
-#endif
-               return set_pmode_reg(cpu, slow_mode);
-}
-
-static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
-{
-       u8 cpu;
-       u8 cbe_pmode_new;
-
-       BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+               rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
 
-       cpu = cbe_node_to_cpu(pmi_msg.data1);
-       cbe_pmode_new = pmi_msg.data2;
+       pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
 
-       pmi_frequency_limit = cbe_freqs[cbe_pmode_new].frequency;
-
-       pr_debug("cbe_handle_pmi: max freq=%d\n", pmi_frequency_limit);
-}
-
-static int pmi_notifier(struct notifier_block *nb,
-                                      unsigned long event, void *data)
-{
-       struct cpufreq_policy *policy = data;
-
-       if (event != CPUFREQ_INCOMPATIBLE)
-               return 0;
-
-       cpufreq_verify_within_limits(policy, 0, pmi_frequency_limit);
-       return 0;
+       return rc;
 }
 
-static struct notifier_block pmi_notifier_block = {
-       .notifier_call = pmi_notifier,
-};
-
-static struct pmi_handler cbe_pmi_handler = {
-       .type                   = PMI_TYPE_FREQ_CHANGE,
-       .handle_pmi_message     = cbe_cpufreq_handle_pmi,
-};
-
-
 /*
  * cpufreq functions
  */
@@ -221,8 +79,19 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        pr_debug("init cpufreq on CPU %d\n", policy->cpu);
 
+       /*
+        * Let's check we can actually get to the CELL regs
+        */
+       if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
+           !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
+               pr_info("invalid CBE regs pointers for cpufreq\n");
+               return -EINVAL;
+       }
+
        max_freqp = of_get_property(cpu, "clock-frequency", NULL);
 
+       of_node_put(cpu);
+
        if (!max_freqp)
                return -EINVAL;
 
@@ -239,10 +108,12 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
        }
 
        policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-       /* if DEBUG is enabled set_pmode() measures the correct latency of a transition */
+
+       /* if DEBUG is enabled set_pmode() measures the latency
+        * of a transition */
        policy->cpuinfo.transition_latency = 25000;
 
-       cur_pmode = get_pmode(policy->cpu);
+       cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
        pr_debug("current pmode is at %d\n",cur_pmode);
 
        policy->cur = cbe_freqs[cur_pmode].frequency;
@@ -253,21 +124,13 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
 
        cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
 
-       if (pmi_dev) {
-               /* frequency might get limited later, initialize limit with max_freq */
-               pmi_frequency_limit = max_freq;
-               cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
-       }
-
-       /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
+       /* this ensures that policy->cpuinfo_min
+        * and policy->cpuinfo_max are set correctly */
        return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
 }
 
 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
 {
-       if (pmi_dev)
-               cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
-
        cpufreq_frequency_table_put_attr(policy->cpu);
        return 0;
 }
@@ -277,13 +140,13 @@ static int cbe_cpufreq_verify(struct cpufreq_policy *policy)
        return cpufreq_frequency_table_verify(policy, cbe_freqs);
 }
 
-
-static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq,
-                           unsigned int relation)
+static int cbe_cpufreq_target(struct cpufreq_policy *policy,
+                             unsigned int target_freq,
+                             unsigned int relation)
 {
        int rc;
        struct cpufreq_freqs freqs;
-       int cbe_pmode_new;
+       unsigned int cbe_pmode_new;
 
        cpufreq_frequency_table_target(policy,
                                       cbe_freqs,
@@ -298,12 +161,14 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target
        mutex_lock(&cbe_switch_mutex);
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
-       pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
+       pr_debug("setting frequency for cpu %d to %d kHz, " \
+                "1/%d of max frequency\n",
                 policy->cpu,
                 cbe_freqs[cbe_pmode_new].frequency,
                 cbe_freqs[cbe_pmode_new].index);
 
        rc = set_pmode(policy->cpu, cbe_pmode_new);
+
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
        mutex_unlock(&cbe_switch_mutex);
 
@@ -326,28 +191,14 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
 
 static int __init cbe_cpufreq_init(void)
 {
-#ifdef CONFIG_PPC_PMI
-       struct device_node *np;
-#endif
        if (!machine_is(cell))
                return -ENODEV;
-#ifdef CONFIG_PPC_PMI
-       np = of_find_node_by_type(NULL, "ibm,pmi");
-
-       pmi_dev = of_find_device_by_node(np);
 
-       if (pmi_dev)
-               pmi_register_handler(pmi_dev, &cbe_pmi_handler);
-#endif
        return cpufreq_register_driver(&cbe_cpufreq_driver);
 }
 
 static void __exit cbe_cpufreq_exit(void)
 {
-#ifdef CONFIG_PPC_PMI
-       if (pmi_dev)
-               pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
-#endif
        cpufreq_unregister_driver(&cbe_cpufreq_driver);
 }
 
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.h b/arch/powerpc/platforms/cell/cbe_cpufreq.h
new file mode 100644 (file)
index 0000000..c1d86bf
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * cbe_cpufreq.h
+ *
+ * This file contains the definitions used by the cbe_cpufreq driver.
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/types.h>
+
+int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode);
+int cbe_cpufreq_get_pmode(int cpu);
+
+int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode);
+
+#if defined(CONFIG_CBE_CPUFREQ_PMI) || defined(CONFIG_CBE_CPUFREQ_PMI_MODULE)
+extern bool cbe_cpufreq_has_pmi;
+#else
+#define cbe_cpufreq_has_pmi (0)
+#endif
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c
new file mode 100644 (file)
index 0000000..163263b
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * pervasive backend for the cbe_cpufreq driver
+ *
+ * This driver makes use of the pervasive unit to
+ * engage the desired frequency.
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <asm/machdep.h>
+#include <asm/hw_irq.h>
+
+#include "cbe_regs.h"
+#include "cbe_cpufreq.h"
+
+/* to write to MIC register */
+static u64 MIC_Slow_Fast_Timer_table[] = {
+       [0 ... 7] = 0x007fc00000000000ull,
+};
+
+/* more values for the MIC */
+static u64 MIC_Slow_Next_Timer_table[] = {
+       0x0000240000000000ull,
+       0x0000268000000000ull,
+       0x000029C000000000ull,
+       0x00002D0000000000ull,
+       0x0000300000000000ull,
+       0x0000334000000000ull,
+       0x000039C000000000ull,
+       0x00003FC000000000ull,
+};
+
+
+int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode)
+{
+       struct cbe_pmd_regs __iomem *pmd_regs;
+       struct cbe_mic_tm_regs __iomem *mic_tm_regs;
+       u64 flags;
+       u64 value;
+#ifdef DEBUG
+       long time;
+#endif
+
+       local_irq_save(flags);
+
+       mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
+       pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+
+#ifdef DEBUG
+       time = jiffies;
+#endif
+
+       out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
+       out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
+
+       out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
+       out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
+
+       value = in_be64(&pmd_regs->pmcr);
+       /* set bits to zero */
+       value &= 0xFFFFFFFFFFFFFFF8ull;
+       /* set bits to next pmode */
+       value |= pmode;
+
+       out_be64(&pmd_regs->pmcr, value);
+
+#ifdef DEBUG
+       /* wait until new pmode appears in status register */
+       value = in_be64(&pmd_regs->pmsr) & 0x07;
+       while (value != pmode) {
+               cpu_relax();
+               value = in_be64(&pmd_regs->pmsr) & 0x07;
+       }
+
+       time = jiffies  - time;
+       time = jiffies_to_msecs(time);
+       pr_debug("had to wait %lu ms for a transition using " \
+                "pervasive unit\n", time);
+#endif
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+
+int cbe_cpufreq_get_pmode(int cpu)
+{
+       int ret;
+       struct cbe_pmd_regs __iomem *pmd_regs;
+
+       pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+       ret = in_be64(&pmd_regs->pmsr) & 0x07;
+
+       return ret;
+}
+
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
new file mode 100644 (file)
index 0000000..fc6f389
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * pmi backend for the cbe_cpufreq driver
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <asm/of_platform.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/pmi.h>
+
+#ifdef DEBUG
+#include <asm/time.h>
+#endif
+
+#include "cbe_regs.h"
+#include "cbe_cpufreq.h"
+
+static u8 pmi_slow_mode_limit[MAX_CBE];
+
+bool cbe_cpufreq_has_pmi = false;
+EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi);
+
+/*
+ * hardware specific functions
+ */
+
+int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode)
+{
+       int ret;
+       pmi_message_t pmi_msg;
+#ifdef DEBUG
+       long time;
+#endif
+       pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
+       pmi_msg.data1 = cbe_cpu_to_node(cpu);
+       pmi_msg.data2 = pmode;
+
+#ifdef DEBUG
+       time = jiffies;
+#endif
+       pmi_send_message(pmi_msg);
+
+#ifdef DEBUG
+       time = jiffies  - time;
+       time = jiffies_to_msecs(time);
+       pr_debug("had to wait %lu ms for a transition using " \
+                "PMI\n", time);
+#endif
+       ret = pmi_msg.data2;
+       pr_debug("PMI returned slow mode %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi);
+
+
+static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg)
+{
+       u8 node, slow_mode;
+
+       BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+
+       node = pmi_msg.data1;
+       slow_mode = pmi_msg.data2;
+
+       pmi_slow_mode_limit[node] = slow_mode;
+
+       pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode);
+}
+
+static int pmi_notifier(struct notifier_block *nb,
+                                      unsigned long event, void *data)
+{
+       struct cpufreq_policy *policy = data;
+       struct cpufreq_frequency_table *cbe_freqs;
+       u8 node;
+
+       cbe_freqs = cpufreq_frequency_get_table(policy->cpu);
+       node = cbe_cpu_to_node(policy->cpu);
+
+       pr_debug("got notified, event=%lu, node=%u\n", event, node);
+
+       if (pmi_slow_mode_limit[node] != 0) {
+               pr_debug("limiting node %d to slow mode %d\n",
+                        node, pmi_slow_mode_limit[node]);
+
+               cpufreq_verify_within_limits(policy, 0,
+
+                       cbe_freqs[pmi_slow_mode_limit[node]].frequency);
+       }
+
+       return 0;
+}
+
+static struct notifier_block pmi_notifier_block = {
+       .notifier_call = pmi_notifier,
+};
+
+static struct pmi_handler cbe_pmi_handler = {
+       .type                   = PMI_TYPE_FREQ_CHANGE,
+       .handle_pmi_message     = cbe_cpufreq_handle_pmi,
+};
+
+
+
+static int __init cbe_cpufreq_pmi_init(void)
+{
+       cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0;
+
+       if (!cbe_cpufreq_has_pmi)
+               return -ENODEV;
+
+       cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+
+       return 0;
+}
+
+static void __exit cbe_cpufreq_pmi_exit(void)
+{
+       cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+       pmi_unregister_handler(&cbe_pmi_handler);
+}
+
+module_init(cbe_cpufreq_pmi_init);
+module_exit(cbe_cpufreq_pmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
index 12c9674b4b1f27d51f20f590613a7f1afb1273be..c8f7f000742216a3a3f87852c6844e4c85b255b0 100644 (file)
@@ -174,6 +174,13 @@ static struct device_node *cbe_get_be_node(int cpu_id)
 
                cpu_handle = of_get_property(np, "cpus", &len);
 
+               /*
+                * the CAB SLOF tree is non compliant, so we just assume
+                * there is only one node
+                */
+               if (WARN_ON_ONCE(!cpu_handle))
+                       return np;
+
                for (i=0; i<len; i++)
                        if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL))
                                return np;
index f370f0fa6f4c87222cd7f679af15b3fc7f00073e..e4132f8f51b31129816102ce5f4400ff74c0f3c4 100644 (file)
@@ -292,7 +292,7 @@ static struct attribute_group ppe_attribute_group = {
 /*
  * initialize throttling with default values
  */
-static void __init init_default_values(void)
+static int __init init_default_values(void)
 {
        int cpu;
        struct cbe_pmd_regs __iomem *pmd_regs;
@@ -339,25 +339,40 @@ static void __init init_default_values(void)
        for_each_possible_cpu (cpu) {
                pr_debug("processing cpu %d\n", cpu);
                sysdev = get_cpu_sysdev(cpu);
+
+               if (!sysdev) {
+                       pr_info("invalid sysdev pointer for cbe_thermal\n");
+                       return -EINVAL;
+               }
+
                pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
 
+               if (!pmd_regs) {
+                       pr_info("invalid CBE regs pointer for cbe_thermal\n");
+                       return -EINVAL;
+               }
+
                out_be64(&pmd_regs->tm_str2, str2);
                out_be64(&pmd_regs->tm_str1.val, str1.val);
                out_be64(&pmd_regs->tm_tpr.val, tpr.val);
                out_be64(&pmd_regs->tm_cr1.val, cr1.val);
                out_be64(&pmd_regs->tm_cr2, cr2);
        }
+
+       return 0;
 }
 
 
 static int __init thermal_init(void)
 {
-       init_default_values();
+       int rc = init_default_values();
 
-       spu_add_sysdev_attr_group(&spu_attribute_group);
-       cpu_add_sysdev_attr_group(&ppe_attribute_group);
+       if (rc == 0) {
+               spu_add_sysdev_attr_group(&spu_attribute_group);
+               cpu_add_sysdev_attr_group(&ppe_attribute_group);
+       }
 
-       return 0;
+       return rc;
 }
 module_init(thermal_init);
 
index 96a8f609690ce846b1d7c58fa04f39b6f1206c02..90124228b8f43c37bd02f06e927402d29a5c058c 100644 (file)
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
 #include <asm/xmon.h>
+#include <asm/prom.h>
+#include "spu_priv1_mmio.h"
 
 const struct spu_management_ops *spu_management_ops;
 EXPORT_SYMBOL_GPL(spu_management_ops);
 
 const struct spu_priv1_ops *spu_priv1_ops;
+EXPORT_SYMBOL_GPL(spu_priv1_ops);
 
-static struct list_head spu_list[MAX_NUMNODES];
-static LIST_HEAD(spu_full_list);
-static DEFINE_MUTEX(spu_mutex);
-static DEFINE_SPINLOCK(spu_list_lock);
+struct cbe_spu_info cbe_spu_info[MAX_NUMNODES];
+EXPORT_SYMBOL_GPL(cbe_spu_info);
 
-EXPORT_SYMBOL_GPL(spu_priv1_ops);
+/*
+ * Protects cbe_spu_info and spu->number.
+ */
+static DEFINE_SPINLOCK(spu_lock);
+
+/*
+ * List of all spus in the system.
+ *
+ * This list is iterated by callers from irq context and callers that
+ * want to sleep.  Thus modifications need to be done with both
+ * spu_full_list_lock and spu_full_list_mutex held, while iterating
+ * through it requires either of these locks.
+ *
+ * In addition spu_full_list_lock protects all assignmens to
+ * spu->mm.
+ */
+static LIST_HEAD(spu_full_list);
+static DEFINE_SPINLOCK(spu_full_list_lock);
+static DEFINE_MUTEX(spu_full_list_mutex);
 
 void spu_invalidate_slbs(struct spu *spu)
 {
@@ -65,12 +84,12 @@ void spu_flush_all_slbs(struct mm_struct *mm)
        struct spu *spu;
        unsigned long flags;
 
-       spin_lock_irqsave(&spu_list_lock, flags);
+       spin_lock_irqsave(&spu_full_list_lock, flags);
        list_for_each_entry(spu, &spu_full_list, full_list) {
                if (spu->mm == mm)
                        spu_invalidate_slbs(spu);
        }
-       spin_unlock_irqrestore(&spu_list_lock, flags);
+       spin_unlock_irqrestore(&spu_full_list_lock, flags);
 }
 
 /* The hack below stinks... try to do something better one of
@@ -88,9 +107,9 @@ void spu_associate_mm(struct spu *spu, struct mm_struct *mm)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&spu_list_lock, flags);
+       spin_lock_irqsave(&spu_full_list_lock, flags);
        spu->mm = mm;
-       spin_unlock_irqrestore(&spu_list_lock, flags);
+       spin_unlock_irqrestore(&spu_full_list_lock, flags);
        if (mm)
                mm_needs_global_tlbie(mm);
 }
@@ -390,7 +409,7 @@ static void spu_free_irqs(struct spu *spu)
                free_irq(spu->irqs[2], spu);
 }
 
-static void spu_init_channels(struct spu *spu)
+void spu_init_channels(struct spu *spu)
 {
        static const struct {
                 unsigned channel;
@@ -423,46 +442,7 @@ static void spu_init_channels(struct spu *spu)
                out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count);
        }
 }
-
-struct spu *spu_alloc_node(int node)
-{
-       struct spu *spu = NULL;
-
-       mutex_lock(&spu_mutex);
-       if (!list_empty(&spu_list[node])) {
-               spu = list_entry(spu_list[node].next, struct spu, list);
-               list_del_init(&spu->list);
-               pr_debug("Got SPU %d %d\n", spu->number, spu->node);
-       }
-       mutex_unlock(&spu_mutex);
-
-       if (spu)
-               spu_init_channels(spu);
-       return spu;
-}
-EXPORT_SYMBOL_GPL(spu_alloc_node);
-
-struct spu *spu_alloc(void)
-{
-       struct spu *spu = NULL;
-       int node;
-
-       for (node = 0; node < MAX_NUMNODES; node++) {
-               spu = spu_alloc_node(node);
-               if (spu)
-                       break;
-       }
-
-       return spu;
-}
-
-void spu_free(struct spu *spu)
-{
-       mutex_lock(&spu_mutex);
-       list_add_tail(&spu->list, &spu_list[spu->node]);
-       mutex_unlock(&spu_mutex);
-}
-EXPORT_SYMBOL_GPL(spu_free);
+EXPORT_SYMBOL_GPL(spu_init_channels);
 
 static int spu_shutdown(struct sys_device *sysdev)
 {
@@ -481,12 +461,12 @@ struct sysdev_class spu_sysdev_class = {
 int spu_add_sysdev_attr(struct sysdev_attribute *attr)
 {
        struct spu *spu;
-       mutex_lock(&spu_mutex);
 
+       mutex_lock(&spu_full_list_mutex);
        list_for_each_entry(spu, &spu_full_list, full_list)
                sysdev_create_file(&spu->sysdev, attr);
+       mutex_unlock(&spu_full_list_mutex);
 
-       mutex_unlock(&spu_mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
@@ -494,12 +474,12 @@ EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
 int spu_add_sysdev_attr_group(struct attribute_group *attrs)
 {
        struct spu *spu;
-       mutex_lock(&spu_mutex);
 
+       mutex_lock(&spu_full_list_mutex);
        list_for_each_entry(spu, &spu_full_list, full_list)
                sysfs_create_group(&spu->sysdev.kobj, attrs);
+       mutex_unlock(&spu_full_list_mutex);
 
-       mutex_unlock(&spu_mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
@@ -508,24 +488,22 @@ EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
 void spu_remove_sysdev_attr(struct sysdev_attribute *attr)
 {
        struct spu *spu;
-       mutex_lock(&spu_mutex);
 
+       mutex_lock(&spu_full_list_mutex);
        list_for_each_entry(spu, &spu_full_list, full_list)
                sysdev_remove_file(&spu->sysdev, attr);
-
-       mutex_unlock(&spu_mutex);
+       mutex_unlock(&spu_full_list_mutex);
 }
 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr);
 
 void spu_remove_sysdev_attr_group(struct attribute_group *attrs)
 {
        struct spu *spu;
-       mutex_lock(&spu_mutex);
 
+       mutex_lock(&spu_full_list_mutex);
        list_for_each_entry(spu, &spu_full_list, full_list)
                sysfs_remove_group(&spu->sysdev.kobj, attrs);
-
-       mutex_unlock(&spu_mutex);
+       mutex_unlock(&spu_full_list_mutex);
 }
 EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group);
 
@@ -553,16 +531,19 @@ static int __init create_spu(void *data)
        int ret;
        static int number;
        unsigned long flags;
+       struct timespec ts;
 
        ret = -ENOMEM;
        spu = kzalloc(sizeof (*spu), GFP_KERNEL);
        if (!spu)
                goto out;
 
+       spu->alloc_state = SPU_FREE;
+
        spin_lock_init(&spu->register_lock);
-       mutex_lock(&spu_mutex);
+       spin_lock(&spu_lock);
        spu->number = number++;
-       mutex_unlock(&spu_mutex);
+       spin_unlock(&spu_lock);
 
        ret = spu_create_spu(spu, data);
 
@@ -579,15 +560,22 @@ static int __init create_spu(void *data)
        if (ret)
                goto out_free_irqs;
 
-       mutex_lock(&spu_mutex);
-       spin_lock_irqsave(&spu_list_lock, flags);
-       list_add(&spu->list, &spu_list[spu->node]);
+       mutex_lock(&cbe_spu_info[spu->node].list_mutex);
+       list_add(&spu->cbe_list, &cbe_spu_info[spu->node].spus);
+       cbe_spu_info[spu->node].n_spus++;
+       mutex_unlock(&cbe_spu_info[spu->node].list_mutex);
+
+       mutex_lock(&spu_full_list_mutex);
+       spin_lock_irqsave(&spu_full_list_lock, flags);
        list_add(&spu->full_list, &spu_full_list);
-       spin_unlock_irqrestore(&spu_list_lock, flags);
-       mutex_unlock(&spu_mutex);
+       spin_unlock_irqrestore(&spu_full_list_lock, flags);
+       mutex_unlock(&spu_full_list_mutex);
+
+       spu->stats.util_state = SPU_UTIL_IDLE_LOADED;
+       ktime_get_ts(&ts);
+       spu->stats.tstamp = timespec_to_ns(&ts);
 
-       spu->stats.utilization_state = SPU_UTIL_IDLE;
-       spu->stats.tstamp = jiffies;
+       INIT_LIST_HEAD(&spu->aff_list);
 
        goto out;
 
@@ -608,12 +596,20 @@ static const char *spu_state_names[] = {
 static unsigned long long spu_acct_time(struct spu *spu,
                enum spu_utilization_state state)
 {
+       struct timespec ts;
        unsigned long long time = spu->stats.times[state];
 
-       if (spu->stats.utilization_state == state)
-               time += jiffies - spu->stats.tstamp;
+       /*
+        * If the spu is idle or the context is stopped, utilization
+        * statistics are not updated.  Apply the time delta from the
+        * last recorded state of the spu.
+        */
+       if (spu->stats.util_state == state) {
+               ktime_get_ts(&ts);
+               time += timespec_to_ns(&ts) - spu->stats.tstamp;
+       }
 
-       return jiffies_to_msecs(time);
+       return time / NSEC_PER_MSEC;
 }
 
 
@@ -623,11 +619,11 @@ static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf)
 
        return sprintf(buf, "%s %llu %llu %llu %llu "
                      "%llu %llu %llu %llu %llu %llu %llu %llu\n",
-               spu_state_names[spu->stats.utilization_state],
+               spu_state_names[spu->stats.util_state],
                spu_acct_time(spu, SPU_UTIL_USER),
                spu_acct_time(spu, SPU_UTIL_SYSTEM),
                spu_acct_time(spu, SPU_UTIL_IOWAIT),
-               spu_acct_time(spu, SPU_UTIL_IDLE),
+               spu_acct_time(spu, SPU_UTIL_IDLE_LOADED),
                spu->stats.vol_ctx_switch,
                spu->stats.invol_ctx_switch,
                spu->stats.slb_flt,
@@ -640,12 +636,146 @@ static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf)
 
 static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL);
 
+/* Hardcoded affinity idxs for QS20 */
+#define SPES_PER_BE 8
+static int QS20_reg_idxs[SPES_PER_BE] =   { 0, 2, 4, 6, 7, 5, 3, 1 };
+static int QS20_reg_memory[SPES_PER_BE] = { 1, 1, 0, 0, 0, 0, 0, 0 };
+
+static struct spu *spu_lookup_reg(int node, u32 reg)
+{
+       struct spu *spu;
+
+       list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+               if (*(u32 *)get_property(spu_devnode(spu), "reg", NULL) == reg)
+                       return spu;
+       }
+       return NULL;
+}
+
+static void init_aff_QS20_harcoded(void)
+{
+       int node, i;
+       struct spu *last_spu, *spu;
+       u32 reg;
+
+       for (node = 0; node < MAX_NUMNODES; node++) {
+               last_spu = NULL;
+               for (i = 0; i < SPES_PER_BE; i++) {
+                       reg = QS20_reg_idxs[i];
+                       spu = spu_lookup_reg(node, reg);
+                       if (!spu)
+                               continue;
+                       spu->has_mem_affinity = QS20_reg_memory[reg];
+                       if (last_spu)
+                               list_add_tail(&spu->aff_list,
+                                               &last_spu->aff_list);
+                       last_spu = spu;
+               }
+       }
+}
+
+static int of_has_vicinity(void)
+{
+       struct spu* spu;
+
+       spu = list_entry(cbe_spu_info[0].spus.next, struct spu, cbe_list);
+       return of_find_property(spu_devnode(spu), "vicinity", NULL) != NULL;
+}
+
+static struct spu *aff_devnode_spu(int cbe, struct device_node *dn)
+{
+       struct spu *spu;
+
+       list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list)
+               if (spu_devnode(spu) == dn)
+                       return spu;
+       return NULL;
+}
+
+static struct spu *
+aff_node_next_to(int cbe, struct device_node *target, struct device_node *avoid)
+{
+       struct spu *spu;
+       const phandle *vic_handles;
+       int lenp, i;
+
+       list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list) {
+               if (spu_devnode(spu) == avoid)
+                       continue;
+               vic_handles = get_property(spu_devnode(spu), "vicinity", &lenp);
+               for (i=0; i < (lenp / sizeof(phandle)); i++) {
+                       if (vic_handles[i] == target->linux_phandle)
+                               return spu;
+               }
+       }
+       return NULL;
+}
+
+static void init_aff_fw_vicinity_node(int cbe)
+{
+       struct spu *spu, *last_spu;
+       struct device_node *vic_dn, *last_spu_dn;
+       phandle avoid_ph;
+       const phandle *vic_handles;
+       const char *name;
+       int lenp, i, added, mem_aff;
+
+       last_spu = list_entry(cbe_spu_info[cbe].spus.next, struct spu, cbe_list);
+       avoid_ph = 0;
+       for (added = 1; added < cbe_spu_info[cbe].n_spus; added++) {
+               last_spu_dn = spu_devnode(last_spu);
+               vic_handles = get_property(last_spu_dn, "vicinity", &lenp);
+
+               for (i = 0; i < (lenp / sizeof(phandle)); i++) {
+                       if (vic_handles[i] == avoid_ph)
+                               continue;
+
+                       vic_dn = of_find_node_by_phandle(vic_handles[i]);
+                       if (!vic_dn)
+                               continue;
+
+                       name = get_property(vic_dn, "name", NULL);
+                       if (strcmp(name, "spe") == 0) {
+                               spu = aff_devnode_spu(cbe, vic_dn);
+                               avoid_ph = last_spu_dn->linux_phandle;
+                       }
+                       else {
+                               mem_aff = strcmp(name, "mic-tm") == 0;
+                               spu = aff_node_next_to(cbe, vic_dn, last_spu_dn);
+                               if (!spu)
+                                       continue;
+                               if (mem_aff) {
+                                       last_spu->has_mem_affinity = 1;
+                                       spu->has_mem_affinity = 1;
+                               }
+                               avoid_ph = vic_dn->linux_phandle;
+                       }
+                       list_add_tail(&spu->aff_list, &last_spu->aff_list);
+                       last_spu = spu;
+                       break;
+               }
+       }
+}
+
+static void init_aff_fw_vicinity(void)
+{
+       int cbe;
+
+       /* sets has_mem_affinity for each spu, as long as the
+        * spu->aff_list list, linking each spu to its neighbors
+        */
+       for (cbe = 0; cbe < MAX_NUMNODES; cbe++)
+               init_aff_fw_vicinity_node(cbe);
+}
+
 static int __init init_spu_base(void)
 {
        int i, ret = 0;
 
-       for (i = 0; i < MAX_NUMNODES; i++)
-               INIT_LIST_HEAD(&spu_list[i]);
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               mutex_init(&cbe_spu_info[i].list_mutex);
+               INIT_LIST_HEAD(&cbe_spu_info[i].spus);
+       }
 
        if (!spu_management_ops)
                goto out;
@@ -675,16 +805,25 @@ static int __init init_spu_base(void)
                fb_append_extra_logo(&logo_spe_clut224, ret);
        }
 
+       mutex_lock(&spu_full_list_mutex);
        xmon_register_spus(&spu_full_list);
-
+       crash_register_spus(&spu_full_list);
+       mutex_unlock(&spu_full_list_mutex);
        spu_add_sysdev_attr(&attr_stat);
 
+       if (of_has_vicinity()) {
+               init_aff_fw_vicinity();
+       } else {
+               long root = of_get_flat_dt_root();
+               if (of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
+                       init_aff_QS20_harcoded();
+       }
+
        return 0;
 
  out_unregister_sysdev_class:
        sysdev_class_unregister(&spu_sysdev_class);
  out:
-
        return ret;
 }
 module_init(init_spu_base);
index 261b507a901afb1f389f51186063a9dcc2156c48..dd2c6688c8aaa6f0bad47ab8b160856b24c34290 100644 (file)
@@ -34,14 +34,27 @@ struct spufs_calls spufs_calls = {
  * this file is not used and the syscalls directly enter the fs code */
 
 asmlinkage long sys_spu_create(const char __user *name,
-               unsigned int flags, mode_t mode)
+               unsigned int flags, mode_t mode, int neighbor_fd)
 {
        long ret;
        struct module *owner = spufs_calls.owner;
+       struct file *neighbor;
+       int fput_needed;
 
        ret = -ENOSYS;
        if (owner && try_module_get(owner)) {
-               ret = spufs_calls.create_thread(name, flags, mode);
+               if (flags & SPU_CREATE_AFFINITY_SPU) {
+                       neighbor = fget_light(neighbor_fd, &fput_needed);
+                       if (neighbor) {
+                               ret = spufs_calls.create_thread(name, flags,
+                                                               mode, neighbor);
+                               fput_light(neighbor, fput_needed);
+                       }
+               }
+               else {
+                       ret = spufs_calls.create_thread(name, flags,
+                                                       mode, NULL);
+               }
                module_put(owner);
        }
        return ret;
index 6d7bd60f5380bf22a477e309b570145a5062df44..6694f86d7000899d6bb67080cc80cd93557f4d04 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <asm/atomic.h>
 #include <asm/spu.h>
@@ -55,12 +56,12 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
        ctx->ops = &spu_backing_ops;
        ctx->owner = get_task_mm(current);
        INIT_LIST_HEAD(&ctx->rq);
+       INIT_LIST_HEAD(&ctx->aff_list);
        if (gang)
                spu_gang_add_ctx(gang, ctx);
        ctx->cpus_allowed = current->cpus_allowed;
        spu_set_timeslice(ctx);
-       ctx->stats.execution_state = SPUCTX_UTIL_USER;
-       ctx->stats.tstamp = jiffies;
+       ctx->stats.util_state = SPU_UTIL_IDLE_LOADED;
 
        atomic_inc(&nr_spu_contexts);
        goto out;
@@ -81,6 +82,8 @@ void destroy_spu_context(struct kref *kref)
        spu_fini_csa(&ctx->csa);
        if (ctx->gang)
                spu_gang_remove_ctx(ctx->gang, ctx);
+       if (ctx->prof_priv_kref)
+               kref_put(ctx->prof_priv_kref, ctx->prof_priv_release);
        BUG_ON(!list_empty(&ctx->rq));
        atomic_dec(&nr_spu_contexts);
        kfree(ctx);
@@ -166,6 +169,39 @@ int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags)
 void spu_acquire_saved(struct spu_context *ctx)
 {
        spu_acquire(ctx);
-       if (ctx->state != SPU_STATE_SAVED)
+       if (ctx->state != SPU_STATE_SAVED) {
+               set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags);
                spu_deactivate(ctx);
+       }
+}
+
+/**
+ * spu_release_saved - unlock spu context and return it to the runqueue
+ * @ctx:       context to unlock
+ */
+void spu_release_saved(struct spu_context *ctx)
+{
+       BUG_ON(ctx->state != SPU_STATE_SAVED);
+
+       if (test_and_clear_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags))
+               spu_activate(ctx, 0);
+
+       spu_release(ctx);
 }
+
+void spu_set_profile_private_kref(struct spu_context *ctx,
+                                 struct kref *prof_info_kref,
+                                 void ( * prof_info_release) (struct kref *kref))
+{
+       ctx->prof_priv_kref = prof_info_kref;
+       ctx->prof_priv_release = prof_info_release;
+}
+EXPORT_SYMBOL_GPL(spu_set_profile_private_kref);
+
+void *spu_get_profile_private_kref(struct spu_context *ctx)
+{
+       return ctx->prof_priv_kref;
+}
+EXPORT_SYMBOL_GPL(spu_get_profile_private_kref);
+
+
index 5d9ad5a0307ba43b6ee47cde43cc25ebcfce907b..5e31799b1e3f929b77286f494215dacbb1749439 100644 (file)
@@ -226,7 +226,7 @@ static void spufs_arch_write_notes(struct file *file)
                spu_acquire_saved(ctx_info->ctx);
                for (j = 0; j < spufs_coredump_num_notes; j++)
                        spufs_arch_write_note(ctx_info, j, file);
-               spu_release(ctx_info->ctx);
+               spu_release_saved(ctx_info->ctx);
                list_del(&ctx_info->list);
                kfree(ctx_info);
        }
index f53a07437472bc51fb2aa99a2d44255c510d9fce..917eab4be486d40ce8f4aa105d84c3325cb2e55f 100644 (file)
@@ -179,16 +179,14 @@ int spufs_handle_class1(struct spu_context *ctx)
        if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
                return 0;
 
-       spuctx_switch_state(ctx, SPUCTX_UTIL_IOWAIT);
+       spuctx_switch_state(ctx, SPU_UTIL_IOWAIT);
 
        pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
                dsisr, ctx->state);
 
        ctx->stats.hash_flt++;
-       if (ctx->state == SPU_STATE_RUNNABLE) {
+       if (ctx->state == SPU_STATE_RUNNABLE)
                ctx->spu->stats.hash_flt++;
-               spu_switch_state(ctx->spu, SPU_UTIL_IOWAIT);
-       }
 
        /* we must not hold the lock when entering spu_handle_mm_fault */
        spu_release(ctx);
@@ -226,7 +224,7 @@ int spufs_handle_class1(struct spu_context *ctx)
        } else
                spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
 
-       spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
+       spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
        return ret;
 }
 EXPORT_SYMBOL_GPL(spufs_handle_class1);
index c2814ea96af2599c0ab32a080bbf06a0e50d948f..7de4e919687b48b717bdb6001f30c088cfe49997 100644 (file)
@@ -370,7 +370,7 @@ spufs_regs_read(struct file *file, char __user *buffer,
 
        spu_acquire_saved(ctx);
        ret = __spufs_regs_read(ctx, buffer, size, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -392,7 +392,7 @@ spufs_regs_write(struct file *file, const char __user *buffer,
        ret = copy_from_user(lscsa->gprs + *pos - size,
                             buffer, size) ? -EFAULT : size;
 
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -421,7 +421,7 @@ spufs_fpcr_read(struct file *file, char __user * buffer,
 
        spu_acquire_saved(ctx);
        ret = __spufs_fpcr_read(ctx, buffer, size, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -443,7 +443,7 @@ spufs_fpcr_write(struct file *file, const char __user * buffer,
        ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
                             buffer, size) ? -EFAULT : size;
 
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -868,7 +868,7 @@ static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
 
        spu_acquire_saved(ctx);
        ret = __spufs_signal1_read(ctx, buf, len, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -934,6 +934,13 @@ static const struct file_operations spufs_signal1_fops = {
        .mmap = spufs_signal1_mmap,
 };
 
+static const struct file_operations spufs_signal1_nosched_fops = {
+       .open = spufs_signal1_open,
+       .release = spufs_signal1_release,
+       .write = spufs_signal1_write,
+       .mmap = spufs_signal1_mmap,
+};
+
 static int spufs_signal2_open(struct inode *inode, struct file *file)
 {
        struct spufs_inode_info *i = SPUFS_I(inode);
@@ -992,7 +999,7 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
 
        spu_acquire_saved(ctx);
        ret = __spufs_signal2_read(ctx, buf, len, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1062,6 +1069,13 @@ static const struct file_operations spufs_signal2_fops = {
        .mmap = spufs_signal2_mmap,
 };
 
+static const struct file_operations spufs_signal2_nosched_fops = {
+       .open = spufs_signal2_open,
+       .release = spufs_signal2_release,
+       .write = spufs_signal2_write,
+       .mmap = spufs_signal2_mmap,
+};
+
 static void spufs_signal1_type_set(void *data, u64 val)
 {
        struct spu_context *ctx = data;
@@ -1612,7 +1626,7 @@ static void spufs_decr_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->decr.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 __spufs_decr_get(void *data)
@@ -1628,7 +1642,7 @@ static u64 spufs_decr_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = __spufs_decr_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
@@ -1637,17 +1651,21 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
 static void spufs_decr_status_set(void *data, u64 val)
 {
        struct spu_context *ctx = data;
-       struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
-       lscsa->decr_status.slot[0] = (u32) val;
-       spu_release(ctx);
+       if (val)
+               ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
+       else
+               ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING;
+       spu_release_saved(ctx);
 }
 
 static u64 __spufs_decr_status_get(void *data)
 {
        struct spu_context *ctx = data;
-       struct spu_lscsa *lscsa = ctx->csa.lscsa;
-       return lscsa->decr_status.slot[0];
+       if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING)
+               return SPU_DECR_STATUS_RUNNING;
+       else
+               return 0;
 }
 
 static u64 spufs_decr_status_get(void *data)
@@ -1656,7 +1674,7 @@ static u64 spufs_decr_status_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = __spufs_decr_status_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
@@ -1668,7 +1686,7 @@ static void spufs_event_mask_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->event_mask.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 __spufs_event_mask_get(void *data)
@@ -1684,7 +1702,7 @@ static u64 spufs_event_mask_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = __spufs_event_mask_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
@@ -1708,7 +1726,7 @@ static u64 spufs_event_status_get(void *data)
 
        spu_acquire_saved(ctx);
        ret = __spufs_event_status_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get,
@@ -1720,7 +1738,7 @@ static void spufs_srr0_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->srr0.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 spufs_srr0_get(void *data)
@@ -1730,7 +1748,7 @@ static u64 spufs_srr0_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = lscsa->srr0.slot[0];
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
@@ -1786,7 +1804,7 @@ static u64 spufs_lslr_get(void *data)
 
        spu_acquire_saved(ctx);
        ret = __spufs_lslr_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1850,7 +1868,7 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_mbox_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1888,7 +1906,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_ibox_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1929,7 +1947,7 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_wbox_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1979,7 +1997,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_dma_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -2030,7 +2048,7 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -2065,14 +2083,26 @@ static const char *ctx_state_names[] = {
 };
 
 static unsigned long long spufs_acct_time(struct spu_context *ctx,
-               enum spuctx_execution_state state)
+               enum spu_utilization_state state)
 {
-       unsigned long time = ctx->stats.times[state];
+       struct timespec ts;
+       unsigned long long time = ctx->stats.times[state];
 
-       if (ctx->stats.execution_state == state)
-               time += jiffies - ctx->stats.tstamp;
+       /*
+        * In general, utilization statistics are updated by the controlling
+        * thread as the spu context moves through various well defined
+        * state transitions, but if the context is lazily loaded its
+        * utilization statistics are not updated as the controlling thread
+        * is not tightly coupled with the execution of the spu context.  We
+        * calculate and apply the time delta from the last recorded state
+        * of the spu context.
+        */
+       if (ctx->spu && ctx->stats.util_state == state) {
+               ktime_get_ts(&ts);
+               time += timespec_to_ns(&ts) - ctx->stats.tstamp;
+       }
 
-       return jiffies_to_msecs(time);
+       return time / NSEC_PER_MSEC;
 }
 
 static unsigned long long spufs_slb_flts(struct spu_context *ctx)
@@ -2107,11 +2137,11 @@ static int spufs_show_stat(struct seq_file *s, void *private)
        spu_acquire(ctx);
        seq_printf(s, "%s %llu %llu %llu %llu "
                      "%llu %llu %llu %llu %llu %llu %llu %llu\n",
-               ctx_state_names[ctx->stats.execution_state],
-               spufs_acct_time(ctx, SPUCTX_UTIL_USER),
-               spufs_acct_time(ctx, SPUCTX_UTIL_SYSTEM),
-               spufs_acct_time(ctx, SPUCTX_UTIL_IOWAIT),
-               spufs_acct_time(ctx, SPUCTX_UTIL_LOADED),
+               ctx_state_names[ctx->stats.util_state],
+               spufs_acct_time(ctx, SPU_UTIL_USER),
+               spufs_acct_time(ctx, SPU_UTIL_SYSTEM),
+               spufs_acct_time(ctx, SPU_UTIL_IOWAIT),
+               spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED),
                ctx->stats.vol_ctx_switch,
                ctx->stats.invol_ctx_switch,
                spufs_slb_flts(ctx),
@@ -2184,8 +2214,8 @@ struct tree_descr spufs_dir_nosched_contents[] = {
        { "mbox_stat", &spufs_mbox_stat_fops, 0444, },
        { "ibox_stat", &spufs_ibox_stat_fops, 0444, },
        { "wbox_stat", &spufs_wbox_stat_fops, 0444, },
-       { "signal1", &spufs_signal1_fops, 0666, },
-       { "signal2", &spufs_signal2_fops, 0666, },
+       { "signal1", &spufs_signal1_nosched_fops, 0222, },
+       { "signal2", &spufs_signal2_nosched_fops, 0222, },
        { "signal1_type", &spufs_signal1_type, 0666, },
        { "signal2_type", &spufs_signal2_type, 0666, },
        { "mss", &spufs_mss_fops, 0666, },
index 212ea78f9051bcf8e7152c2f7f408bd24dd20c5d..71a443253021060abe0a97897f2980a12700aaa0 100644 (file)
@@ -35,7 +35,9 @@ struct spu_gang *alloc_spu_gang(void)
 
        kref_init(&gang->kref);
        mutex_init(&gang->mutex);
+       mutex_init(&gang->aff_mutex);
        INIT_LIST_HEAD(&gang->list);
+       INIT_LIST_HEAD(&gang->aff_list_head);
 
 out:
        return gang;
@@ -73,6 +75,10 @@ void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx)
 {
        mutex_lock(&gang->mutex);
        WARN_ON(ctx->gang != gang);
+       if (!list_empty(&ctx->aff_list)) {
+               list_del_init(&ctx->aff_list);
+               gang->aff_flags &= ~AFF_OFFSETS_SET;
+       }
        list_del_init(&ctx->gang_list);
        gang->contexts--;
        mutex_unlock(&gang->mutex);
index 7eb4d6cbcb743cf73abb0545e3912a759df94ce8..b3d0dd118dd0ededd97d842e7ab9db1408bda23e 100644 (file)
@@ -316,11 +316,107 @@ out:
        return ret;
 }
 
-static int spufs_create_context(struct inode *inode,
-                       struct dentry *dentry,
-                       struct vfsmount *mnt, int flags, int mode)
+static struct spu_context *
+spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
+                                               struct file *filp)
+{
+       struct spu_context *tmp, *neighbor;
+       int count, node;
+       int aff_supp;
+
+       aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
+                                       struct spu, cbe_list))->aff_list);
+
+       if (!aff_supp)
+               return ERR_PTR(-EINVAL);
+
+       if (flags & SPU_CREATE_GANG)
+               return ERR_PTR(-EINVAL);
+
+       if (flags & SPU_CREATE_AFFINITY_MEM &&
+           gang->aff_ref_ctx &&
+           gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
+               return ERR_PTR(-EEXIST);
+
+       if (gang->aff_flags & AFF_MERGED)
+               return ERR_PTR(-EBUSY);
+
+       neighbor = NULL;
+       if (flags & SPU_CREATE_AFFINITY_SPU) {
+               if (!filp || filp->f_op != &spufs_context_fops)
+                       return ERR_PTR(-EINVAL);
+
+               neighbor = get_spu_context(
+                               SPUFS_I(filp->f_dentry->d_inode)->i_ctx);
+
+               if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
+                   !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
+                   !list_entry(neighbor->aff_list.next, struct spu_context,
+                   aff_list)->aff_head)
+                       return ERR_PTR(-EEXIST);
+
+               if (gang != neighbor->gang)
+                       return ERR_PTR(-EINVAL);
+
+               count = 1;
+               list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+                       count++;
+               if (list_empty(&neighbor->aff_list))
+                       count++;
+
+               for (node = 0; node < MAX_NUMNODES; node++) {
+                       if ((cbe_spu_info[node].n_spus - atomic_read(
+                               &cbe_spu_info[node].reserved_spus)) >= count)
+                               break;
+               }
+
+               if (node == MAX_NUMNODES)
+                       return ERR_PTR(-EEXIST);
+       }
+
+       return neighbor;
+}
+
+static void
+spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
+                                       struct spu_context *neighbor)
+{
+       if (flags & SPU_CREATE_AFFINITY_MEM)
+               ctx->gang->aff_ref_ctx = ctx;
+
+       if (flags & SPU_CREATE_AFFINITY_SPU) {
+               if (list_empty(&neighbor->aff_list)) {
+                       list_add_tail(&neighbor->aff_list,
+                               &ctx->gang->aff_list_head);
+                       neighbor->aff_head = 1;
+               }
+
+               if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
+                   || list_entry(neighbor->aff_list.next, struct spu_context,
+                                                       aff_list)->aff_head) {
+                       list_add(&ctx->aff_list, &neighbor->aff_list);
+               } else  {
+                       list_add_tail(&ctx->aff_list, &neighbor->aff_list);
+                       if (neighbor->aff_head) {
+                               neighbor->aff_head = 0;
+                               ctx->aff_head = 1;
+                       }
+               }
+
+               if (!ctx->gang->aff_ref_ctx)
+                       ctx->gang->aff_ref_ctx = ctx;
+       }
+}
+
+static int
+spufs_create_context(struct inode *inode, struct dentry *dentry,
+                       struct vfsmount *mnt, int flags, int mode,
+                       struct file *aff_filp)
 {
        int ret;
+       int affinity;
+       struct spu_gang *gang;
+       struct spu_context *neighbor;
 
        ret = -EPERM;
        if ((flags & SPU_CREATE_NOSCHED) &&
@@ -336,9 +432,29 @@ static int spufs_create_context(struct inode *inode,
        if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
                goto out_unlock;
 
+       gang = NULL;
+       neighbor = NULL;
+       affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
+       if (affinity) {
+               gang = SPUFS_I(inode)->i_gang;
+               ret = -EINVAL;
+               if (!gang)
+                       goto out_unlock;
+               mutex_lock(&gang->aff_mutex);
+               neighbor = spufs_assert_affinity(flags, gang, aff_filp);
+               if (IS_ERR(neighbor)) {
+                       ret = PTR_ERR(neighbor);
+                       goto out_aff_unlock;
+               }
+       }
+
        ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
        if (ret)
-               goto out_unlock;
+               goto out_aff_unlock;
+
+       if (affinity)
+               spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
+                                                               neighbor);
 
        /*
         * get references for dget and mntget, will be released
@@ -352,6 +468,9 @@ static int spufs_create_context(struct inode *inode,
                goto out;
        }
 
+out_aff_unlock:
+       if (affinity)
+               mutex_unlock(&gang->aff_mutex);
 out_unlock:
        mutex_unlock(&inode->i_mutex);
 out:
@@ -450,7 +569,8 @@ out:
 
 static struct file_system_type spufs_type;
 
-long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
+long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode,
+                                                       struct file *filp)
 {
        struct dentry *dentry;
        int ret;
@@ -487,7 +607,7 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
                                        dentry, nd->mnt, mode);
        else
                return spufs_create_context(nd->dentry->d_inode,
-                                       dentry, nd->mnt, flags, mode);
+                                       dentry, nd->mnt, flags, mode, filp);
 
 out_dput:
        dput(dentry);
index 58ae13b7de84cd50677a740f87d2d25dc0cba7ee..0b50fa5cb39d5af406047391ad7914eafd31d9be 100644 (file)
@@ -18,15 +18,17 @@ void spufs_stop_callback(struct spu *spu)
        wake_up_all(&ctx->stop_wq);
 }
 
-static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+static inline int spu_stopped(struct spu_context *ctx, u32 *stat)
 {
        struct spu *spu;
        u64 pte_fault;
 
        *stat = ctx->ops->status_read(ctx);
-       if (ctx->state != SPU_STATE_RUNNABLE)
-               return 1;
+
        spu = ctx->spu;
+       if (ctx->state != SPU_STATE_RUNNABLE ||
+           test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags))
+               return 1;
        pte_fault = spu->dsisr &
            (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
        return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ?
@@ -124,8 +126,10 @@ out:
        return ret;
 }
 
-static int spu_run_init(struct spu_context *ctx, u32 * npc)
+static int spu_run_init(struct spu_context *ctx, u32 *npc)
 {
+       spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
        if (ctx->flags & SPU_CREATE_ISOLATE) {
                unsigned long runcntl;
 
@@ -151,16 +155,20 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc)
                ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
        }
 
+       spuctx_switch_state(ctx, SPU_UTIL_USER);
+
        return 0;
 }
 
-static int spu_run_fini(struct spu_context *ctx, u32 * npc,
-                              u32 * status)
+static int spu_run_fini(struct spu_context *ctx, u32 *npc,
+                              u32 *status)
 {
        int ret = 0;
 
        *status = ctx->ops->status_read(ctx);
        *npc = ctx->ops->npc_read(ctx);
+
+       spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
        spu_release(ctx);
 
        if (signal_pending(current))
@@ -289,10 +297,10 @@ static inline int spu_process_events(struct spu_context *ctx)
        return ret;
 }
 
-long spufs_run_spu(struct file *file, struct spu_context *ctx,
-                  u32 *npc, u32 *event)
+long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
 {
        int ret;
+       struct spu *spu;
        u32 status;
 
        if (mutex_lock_interruptible(&ctx->run_mutex))
@@ -328,6 +336,17 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
                ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
                if (unlikely(ret))
                        break;
+               spu = ctx->spu;
+               if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE,
+                                               &ctx->sched_flags))) {
+                       if (!(status & SPU_STATUS_STOPPED_BY_STOP)) {
+                               spu_switch_notify(spu, ctx);
+                               continue;
+                       }
+               }
+
+               spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
                if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
                    (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
                        ret = spu_process_callback(ctx);
@@ -356,6 +375,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
            (ctx->state == SPU_STATE_RUNNABLE))
                ctx->stats.libassist++;
 
+
        ctx->ops->master_stop(ctx);
        ret = spu_run_fini(ctx, npc, &status);
        spu_yield(ctx);
index e5b4dd1db286e8c834e9d64ca12b6237fc932d6f..227968b4779d3adc531fac2a71ef68dd1f18c386 100644 (file)
@@ -51,9 +51,6 @@ struct spu_prio_array {
        DECLARE_BITMAP(bitmap, MAX_PRIO);
        struct list_head runq[MAX_PRIO];
        spinlock_t runq_lock;
-       struct list_head active_list[MAX_NUMNODES];
-       struct mutex active_mutex[MAX_NUMNODES];
-       int nr_active[MAX_NUMNODES];
        int nr_waiting;
 };
 
@@ -127,7 +124,7 @@ void __spu_update_sched_info(struct spu_context *ctx)
        ctx->policy = current->policy;
 
        /*
-        * A lot of places that don't hold active_mutex poke into
+        * A lot of places that don't hold list_mutex poke into
         * cpus_allowed, including grab_runnable_context which
         * already holds the runq_lock.  So abuse runq_lock
         * to protect this field aswell.
@@ -141,9 +138,9 @@ void spu_update_sched_info(struct spu_context *ctx)
 {
        int node = ctx->spu->node;
 
-       mutex_lock(&spu_prio->active_mutex[node]);
+       mutex_lock(&cbe_spu_info[node].list_mutex);
        __spu_update_sched_info(ctx);
-       mutex_unlock(&spu_prio->active_mutex[node]);
+       mutex_unlock(&cbe_spu_info[node].list_mutex);
 }
 
 static int __node_allowed(struct spu_context *ctx, int node)
@@ -169,56 +166,56 @@ static int node_allowed(struct spu_context *ctx, int node)
        return rval;
 }
 
-/**
- * spu_add_to_active_list - add spu to active list
- * @spu:       spu to add to the active list
- */
-static void spu_add_to_active_list(struct spu *spu)
-{
-       int node = spu->node;
-
-       mutex_lock(&spu_prio->active_mutex[node]);
-       spu_prio->nr_active[node]++;
-       list_add_tail(&spu->list, &spu_prio->active_list[node]);
-       mutex_unlock(&spu_prio->active_mutex[node]);
-}
+static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
 
-static void __spu_remove_from_active_list(struct spu *spu)
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
 {
-       list_del_init(&spu->list);
-       spu_prio->nr_active[spu->node]--;
+       blocking_notifier_call_chain(&spu_switch_notifier,
+                           ctx ? ctx->object_id : 0, spu);
 }
 
-/**
- * spu_remove_from_active_list - remove spu from active list
- * @spu:       spu to remove from the active list
- */
-static void spu_remove_from_active_list(struct spu *spu)
+static void notify_spus_active(void)
 {
-       int node = spu->node;
-
-       mutex_lock(&spu_prio->active_mutex[node]);
-       __spu_remove_from_active_list(spu);
-       mutex_unlock(&spu_prio->active_mutex[node]);
-}
+       int node;
 
-static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
+       /*
+        * Wake up the active spu_contexts.
+        *
+        * When the awakened processes see their "notify_active" flag is set,
+        * they will call spu_switch_notify();
+        */
+       for_each_online_node(node) {
+               struct spu *spu;
 
-static void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
-{
-       blocking_notifier_call_chain(&spu_switch_notifier,
-                           ctx ? ctx->object_id : 0, spu);
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+                       if (spu->alloc_state != SPU_FREE) {
+                               struct spu_context *ctx = spu->ctx;
+                               set_bit(SPU_SCHED_NOTIFY_ACTIVE,
+                                       &ctx->sched_flags);
+                               mb();
+                               wake_up_all(&ctx->stop_wq);
+                       }
+               }
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
+       }
 }
 
 int spu_switch_event_register(struct notifier_block * n)
 {
-       return blocking_notifier_chain_register(&spu_switch_notifier, n);
+       int ret;
+       ret = blocking_notifier_chain_register(&spu_switch_notifier, n);
+       if (!ret)
+               notify_spus_active();
+       return ret;
 }
+EXPORT_SYMBOL_GPL(spu_switch_event_register);
 
 int spu_switch_event_unregister(struct notifier_block * n)
 {
        return blocking_notifier_chain_unregister(&spu_switch_notifier, n);
 }
+EXPORT_SYMBOL_GPL(spu_switch_event_unregister);
 
 /**
  * spu_bind_context - bind spu context to physical spu
@@ -229,6 +226,12 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
 {
        pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
                 spu->number, spu->node);
+       spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
+       if (ctx->flags & SPU_CREATE_NOSCHED)
+               atomic_inc(&cbe_spu_info[spu->node].reserved_spus);
+       if (!list_empty(&ctx->aff_list))
+               atomic_inc(&ctx->gang->aff_sched_count);
 
        ctx->stats.slb_flt_base = spu->stats.slb_flt;
        ctx->stats.class2_intr_base = spu->stats.class2_intr;
@@ -238,6 +241,7 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
        ctx->spu = spu;
        ctx->ops = &spu_hw_ops;
        spu->pid = current->pid;
+       spu->tgid = current->tgid;
        spu_associate_mm(spu, ctx->owner);
        spu->ibox_callback = spufs_ibox_callback;
        spu->wbox_callback = spufs_wbox_callback;
@@ -251,7 +255,153 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
        spu_cpu_affinity_set(spu, raw_smp_processor_id());
        spu_switch_notify(spu, ctx);
        ctx->state = SPU_STATE_RUNNABLE;
-       spu_switch_state(spu, SPU_UTIL_SYSTEM);
+
+       spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
+}
+
+/*
+ * Must be used with the list_mutex held.
+ */
+static inline int sched_spu(struct spu *spu)
+{
+       BUG_ON(!mutex_is_locked(&cbe_spu_info[spu->node].list_mutex));
+
+       return (!spu->ctx || !(spu->ctx->flags & SPU_CREATE_NOSCHED));
+}
+
+static void aff_merge_remaining_ctxs(struct spu_gang *gang)
+{
+       struct spu_context *ctx;
+
+       list_for_each_entry(ctx, &gang->aff_list_head, aff_list) {
+               if (list_empty(&ctx->aff_list))
+                       list_add(&ctx->aff_list, &gang->aff_list_head);
+       }
+       gang->aff_flags |= AFF_MERGED;
+}
+
+static void aff_set_offsets(struct spu_gang *gang)
+{
+       struct spu_context *ctx;
+       int offset;
+
+       offset = -1;
+       list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
+                                                               aff_list) {
+               if (&ctx->aff_list == &gang->aff_list_head)
+                       break;
+               ctx->aff_offset = offset--;
+       }
+
+       offset = 0;
+       list_for_each_entry(ctx, gang->aff_ref_ctx->aff_list.prev, aff_list) {
+               if (&ctx->aff_list == &gang->aff_list_head)
+                       break;
+               ctx->aff_offset = offset++;
+       }
+
+       gang->aff_flags |= AFF_OFFSETS_SET;
+}
+
+static struct spu *aff_ref_location(struct spu_context *ctx, int mem_aff,
+                int group_size, int lowest_offset)
+{
+       struct spu *spu;
+       int node, n;
+
+       /*
+        * TODO: A better algorithm could be used to find a good spu to be
+        *       used as reference location for the ctxs chain.
+        */
+       node = cpu_to_node(raw_smp_processor_id());
+       for (n = 0; n < MAX_NUMNODES; n++, node++) {
+               node = (node < MAX_NUMNODES) ? node : 0;
+               if (!node_allowed(ctx, node))
+                       continue;
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+                       if ((!mem_aff || spu->has_mem_affinity) &&
+                                                       sched_spu(spu)) {
+                               mutex_unlock(&cbe_spu_info[node].list_mutex);
+                               return spu;
+                       }
+               }
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
+       }
+       return NULL;
+}
+
+static void aff_set_ref_point_location(struct spu_gang *gang)
+{
+       int mem_aff, gs, lowest_offset;
+       struct spu_context *ctx;
+       struct spu *tmp;
+
+       mem_aff = gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM;
+       lowest_offset = 0;
+       gs = 0;
+
+       list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+               gs++;
+
+       list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
+                                                               aff_list) {
+               if (&ctx->aff_list == &gang->aff_list_head)
+                       break;
+               lowest_offset = ctx->aff_offset;
+       }
+
+       gang->aff_ref_spu = aff_ref_location(ctx, mem_aff, gs, lowest_offset);
+}
+
+static struct spu *ctx_location(struct spu *ref, int offset, int node)
+{
+       struct spu *spu;
+
+       spu = NULL;
+       if (offset >= 0) {
+               list_for_each_entry(spu, ref->aff_list.prev, aff_list) {
+                       BUG_ON(spu->node != node);
+                       if (offset == 0)
+                               break;
+                       if (sched_spu(spu))
+                               offset--;
+               }
+       } else {
+               list_for_each_entry_reverse(spu, ref->aff_list.next, aff_list) {
+                       BUG_ON(spu->node != node);
+                       if (offset == 0)
+                               break;
+                       if (sched_spu(spu))
+                               offset++;
+               }
+       }
+
+       return spu;
+}
+
+/*
+ * affinity_check is called each time a context is going to be scheduled.
+ * It returns the spu ptr on which the context must run.
+ */
+static int has_affinity(struct spu_context *ctx)
+{
+       struct spu_gang *gang = ctx->gang;
+
+       if (list_empty(&ctx->aff_list))
+               return 0;
+
+       mutex_lock(&gang->aff_mutex);
+       if (!gang->aff_ref_spu) {
+               if (!(gang->aff_flags & AFF_MERGED))
+                       aff_merge_remaining_ctxs(gang);
+               if (!(gang->aff_flags & AFF_OFFSETS_SET))
+                       aff_set_offsets(gang);
+               aff_set_ref_point_location(gang);
+       }
+       mutex_unlock(&gang->aff_mutex);
+
+       return gang->aff_ref_spu != NULL;
 }
 
 /**
@@ -263,9 +413,13 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
 {
        pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
                 spu->pid, spu->number, spu->node);
+       spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
 
-       spu_switch_state(spu, SPU_UTIL_IDLE);
-
+       if (spu->ctx->flags & SPU_CREATE_NOSCHED)
+               atomic_dec(&cbe_spu_info[spu->node].reserved_spus);
+       if (!list_empty(&ctx->aff_list))
+               if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
+                       ctx->gang->aff_ref_spu = NULL;
        spu_switch_notify(spu, NULL);
        spu_unmap_mappings(ctx);
        spu_save(&ctx->csa, spu);
@@ -278,8 +432,8 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
        spu->dma_callback = NULL;
        spu_associate_mm(spu, NULL);
        spu->pid = 0;
+       spu->tgid = 0;
        ctx->ops = &spu_backing_ops;
-       ctx->spu = NULL;
        spu->flags = 0;
        spu->ctx = NULL;
 
@@ -287,6 +441,10 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
                (spu->stats.slb_flt - ctx->stats.slb_flt_base);
        ctx->stats.class2_intr +=
                (spu->stats.class2_intr - ctx->stats.class2_intr_base);
+
+       /* This maps the underlying spu state to idle */
+       spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
+       ctx->spu = NULL;
 }
 
 /**
@@ -352,18 +510,41 @@ static void spu_prio_wait(struct spu_context *ctx)
 
 static struct spu *spu_get_idle(struct spu_context *ctx)
 {
-       struct spu *spu = NULL;
-       int node = cpu_to_node(raw_smp_processor_id());
-       int n;
+       struct spu *spu;
+       int node, n;
+
+       if (has_affinity(ctx)) {
+               node = ctx->gang->aff_ref_spu->node;
 
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               spu = ctx_location(ctx->gang->aff_ref_spu, ctx->aff_offset, node);
+               if (spu && spu->alloc_state == SPU_FREE)
+                       goto found;
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
+               return NULL;
+       }
+
+       node = cpu_to_node(raw_smp_processor_id());
        for (n = 0; n < MAX_NUMNODES; n++, node++) {
                node = (node < MAX_NUMNODES) ? node : 0;
                if (!node_allowed(ctx, node))
                        continue;
-               spu = spu_alloc_node(node);
-               if (spu)
-                       break;
+
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+                       if (spu->alloc_state == SPU_FREE)
+                               goto found;
+               }
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
        }
+
+       return NULL;
+
+ found:
+       spu->alloc_state = SPU_USED;
+       mutex_unlock(&cbe_spu_info[node].list_mutex);
+       pr_debug("Got SPU %d %d\n", spu->number, spu->node);
+       spu_init_channels(spu);
        return spu;
 }
 
@@ -393,15 +574,15 @@ static struct spu *find_victim(struct spu_context *ctx)
                if (!node_allowed(ctx, node))
                        continue;
 
-               mutex_lock(&spu_prio->active_mutex[node]);
-               list_for_each_entry(spu, &spu_prio->active_list[node], list) {
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
                        struct spu_context *tmp = spu->ctx;
 
                        if (tmp->prio > ctx->prio &&
                            (!victim || tmp->prio > victim->prio))
                                victim = spu->ctx;
                }
-               mutex_unlock(&spu_prio->active_mutex[node]);
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
 
                if (victim) {
                        /*
@@ -426,7 +607,11 @@ static struct spu *find_victim(struct spu_context *ctx)
                                victim = NULL;
                                goto restart;
                        }
-                       spu_remove_from_active_list(spu);
+
+                       mutex_lock(&cbe_spu_info[node].list_mutex);
+                       cbe_spu_info[node].nr_active--;
+                       mutex_unlock(&cbe_spu_info[node].list_mutex);
+
                        spu_unbind_context(spu, victim);
                        victim->stats.invol_ctx_switch++;
                        spu->stats.invol_ctx_switch++;
@@ -455,8 +640,6 @@ static struct spu *find_victim(struct spu_context *ctx)
  */
 int spu_activate(struct spu_context *ctx, unsigned long flags)
 {
-       spuctx_switch_state(ctx, SPUCTX_UTIL_SYSTEM);
-
        do {
                struct spu *spu;
 
@@ -477,8 +660,12 @@ int spu_activate(struct spu_context *ctx, unsigned long flags)
                if (!spu && rt_prio(ctx->prio))
                        spu = find_victim(ctx);
                if (spu) {
+                       int node = spu->node;
+
+                       mutex_lock(&cbe_spu_info[node].list_mutex);
                        spu_bind_context(spu, ctx);
-                       spu_add_to_active_list(spu);
+                       cbe_spu_info[node].nr_active++;
+                       mutex_unlock(&cbe_spu_info[node].list_mutex);
                        return 0;
                }
 
@@ -500,7 +687,7 @@ static struct spu_context *grab_runnable_context(int prio, int node)
        int best;
 
        spin_lock(&spu_prio->runq_lock);
-       best = sched_find_first_bit(spu_prio->bitmap);
+       best = find_first_bit(spu_prio->bitmap, prio);
        while (best < prio) {
                struct list_head *rq = &spu_prio->runq[best];
 
@@ -527,11 +714,17 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
        if (spu) {
                new = grab_runnable_context(max_prio, spu->node);
                if (new || force) {
-                       spu_remove_from_active_list(spu);
+                       int node = spu->node;
+
+                       mutex_lock(&cbe_spu_info[node].list_mutex);
                        spu_unbind_context(spu, ctx);
+                       spu->alloc_state = SPU_FREE;
+                       cbe_spu_info[node].nr_active--;
+                       mutex_unlock(&cbe_spu_info[node].list_mutex);
+
                        ctx->stats.vol_ctx_switch++;
                        spu->stats.vol_ctx_switch++;
-                       spu_free(spu);
+
                        if (new)
                                wake_up(&new->stop_wq);
                }
@@ -550,21 +743,11 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
  */
 void spu_deactivate(struct spu_context *ctx)
 {
-       /*
-        * We must never reach this for a nosched context,
-        * but handle the case gracefull instead of panicing.
-        */
-       if (ctx->flags & SPU_CREATE_NOSCHED) {
-               WARN_ON(1);
-               return;
-       }
-
        __spu_deactivate(ctx, 1, MAX_PRIO);
-       spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
 }
 
 /**
- * spu_yield -  yield a physical spu if others are waiting
+ * spu_yield - yield a physical spu if others are waiting
  * @ctx:       spu context to yield
  *
  * Check if there is a higher priority context waiting and if yes
@@ -575,17 +758,12 @@ void spu_yield(struct spu_context *ctx)
 {
        if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
                mutex_lock(&ctx->state_mutex);
-               if (__spu_deactivate(ctx, 0, MAX_PRIO))
-                       spuctx_switch_state(ctx, SPUCTX_UTIL_USER);
-               else {
-                       spuctx_switch_state(ctx, SPUCTX_UTIL_LOADED);
-                       spu_switch_state(ctx->spu, SPU_UTIL_USER);
-               }
+               __spu_deactivate(ctx, 0, MAX_PRIO);
                mutex_unlock(&ctx->state_mutex);
        }
 }
 
-static void spusched_tick(struct spu_context *ctx)
+static noinline void spusched_tick(struct spu_context *ctx)
 {
        if (ctx->flags & SPU_CREATE_NOSCHED)
                return;
@@ -596,7 +774,7 @@ static void spusched_tick(struct spu_context *ctx)
                return;
 
        /*
-        * Unfortunately active_mutex ranks outside of state_mutex, so
+        * Unfortunately list_mutex ranks outside of state_mutex, so
         * we have to trylock here.  If we fail give the context another
         * tick and try again.
         */
@@ -606,12 +784,11 @@ static void spusched_tick(struct spu_context *ctx)
 
                new = grab_runnable_context(ctx->prio + 1, spu->node);
                if (new) {
-
-                       __spu_remove_from_active_list(spu);
                        spu_unbind_context(spu, ctx);
                        ctx->stats.invol_ctx_switch++;
                        spu->stats.invol_ctx_switch++;
-                       spu_free(spu);
+                       spu->alloc_state = SPU_FREE;
+                       cbe_spu_info[spu->node].nr_active--;
                        wake_up(&new->stop_wq);
                        /*
                         * We need to break out of the wait loop in
@@ -632,7 +809,7 @@ static void spusched_tick(struct spu_context *ctx)
  *
  * Return the number of tasks currently running or waiting to run.
  *
- * Note that we don't take runq_lock / active_mutex here.  Reading
+ * Note that we don't take runq_lock / list_mutex here.  Reading
  * a single 32bit value is atomic on powerpc, and we don't care
  * about memory ordering issues here.
  */
@@ -641,7 +818,7 @@ static unsigned long count_active_contexts(void)
        int nr_active = 0, node;
 
        for (node = 0; node < MAX_NUMNODES; node++)
-               nr_active += spu_prio->nr_active[node];
+               nr_active += cbe_spu_info[node].nr_active;
        nr_active += spu_prio->nr_waiting;
 
        return nr_active;
@@ -681,19 +858,18 @@ static void spusched_wake(unsigned long data)
 
 static int spusched_thread(void *unused)
 {
-       struct spu *spu, *next;
+       struct spu *spu;
        int node;
 
        while (!kthread_should_stop()) {
                set_current_state(TASK_INTERRUPTIBLE);
                schedule();
                for (node = 0; node < MAX_NUMNODES; node++) {
-                       mutex_lock(&spu_prio->active_mutex[node]);
-                       list_for_each_entry_safe(spu, next,
-                                                &spu_prio->active_list[node],
-                                                list)
-                               spusched_tick(spu->ctx);
-                       mutex_unlock(&spu_prio->active_mutex[node]);
+                       mutex_lock(&cbe_spu_info[node].list_mutex);
+                       list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
+                               if (spu->ctx)
+                                       spusched_tick(spu->ctx);
+                       mutex_unlock(&cbe_spu_info[node].list_mutex);
                }
        }
 
@@ -751,10 +927,9 @@ int __init spu_sched_init(void)
                INIT_LIST_HEAD(&spu_prio->runq[i]);
                __clear_bit(i, spu_prio->bitmap);
        }
-       __set_bit(MAX_PRIO, spu_prio->bitmap);
        for (i = 0; i < MAX_NUMNODES; i++) {
-               mutex_init(&spu_prio->active_mutex[i]);
-               INIT_LIST_HEAD(&spu_prio->active_list[i]);
+               mutex_init(&cbe_spu_info[i].list_mutex);
+               INIT_LIST_HEAD(&cbe_spu_info[i].spus);
        }
        spin_lock_init(&spu_prio->runq_lock);
 
@@ -783,9 +958,9 @@ int __init spu_sched_init(void)
        return err;
 }
 
-void __exit spu_sched_exit(void)
+void spu_sched_exit(void)
 {
-       struct spu *spu, *tmp;
+       struct spu *spu;
        int node;
 
        remove_proc_entry("spu_loadavg", NULL);
@@ -794,13 +969,11 @@ void __exit spu_sched_exit(void)
        kthread_stop(spusched_task);
 
        for (node = 0; node < MAX_NUMNODES; node++) {
-               mutex_lock(&spu_prio->active_mutex[node]);
-               list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node],
-                                        list) {
-                       list_del_init(&spu->list);
-                       spu_free(spu);
-               }
-               mutex_unlock(&spu_prio->active_mutex[node]);
+               mutex_lock(&cbe_spu_info[node].list_mutex);
+               list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
+                       if (spu->alloc_state != SPU_FREE)
+                               spu->alloc_state = SPU_FREE;
+               mutex_unlock(&cbe_spu_info[node].list_mutex);
        }
        kfree(spu_prio);
 }
index 4e19ed7a07568b67991e4e1fce53ca1e9ee65cec..21a9c952d88b4435edbb820a0a98790b1489e058 100644 (file)
@@ -84,13 +84,13 @@ static inline void restore_decr(void)
        unsigned int decr_running;
        unsigned int decr;
 
-       /* Restore, Step 6:
+       /* Restore, Step 6(moved):
         *    If the LSCSA "decrementer running" flag is set
         *    then write the SPU_WrDec channel with the
         *    decrementer value from LSCSA.
         */
        offset = LSCSA_QW_OFFSET(decr_status);
-       decr_running = regs_spill[offset].slot[0];
+       decr_running = regs_spill[offset].slot[0] & SPU_DECR_STATUS_RUNNING;
        if (decr_running) {
                offset = LSCSA_QW_OFFSET(decr);
                decr = regs_spill[offset].slot[0];
@@ -318,10 +318,10 @@ int main()
        build_dma_list(lscsa_ea);       /* Step 3.  */
        restore_upper_240kb(lscsa_ea);  /* Step 4.  */
                                        /* Step 5: done by 'exit'. */
-       restore_decr();                 /* Step 6. */
        enqueue_putllc(lscsa_ea);       /* Step 7. */
        set_tag_update();               /* Step 8. */
        read_tag_status();              /* Step 9. */
+       restore_decr();                 /* moved Step 6. */
        read_llar_status();             /* Step 10. */
        write_ppu_mb();                 /* Step 11. */
        write_ppuint_mb();              /* Step 12. */
index 15183d209b580f300547769e292d1839d7a580cb..f383b027e8bfd734d78d819c9012252e17dcc34e 100644 (file)
@@ -10,7 +10,7 @@ static unsigned int spu_restore_code[]  __attribute__((__aligned__(128))) = {
 0x24fd8081,
 0x1cd80081,
 0x33001180,
-0x42030003,
+0x42034003,
 0x33800284,
 0x1c010204,
 0x40200000,
@@ -24,22 +24,22 @@ static unsigned int spu_restore_code[]  __attribute__((__aligned__(128))) = {
 0x23fffd84,
 0x1c100183,
 0x217ffa85,
-0x3080a000,
-0x3080a201,
-0x3080a402,
-0x3080a603,
-0x3080a804,
-0x3080aa05,
-0x3080ac06,
-0x3080ae07,
-0x3080b008,
-0x3080b209,
-0x3080b40a,
-0x3080b60b,
-0x3080b80c,
-0x3080ba0d,
-0x3080bc0e,
-0x3080be0f,
+0x3080b000,
+0x3080b201,
+0x3080b402,
+0x3080b603,
+0x3080b804,
+0x3080ba05,
+0x3080bc06,
+0x3080be07,
+0x3080c008,
+0x3080c209,
+0x3080c40a,
+0x3080c60b,
+0x3080c80c,
+0x3080ca0d,
+0x3080cc0e,
+0x3080ce0f,
 0x00003ffc,
 0x00000000,
 0x00000000,
@@ -48,19 +48,18 @@ static unsigned int spu_restore_code[]  __attribute__((__aligned__(128))) = {
 0x3ec00083,
 0xb0a14103,
 0x01a00204,
-0x3ec10082,
-0x4202800e,
-0x04000703,
-0xb0a14202,
-0x21a00803,
-0x3fbf028d,
-0x3f20068d,
-0x3fbe0682,
+0x3ec10083,
+0x4202c002,
+0xb0a14203,
+0x21a00802,
+0x3fbf028a,
+0x3f20050a,
+0x3fbe0502,
 0x3fe30102,
 0x21a00882,
-0x3f82028f,
-0x3fe3078f,
-0x3fbf0784,
+0x3f82028b,
+0x3fe3058b,
+0x3fbf0584,
 0x3f200204,
 0x3fbe0204,
 0x3fe30204,
@@ -75,252 +74,285 @@ static unsigned int spu_restore_code[]  __attribute__((__aligned__(128))) = {
 0x21a00083,
 0x40800082,
 0x21a00b02,
-0x10002818,
-0x42a00002,
-0x32800007,
-0x4207000c,
-0x18008208,
-0x40a0000b,
-0x4080020a,
-0x40800709,
-0x00200000,
-0x42070002,
-0x3ac30384,
+0x10002612,
+0x42a00003,
+0x42074006,
+0x1800c204,
+0x40a00008,
+0x40800789,
+0x1c010305,
+0x34000302,
 0x1cffc489,
-0x00200000,
-0x18008383,
-0x38830382,
-0x4cffc486,
-0x3ac28185,
-0xb0408584,
-0x28830382,
-0x1c020387,
-0x38828182,
-0xb0408405,
-0x1802c408,
-0x28828182,
-0x217ff886,
-0x04000583,
-0x21a00803,
-0x3fbe0682,
-0x3fe30102,
-0x04000106,
-0x21a00886,
-0x04000603,
-0x21a00903,
-0x40803c02,
-0x21a00982,
-0x40800003,
-0x04000184,
-0x21a00a04,
+0x3ec00303,
+0x3ec00287,
+0xb0408403,
+0x24000302,
+0x34000282,
+0x1c020306,
+0xb0408207,
+0x18020204,
+0x24000282,
+0x217ffa09,
+0x04000402,
+0x21a00802,
+0x3fbe0504,
+0x3fe30204,
+0x21a00884,
+0x42074002,
+0x21a00902,
+0x40803c03,
+0x21a00983,
+0x04000485,
+0x21a00a05,
 0x40802202,
 0x21a00a82,
-0x42028005,
-0x34208702,
-0x21002282,
-0x21a00804,
-0x21a00886,
-0x3fbf0782,
+0x21a00805,
+0x21a00884,
+0x3fbf0582,
 0x3f200102,
 0x3fbe0102,
 0x3fe30102,
 0x21a00902,
 0x40804003,
 0x21a00983,
-0x21a00a04,
+0x21a00a05,
 0x40805a02,
 0x21a00a82,
 0x40800083,
 0x21a00b83,
 0x01a00c02,
-0x01a00d83,
-0x3420c282,
+0x30809c03,
+0x34000182,
+0x14004102,
+0x21002082,
+0x01a00d82,
+0x3080a003,
+0x34000182,
 0x21a00e02,
-0x34210283,
-0x21a00f03,
-0x34200284,
-0x77400200,
-0x3421c282,
+0x3080a203,
+0x34000182,
+0x21a00f02,
+0x3080a403,
+0x34000182,
+0x77400100,
+0x3080a603,
+0x34000182,
 0x21a00702,
-0x34218283,
-0x21a00083,
-0x34214282,
+0x3080a803,
+0x34000182,
+0x21a00082,
+0x3080aa03,
+0x34000182,
 0x21a00b02,
-0x4200480c,
-0x00200000,
-0x1c010286,
-0x34220284,
-0x34220302,
-0x0f608203,
-0x5c024204,
-0x3b81810b,
-0x42013c02,
-0x00200000,
-0x18008185,
-0x38808183,
-0x3b814182,
-0x21004e84,
+0x4020007f,
+0x3080ae02,
+0x42004805,
+0x3080ac04,
+0x34000103,
+0x34000202,
+0x1cffc183,
+0x3b810106,
+0x0f608184,
+0x42013802,
+0x5c020183,
+0x38810102,
+0x3b810102,
+0x21000e83,
 0x4020007f,
 0x35000100,
-0x000004e0,
-0x000002a0,
-0x000002e8,
-0x00000428,
+0x00000470,
+0x000002f8,
+0x00000430,
 0x00000360,
-0x000002e8,
-0x000004a0,
-0x00000468,
+0x000002f8,
 0x000003c8,
+0x000004a8,
+0x00000298,
 0x00000360,
+0x00200000,
 0x409ffe02,
 0x30801203,
-0x40800204,
-0x3ec40085,
-0x10009c09,
-0x3ac10606,
-0xb060c105,
-0x4020007f,
-0x4020007f,
+0x40800208,
+0x3ec40084,
+0x40800407,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
 0x20801203,
-0x38810602,
-0xb0408586,
-0x28810602,
-0x32004180,
-0x34204702,
+0x38820282,
+0x41004003,
+0xb0408189,
+0x28820282,
+0x3881c282,
+0xb0408304,
+0x2881c282,
+0x00400000,
+0x40800003,
+0x35000000,
+0x30809e03,
+0x34000182,
 0x21a00382,
 0x4020007f,
-0x327fdc80,
+0x327fde00,
 0x409ffe02,
 0x30801203,
-0x40800204,
-0x3ec40087,
-0x40800405,
-0x00200000,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x40800206,
+0x3ec40084,
+0x40800407,
+0x40800608,
+0x3ac1828a,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
 0x20801203,
+0x38818282,
 0x41004003,
-0x38810602,
-0x4020007f,
-0xb0408188,
-0x4020007f,
-0x28810602,
-0x41201002,
-0x38814603,
-0x10009c09,
-0xb060c109,
-0x4020007f,
-0x28814603,
+0xb040818a,
+0x10005b0b,
+0x41201003,
+0x28818282,
+0x3881c282,
+0xb0408184,
 0x41193f83,
-0x38818602,
 0x60ffc003,
-0xb040818a,
-0x28818602,
-0x32003080,
+0x2881c282,
+0x38820282,
+0xb0408189,
+0x28820282,
+0x327fef80,
 0x409ffe02,
 0x30801203,
-0x40800204,
-0x3ec40087,
-0x41201008,
-0x10009c14,
-0x40800405,
-0x3ac10609,
-0x40800606,
-0x3ac1460a,
-0xb060c107,
-0x3ac1860b,
+0x40800207,
+0x3ec40086,
+0x4120100b,
+0x10005b14,
+0x40800404,
+0x3ac1c289,
+0x40800608,
+0xb060c106,
+0x3ac10286,
+0x3ac2028a,
 0x20801203,
-0x38810602,
-0xb0408409,
-0x28810602,
-0x38814603,
-0xb060c40a,
-0x4020007f,
-0x28814603,
+0x3881c282,
 0x41193f83,
-0x38818602,
 0x60ffc003,
-0xb040818b,
-0x28818602,
-0x32002380,
-0x409ffe02,
-0x30801204,
-0x40800205,
-0x3ec40083,
-0x40800406,
-0x3ac14607,
-0x3ac18608,
-0xb0810103,
-0x41004002,
-0x20801204,
-0x4020007f,
-0x38814603,
-0x10009c0b,
-0xb060c107,
-0x4020007f,
-0x4020007f,
-0x28814603,
-0x38818602,
-0x4020007f,
+0xb0408589,
+0x2881c282,
+0x38810282,
+0xb0408586,
+0x28810282,
+0x38820282,
+0xb040818a,
+0x28820282,
 0x4020007f,
-0xb0408588,
-0x28818602,
+0x327fe280,
+0x409ffe02,
+0x30801203,
+0x40800207,
+0x3ec40084,
+0x40800408,
+0x10005b14,
+0x40800609,
+0x3ac1c28a,
+0x3ac2028b,
+0xb060c104,
+0x3ac24284,
+0x20801203,
+0x41201003,
+0x3881c282,
+0xb040830a,
+0x2881c282,
+0x38820282,
+0xb040818b,
+0x41193f83,
+0x60ffc003,
+0x28820282,
+0x38824282,
+0xb0408184,
+0x28824282,
 0x4020007f,
-0x32001780,
+0x327fd580,
 0x409ffe02,
-0x1000640e,
-0x40800204,
+0x1000658e,
+0x40800206,
 0x30801203,
-0x40800405,
-0x3ec40087,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x40800407,
+0x3ec40084,
+0x40800608,
+0x3ac1828a,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
 0x20801203,
 0x413d8003,
-0x38810602,
+0x38818282,
 0x4020007f,
-0x327fd780,
-0x409ffe02,
-0x10007f0c,
-0x40800205,
-0x30801204,
-0x40800406,
-0x3ec40083,
-0x3ac14607,
-0x3ac18608,
-0xb0810103,
-0x413d8002,
-0x20801204,
-0x38814603,
+0x327fd800,
+0x409ffe03,
+0x30801202,
+0x40800207,
+0x3ec40084,
+0x10005b09,
+0x3ac1c288,
+0xb0408184,
 0x4020007f,
-0x327feb80,
+0x4020007f,
+0x20801202,
+0x3881c282,
+0xb0408308,
+0x2881c282,
+0x327fc680,
 0x409ffe02,
+0x1000588b,
+0x40800208,
 0x30801203,
-0x40800204,
-0x3ec40087,
-0x40800405,
-0x1000650a,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x40800407,
+0x3ec40084,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
 0x20801203,
-0x38810602,
-0xb0408588,
-0x4020007f,
-0x327fc980,
-0x00400000,
-0x40800003,
-0x4020007f,
-0x35000000,
+0x413d8003,
+0x38820282,
+0x327fbd80,
+0x00200000,
+0x00000da0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000d90,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000db0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000dc0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000d80,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000df0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000de0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000dd0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000e04,
+0x00000000,
+0x00000000,
 0x00000000,
+0x00000e00,
 0x00000000,
 0x00000000,
 0x00000000,
index 08b3530288ac34d222ba165f72338d27ebc88d5d..8b20c0c1556fe854a9f3426464b8fcf16aae877e 100644 (file)
@@ -40,17 +40,13 @@ enum {
 struct spu_context_ops;
 struct spu_gang;
 
-/*
- * This is the state for spu utilization reporting to userspace.
- * Because this state is visible to userspace it must never change and needs
- * to be kept strictly separate from any internal state kept by the kernel.
- */
-enum spuctx_execution_state {
-       SPUCTX_UTIL_USER = 0,
-       SPUCTX_UTIL_SYSTEM,
-       SPUCTX_UTIL_IOWAIT,
-       SPUCTX_UTIL_LOADED,
-       SPUCTX_UTIL_MAX
+enum {
+       SPU_SCHED_WAS_ACTIVE,   /* was active upon spu_acquire_saved()  */
+};
+
+/* ctx->sched_flags */
+enum {
+       SPU_SCHED_NOTIFY_ACTIVE,
 };
 
 struct spu_context {
@@ -89,6 +85,8 @@ struct spu_context {
 
        struct list_head gang_list;
        struct spu_gang *gang;
+       struct kref *prof_priv_kref;
+       void ( * prof_priv_release) (struct kref *kref);
 
        /* owner thread */
        pid_t tid;
@@ -104,9 +102,9 @@ struct spu_context {
        /* statistics */
        struct {
                /* updates protected by ctx->state_mutex */
-               enum spuctx_execution_state execution_state;
-               unsigned long tstamp;           /* time of last ctx switch */
-               unsigned long times[SPUCTX_UTIL_MAX];
+               enum spu_utilization_state util_state;
+               unsigned long long tstamp;      /* time of last state switch */
+               unsigned long long times[SPU_UTIL_MAX];
                unsigned long long vol_ctx_switch;
                unsigned long long invol_ctx_switch;
                unsigned long long min_flt;
@@ -118,6 +116,10 @@ struct spu_context {
                unsigned long long class2_intr_base; /* # at last ctx switch */
                unsigned long long libassist;
        } stats;
+
+       struct list_head aff_list;
+       int aff_head;
+       int aff_offset;
 };
 
 struct spu_gang {
@@ -125,8 +127,19 @@ struct spu_gang {
        struct mutex mutex;
        struct kref kref;
        int contexts;
+
+       struct spu_context *aff_ref_ctx;
+       struct list_head aff_list_head;
+       struct mutex aff_mutex;
+       int aff_flags;
+       struct spu *aff_ref_spu;
+       atomic_t aff_sched_count;
 };
 
+/* Flag bits for spu_gang aff_flags */
+#define AFF_OFFSETS_SET                1
+#define AFF_MERGED             2
+
 struct mfc_dma_command {
        int32_t pad;    /* reserved */
        uint32_t lsa;   /* local storage address */
@@ -190,10 +203,9 @@ extern struct tree_descr spufs_dir_contents[];
 extern struct tree_descr spufs_dir_nosched_contents[];
 
 /* system call implementation */
-long spufs_run_spu(struct file *file,
-                  struct spu_context *ctx, u32 *npc, u32 *status);
-long spufs_create(struct nameidata *nd,
-                        unsigned int flags, mode_t mode);
+long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status);
+long spufs_create(struct nameidata *nd, unsigned int flags,
+                       mode_t mode, struct file *filp);
 extern const struct file_operations spufs_context_fops;
 
 /* gang management */
@@ -206,6 +218,9 @@ void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
 /* fault handling */
 int spufs_handle_class1(struct spu_context *ctx);
 
+/* affinity */
+struct spu *affinity_check(struct spu_context *ctx);
+
 /* context management */
 extern atomic_t nr_spu_contexts;
 static inline void spu_acquire(struct spu_context *ctx)
@@ -227,15 +242,17 @@ void spu_unmap_mappings(struct spu_context *ctx);
 void spu_forget(struct spu_context *ctx);
 int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags);
 void spu_acquire_saved(struct spu_context *ctx);
+void spu_release_saved(struct spu_context *ctx);
 
 int spu_activate(struct spu_context *ctx, unsigned long flags);
 void spu_deactivate(struct spu_context *ctx);
 void spu_yield(struct spu_context *ctx);
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx);
 void spu_set_timeslice(struct spu_context *ctx);
 void spu_update_sched_info(struct spu_context *ctx);
 void __spu_update_sched_info(struct spu_context *ctx);
 int __init spu_sched_init(void);
-void __exit spu_sched_exit(void);
+void spu_sched_exit(void);
 
 extern char *isolated_loader;
 
@@ -293,30 +310,34 @@ extern int spufs_coredump_num_notes;
  * line.
  */
 static inline void spuctx_switch_state(struct spu_context *ctx,
-               enum spuctx_execution_state new_state)
+               enum spu_utilization_state new_state)
 {
-       WARN_ON(!mutex_is_locked(&ctx->state_mutex));
-
-       if (ctx->stats.execution_state != new_state) {
-               unsigned long curtime = jiffies;
-
-               ctx->stats.times[ctx->stats.execution_state] +=
-                                curtime - ctx->stats.tstamp;
-               ctx->stats.tstamp = curtime;
-               ctx->stats.execution_state = new_state;
-       }
-}
+       unsigned long long curtime;
+       signed long long delta;
+       struct timespec ts;
+       struct spu *spu;
+       enum spu_utilization_state old_state;
 
-static inline void spu_switch_state(struct spu *spu,
-               enum spuctx_execution_state new_state)
-{
-       if (spu->stats.utilization_state != new_state) {
-               unsigned long curtime = jiffies;
+       ktime_get_ts(&ts);
+       curtime = timespec_to_ns(&ts);
+       delta = curtime - ctx->stats.tstamp;
 
-               spu->stats.times[spu->stats.utilization_state] +=
-                                curtime - spu->stats.tstamp;
+       WARN_ON(!mutex_is_locked(&ctx->state_mutex));
+       WARN_ON(delta < 0);
+
+       spu = ctx->spu;
+       old_state = ctx->stats.util_state;
+       ctx->stats.util_state = new_state;
+       ctx->stats.tstamp = curtime;
+
+       /*
+        * Update the physical SPU utilization statistics.
+        */
+       if (spu) {
+               ctx->stats.times[old_state] += delta;
+               spu->stats.times[old_state] += delta;
+               spu->stats.util_state = new_state;
                spu->stats.tstamp = curtime;
-               spu->stats.utilization_state = new_state;
        }
 }
 
index 9c506ba08cdcb4691e32b4d40b7a5ec3a2090894..27ffdae98e5af3cc5b6420aa926f11293e4d32f9 100644 (file)
@@ -180,7 +180,7 @@ static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
        case MFC_CNTL_SUSPEND_COMPLETE:
                if (csa) {
                        csa->priv2.mfc_control_RW =
-                               in_be64(&priv2->mfc_control_RW) |
+                               MFC_CNTL_SUSPEND_MASK |
                                MFC_CNTL_SUSPEND_DMA_QUEUE;
                }
                break;
@@ -190,9 +190,7 @@ static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
                                  MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
                                 MFC_CNTL_SUSPEND_COMPLETE);
                if (csa) {
-                       csa->priv2.mfc_control_RW =
-                               in_be64(&priv2->mfc_control_RW) &
-                               ~MFC_CNTL_SUSPEND_DMA_QUEUE;
+                       csa->priv2.mfc_control_RW = 0;
                }
                break;
        }
@@ -251,16 +249,8 @@ static inline void save_mfc_decr(struct spu_state *csa, struct spu *spu)
         *     Read MFC_CNTL[Ds].  Update saved copy of
         *     CSA.MFC_CNTL[Ds].
         */
-       if (in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING) {
-               csa->priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
-               csa->suspend_time = get_cycles();
-               out_be64(&priv2->spu_chnlcntptr_RW, 7ULL);
-               eieio();
-               csa->spu_chnldata_RW[7] = in_be64(&priv2->spu_chnldata_RW);
-               eieio();
-       } else {
-               csa->priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING;
-       }
+       csa->priv2.mfc_control_RW |=
+               in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING;
 }
 
 static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
@@ -271,7 +261,8 @@ static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
         *     Write MFC_CNTL[Dh] set to a '1' to halt
         *     the decrementer.
         */
-       out_be64(&priv2->mfc_control_RW, MFC_CNTL_DECREMENTER_HALTED);
+       out_be64(&priv2->mfc_control_RW,
+                MFC_CNTL_DECREMENTER_HALTED | MFC_CNTL_SUSPEND_MASK);
        eieio();
 }
 
@@ -615,7 +606,7 @@ static inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu)
 static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
-       u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+       u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
        int i;
 
        /* Save, Step 42:
@@ -626,7 +617,7 @@ static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
        csa->spu_chnldata_RW[1] = in_be64(&priv2->spu_chnldata_RW);
 
        /* Save the following CH: [0,3,4,24,25,27] */
-       for (i = 0; i < 7; i++) {
+       for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
                idx = ch_indices[i];
                out_be64(&priv2->spu_chnlcntptr_RW, idx);
                eieio();
@@ -983,13 +974,13 @@ static inline void terminate_spu_app(struct spu_state *csa, struct spu *spu)
         */
 }
 
-static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+static inline void suspend_mfc_and_halt_decr(struct spu_state *csa,
+               struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
 
        /* Restore, Step 7:
-        * Restore, Step 47.
-        *     Write MFC_Cntl[Dh,Sc]='1','1' to suspend
+        *     Write MFC_Cntl[Dh,Sc,Sm]='1','1','0' to suspend
         *     the queue and halt the decrementer.
         */
        out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE |
@@ -1090,7 +1081,7 @@ static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
 static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
-       u64 ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+       u64 ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
        u64 idx;
        int i;
 
@@ -1102,7 +1093,7 @@ static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
        out_be64(&priv2->spu_chnldata_RW, 0UL);
 
        /* Reset the following CH: [0,3,4,24,25,27] */
-       for (i = 0; i < 7; i++) {
+       for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
                idx = ch_indices[i];
                out_be64(&priv2->spu_chnlcntptr_RW, idx);
                eieio();
@@ -1289,7 +1280,15 @@ static inline void setup_decr(struct spu_state *csa, struct spu *spu)
                cycles_t resume_time = get_cycles();
                cycles_t delta_time = resume_time - csa->suspend_time;
 
+               csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING;
+               if (csa->lscsa->decr.slot[0] < delta_time) {
+                       csa->lscsa->decr_status.slot[0] |=
+                                SPU_DECR_STATUS_WRAPPED;
+               }
+
                csa->lscsa->decr.slot[0] -= delta_time;
+       } else {
+               csa->lscsa->decr_status.slot[0] = 0;
        }
 }
 
@@ -1398,6 +1397,18 @@ static inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu)
        send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
 }
 
+static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+{
+       struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+       /* Restore, Step 47.
+        *     Write MFC_Cntl[Sc,Sm]='1','0' to suspend
+        *     the queue.
+        */
+       out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE);
+       eieio();
+}
+
 static inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
 {
        /* Restore, Step 49:
@@ -1548,10 +1559,10 @@ static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
         *     "wrapped" flag is set, OR in a '1' to
         *     CSA.SPU_Event_Status[Tm].
         */
-       if (csa->lscsa->decr_status.slot[0] == 1) {
+       if (csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) {
                csa->spu_chnldata_RW[0] |= 0x20;
        }
-       if ((csa->lscsa->decr_status.slot[0] == 1) &&
+       if ((csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) &&
            (csa->spu_chnlcnt_RW[0] == 0 &&
             ((csa->spu_chnldata_RW[2] & 0x20) == 0x0) &&
             ((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) {
@@ -1562,18 +1573,13 @@ static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
 static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu)
 {
        struct spu_priv2 __iomem *priv2 = spu->priv2;
-       u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+       u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
        int i;
 
        /* Restore, Step 59:
+        *      Restore the following CH: [0,3,4,24,25,27]
         */
-
-       /* Restore CH 1 without count */
-       out_be64(&priv2->spu_chnlcntptr_RW, 1);
-       out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[1]);
-
-       /* Restore the following CH: [0,3,4,24,25,27] */
-       for (i = 0; i < 7; i++) {
+       for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
                idx = ch_indices[i];
                out_be64(&priv2->spu_chnlcntptr_RW, idx);
                eieio();
@@ -1932,7 +1938,7 @@ static void harvest(struct spu_state *prev, struct spu *spu)
        set_switch_pending(prev, spu);          /* Step 5.  */
        stop_spu_isolate(spu);                  /* NEW.     */
        remove_other_spu_access(prev, spu);     /* Step 6.  */
-       suspend_mfc(prev, spu);                 /* Step 7.  */
+       suspend_mfc_and_halt_decr(prev, spu);   /* Step 7.  */
        wait_suspend_mfc_complete(prev, spu);   /* Step 8.  */
        if (!suspend_spe(prev, spu))            /* Step 9.  */
                clear_spu_status(prev, spu);    /* Step 10. */
index 8e37bdf4dfdad4e7633540126a0227a35df7b2da..43f0fb88abbc0812117e44758aec94883a70d31a 100644 (file)
@@ -47,7 +47,7 @@ static long do_spu_run(struct file *filp,
                goto out;
 
        i = SPUFS_I(filp->f_path.dentry->d_inode);
-       ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
+       ret = spufs_run_spu(i->i_ctx, &npc, &status);
 
        if (put_user(npc, unpc))
                ret = -EFAULT;
@@ -76,8 +76,8 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
 }
 #endif
 
-asmlinkage long sys_spu_create(const char __user *pathname,
-                                       unsigned int flags, mode_t mode)
+asmlinkage long do_spu_create(const char __user *pathname, unsigned int flags,
+                               mode_t mode, struct file *neighbor)
 {
        char *tmp;
        int ret;
@@ -90,7 +90,7 @@ asmlinkage long sys_spu_create(const char __user *pathname,
                ret = path_lookup(tmp, LOOKUP_PARENT|
                                LOOKUP_OPEN|LOOKUP_CREATE, &nd);
                if (!ret) {
-                       ret = spufs_create(&nd, flags, mode);
+                       ret = spufs_create(&nd, flags, mode, neighbor);
                        path_release(&nd);
                }
                putname(tmp);
@@ -99,8 +99,32 @@ asmlinkage long sys_spu_create(const char __user *pathname,
        return ret;
 }
 
+#ifndef MODULE
+asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags,
+                               mode_t mode, int neighbor_fd)
+{
+       int fput_needed;
+       struct file *neighbor;
+       long ret;
+
+       if (flags & SPU_CREATE_AFFINITY_SPU) {
+               ret = -EBADF;
+               neighbor = fget_light(neighbor_fd, &fput_needed);
+               if (neighbor) {
+                       ret = do_spu_create(pathname, flags, mode, neighbor);
+                       fput_light(neighbor, fput_needed);
+               }
+       }
+       else {
+               ret = do_spu_create(pathname, flags, mode, NULL);
+       }
+
+       return ret;
+}
+#endif
+
 struct spufs_calls spufs_calls = {
-       .create_thread = sys_spu_create,
+       .create_thread = do_spu_create,
        .spu_run = do_spu_run,
        .owner = THIS_MODULE,
 };
index f65078c3d3b38fe0048f1437f27cf702e2d28746..484eb4e0e9dbd16c86cf39024ef052c10b785fed 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_QUICC_ENGINE)    += qe_lib/
 mv64x60-$(CONFIG_PCI)          += mv64x60_pci.o
 obj-$(CONFIG_MV64X60)          += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o
 obj-$(CONFIG_RTC_DRV_CMOS)     += rtc_cmos_setup.o
+obj-$(CONFIG_AXON_RAM)         += axonram.o
 
 # contains only the suspend handler for time
 ifeq ($(CONFIG_RTC_CLASS),)
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
new file mode 100644 (file)
index 0000000..2326d5d
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2006
+ *
+ * Author: Maxim Shchetynin <maxim@de.ibm.com>
+ *
+ * Axon DDR2 device driver.
+ * It registers one block device per Axon's DDR2 memory bank found on a system.
+ * Block devices are called axonram?, their major and minor numbers are
+ * available in /proc/devices, /proc/partitions or in /sys/block/axonram?/dev.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include <asm/page.h>
+#include <asm/prom.h>
+
+#define AXON_RAM_MODULE_NAME           "axonram"
+#define AXON_RAM_DEVICE_NAME           "axonram"
+#define AXON_RAM_MINORS_PER_DISK       16
+#define AXON_RAM_BLOCK_SHIFT           PAGE_SHIFT
+#define AXON_RAM_BLOCK_SIZE            1 << AXON_RAM_BLOCK_SHIFT
+#define AXON_RAM_SECTOR_SHIFT          9
+#define AXON_RAM_SECTOR_SIZE           1 << AXON_RAM_SECTOR_SHIFT
+#define AXON_RAM_IRQ_FLAGS             IRQF_SHARED | IRQF_TRIGGER_RISING
+
+struct axon_ram_bank {
+       struct of_device        *device;
+       struct gendisk          *disk;
+       unsigned int            irq_correctable;
+       unsigned int            irq_uncorrectable;
+       unsigned long           ph_addr;
+       unsigned long           io_addr;
+       unsigned long           size;
+       unsigned long           ecc_counter;
+};
+
+static ssize_t
+axon_ram_sysfs_ecc(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct of_device *device = to_of_device(dev);
+       struct axon_ram_bank *bank = device->dev.platform_data;
+
+       BUG_ON(!bank);
+
+       return sprintf(buf, "%ld\n", bank->ecc_counter);
+}
+
+static DEVICE_ATTR(ecc, S_IRUGO, axon_ram_sysfs_ecc, NULL);
+
+/**
+ * axon_ram_irq_handler - interrupt handler for Axon RAM ECC
+ * @irq: interrupt ID
+ * @dev: pointer to of_device
+ */
+static irqreturn_t
+axon_ram_irq_handler(int irq, void *dev)
+{
+       struct of_device *device = dev;
+       struct axon_ram_bank *bank = device->dev.platform_data;
+
+       BUG_ON(!bank);
+
+       if (irq == bank->irq_correctable) {
+               dev_err(&device->dev, "Correctable memory error occured\n");
+               bank->ecc_counter++;
+               return IRQ_HANDLED;
+       } else if (irq == bank->irq_uncorrectable) {
+               dev_err(&device->dev, "Uncorrectable memory error occured\n");
+               panic("Critical ECC error on %s", device->node->full_name);
+       }
+
+       return IRQ_NONE;
+}
+
+/**
+ * axon_ram_make_request - make_request() method for block device
+ * @queue, @bio: see blk_queue_make_request()
+ */
+static int
+axon_ram_make_request(struct request_queue *queue, struct bio *bio)
+{
+       struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data;
+       unsigned long phys_mem, phys_end;
+       void *user_mem;
+       struct bio_vec *vec;
+       unsigned int transfered;
+       unsigned short idx;
+       int rc = 0;
+
+       phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT);
+       phys_end = bank->io_addr + bank->size;
+       transfered = 0;
+       bio_for_each_segment(vec, bio, idx) {
+               if (unlikely(phys_mem + vec->bv_len > phys_end)) {
+                       bio_io_error(bio, bio->bi_size);
+                       rc = -ERANGE;
+                       break;
+               }
+
+               user_mem = page_address(vec->bv_page) + vec->bv_offset;
+               if (bio_data_dir(bio) == READ)
+                       memcpy(user_mem, (void *) phys_mem, vec->bv_len);
+               else
+                       memcpy((void *) phys_mem, user_mem, vec->bv_len);
+
+               phys_mem += vec->bv_len;
+               transfered += vec->bv_len;
+       }
+       bio_endio(bio, transfered, 0);
+
+       return rc;
+}
+
+/**
+ * axon_ram_direct_access - direct_access() method for block device
+ * @device, @sector, @data: see block_device_operations method
+ */
+static int
+axon_ram_direct_access(struct block_device *device, sector_t sector,
+                      unsigned long *data)
+{
+       struct axon_ram_bank *bank = device->bd_disk->private_data;
+       loff_t offset;
+
+       offset = sector << AXON_RAM_SECTOR_SHIFT;
+       if (offset >= bank->size) {
+               dev_err(&bank->device->dev, "Access outside of address space\n");
+               return -ERANGE;
+       }
+
+       *data = bank->ph_addr + offset;
+
+       return 0;
+}
+
+static struct block_device_operations axon_ram_devops = {
+       .owner          = THIS_MODULE,
+       .direct_access  = axon_ram_direct_access
+};
+
+/**
+ * axon_ram_probe - probe() method for platform driver
+ * @device, @device_id: see of_platform_driver method
+ */
+static int
+axon_ram_probe(struct of_device *device, const struct of_device_id *device_id)
+{
+       static int axon_ram_bank_id = -1;
+       struct axon_ram_bank *bank;
+       struct resource resource;
+       int rc = 0;
+
+       axon_ram_bank_id++;
+
+       dev_info(&device->dev, "Found memory controller on %s\n",
+                       device->node->full_name);
+
+       bank = kzalloc(sizeof(struct axon_ram_bank), GFP_KERNEL);
+       if (bank == NULL) {
+               dev_err(&device->dev, "Out of memory\n");
+               rc = -ENOMEM;
+               goto failed;
+       }
+
+       device->dev.platform_data = bank;
+
+       bank->device = device;
+
+       if (of_address_to_resource(device->node, 0, &resource) != 0) {
+               dev_err(&device->dev, "Cannot access device tree\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       bank->size = resource.end - resource.start + 1;
+
+       if (bank->size == 0) {
+               dev_err(&device->dev, "No DDR2 memory found for %s%d\n",
+                               AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
+               rc = -ENODEV;
+               goto failed;
+       }
+
+       dev_info(&device->dev, "Register DDR2 memory device %s%d with %luMB\n",
+                       AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20);
+
+       bank->ph_addr = resource.start;
+       bank->io_addr = (unsigned long) ioremap_flags(
+                       bank->ph_addr, bank->size, _PAGE_NO_CACHE);
+       if (bank->io_addr == 0) {
+               dev_err(&device->dev, "ioremap() failed\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       bank->disk = alloc_disk(AXON_RAM_MINORS_PER_DISK);
+       if (bank->disk == NULL) {
+               dev_err(&device->dev, "Cannot register disk\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       bank->disk->first_minor = 0;
+       bank->disk->fops = &axon_ram_devops;
+       bank->disk->private_data = bank;
+       bank->disk->driverfs_dev = &device->dev;
+
+       sprintf(bank->disk->disk_name, "%s%d",
+                       AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
+       bank->disk->major = register_blkdev(0, bank->disk->disk_name);
+       if (bank->disk->major < 0) {
+               dev_err(&device->dev, "Cannot register block device\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       bank->disk->queue = blk_alloc_queue(GFP_KERNEL);
+       if (bank->disk->queue == NULL) {
+               dev_err(&device->dev, "Cannot register disk queue\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT);
+       blk_queue_make_request(bank->disk->queue, axon_ram_make_request);
+       blk_queue_hardsect_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE);
+       add_disk(bank->disk);
+
+       bank->irq_correctable = irq_of_parse_and_map(device->node, 0);
+       bank->irq_uncorrectable = irq_of_parse_and_map(device->node, 1);
+       if ((bank->irq_correctable <= 0) || (bank->irq_uncorrectable <= 0)) {
+               dev_err(&device->dev, "Cannot access ECC interrupt ID\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       rc = request_irq(bank->irq_correctable, axon_ram_irq_handler,
+                       AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
+       if (rc != 0) {
+               dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
+               bank->irq_correctable = bank->irq_uncorrectable = 0;
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       rc = request_irq(bank->irq_uncorrectable, axon_ram_irq_handler,
+                       AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
+       if (rc != 0) {
+               dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
+               bank->irq_uncorrectable = 0;
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       rc = device_create_file(&device->dev, &dev_attr_ecc);
+       if (rc != 0) {
+               dev_err(&device->dev, "Cannot create sysfs file\n");
+               rc = -EFAULT;
+               goto failed;
+       }
+
+       return 0;
+
+failed:
+       if (bank != NULL) {
+               if (bank->irq_uncorrectable > 0)
+                       free_irq(bank->irq_uncorrectable, device);
+               if (bank->irq_correctable > 0)
+                       free_irq(bank->irq_correctable, device);
+               if (bank->disk != NULL) {
+                       if (bank->disk->queue != NULL)
+                               blk_cleanup_queue(bank->disk->queue);
+                       if (bank->disk->major > 0)
+                               unregister_blkdev(bank->disk->major,
+                                               bank->disk->disk_name);
+                       del_gendisk(bank->disk);
+               }
+               device->dev.platform_data = NULL;
+               if (bank->io_addr != 0)
+                       iounmap((void __iomem *) bank->io_addr);
+               kfree(bank);
+       }
+
+       return rc;
+}
+
+/**
+ * axon_ram_remove - remove() method for platform driver
+ * @device: see of_platform_driver method
+ */
+static int
+axon_ram_remove(struct of_device *device)
+{
+       struct axon_ram_bank *bank = device->dev.platform_data;
+
+       BUG_ON(!bank || !bank->disk);
+
+       device_remove_file(&device->dev, &dev_attr_ecc);
+       free_irq(bank->irq_uncorrectable, device);
+       free_irq(bank->irq_correctable, device);
+       blk_cleanup_queue(bank->disk->queue);
+       unregister_blkdev(bank->disk->major, bank->disk->disk_name);
+       del_gendisk(bank->disk);
+       iounmap((void __iomem *) bank->io_addr);
+       kfree(bank);
+
+       return 0;
+}
+
+static struct of_device_id axon_ram_device_id[] = {
+       {
+               .type   = "dma-memory"
+       },
+       {}
+};
+
+static struct of_platform_driver axon_ram_driver = {
+       .owner          = THIS_MODULE,
+       .name           = AXON_RAM_MODULE_NAME,
+       .match_table    = axon_ram_device_id,
+       .probe          = axon_ram_probe,
+       .remove         = axon_ram_remove
+};
+
+/**
+ * axon_ram_init
+ */
+static int __init
+axon_ram_init(void)
+{
+       return of_register_platform_driver(&axon_ram_driver);
+}
+
+/**
+ * axon_ram_exit
+ */
+static void __exit
+axon_ram_exit(void)
+{
+       of_unregister_platform_driver(&axon_ram_driver);
+}
+
+module_init(axon_ram_init);
+module_exit(axon_ram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Shchetynin <maxim@de.ibm.com>");
+MODULE_DESCRIPTION("Axon DDR2 RAM device driver for IBM Cell BE");
index 85a7c99c1003682c10c4317a5f7f4888c0033c80..2f91b55b775475a8c839299801b390b670c4e183 100644 (file)
@@ -48,15 +48,13 @@ struct pmi_data {
        struct work_struct      work;
 };
 
+static struct pmi_data *data;
 
 static int pmi_irq_handler(int irq, void *dev_id)
 {
-       struct pmi_data *data;
        u8 type;
        int rc;
 
-       data = dev_id;
-
        spin_lock(&data->pmi_spinlock);
 
        type = ioread8(data->pmi_reg + PMI_READ_TYPE);
@@ -111,16 +109,13 @@ MODULE_DEVICE_TABLE(of, pmi_match);
 
 static void pmi_notify_handlers(struct work_struct *work)
 {
-       struct pmi_data *data;
        struct pmi_handler *handler;
 
-       data = container_of(work, struct pmi_data, work);
-
        spin_lock(&data->handler_spinlock);
        list_for_each_entry(handler, &data->handler, node) {
                pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler);
                if (handler->type == data->msg.type)
-                       handler->handle_pmi_message(data->dev, data->msg);
+                       handler->handle_pmi_message(data->msg);
        }
        spin_unlock(&data->handler_spinlock);
 }
@@ -129,9 +124,14 @@ static int pmi_of_probe(struct of_device *dev,
                        const struct of_device_id *match)
 {
        struct device_node *np = dev->node;
-       struct pmi_data *data;
        int rc;
 
+       if (data) {
+               printk(KERN_ERR "pmi: driver has already been initialized.\n");
+               rc = -EBUSY;
+               goto out;
+       }
+
        data = kzalloc(sizeof(struct pmi_data), GFP_KERNEL);
        if (!data) {
                printk(KERN_ERR "pmi: could not allocate memory.\n");
@@ -154,7 +154,6 @@ static int pmi_of_probe(struct of_device *dev,
 
        INIT_WORK(&data->work, pmi_notify_handlers);
 
-       dev->dev.driver_data = data;
        data->dev = dev;
 
        data->irq = irq_of_parse_and_map(np, 0);
@@ -164,7 +163,7 @@ static int pmi_of_probe(struct of_device *dev,
                goto error_cleanup_iomap;
        }
 
-       rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", data);
+       rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", NULL);
        if (rc) {
                printk(KERN_ERR "pmi: can't request IRQ %d: returned %d\n",
                                data->irq, rc);
@@ -187,12 +186,9 @@ out:
 
 static int pmi_of_remove(struct of_device *dev)
 {
-       struct pmi_data *data;
        struct pmi_handler *handler, *tmp;
 
-       data = dev->dev.driver_data;
-
-       free_irq(data->irq, data);
+       free_irq(data->irq, NULL);
        iounmap(data->pmi_reg);
 
        spin_lock(&data->handler_spinlock);
@@ -202,7 +198,8 @@ static int pmi_of_remove(struct of_device *dev)
 
        spin_unlock(&data->handler_spinlock);
 
-       kfree(dev->dev.driver_data);
+       kfree(data);
+       data = NULL;
 
        return 0;
 }
@@ -226,13 +223,13 @@ static void __exit pmi_module_exit(void)
 }
 module_exit(pmi_module_exit);
 
-void pmi_send_message(struct of_device *device, pmi_message_t msg)
+int pmi_send_message(pmi_message_t msg)
 {
-       struct pmi_data *data;
        unsigned long flags;
        DECLARE_COMPLETION_ONSTACK(completion);
 
-       data = device->dev.driver_data;
+       if (!data)
+               return -ENODEV;
 
        mutex_lock(&data->msg_mutex);
 
@@ -256,30 +253,26 @@ void pmi_send_message(struct of_device *device, pmi_message_t msg)
        data->completion = NULL;
 
        mutex_unlock(&data->msg_mutex);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(pmi_send_message);
 
-void pmi_register_handler(struct of_device *device,
-                         struct pmi_handler *handler)
+int pmi_register_handler(struct pmi_handler *handler)
 {
-       struct pmi_data *data;
-       data = device->dev.driver_data;
-
        if (!data)
-               return;
+               return -ENODEV;
 
        spin_lock(&data->handler_spinlock);
        list_add_tail(&handler->node, &data->handler);
        spin_unlock(&data->handler_spinlock);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(pmi_register_handler);
 
-void pmi_unregister_handler(struct of_device *device,
-                           struct pmi_handler *handler)
+void pmi_unregister_handler(struct pmi_handler *handler)
 {
-       struct pmi_data *data;
-       data = device->dev.driver_data;
-
        if (!data)
                return;
 
index d8ed6676ae86c378cdadd5c7296154cbdc8d84be..f87f429e0b24015565f1090616e074cf8dbc402f 100644 (file)
@@ -178,6 +178,9 @@ config CPU_HAS_PINT_IRQ
 config CPU_HAS_MASKREG_IRQ
        bool
 
+config CPU_HAS_INTC_IRQ
+       bool
+
 config CPU_HAS_INTC2_IRQ
        bool
 
@@ -209,6 +212,7 @@ config SOLUTION_ENGINE
 config SH_SOLUTION_ENGINE
        bool "SolutionEngine"
        select SOLUTION_ENGINE
+       select CPU_HAS_IPR_IRQ
        depends on CPU_SUBTYPE_SH7709 || CPU_SUBTYPE_SH7750
        help
          Select SolutionEngine if configuring for a Hitachi SH7709
@@ -241,6 +245,7 @@ config SH_7722_SOLUTION_ENGINE
 config SH_7751_SOLUTION_ENGINE
        bool "SolutionEngine7751"
        select SOLUTION_ENGINE
+       select CPU_HAS_IPR_IRQ
        depends on CPU_SUBTYPE_SH7751
        help
          Select 7751 SolutionEngine if configuring for a Hitachi SH7751
@@ -250,6 +255,7 @@ config SH_7780_SOLUTION_ENGINE
        bool "SolutionEngine7780"
        select SOLUTION_ENGINE
        select SYS_SUPPORTS_PCI
+       select CPU_HAS_INTC2_IRQ
        depends on CPU_SUBTYPE_SH7780
        help
          Select 7780 SolutionEngine if configuring for a Renesas SH7780
@@ -317,6 +323,7 @@ config SH_MPC1211
 config SH_SH03
        bool "Interface CTP/PCI-SH03"
        depends on CPU_SUBTYPE_SH7751 && BROKEN
+       select CPU_HAS_IPR_IRQ
        select SYS_SUPPORTS_PCI
        help
          CTP/PCI-SH03 is a CPU module computer that is produced
@@ -326,6 +333,7 @@ config SH_SH03
 config SH_SECUREEDGE5410
        bool "SecureEdge5410"
        depends on CPU_SUBTYPE_SH7751R
+       select CPU_HAS_IPR_IRQ
        select SYS_SUPPORTS_PCI
        help
          Select SecureEdge5410 if configuring for a SnapGear SH board.
@@ -380,6 +388,7 @@ config SH_LANDISK
 config SH_TITAN
        bool "TITAN"
        depends on CPU_SUBTYPE_SH7751R
+       select CPU_HAS_IPR_IRQ
        select SYS_SUPPORTS_PCI
        help
          Select Titan if you are configuring for a Nimble Microsystems
@@ -388,6 +397,7 @@ config SH_TITAN
 config SH_SHMIN
        bool "SHMIN"
        depends on CPU_SUBTYPE_SH7706
+       select CPU_HAS_IPR_IRQ
        help
          Select SHMIN if configuring for the SHMIN board.
 
index 77fecc62a056ebec0e776e33d2b41d437a790b66..0016609d1ebaac288b7541e91c46aacdb213c948 100644 (file)
@@ -121,8 +121,7 @@ core-y      += $(addprefix arch/sh/boards/, \
 endif
 
 # Companion chips
-core-$(CONFIG_HD64461)         += arch/sh/cchips/hd6446x/hd64461/
-core-$(CONFIG_HD64465)         += arch/sh/cchips/hd6446x/hd64465/
+core-$(CONFIG_HD6446X_SERIES)  += arch/sh/cchips/hd6446x/
 core-$(CONFIG_VOYAGERGX)       += arch/sh/cchips/voyagergx/
 
 cpuincdir-$(CONFIG_CPU_SH2)    := cpu-sh2
index 4ed1a95c6d560d81d09c8b4ff195c2fc84b86b82..23849f70f13396b48fe8d1de52d81bbcb69a6b84 100644 (file)
@@ -187,7 +187,7 @@ char * __devinit pcibios_setup(char *str)
  *  are examined.
  */
 
-void __init pcibios_fixup_bus(struct pci_bus *b)
+void __devinit pcibios_fixup_bus(struct pci_bus *b)
 {
        pci_read_bridge_bases(b);
 }
index 5afb864a1ec51d0637ff6bc82d2a11429719d3d1..adb529d01bae302ce06cfeb3064952670ee31877 100644 (file)
 #include <asm/clock.h>
 #include <asm/io.h>
 
+static struct resource r8a66597_usb_host_resources[] = {
+       [0] = {
+               .name   = "r8a66597_hcd",
+               .start  = 0xA4200000,
+               .end    = 0xA42000FF,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .name   = "r8a66597_hcd",
+               .start  = 11,           /* irq number */
+               .end    = 11,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+       .name           = "r8a66597_hcd",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = NULL,         /* don't use dma */
+               .coherent_dma_mask      = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(r8a66597_usb_host_resources),
+       .resource       = r8a66597_usb_host_resources,
+};
+
+static struct resource m66592_usb_peripheral_resources[] = {
+       [0] = {
+               .name   = "m66592_udc",
+               .start  = 0xb0000000,
+               .end    = 0xb00000FF,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .name   = "m66592_udc",
+               .start  = 9,            /* irq number */
+               .end    = 9,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m66592_usb_peripheral_device = {
+       .name           = "m66592_udc",
+       .id             = -1,
+       .dev = {
+               .dma_mask               = NULL,         /* don't use dma */
+               .coherent_dma_mask      = 0xffffffff,
+       },
+       .num_resources  = ARRAY_SIZE(m66592_usb_peripheral_resources),
+       .resource       = m66592_usb_peripheral_resources,
+};
+
 static struct resource cf_ide_resources[] = {
        [0] = {
                .start  = PA_AREA5_IO + 0x1000,
@@ -81,6 +133,8 @@ static struct platform_device heartbeat_device = {
 };
 
 static struct platform_device *r7780rp_devices[] __initdata = {
+       &r8a66597_usb_host_device,
+       &m66592_usb_peripheral_device,
        &cf_ide_device,
        &heartbeat_device,
 };
index 656fda30ef704b36951a9123602ad9dfa54ec10a..e165d85c03b5543050d721bd98ef2b5c7b4f9166 100644 (file)
@@ -86,7 +86,8 @@ static struct plat_serial8250_port uart_platform_data[] = {
                .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
                .regshift       = 2,
                .uartclk        = (9600 * 16),
-       }
+       },
+       { 0 },
 };
 
 static struct platform_device uart_device = {
index 26cff0efda4037b156540f5c158332992bebe028..0b03f3f610b83459fda11be7e7deee2ee4fe3f53 100644 (file)
 #include <asm/io.h>
 #include <asm/se7722.h>
 
-#define INTC_INTMSK0             0xFFD00044
-#define INTC_INTMSKCLR0          0xFFD00064
-
-struct se7722_data {
-       unsigned char irq;
-       unsigned char ipr_idx;
-       unsigned char shift;
-       unsigned short priority;
-       unsigned long addr;
-};
-
-
 static void disable_se7722_irq(unsigned int irq)
 {
-       struct se7722_data *p = get_irq_chip_data(irq);
-       ctrl_outw( ctrl_inw( p->addr ) | p->priority , p->addr );
+       unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+       ctrl_outw(ctrl_inw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
 }
 
 static void enable_se7722_irq(unsigned int irq)
 {
-       struct se7722_data *p = get_irq_chip_data(irq);
-       ctrl_outw( ctrl_inw( p->addr ) & ~p->priority , p->addr );
+       unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+       ctrl_outw(ctrl_inw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
 }
 
 static struct irq_chip se7722_irq_chip __read_mostly = {
-       .name           = "SE7722",
+       .name           = "SE7722-FPGA",
        .mask           = disable_se7722_irq,
        .unmask         = enable_se7722_irq,
        .mask_ack       = disable_se7722_irq,
 };
 
-static struct se7722_data ipr_irq_table[] = {
-       /* irq        ,idx,sft, priority     , addr   */
-       { MRSHPC_IRQ0 , 0 , 0 , MRSHPC_BIT0 , IRQ01_MASK } ,
-       { MRSHPC_IRQ1 , 0 , 0 , MRSHPC_BIT1 , IRQ01_MASK } ,
-       { MRSHPC_IRQ2 , 0 , 0 , MRSHPC_BIT2 , IRQ01_MASK } ,
-       { MRSHPC_IRQ3 , 0 , 0 , MRSHPC_BIT3 , IRQ01_MASK } ,
-       { SMC_IRQ     , 0 , 0 , SMC_BIT     , IRQ01_MASK } ,
-       { EXT_IRQ     , 0 , 0 , EXT_BIT     , IRQ01_MASK } ,
-};
-
-int se7722_irq_demux(int irq)
+static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
+       unsigned short intv = ctrl_inw(IRQ01_STS);
+       struct irq_desc *ext_desc;
+       unsigned int ext_irq = SE7722_FPGA_IRQ_BASE;
+
+       intv &= (1 << SE7722_FPGA_IRQ_NR) - 1;
 
-       if ((irq == IRQ0_IRQ)||(irq == IRQ1_IRQ)) {
-               volatile unsigned short intv =
-                       *(volatile unsigned short *)IRQ01_STS;
-               if (irq == IRQ0_IRQ){
-                       if(intv & SMC_BIT ) {
-                               return SMC_IRQ;
-                       } else if(intv & USB_BIT) {
-                               return USB_IRQ;
-                       } else {
-                               printk("intv =%04x\n", intv);
-                               return SMC_IRQ;
-                       }
-               } else if(irq == IRQ1_IRQ){
-                       if(intv & MRSHPC_BIT0) {
-                               return MRSHPC_IRQ0;
-                       } else if(intv & MRSHPC_BIT1) {
-                               return MRSHPC_IRQ1;
-                       } else if(intv & MRSHPC_BIT2) {
-                               return MRSHPC_IRQ2;
-                       } else if(intv & MRSHPC_BIT3) {
-                               return MRSHPC_IRQ3;
-                       } else {
-                               printk("BIT_EXTENTION =%04x\n", intv);
-                               return EXT_IRQ;
-                       }
+       while (intv) {
+               if (intv & 1) {
+                       ext_desc = irq_desc + ext_irq;
+                       handle_level_irq(ext_irq, ext_desc);
                }
+               intv >>= 1;
+               ext_irq++;
        }
-       return irq;
-
 }
+
 /*
  * Initialize IRQ setting
  */
 void __init init_se7722_IRQ(void)
 {
-       int i = 0;
+       int i;
+
+       ctrl_outw(0, IRQ01_MASK);       /* disable all irqs */
        ctrl_outw(0x2000, 0xb03fffec);  /* mrshpc irq enable */
-       ctrl_outl((3 << ((7 - 0) * 4))|(3 << ((7 - 1) * 4)), INTC_INTPRI0);     /* irq0 pri=3,irq1,pri=3 */
-       ctrl_outw((2 << ((7 - 0) * 2))|(2 << ((7 - 1) * 2)), INTC_ICR1);        /* irq0,1 low-level irq */
 
-       for (i = 0; i < ARRAY_SIZE(ipr_irq_table); i++) {
-               disable_irq_nosync(ipr_irq_table[i].irq);
-               set_irq_chip_and_handler_name( ipr_irq_table[i].irq, &se7722_irq_chip,
-                       handle_level_irq, "level");
-               set_irq_chip_data( ipr_irq_table[i].irq, &ipr_irq_table[i] );
-               disable_se7722_irq(ipr_irq_table[i].irq);
-       }
+       for (i = 0; i < SE7722_FPGA_IRQ_NR; i++)
+               set_irq_chip_and_handler_name(SE7722_FPGA_IRQ_BASE + i,
+                                             &se7722_irq_chip,
+                                             handle_level_irq, "level");
+
+       set_irq_chained_handler(IRQ0_IRQ, se7722_irq_demux);
+       set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
+
+       set_irq_chained_handler(IRQ1_IRQ, se7722_irq_demux);
+       set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
 }
index 6cca6cbc80690383204c61bb6887e4dada8f4268..495fc7e2b60f4e9663c5ffe9c1d1e275b2356840 100644 (file)
@@ -77,6 +77,7 @@ static struct resource cf_ide_resources[] = {
        },
        [2] = {
                .start  = MRSHPC_IRQ0,
+               .end    = MRSHPC_IRQ0,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -140,8 +141,6 @@ static void __init se7722_setup(char **cmdline_p)
 static struct sh_machine_vector mv_se7722 __initmv = {
        .mv_name                = "Solution Engine 7722" ,
        .mv_setup               = se7722_setup ,
-       .mv_nr_irqs             = 109 ,
+       .mv_nr_irqs             = SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_NR,
        .mv_init_irq            = init_se7722_IRQ,
-       .mv_irq_demux           = se7722_irq_demux,
-
 };
diff --git a/arch/sh/cchips/hd6446x/Makefile b/arch/sh/cchips/hd6446x/Makefile
new file mode 100644 (file)
index 0000000..a106dd9
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_HD64461)  += hd64461.o
+obj-$(CONFIG_HD64465)  += hd64465/
similarity index 98%
rename from arch/sh/cchips/hd6446x/hd64461/setup.c
rename to arch/sh/cchips/hd6446x/hd64461.c
index 4d49b5cbcc1333632c685adb64cef2b5e79210f7..97f6512aa1b7c565a1aa3e2bd04ba777b84ac5b6 100644 (file)
@@ -1,5 +1,4 @@
 /*
- *     $Id: setup.c,v 1.5 2004/03/16 00:07:50 lethal Exp $
  *     Copyright (C) 2000 YAEGASHI Takeshi
  *     Hitachi HD64461 companion chip support
  */
diff --git a/arch/sh/cchips/hd6446x/hd64461/Makefile b/arch/sh/cchips/hd6446x/hd64461/Makefile
deleted file mode 100644 (file)
index bff4b92..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for the HD64461 
-#
-
-obj-y   := setup.o io.o
-
diff --git a/arch/sh/cchips/hd6446x/hd64461/io.c b/arch/sh/cchips/hd6446x/hd64461/io.c
deleted file mode 100644 (file)
index 7909a1b..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- *     Copyright (C) 2000 YAEGASHI Takeshi
- *     Typical I/O routines for HD64461 system.
- */
-
-#include <asm/io.h>
-#include <asm/hd64461.h>
-
-#define MEM_BASE (CONFIG_HD64461_IOBASE - HD64461_STBCR)
-
-static __inline__ unsigned long PORT2ADDR(unsigned long port)
-{
-       /* 16550A: HD64461 internal */
-       if (0x3f8<=port && port<=0x3ff)
-               return CONFIG_HD64461_IOBASE + 0x8000 + ((port-0x3f8)<<1);
-       if (0x2f8<=port && port<=0x2ff)
-               return CONFIG_HD64461_IOBASE + 0x7000 + ((port-0x2f8)<<1);
-
-#ifdef CONFIG_HD64461_ENABLER
-       /* NE2000: HD64461 PCMCIA channel 0 (I/O) */
-       if (0x300<=port && port<=0x31f)
-               return 0xba000000 + port;
-
-       /* ide0: HD64461 PCMCIA channel 1 (memory) */
-       /* On HP690, CF in slot 1 is configured as a memory card
-          device.  See CF+ and CompactFlash Specification for the
-          detail of CF's memory mapped addressing. */
-       if (0x1f0<=port && port<=0x1f7) return 0xb5000000 + port;
-       if (port == 0x3f6) return 0xb50001fe;
-       if (port == 0x3f7) return 0xb50001ff;
-
-       /* ide1 */
-       if (0x170<=port && port<=0x177) return 0xba000000 + port;
-       if (port == 0x376) return 0xba000376;
-       if (port == 0x377) return 0xba000377;
-#endif
-
-       /* ??? */
-       if (port < 0xf000) return 0xa0000000 + port;
-       /* PCMCIA channel 0, I/O (0xba000000) */
-       if (port < 0x10000) return 0xba000000 + port - 0xf000;
-
-       /* HD64461 internal devices (0xb0000000) */
-       if (port < 0x20000) return CONFIG_HD64461_IOBASE + port - 0x10000;
-
-       /* PCMCIA channel 0, I/O (0xba000000) */
-       if (port < 0x30000) return 0xba000000 + port - 0x20000;
-
-       /* PCMCIA channel 1, memory (0xb5000000) */
-       if (port < 0x40000) return 0xb5000000 + port - 0x30000;
-
-       /* Whole physical address space (0xa0000000) */
-       return 0xa0000000 + (port & 0x1fffffff);
-}
-
-unsigned char hd64461_inb(unsigned long port)
-{
-       return *(volatile unsigned char*)PORT2ADDR(port);
-}
-
-unsigned char hd64461_inb_p(unsigned long port)
-{
-       unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
-       ctrl_delay();
-       return v;
-}
-
-unsigned short hd64461_inw(unsigned long port)
-{
-       return *(volatile unsigned short*)PORT2ADDR(port);
-}
-
-unsigned int hd64461_inl(unsigned long port)
-{
-       return *(volatile unsigned long*)PORT2ADDR(port);
-}
-
-void hd64461_outb(unsigned char b, unsigned long port)
-{
-       *(volatile unsigned char*)PORT2ADDR(port) = b;
-}
-
-void hd64461_outb_p(unsigned char b, unsigned long port)
-{
-       *(volatile unsigned char*)PORT2ADDR(port) = b;
-       ctrl_delay();
-}
-
-void hd64461_outw(unsigned short b, unsigned long port)
-{
-       *(volatile unsigned short*)PORT2ADDR(port) = b;
-}
-
-void hd64461_outl(unsigned int b, unsigned long port)
-{
-        *(volatile unsigned long*)PORT2ADDR(port) = b;
-}
-
-void hd64461_insb(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned char* addr=(volatile unsigned char*)PORT2ADDR(port);
-       unsigned char *buf=buffer;
-       while(count--) *buf++=*addr;
-}
-
-void hd64461_insw(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned short* addr=(volatile unsigned short*)PORT2ADDR(port);
-       unsigned short *buf=buffer;
-       while(count--) *buf++=*addr;
-}
-
-void hd64461_insl(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned long* addr=(volatile unsigned long*)PORT2ADDR(port);
-       unsigned long *buf=buffer;
-       while(count--) *buf++=*addr;
-}
-
-void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned char* addr=(volatile unsigned char*)PORT2ADDR(port);
-       const unsigned char *buf=buffer;
-       while(count--) *addr=*buf++;
-}
-
-void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned short* addr=(volatile unsigned short*)PORT2ADDR(port);
-       const unsigned short *buf=buffer;
-       while(count--) *addr=*buf++;
-}
-
-void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned long* addr=(volatile unsigned long*)PORT2ADDR(port);
-       const unsigned long *buf=buffer;
-       while(count--) *addr=*buf++;
-}
-
-unsigned short hd64461_readw(void __iomem *addr)
-{
-       return ctrl_inw(MEM_BASE+(unsigned long __force)addr);
-}
-
-void hd64461_writew(unsigned short b, void __iomem *addr)
-{
-       ctrl_outw(b, MEM_BASE+(unsigned long __force)addr);
-}
-
index e7f8ddb0ada436bf693191b4bc7349caea54d954..07310fa03250b475dc6c73ddd78b86c37506176e 100644 (file)
@@ -217,7 +217,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
index be86414dcc87064d5b5d9a068a0d5b7e3f8b03f9..fa09d68d057a2a23e78afac25f00f438e32d83e1 100644 (file)
@@ -222,7 +222,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
index 17f7402b31d8e142d4250897d4227165fdea5cf8..ac4de4973b60c74b73a39b5ec8ec6a4a1955eb69 100644 (file)
@@ -191,7 +191,7 @@ CONFIG_SH_FPU=y
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_SPECULATIVE_EXECUTION=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
index 48c6a2194c98c53c91483a32fcabbbf0861f59bf..12cc01910cf87edc400a8af52773b8059d055447 100644 (file)
@@ -241,7 +241,7 @@ CONFIG_SH_FPU=y
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_SPECULATIVE_EXECUTION=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
index a59bb78bd071e01c58fec3a7c065b0b57a034870..f1e979b1e4952f2d499296cc5199c5739d737d93 100644 (file)
@@ -155,7 +155,7 @@ CONFIG_CPU_SH4=y
 # CONFIG_CPU_SUBTYPE_SH7091 is not set
 # CONFIG_CPU_SUBTYPE_SH7750R is not set
 # CONFIG_CPU_SUBTYPE_SH7750S is not set
-CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
 CONFIG_CPU_SUBTYPE_SH7751R=y
 # CONFIG_CPU_SUBTYPE_SH7760 is not set
 # CONFIG_CPU_SUBTYPE_SH4_202 is not set
@@ -218,7 +218,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
@@ -280,7 +280,7 @@ CONFIG_ZERO_PAGE_OFFSET=0x00010000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
 # CONFIG_UBC_WAKEUP is not set
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1"
+CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=bios"
 
 #
 # Bus options
@@ -1323,7 +1323,7 @@ CONFIG_ENABLE_MUST_CHECK=y
 # CONFIG_DEBUG_KERNEL is not set
 CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_SH_STANDARD_BIOS=y
 CONFIG_EARLY_SCIF_CONSOLE=y
 CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000
 CONFIG_EARLY_PRINTK=y
index 764b813c4051df05115a1a2160b8d002c5b72d07..8e6a6baf5d27cc0d64dd4babde53559bf1d94996 100644 (file)
@@ -200,7 +200,7 @@ CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_SH_DSP=y
 CONFIG_SH_STORE_QUEUES=y
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
@@ -565,7 +565,7 @@ CONFIG_SERIO_LIBPS2=y
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
 CONFIG_SERIAL_SH_SCI_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
index 4e6e77fa4ce761b7baafb6335ef9ea4e24d6153c..c60b6fd4fc421cb9fbbb19c68532c62349b36387 100644 (file)
@@ -226,7 +226,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_DSP is not set
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 CONFIG_CPU_HAS_PTEA=y
 
index 538661e9879392ecc7eb1e698ccb418a12aecb85..f68743dc3931e876838f03d5a4dfdddbdf69e96b 100644 (file)
@@ -218,6 +218,7 @@ CONFIG_SH_FPU=y
 # CONFIG_SH_STORE_QUEUES is not set
 CONFIG_CPU_HAS_INTEVT=y
 CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
 CONFIG_CPU_HAS_SR_RB=y
 
 #
index 333898077c7c55f2da5ac60a06e0bf3628e4c2a0..ee711431e50451805a8580d3a5368fcaf268279d 100644 (file)
@@ -5,12 +5,13 @@ config SH_DMA_API
 
 config SH_DMA
        bool "SuperH on-chip DMA controller (DMAC) support"
+       depends on CPU_SH3 || CPU_SH4
        select SH_DMA_API
        default n
 
 config NR_ONCHIP_DMA_CHANNELS
+       int
        depends on SH_DMA
-       int "Number of on-chip DMAC channels"
        default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
        default "12" if CPU_SUBTYPE_SH7780
        default "4"
index 23dd6080422f155cdb422b7f373e2964eedf41d6..10c1828c9ff51b5fbd3cf5d104153ef77fb40afd 100644 (file)
@@ -78,7 +78,7 @@ static int heartbeat_drv_probe(struct platform_device *pdev)
                        hd->bit_pos[i] = i;
        }
 
-       hd->base = (void __iomem *)res->start;
+       hd->base = (void __iomem *)(unsigned long)res->start;
 
        setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd);
        platform_set_drvdata(pdev, hd);
index 0e9b532b9fbc14ff724c8ac194ac9f71c8c39548..2f65ac72f48ae7b1ee931ed79861c14dc373910a 100644 (file)
@@ -7,6 +7,7 @@ obj-$(CONFIG_PCI_AUTO)                  += pci-auto.o
 
 obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)     += pci-st40.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7751)       += pci-sh7751.o ops-sh4.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751R)      += pci-sh7751.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7780)       += pci-sh7780.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)       += pci-sh7780.o ops-sh4.o
 
index 54232f13e406b01c87a497e9d81375f896ec930a..710a3b0306e59739c8b6b9b0e4157fc267dd8bbc 100644 (file)
@@ -153,7 +153,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
 
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
 {
        if (!strcmp(str, "off")) {
                pci_probe = 0;
index 543417ff8314c41d02d88498a86517af5113ac31..1502a14386b65cbc16d6af22571e09d8a982c84f 100644 (file)
@@ -328,7 +328,7 @@ int __init st40pci_init(unsigned memStart, unsigned memSize)
        return 1;
 }
 
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
 {
        return str;
 }
index d439336d2e18258c1a19865c529b12a59fb78544..ccaba368ac9b2f9039570079d6f65dac2ee5355f 100644 (file)
@@ -71,7 +71,7 @@ subsys_initcall(pcibios_init);
  *  Called after each bus is probed, but before its children
  *  are examined.
  */
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        pci_read_bridge_bases(bus);
 }
index b3d20c0e021fee71a00620fb767c120697911e17..725be6de589b4e81081ea63a364229ed6bf54911 100644 (file)
@@ -138,4 +138,4 @@ module_exit(switch_exit);
 
 MODULE_VERSION(DRV_VERSION);
 MODULE_AUTHOR("Paul Mundt");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
index 63251549e9a8b2dfddf1308f6ce13374cf8f9942..92807ffa8e2036a9d4ac66dbcf5d3e86276ea309 100644 (file)
@@ -229,6 +229,22 @@ void clk_recalc_rate(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_recalc_rate);
 
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       if (likely(clk->ops && clk->ops->round_rate)) {
+               unsigned long flags, rounded;
+
+               spin_lock_irqsave(&clock_lock, flags);
+               rounded = clk->ops->round_rate(clk, rate);
+               spin_unlock_irqrestore(&clock_lock, flags);
+
+               return rounded;
+       }
+
+       return clk_get_rate(clk);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
 /*
  * Returns a clock. Note that we first try to use device id on the bus
  * and clock name. If this fails, we try to use clock name only.
index 1c23308cfc25728373682992cb7575ab43d49fa1..9ddb446ac930107b973ae8d8a63579e6b3133fad 100644 (file)
@@ -6,4 +6,5 @@ obj-y   += imask.o
 obj-$(CONFIG_CPU_HAS_IPR_IRQ)          += ipr.o
 obj-$(CONFIG_CPU_HAS_PINT_IRQ)         += pint.o 
 obj-$(CONFIG_CPU_HAS_MASKREG_IRQ)      += maskreg.o
+obj-$(CONFIG_CPU_HAS_INTC_IRQ)         += intc.o
 obj-$(CONFIG_CPU_HAS_INTC2_IRQ)                += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
new file mode 100644 (file)
index 0000000..9345a71
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007 Magnus Damm
+ *
+ * Based on intc2.c and ipr.c
+ *
+ * Copyright (C) 1999  Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000  Kazumoto Kojima
+ * Copyright (C) 2001  David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003  Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Copyright (C) 2005, 2006  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+#define _INTC_MK(fn, idx, bit, value) \
+       ((fn) << 24 | ((value) << 16) | ((idx) << 8) | (bit))
+#define _INTC_FN(h) (h >> 24)
+#define _INTC_VALUE(h) ((h >> 16) & 0xff)
+#define _INTC_IDX(h) ((h >> 8) & 0xff)
+#define _INTC_BIT(h) (h & 0xff)
+
+#define _INTC_PTR(desc, member, data) \
+       (desc->member + _INTC_IDX(data))
+
+static inline struct intc_desc *get_intc_desc(unsigned int irq)
+{
+       struct irq_chip *chip = get_irq_chip(irq);
+       return (void *)((char *)chip - offsetof(struct intc_desc, chip));
+}
+
+static inline unsigned int set_field(unsigned int value,
+                                    unsigned int field_value,
+                                    unsigned int width,
+                                    unsigned int shift)
+{
+       value &= ~(((1 << width) - 1) << shift);
+       value |= field_value << shift;
+       return value;
+}
+
+static inline unsigned int set_prio_field(struct intc_desc *desc,
+                                         unsigned int value,
+                                         unsigned int priority,
+                                         unsigned int data)
+{
+       unsigned int width = _INTC_PTR(desc, prio_regs, data)->field_width;
+
+       return set_field(value, priority, width, _INTC_BIT(data));
+}
+
+static void disable_prio_16(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+
+       ctrl_outw(set_prio_field(desc, ctrl_inw(addr), 0, data), addr);
+}
+
+static void enable_prio_16(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+       unsigned int prio = _INTC_VALUE(data);
+
+       ctrl_outw(set_prio_field(desc, ctrl_inw(addr), prio, data), addr);
+}
+
+static void disable_prio_32(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+
+       ctrl_outl(set_prio_field(desc, ctrl_inl(addr), 0, data), addr);
+}
+
+static void enable_prio_32(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+       unsigned int prio = _INTC_VALUE(data);
+
+       ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr);
+}
+
+static void disable_mask_8(struct intc_desc *desc, unsigned int data)
+{
+       ctrl_outb(1 << _INTC_BIT(data),
+                 _INTC_PTR(desc, mask_regs, data)->set_reg);
+}
+
+static void enable_mask_8(struct intc_desc *desc, unsigned int data)
+{
+       ctrl_outb(1 << _INTC_BIT(data),
+                 _INTC_PTR(desc, mask_regs, data)->clr_reg);
+}
+
+static void disable_mask_32(struct intc_desc *desc, unsigned int data)
+{
+       ctrl_outl(1 << _INTC_BIT(data),
+                 _INTC_PTR(desc, mask_regs, data)->set_reg);
+}
+
+static void enable_mask_32(struct intc_desc *desc, unsigned int data)
+{
+       ctrl_outl(1 << _INTC_BIT(data),
+                 _INTC_PTR(desc, mask_regs, data)->clr_reg);
+}
+
+enum { REG_FN_ERROR=0,
+       REG_FN_MASK_8, REG_FN_MASK_32,
+       REG_FN_PRIO_16, REG_FN_PRIO_32 };
+
+static struct {
+       void (*enable)(struct intc_desc *, unsigned int);
+       void (*disable)(struct intc_desc *, unsigned int);
+} intc_reg_fns[] = {
+       [REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 },
+       [REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 },
+       [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 },
+       [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 },
+};
+
+static void intc_enable(unsigned int irq)
+{
+       struct intc_desc *desc = get_intc_desc(irq);
+       unsigned int data = (unsigned int) get_irq_chip_data(irq);
+
+       intc_reg_fns[_INTC_FN(data)].enable(desc, data);
+}
+
+static void intc_disable(unsigned int irq)
+{
+       struct intc_desc *desc = get_intc_desc(irq);
+       unsigned int data = (unsigned int) get_irq_chip_data(irq);
+
+       intc_reg_fns[_INTC_FN(data)].disable(desc, data);
+}
+
+static void set_sense_16(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
+       unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
+       unsigned int bit = _INTC_BIT(data);
+       unsigned int value = _INTC_VALUE(data);
+
+       ctrl_outw(set_field(ctrl_inw(addr), value, width, bit), addr);
+}
+
+static void set_sense_32(struct intc_desc *desc, unsigned int data)
+{
+       unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
+       unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
+       unsigned int bit = _INTC_BIT(data);
+       unsigned int value = _INTC_VALUE(data);
+
+       ctrl_outl(set_field(ctrl_inl(addr), value, width, bit), addr);
+}
+
+#define VALID(x) (x | 0x80)
+
+static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+       [IRQ_TYPE_EDGE_FALLING] = VALID(0),
+       [IRQ_TYPE_EDGE_RISING] = VALID(1),
+       [IRQ_TYPE_LEVEL_LOW] = VALID(2),
+       [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
+};
+
+static int intc_set_sense(unsigned int irq, unsigned int type)
+{
+       struct intc_desc *desc = get_intc_desc(irq);
+       unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
+       unsigned int i, j, data, bit;
+       intc_enum enum_id = 0;
+
+       for (i = 0; i < desc->nr_vectors; i++) {
+               struct intc_vect *vect = desc->vectors + i;
+
+               if (evt2irq(vect->vect) != irq)
+                       continue;
+
+               enum_id = vect->enum_id;
+               break;
+       }
+
+       if (!enum_id || !value)
+               return -EINVAL;
+
+       value ^= VALID(0);
+
+       for (i = 0; i < desc->nr_sense_regs; i++) {
+               struct intc_sense_reg *sr = desc->sense_regs + i;
+
+               for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+                       if (sr->enum_ids[j] != enum_id)
+                               continue;
+
+                       bit = sr->reg_width - ((j + 1) * sr->field_width);
+                       data = _INTC_MK(0, i, bit, value);
+
+                       switch(sr->reg_width) {
+                       case 16:
+                               set_sense_16(desc, data);
+                               break;
+                       case 32:
+                               set_sense_32(desc, data);
+                               break;
+                       }
+
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static unsigned int __init intc_find_mask_handler(unsigned int width)
+{
+       switch (width) {
+       case 8:
+               return REG_FN_MASK_8;
+       case 32:
+               return REG_FN_MASK_32;
+       }
+
+       BUG();
+       return REG_FN_ERROR;
+}
+
+static unsigned int __init intc_find_prio_handler(unsigned int width)
+{
+       switch (width) {
+       case 16:
+               return REG_FN_PRIO_16;
+       case 32:
+               return REG_FN_PRIO_32;
+       }
+
+       BUG();
+       return REG_FN_ERROR;
+}
+
+static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id)
+{
+       struct intc_group *g = desc->groups;
+       unsigned int i, j;
+
+       for (i = 0; g && enum_id && i < desc->nr_groups; i++) {
+               g = desc->groups + i;
+
+               for (j = 0; g->enum_ids[j]; j++) {
+                       if (g->enum_ids[j] != enum_id)
+                               continue;
+
+                       return g->enum_id;
+               }
+       }
+
+       return 0;
+}
+
+static unsigned int __init intc_prio_value(struct intc_desc *desc,
+                                          intc_enum enum_id, int do_grps)
+{
+       struct intc_prio *p = desc->priorities;
+       unsigned int i;
+
+       for (i = 0; p && enum_id && i < desc->nr_priorities; i++) {
+               p = desc->priorities + i;
+
+               if (p->enum_id != enum_id)
+                       continue;
+
+               return p->priority;
+       }
+
+       if (do_grps)
+               return intc_prio_value(desc, intc_grp_id(desc, enum_id), 0);
+
+       /* default to the lowest priority possible if no priority is set
+        * - this needs to be at least 2 for 5-bit priorities on 7780
+        */
+
+       return 2;
+}
+
+static unsigned int __init intc_mask_data(struct intc_desc *desc,
+                                         intc_enum enum_id, int do_grps)
+{
+       struct intc_mask_reg *mr = desc->mask_regs;
+       unsigned int i, j, fn;
+
+       for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
+               mr = desc->mask_regs + i;
+
+               for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+                       if (mr->enum_ids[j] != enum_id)
+                               continue;
+
+                       fn = intc_find_mask_handler(mr->reg_width);
+                       if (fn == REG_FN_ERROR)
+                               return 0;
+
+                       return _INTC_MK(fn, i, (mr->reg_width - 1) - j, 0);
+               }
+       }
+
+       if (do_grps)
+               return intc_mask_data(desc, intc_grp_id(desc, enum_id), 0);
+
+       return 0;
+}
+
+static unsigned int __init intc_prio_data(struct intc_desc *desc,
+                                         intc_enum enum_id, int do_grps)
+{
+       struct intc_prio_reg *pr = desc->prio_regs;
+       unsigned int i, j, fn, bit, prio;
+
+       for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
+               pr = desc->prio_regs + i;
+
+               for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) {
+                       if (pr->enum_ids[j] != enum_id)
+                               continue;
+
+                       fn = intc_find_prio_handler(pr->reg_width);
+                       if (fn == REG_FN_ERROR)
+                               return 0;
+
+                       prio = intc_prio_value(desc, enum_id, 1);
+                       bit = pr->reg_width - ((j + 1) * pr->field_width);
+
+                       BUG_ON(bit < 0);
+
+                       return _INTC_MK(fn, i, bit, prio);
+               }
+       }
+
+       if (do_grps)
+               return intc_prio_data(desc, intc_grp_id(desc, enum_id), 0);
+
+       return 0;
+}
+
+static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
+                                    unsigned int irq)
+{
+       unsigned int data[2], primary;
+
+       /* Prefer single interrupt source bitmap over other combinations:
+        * 1. bitmap, single interrupt source
+        * 2. priority, single interrupt source
+        * 3. bitmap, multiple interrupt sources (groups)
+        * 4. priority, multiple interrupt sources (groups)
+        */
+
+       data[0] = intc_mask_data(desc, enum_id, 0);
+       data[1] = intc_prio_data(desc, enum_id, 0);
+
+       primary = 0;
+       if (!data[0] && data[1])
+               primary = 1;
+
+       data[0] = data[0] ? data[0] : intc_mask_data(desc, enum_id, 1);
+       data[1] = data[1] ? data[1] : intc_prio_data(desc, enum_id, 1);
+
+       if (!data[primary])
+               primary ^= 1;
+
+       BUG_ON(!data[primary]); /* must have primary masking method */
+
+       disable_irq_nosync(irq);
+       set_irq_chip_and_handler_name(irq, &desc->chip,
+                                     handle_level_irq, "level");
+       set_irq_chip_data(irq, (void *)data[primary]);
+
+       /* enable secondary masking method if present */
+       if (data[!primary])
+               intc_reg_fns[_INTC_FN(data[!primary])].enable(desc,
+                                                             data[!primary]);
+
+       /* irq should be disabled by default */
+       desc->chip.mask(irq);
+}
+
+void __init register_intc_controller(struct intc_desc *desc)
+{
+       unsigned int i;
+
+       desc->chip.mask = intc_disable;
+       desc->chip.unmask = intc_enable;
+       desc->chip.mask_ack = intc_disable;
+       desc->chip.set_type = intc_set_sense;
+
+       for (i = 0; i < desc->nr_vectors; i++) {
+               struct intc_vect *vect = desc->vectors + i;
+
+               intc_register_irq(desc, vect->enum_id, evt2irq(vect->vect));
+       }
+}
index 1a107fe22dde3b1b33ed3eb5b5a0c1c8b8d8c23d..a979b981e6a38cc85fe93c673432ef23fa264560 100644 (file)
@@ -88,7 +88,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index b6e3a6351fa6fb72b32e739ffd0ecb03a266cfe7..deab16500167c79fdd1fcec616ffc19f01114275 100644 (file)
@@ -107,7 +107,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index a55b8ce2c54c46e156319f674928e36f07bd7f15..ebd9d06d8bdd10bb7454c62533ddcd467d451c54 100644 (file)
@@ -92,7 +92,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index d79ec0c0522fb33121023cc70f1d9c285a83140b..086f8e2545afc1bfdb02778a2266e34a2f1a4195 100644 (file)
@@ -139,7 +139,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index f40e6dac337d91602b860890bd3d6f444106a6f6..1322848933736d49aea74f268215d283be8b5d9b 100644 (file)
@@ -101,7 +101,7 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
        register_ipr_controller(&ipr_irq_desc);
 }
index da153bcdfeb2b0a6c27af5e1c22e43f344341826..f2286de22bd5abe1718f402d72230d6f3364d9dc 100644 (file)
@@ -82,88 +82,213 @@ static int __init sh7750_devices_setup(void)
 }
 __initcall(sh7750_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-       /* IRQ, IPR-idx, shift, priority */
-       { 16, 0, 12, 2 }, /* TMU0 TUNI*/
-       { 17, 0, 12, 2 }, /* TMU1 TUNI */
-       { 18, 0,  4, 2 }, /* TMU2 TUNI */
-       { 19, 0,  4, 2 }, /* TMU2 TIPCI */
-       { 27, 1, 12, 2 }, /* WDT ITI */
-       { 20, 0,  0, 2 }, /* RTC ATI (alarm) */
-       { 21, 0,  0, 2 }, /* RTC PRI (period) */
-       { 22, 0,  0, 2 }, /* RTC CUI (carry) */
-       { 23, 1,  4, 3 }, /* SCI ERI */
-       { 24, 1,  4, 3 }, /* SCI RXI */
-       { 25, 1,  4, 3 }, /* SCI TXI */
-       { 40, 2,  4, 3 }, /* SCIF ERI */
-       { 41, 2,  4, 3 }, /* SCIF RXI */
-       { 42, 2,  4, 3 }, /* SCIF BRI */
-       { 43, 2,  4, 3 }, /* SCIF TXI */
-       { 34, 2,  8, 7 }, /* DMAC DMTE0 */
-       { 35, 2,  8, 7 }, /* DMAC DMTE1 */
-       { 36, 2,  8, 7 }, /* DMAC DMTE2 */
-       { 37, 2,  8, 7 }, /* DMAC DMTE3 */
-       { 38, 2,  8, 7 }, /* DMAC DMAE */
-};
-
-static unsigned long ipr_offsets[] = {
-       0xffd00004UL,   /* 0: IPRA */
-       0xffd00008UL,   /* 1: IPRB */
-       0xffd0000cUL,   /* 2: IPRC */
-       0xffd00010UL,   /* 3: IPRD */
-};
-
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
-
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
-
-       .chip = {
-               .name   = "IPR-sh7750",
-       },
+enum {
+       UNUSED = 0,
+
+       /* interrupt sources */
+       IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
+       HUDI, GPIOI,
+       DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
+       DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
+       DMAC_DMAE,
+       PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+       PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
+       TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI,
+       SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI,
+       WDT,
+       REF_RCMI, REF_ROVI,
+
+       /* interrupt groups */
+       DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
 };
 
-#ifdef CONFIG_CPU_SUBTYPE_SH7751
-static struct ipr_data ipr_irq_table_sh7751[] = {
-       { 44, 2,  8, 7 }, /* DMAC DMTE4 */
-       { 45, 2,  8, 7 }, /* DMAC DMTE5 */
-       { 46, 2,  8, 7 }, /* DMAC DMTE6 */
-       { 47, 2,  8, 7 }, /* DMAC DMTE7 */
-       /* The following use INTC_INPRI00 for masking, which is a 32-bit
-          register, not a 16-bit register like the IPRx registers, so it
-          would need special support */
-       /*{ 72, INTPRI00,  8, ? },*/ /* TMU3 TUNI */
-       /*{ 76, INTPRI00, 12, ? },*/ /* TMU4 TUNI */
+static struct intc_vect vectors[] = {
+       INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500),
+       INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540),
+       INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720),
+       INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760),
+       INTC_VECT(WDT, 0x560),
+       INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
 };
 
-static struct ipr_desc ipr_irq_desc_sh7751 = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
+static struct intc_group groups[] = {
+       INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
+       INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI),
+       INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+};
 
-       .ipr_data       = ipr_irq_table_sh7751,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table_sh7751),
+static struct intc_prio priorities[] = {
+       INTC_PRIO(SCIF, 3),
+       INTC_PRIO(SCI1, 3),
+       INTC_PRIO(DMAC, 7),
+};
 
-       .chip = {
-               .name   = "IPR-sh7751",
-       },
+static struct intc_prio_reg prio_registers[] = {
+       { 0xffd00004, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+       { 0xffd00008, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
+       { 0xffd0000c, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
+       { 0xffd00010, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+       { 0xfe080000, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
+                                             TMU4, TMU3,
+                                             PCIC1, PCIC0_PCISERR } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
+                        priorities, NULL, prio_registers, NULL);
+
+/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7091)
+static struct intc_vect vectors_dma4[] = {
+       INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+       INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+       INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma4[] = {
+       INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+                  DMAC_DMTE3, DMAC_DMAE),
+};
+
+static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
+                        vectors_dma4, groups_dma4,
+                        priorities, NULL, prio_registers, NULL);
+#endif
+
+/* SH7750R and SH7751R both have 8-channel DMA controllers */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_dma8[] = {
+       INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+       INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+       INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
+       INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
+       INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma8[] = {
+       INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+                  DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
+                  DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
+};
+
+static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
+                        vectors_dma8, groups_dma8,
+                        priorities, NULL, prio_registers, NULL);
+#endif
+
+/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_tmu34[] = {
+       INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
 };
+
+static struct intc_mask_reg mask_registers[] = {
+       { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+           0, 0, 0, 0, 0, 0, TMU4, TMU3,
+           PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+           PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2,
+           PCIC1_PCIDMA3, PCIC0_PCISERR } },
+};
+
+static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34",
+                        vectors_tmu34, NULL, priorities,
+                        mask_registers, prio_registers, NULL);
 #endif
 
-void __init init_IRQ_ipr(void)
+/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
+static struct intc_vect vectors_irlm[] = {
+       INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
+       INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL,
+                        priorities, NULL, prio_registers, NULL);
+
+/* SH7751 and SH7751R both have PCI */
+#if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_pci[] = {
+       INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
+       INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
+       INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
+       INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
+};
+
+static struct intc_group groups_pci[] = {
+       INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+                  PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
+};
+
+static DECLARE_INTC_DESC(intc_desc_pci, "sh7750_pci", vectors_pci, groups_pci,
+                        priorities, mask_registers, prio_registers, NULL);
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+       defined(CONFIG_CPU_SUBTYPE_SH7091)
+void __init plat_irq_setup(void)
 {
-       register_ipr_controller(&ipr_irq_desc);
-#ifdef CONFIG_CPU_SUBTYPE_SH7751
-       register_ipr_controller(&ipr_irq_desc_sh7751);
+       /*
+        * same vectors for SH7750, SH7750S and SH7091 except for IRLM,
+        * see below..
+        */
+       register_intc_controller(&intc_desc);
+       register_intc_controller(&intc_desc_dma4);
+}
 #endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R)
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+       register_intc_controller(&intc_desc_dma8);
+       register_intc_controller(&intc_desc_tmu34);
 }
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7751)
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+       register_intc_controller(&intc_desc_dma4);
+       register_intc_controller(&intc_desc_tmu34);
+       register_intc_controller(&intc_desc_pci);
+}
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7751R)
+void __init plat_irq_setup(void)
+{
+       register_intc_controller(&intc_desc);
+       register_intc_controller(&intc_desc_dma8);
+       register_intc_controller(&intc_desc_tmu34);
+       register_intc_controller(&intc_desc_pci);
+}
+#endif
 
 #define INTC_ICR       0xffd00000UL
 #define INTC_ICR_IRLM   (1<<7)
 
 /* enable individual interrupt mode for external interupts */
-void ipr_irq_enable_irlm(void)
+void __init ipr_irq_enable_irlm(void)
 {
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7091)
+       BUG(); /* impossible to mask interrupts on SH7750 and SH7091 */
+#endif
+       register_intc_controller(&intc_desc_irlm);
+
        ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
 }
index 3df169755673da10c15fcf1677e2f9dab74b0105..47fa270562537360d860d7adfea51b7d16d942d9 100644 (file)
@@ -109,11 +109,6 @@ static struct intc2_desc intc2_irq_desc __read_mostly = {
        },
 };
 
-void __init init_IRQ_intc2(void)
-{
-       register_intc2_controller(&intc2_irq_desc);
-}
-
 static struct ipr_data ipr_irq_table[] = {
        /* IRQ, IPR-idx, shift, priority */
        { 16, 0, 12, 2 }, /* TMU0 TUNI*/
@@ -163,7 +158,8 @@ static struct ipr_desc ipr_irq_desc = {
        },
 };
 
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
 {
+       register_intc2_controller(&intc2_irq_desc);
        register_ipr_controller(&ipr_irq_desc);
 }
index 51b386d454deaedd7f31b32410adbc6bedf857c7..a0fd8bb21f7c4f74f3e16d97a3f10eeaf62bfd43 100644 (file)
@@ -387,9 +387,24 @@ out_err:
        return err;
 }
 
+static long sh7722_frqcr_round_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned long parent_rate = clk->parent->rate;
+       int div;
+
+       /* look for multiplier/divisor pair */
+       div = sh7722_find_divisors(parent_rate, rate);
+       if (div < 0)
+               return clk->rate;
+
+       /* calculate new value of clock rate */
+       return parent_rate * 2 / div;
+}
+
 static struct clk_ops sh7722_frqcr_clk_ops = {
        .recalc = sh7722_frqcr_recalc,
        .set_rate = sh7722_frqcr_set_rate,
+       .round_rate = sh7722_frqcr_round_rate,
 };
 
 /*
index a3e159ef6dfed4379444a63601fec6bab88ff29d..25b913e07e2ca3984e066c43987fe0101082723c 100644 (file)
@@ -19,8 +19,21 @@ static struct plat_sci_port sci_platform_data[] = {
                .mapbase        = 0xffe00000,
                .flags          = UPF_BOOT_AUTOCONF,
                .type           = PORT_SCIF,
-               .irqs           = { 80, 81, 83, 82 },
-       }, {
+               .irqs           = { 80, 80, 80, 80 },
+       },
+       {
+               .mapbase        = 0xffe10000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 81, 81, 81, 81 },
+       },
+       {
+               .mapbase        = 0xffe20000,
+               .flags          = UPF_BOOT_AUTOCONF,
+               .type           = PORT_SCIF,
+               .irqs           = { 82, 82, 82, 82 },
+       },
+       {
                .flags = 0,
        }
 };
@@ -44,46 +57,145 @@ static int __init sh7722_devices_setup(void)
 }
 __initcall(sh7722_devices_setup);
 
-static struct ipr_data ipr_irq_table[] = {
-       /* IRQ, IPR-idx, shift, prio */
-       { 16, 0, 12, 2 }, /* TMU0 */
-       { 17, 0,  8, 2 }, /* TMU1 */
-       { 80, 6, 12, 3 }, /* SCIF ERI */
-       { 81, 6, 12, 3 }, /* SCIF RXI */
-       { 82, 6, 12, 3 }, /* SCIF BRI */
-       { 83, 6, 12, 3 }, /* SCIF TXI */
+enum {
+       UNUSED=0,
+
+       /* interrupt sources */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       HUDI,
+       SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       DMAC0, DMAC1, DMAC2, DMAC3,
+       VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU,
+       VPU, TPU,
+       USB_USBI0, USB_USBI1,
+       DMAC4, DMAC5, DMAC_DADERR,
+       KEYSC,
+       SCIF0, SCIF1, SCIF2, SIOF0, SIOF1, SIO,
+       FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
+       I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI,
+       SDHI0, SDHI1, SDHI2, SDHI3,
+       CMT, TSIF, SIU, TWODG,
+       TMU0, TMU1, TMU2,
+       IRDA, JPU, LCDC,
+
+       /* interrupt groups */
+
+       SIM, RTC, DMAC0123, VIOVOU, USB, DMAC45, FLCTL, I2C, SDHI,
 };
 
-static unsigned long ipr_offsets[] = {
-       0xa4080000, /*  0: IPRA */
-       0xa4080004, /*  1: IPRB */
-       0xa4080008, /*  2: IPRC */
-       0xa408000c, /*  3: IPRD */
-       0xa4080010, /*  4: IPRE */
-       0xa4080014, /*  5: IPRF */
-       0xa4080018, /*  6: IPRG */
-       0xa408001c, /*  7: IPRH */
-       0xa4080020, /*  8: IPRI */
-       0xa4080024, /*  9: IPRJ */
-       0xa4080028, /* 10: IPRK */
-       0xa408002c, /* 11: IPRL */
+static struct intc_vect vectors[] = {
+       INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+       INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+       INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+       INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0),
+       INTC_VECT(SIM_ERI, 0x700), INTC_VECT(SIM_RXI, 0x720),
+       INTC_VECT(SIM_TXI, 0x740), INTC_VECT(SIM_TEI, 0x760),
+       INTC_VECT(RTC_ATI, 0x780), INTC_VECT(RTC_PRI, 0x7a0),
+       INTC_VECT(RTC_CUI, 0x7c0),
+       INTC_VECT(DMAC0, 0x800), INTC_VECT(DMAC1, 0x820),
+       INTC_VECT(DMAC2, 0x840), INTC_VECT(DMAC3, 0x860),
+       INTC_VECT(VIO_CEUI, 0x880), INTC_VECT(VIO_BEUI, 0x8a0),
+       INTC_VECT(VIO_VEUI, 0x8c0), INTC_VECT(VOU, 0x8e0),
+       INTC_VECT(VPU, 0x980), INTC_VECT(TPU, 0x9a0),
+       INTC_VECT(USB_USBI0, 0xa20), INTC_VECT(USB_USBI1, 0xa40),
+       INTC_VECT(DMAC4, 0xb80), INTC_VECT(DMAC5, 0xba0),
+       INTC_VECT(DMAC_DADERR, 0xbc0), INTC_VECT(KEYSC, 0xbe0),
+       INTC_VECT(SCIF0, 0xc00), INTC_VECT(SCIF1, 0xc20),
+       INTC_VECT(SCIF2, 0xc40), INTC_VECT(SIOF0, 0xc80),
+       INTC_VECT(SIOF1, 0xca0), INTC_VECT(SIO, 0xd00),
+       INTC_VECT(FLCTL_FLSTEI, 0xd80), INTC_VECT(FLCTL_FLENDI, 0xda0),
+       INTC_VECT(FLCTL_FLTREQ0I, 0xdc0), INTC_VECT(FLCTL_FLTREQ1I, 0xde0),
+       INTC_VECT(I2C_ALI, 0xe00), INTC_VECT(I2C_TACKI, 0xe20),
+       INTC_VECT(I2C_WAITI, 0xe40), INTC_VECT(I2C_DTEI, 0xe60),
+       INTC_VECT(SDHI0, 0xe80), INTC_VECT(SDHI1, 0xea0),
+       INTC_VECT(SDHI2, 0xec0), INTC_VECT(SDHI3, 0xee0),
+       INTC_VECT(CMT, 0xf00), INTC_VECT(TSIF, 0xf20),
+       INTC_VECT(SIU, 0xf80), INTC_VECT(TWODG, 0xfa0),
+       INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+       INTC_VECT(TMU2, 0x440), INTC_VECT(IRDA, 0x480),
+       INTC_VECT(JPU, 0x560), INTC_VECT(LCDC, 0x580),
 };
 
-static struct ipr_desc ipr_irq_desc = {
-       .ipr_offsets    = ipr_offsets,
-       .nr_offsets     = ARRAY_SIZE(ipr_offsets),
+static struct intc_group groups[] = {
+       INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3),
+       INTC_GROUP(VIOVOU, VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU),
+       INTC_GROUP(USB, USB_USBI0, USB_USBI1),
+       INTC_GROUP(DMAC45, DMAC4, DMAC5, DMAC_DADERR),
+       INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLENDI,
+                  FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
+       INTC_GROUP(I2C, I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI),
+       INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3),
+};
 
-       .ipr_data       = ipr_irq_table,
-       .nr_irqs        = ARRAY_SIZE(ipr_irq_table),
+static struct intc_prio priorities[] = {
+       INTC_PRIO(SCIF0, 3),
+       INTC_PRIO(SCIF1, 3),
+       INTC_PRIO(SCIF2, 3),
+       INTC_PRIO(TMU0, 2),
+       INTC_PRIO(TMU1, 2),
+};
 
-       .chip = {
-               .name   = "IPR-sh7722",
-       },
+static struct intc_mask_reg mask_registers[] = {
+       { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
+         { } },
+       { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
+         { VOU, VIO_VEUI, VIO_BEUI, VIO_CEUI, DMAC3, DMAC2, DMAC1, DMAC0 } },
+       { 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */
+         { 0, 0, 0, VPU, } },
+       { 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */
+         { SIM_TEI, SIM_TXI, SIM_RXI, SIM_ERI, 0, 0, 0, IRDA } },
+       { 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */
+         { 0, TMU2, TMU1, TMU0, JPU, 0, 0, LCDC } },
+       { 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */
+         { KEYSC, DMAC_DADERR, DMAC5, DMAC4, 0, SCIF2, SCIF1, SCIF0 } },
+       { 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */
+         { 0, 0, 0, SIO, 0, 0, SIOF1, SIOF0 } },
+       { 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */
+         { I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI,
+           FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLENDI, FLCTL_FLSTEI } },
+       { 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */
+         { SDHI3, SDHI2, SDHI1, SDHI0, 0, 0, TWODG, SIU } },
+       { 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */
+         { 0, 0, 0, CMT, 0, USB_USBI1, USB_USBI0, } },
+       { 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */
+         { } },
+       { 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */
+         { 0, RTC_CUI, RTC_PRI, RTC_ATI, 0, TPU, 0, TSIF } },
+       { 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-void __init init_IRQ_ipr(void)
+static struct intc_prio_reg prio_registers[] = {
+       { 0xa4080000, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } },
+       { 0xa4080004, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
+       { 0xa4080008, 16, 4, /* IPRC */ { } },
+       { 0xa408000c, 16, 4, /* IPRD */ { } },
+       { 0xa4080010, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } },
+       { 0xa4080014, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
+       { 0xa4080018, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } },
+       { 0xa408001c, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } },
+       { 0xa4080020, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } },
+       { 0xa4080024, 16, 4, /* IPRJ */ { 0, 0, SIU } },
+       { 0xa4080028, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } },
+       { 0xa408002c, 16, 4, /* IPRL */ { TWODG, 0, TPU } },
+       { 0xa4140010, 32, 4, /* INTPRI00 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_sense_reg sense_registers[] = {
+       { 0xa414001c, 16, 2, /* ICR1 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7722", vectors, groups, priorities,
+                        mask_registers, prio_registers, sense_registers);
+
+void __init plat_irq_setup(void)
 {
-       register_ipr_controller(&ipr_irq_desc);
+       register_intc_controller(&intc_desc);
 }
 
 void __init plat_mem_setup(void)
index b57c760bffde4abdc6af3505a864eda18f4a4f2f..a4127ec15203dc78352cc24060edafb3db02611c 100644 (file)
@@ -30,7 +30,7 @@ static struct resource rtc_resources[] = {
        },
        [3] = {
                /* Alarm IRQ */
-               .start  = 23,
+               .start  = 20,
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -78,44 +78,205 @@ static int __init sh7780_devices_setup(void)
 }
 __initcall(sh7780_devices_setup);
 
-static struct intc2_data intc2_irq_table[] = {
-       { 28, 0, 24, 0, 0, 2 },         /* TMU0 */
+enum {
+       UNUSED = 0,
 
-       { 21, 1,  0, 0, 2, 2 },
-       { 22, 1,  1, 0, 2, 2 },
-       { 23, 1,  2, 0, 2, 2 },
+       /* interrupt sources */
 
-       { 40, 8, 24, 0, 3, 3 },         /* SCIF0 ERI */
-       { 41, 8, 24, 0, 3, 3 },         /* SCIF0 RXI */
-       { 42, 8, 24, 0, 3, 3 },         /* SCIF0 BRI */
-       { 43, 8, 24, 0, 3, 3 },         /* SCIF0 TXI */
+       IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+       IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+       IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+       IRL_HHLL, IRL_HHLH, IRL_HHHL,
 
-       { 76, 8, 16, 0, 4, 3 },         /* SCIF1 ERI */
-       { 77, 8, 16, 0, 4, 3 },         /* SCIF1 RXI */
-       { 78, 8, 16, 0, 4, 3 },         /* SCIF1 BRI */
-       { 79, 8, 16, 0, 4, 3 },         /* SCIF1 TXI */
+       IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+       RTC_ATI, RTC_PRI, RTC_CUI,
+       WDT,
+       TMU0, TMU1, TMU2, TMU2_TICPI,
+       HUDI,
+       DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, DMAC0_DMAE,
+       SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+       DMAC0_DMINT4, DMAC0_DMINT5, DMAC1_DMINT6, DMAC1_DMINT7,
+       CMT, HAC,
+       PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
+       PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
+       SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+       SIOF, HSPI,
+       MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
+       DMAC1_DMINT8, DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11,
+       TMU3, TMU4, TMU5,
+       SSI,
+       FLCTL_FLSTE, FLCTL_FLEND, FLCTL_FLTRQ0, FLCTL_FLTRQ1,
+       GPIOI0, GPIOI1, GPIOI2, GPIOI3,
 
-       { 64, 0x10,  8, 0, 14, 2 },     /* PCIC0 */
-       { 65, 0x10,  0, 0, 15, 2 },     /* PCIC1 */
-       { 66, 0x14, 24, 0, 16, 2 },     /* PCIC2 */
-       { 67, 0x14, 16, 0, 17, 2 },     /* PCIC3 */
-       { 68, 0x14,  8, 0, 18, 2 },     /* PCIC4 */
+       /* interrupt groups */
+
+       RTC, TMU012, DMAC0, SCIF0, DMAC45, DMAC1,
+       PCIC5, SCIF1, MMCIF, TMU345, FLCTL, GPIO,
 };
 
-static struct intc2_desc intc2_irq_desc __read_mostly = {
-       .prio_base      = 0xffd40000,
-       .msk_base       = 0xffd40038,
-       .mskclr_base    = 0xffd4003c,
+static struct intc_vect vectors[] = {
+       INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+       INTC_VECT(RTC_CUI, 0x4c0),
+       INTC_VECT(WDT, 0x560),
+       INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
+       INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
+       INTC_VECT(HUDI, 0x600),
+       INTC_VECT(DMAC0_DMINT0, 0x640), INTC_VECT(DMAC0_DMINT1, 0x660),
+       INTC_VECT(DMAC0_DMINT2, 0x680), INTC_VECT(DMAC0_DMINT3, 0x6a0),
+       INTC_VECT(DMAC0_DMAE, 0x6c0),
+       INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
+       INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
+       INTC_VECT(DMAC0_DMINT4, 0x780), INTC_VECT(DMAC0_DMINT5, 0x7a0),
+       INTC_VECT(DMAC1_DMINT6, 0x7c0), INTC_VECT(DMAC1_DMINT7, 0x7e0),
+       INTC_VECT(CMT, 0x900), INTC_VECT(HAC, 0x980),
+       INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
+       INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
+       INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
+       INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
+       INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
+       INTC_VECT(SCIF1_ERI, 0xb80), INTC_VECT(SCIF1_RXI, 0xba0),
+       INTC_VECT(SCIF1_BRI, 0xbc0), INTC_VECT(SCIF1_TXI, 0xbe0),
+       INTC_VECT(SIOF, 0xc00), INTC_VECT(HSPI, 0xc80),
+       INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
+       INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
+       INTC_VECT(DMAC1_DMINT8, 0xd80), INTC_VECT(DMAC1_DMINT9, 0xda0),
+       INTC_VECT(DMAC1_DMINT10, 0xdc0), INTC_VECT(DMAC1_DMINT11, 0xde0),
+       INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
+       INTC_VECT(TMU5, 0xe40),
+       INTC_VECT(SSI, 0xe80),
+       INTC_VECT(FLCTL_FLSTE, 0xf00), INTC_VECT(FLCTL_FLEND, 0xf20),
+       INTC_VECT(FLCTL_FLTRQ0, 0xf40), INTC_VECT(FLCTL_FLTRQ1, 0xf60),
+       INTC_VECT(GPIOI0, 0xf80), INTC_VECT(GPIOI1, 0xfa0),
+       INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
+};
 
-       .intc2_data     = intc2_irq_table,
-       .nr_irqs        = ARRAY_SIZE(intc2_irq_table),
+static struct intc_group groups[] = {
+       INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+       INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
+       INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+                  DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
+       INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+       INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
+                  DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
+       INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
+       INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+       INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
+       INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
+       INTC_GROUP(FLCTL, FLCTL_FLSTE, FLCTL_FLEND,
+                  FLCTL_FLTRQ0, FLCTL_FLTRQ1),
+       INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
+};
 
-       .chip = {
-               .name   = "INTC2-sh7780",
-       },
+static struct intc_prio priorities[] = {
+       INTC_PRIO(SCIF0, 3),
+       INTC_PRIO(SCIF1, 3),
+};
+
+static struct intc_mask_reg mask_registers[] = {
+       { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
+         { 0, 0, 0, 0, 0, 0, GPIO, FLCTL,
+           SSI, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB,
+           PCIINTA, PCISERR, HAC, CMT, 0, 0, DMAC1, DMAC0,
+           HUDI, 0, WDT, SCIF1, SCIF0, RTC, TMU345, TMU012 } },
+};
+
+static struct intc_prio_reg prio_registers[] = {
+       { 0xffd40000, 32, 8, /* INT2PRI0 */ { TMU0, TMU1, TMU2, TMU2_TICPI } },
+       { 0xffd40004, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
+       { 0xffd40008, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
+       { 0xffd4000c, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } },
+       { 0xffd40010, 32, 8, /* INT2PRI4 */ { CMT, HAC, PCISERR, PCIINTA, } },
+       { 0xffd40014, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
+                                             PCIINTD, PCIC5 } },
+       { 0xffd40018, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } },
+       { 0xffd4001c, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
+                        mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect irq_vectors[] = {
+       INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+       INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+       INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
+       INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
+};
+
+static struct intc_mask_reg irq_mask_registers[] = {
+       { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
+         { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_prio_reg irq_prio_registers[] = {
+       { 0xffd00010, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
+                                           IRQ4, IRQ5, IRQ6, IRQ7 } },
 };
 
-void __init init_IRQ_intc2(void)
+static struct intc_sense_reg irq_sense_registers[] = {
+       { 0xffd0001c, 32, 2, /* ICR1 */   { IRQ0, IRQ1, IRQ2, IRQ3,
+                                           IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_irq_desc, "sh7780-irq", irq_vectors,
+                        NULL, NULL, irq_mask_registers, irq_prio_registers,
+                        irq_sense_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect irl_vectors[] = {
+       INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+       INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+       INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+       INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+       INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+       INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+       INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+       INTC_VECT(IRL_HHHL, 0x3c0),
+};
+
+static struct intc_mask_reg irl3210_mask_registers[] = {
+       { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+         { IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+           IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+           IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+           IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static struct intc_mask_reg irl7654_mask_registers[] = {
+       { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+           IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+           IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+           IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+           IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors,
+                        NULL, NULL, irl7654_mask_registers, NULL, NULL);
+
+static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors,
+                        NULL, NULL, irl3210_mask_registers, NULL, NULL);
+
+void __init plat_irq_setup(void)
 {
-       register_intc2_controller(&intc2_irq_desc);
+       register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+       switch (mode) {
+       case IRQ_MODE_IRQ:
+               register_intc_controller(&intc_irq_desc);
+               break;
+       case IRQ_MODE_IRL7654:
+               register_intc_controller(&intc_irl7654_desc);
+               break;
+       case IRQ_MODE_IRL3210:
+               register_intc_controller(&intc_irl3210_desc);
+               break;
+       default:
+               BUG();
+       }
 }
index ce10ec5d6914dcd55e2fecc608338d5968e57820..cf047562e43fd59fd60b4aa90acd0fb5497122be 100644 (file)
@@ -110,7 +110,7 @@ static struct intc2_desc intc2_irq_desc __read_mostly = {
        },
 };
 
-void __init init_IRQ_intc2(void)
+void __init plat_irq_setup(void)
 {
        register_intc2_controller(&intc2_irq_desc);
 }
index 70683ea12b83049368f6983c62124ac7c1c10947..704c064f70dc90ad58f5f7ef25843845b5d9ca2c 100644 (file)
@@ -79,7 +79,7 @@ static struct intc2_desc intc2_irq_desc __read_mostly = {
        },
 };
 
-void __init init_IRQ_intc2(void)
+void __init plat_irq_setup(void)
 {
        register_intc2_controller(&intc2_irq_desc);
 }
index 47abf6e49dfb116ce712c94c6ccbd4e3efb17d6e..e61890217c5012b006fa8437975d4fe55a0fe108 100644 (file)
@@ -3,89 +3,46 @@
  *
  * cpufreq driver for the SuperH processors.
  *
- * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
  * Copyright (C) 2002 M. R. Brown
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
+ *
+ *   Copyright (C) 2004-2007 Atmel Corporation
+ *
+ * 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/cpufreq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 #include <linux/sched.h>       /* set_cpus_allowed() */
+#include <linux/clk.h>
 
-#include <asm/processor.h>
-#include <asm/watchdog.h>
-#include <asm/freq.h>
-#include <asm/io.h>
-
-/*
- * For SuperH, each policy change requires that we change the IFC, BFC, and
- * PFC at the same time.  Here we define sane values that won't trash the
- * system.
- *
- * Note the max set is computed at runtime, we use the divisors that we booted
- * with to setup our maximum operating frequencies.
- */
-struct clock_set {
-       unsigned int ifc;
-       unsigned int bfc;
-       unsigned int pfc;
-} clock_sets[] = {
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH2)
-       { 0, 0, 0 },    /* not implemented yet */
-#elif defined(CONFIG_CPU_SH4)
-       { 4, 8, 8 },    /* min - IFC: 1/4, BFC: 1/8, PFC: 1/8 */
-       { 1, 2, 2 },    /* max - IFC: 1, BFC: 1/2, PFC: 1/2 */
-#endif
-};
-
-#define MIN_CLOCK_SET  0
-#define MAX_CLOCK_SET  (ARRAY_SIZE(clock_sets) - 1)
-
-/*
- * For the time being, we only support two frequencies, which in turn are
- * aimed at the POWERSAVE and PERFORMANCE policies, which in turn are derived
- * directly from the respective min/max clock sets. Technically we could
- * support a wider range of frequencies, but these vary far too much for each
- * CPU subtype (and we'd have to construct a frequency table for each subtype).
- *
- * Maybe something to implement in the future..
- */
-#define SH_FREQ_MAX    0
-#define SH_FREQ_MIN    1
-
-static struct cpufreq_frequency_table sh_freqs[] = {
-       { SH_FREQ_MAX,  0 },
-       { SH_FREQ_MIN,  0 },
-       { 0,            CPUFREQ_TABLE_END },
-};
+static struct clk *cpuclk;
 
-static void sh_cpufreq_update_clocks(unsigned int set)
+static unsigned int sh_cpufreq_get(unsigned int cpu)
 {
-       current_cpu_data.cpu_clock = current_cpu_data.master_clock / clock_sets[set].ifc;
-       current_cpu_data.bus_clock = current_cpu_data.master_clock / clock_sets[set].bfc;
-       current_cpu_data.module_clock = current_cpu_data.master_clock / clock_sets[set].pfc;
-       current_cpu_data.loops_per_jiffy = loops_per_jiffy;
+       return (clk_get_rate(cpuclk) + 500) / 1000;
 }
 
-/* XXX: This needs to be split out per CPU and CPU subtype. */
 /*
  * Here we notify other drivers of the proposed change and the final change.
  */
-static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
+static int sh_cpufreq_target(struct cpufreq_policy *policy,
+                            unsigned int target_freq,
+                            unsigned int relation)
 {
-       unsigned short frqcr = ctrl_inw(FRQCR);
+       unsigned int cpu = policy->cpu;
        cpumask_t cpus_allowed;
        struct cpufreq_freqs freqs;
+       long freq;
 
        if (!cpu_online(cpu))
                return -ENODEV;
@@ -95,125 +52,109 @@ static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
 
        BUG_ON(smp_processor_id() != cpu);
 
-       freqs.cpu = cpu;
-       freqs.old = current_cpu_data.cpu_clock / 1000;
-       freqs.new = (current_cpu_data.master_clock / clock_sets[set].ifc) / 1000;
+       /* Convert target_freq from kHz to Hz */
+       freq = clk_round_rate(cpuclk, target_freq * 1000);
 
-       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-#if defined(CONFIG_CPU_SH3)
-       frqcr |= (newstate & 0x4000) << 14;
-       frqcr |= (newstate & 0x000c) <<  2;
-#elif defined(CONFIG_CPU_SH4)
-       /*
-        * FRQCR.PLL2EN is 1, we need to allow the PLL to stabilize by
-        * initializing the WDT.
-        */
-       if (frqcr & (1 << 9)) {
-               __u8 csr;
-
-               /*
-                * Set the overflow period to the highest available,
-                * in this case a 1/4096 division ratio yields a 5.25ms
-                * overflow period. See asm-sh/watchdog.h for more
-                * information and a range of other divisors.
-                */
-               csr = sh_wdt_read_csr();
-               csr |= WTCSR_CKS_4096;
-               sh_wdt_write_csr(csr);
-
-               sh_wdt_write_cnt(0);
-       }
-       frqcr &= 0x0e00;        /* Clear ifc, bfc, pfc */
-       frqcr |= get_ifc_value(clock_sets[set].ifc) << 6;
-       frqcr |= get_bfc_value(clock_sets[set].bfc) << 3;
-       frqcr |= get_pfc_value(clock_sets[set].pfc);
-#endif
-       ctrl_outw(frqcr, FRQCR);
-       sh_cpufreq_update_clocks(set);
+       if (freq < (policy->min * 1000) || freq > (policy->max * 1000))
+               return -EINVAL;
+
+       pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
 
+       freqs.cpu       = cpu;
+       freqs.old       = sh_cpufreq_get(cpu);
+       freqs.new       = (freq + 500) / 1000;
+       freqs.flags     = 0;
+
+       cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
        set_cpus_allowed(current, cpus_allowed);
+       clk_set_rate(cpuclk, freq);
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
+       pr_debug("cpufreq: set frequency %lu Hz\n", freq);
+
        return 0;
 }
 
 static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-       unsigned int min_freq, max_freq;
-       unsigned int ifc, bfc, pfc;
+       printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n");
 
        if (!cpu_online(policy->cpu))
                return -ENODEV;
 
-       /* Update our maximum clock set */
-       get_current_frequency_divisors(&ifc, &bfc, &pfc);
-       clock_sets[MAX_CLOCK_SET].ifc = ifc;
-       clock_sets[MAX_CLOCK_SET].bfc = bfc;
-       clock_sets[MAX_CLOCK_SET].pfc = pfc;
-
-       /* Convert from Hz to kHz */
-       max_freq = current_cpu_data.cpu_clock / 1000;
-       min_freq = (current_cpu_data.master_clock / clock_sets[MIN_CLOCK_SET].ifc) / 1000;
-       
-       sh_freqs[SH_FREQ_MAX].frequency = max_freq;
-       sh_freqs[SH_FREQ_MIN].frequency = min_freq;
+       cpuclk = clk_get(NULL, "cpu_clk");
+       if (IS_ERR(cpuclk)) {
+               printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
+               return PTR_ERR(cpuclk);
+       }
 
        /* cpuinfo and default policy values */
-       policy->governor                   = CPUFREQ_DEFAULT_GOVERNOR;
+       policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+       policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
        policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
-       policy->cur                        = max_freq;
 
-       return cpufreq_frequency_table_cpuinfo(policy, &sh_freqs[0]);
-}
+       policy->governor        = CPUFREQ_DEFAULT_GOVERNOR;
+       policy->cur             = sh_cpufreq_get(policy->cpu);
+       policy->min             = policy->cpuinfo.min_freq;
+       policy->max             = policy->cpuinfo.max_freq;
 
-static int sh_cpufreq_verify(struct cpufreq_policy *policy)
-{
-       return cpufreq_frequency_table_verify(policy, &sh_freqs[0]);
-}
 
-static int sh_cpufreq_target(struct cpufreq_policy *policy,
-                            unsigned int target_freq,
-                            unsigned int relation)
-{
-       unsigned int set, idx = 0;
+       /*
+        * Catch the cases where the clock framework hasn't been wired up
+        * properly to support scaling.
+        */
+       if (unlikely(policy->min == policy->max)) {
+               printk(KERN_ERR "cpufreq: clock framework rate rounding "
+                      "not supported on this CPU.\n");
 
-       if (cpufreq_frequency_table_target(policy, &sh_freqs[0], target_freq, relation, &idx))
+               clk_put(cpuclk);
                return -EINVAL;
+       }
 
-       set = (idx == SH_FREQ_MIN) ? MIN_CLOCK_SET : MAX_CLOCK_SET;
+       printk(KERN_INFO "cpufreq: Frequencies - Minimum %u.%03u MHz, "
+              "Maximum %u.%03u MHz.\n",
+              policy->min / 1000, policy->min % 1000,
+              policy->max / 1000, policy->max % 1000);
 
-       sh_cpufreq_setstate(policy->cpu, set);
+       return 0;
+}
 
+static int sh_cpufreq_verify(struct cpufreq_policy *policy)
+{
+       cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+                                    policy->cpuinfo.max_freq);
+       return 0;
+}
+
+static int sh_cpufreq_exit(struct cpufreq_policy *policy)
+{
+       clk_put(cpuclk);
        return 0;
 }
 
 static struct cpufreq_driver sh_cpufreq_driver = {
        .owner          = THIS_MODULE,
-       .name           = "SH cpufreq",
+       .name           = "sh",
        .init           = sh_cpufreq_cpu_init,
        .verify         = sh_cpufreq_verify,
        .target         = sh_cpufreq_target,
+       .get            = sh_cpufreq_get,
+       .exit           = sh_cpufreq_exit,
 };
 
-static int __init sh_cpufreq_init(void)
+static int __init sh_cpufreq_module_init(void)
 {
-       if (!current_cpu_data.cpu_clock)
-               return -EINVAL;
-       if (cpufreq_register_driver(&sh_cpufreq_driver))
-               return -EINVAL;
-
-       return 0;
+       return cpufreq_register_driver(&sh_cpufreq_driver);
 }
 
-static void __exit sh_cpufreq_exit(void)
+static void __exit sh_cpufreq_module_exit(void)
 {
        cpufreq_unregister_driver(&sh_cpufreq_driver);
 }
 
-module_init(sh_cpufreq_init);
-module_exit(sh_cpufreq_exit);
+module_init(sh_cpufreq_module_init);
+module_exit(sh_cpufreq_module_exit);
 
 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
 MODULE_DESCRIPTION("cpufreq driver for SuperH");
 MODULE_LICENSE("GPL");
-
index 71a3ad7d283e2156cbbae33a2338738e2005b090..0bccc0ca5a0f73ff624ed862bc55fbf1764bf80d 100644 (file)
@@ -36,7 +36,8 @@ ENTRY(empty_zero_page)
 1:
        .skip   PAGE_SIZE - empty_zero_page - 1b
 
-       .text   
+       .section        .text.head, "ax"
+
 /*
  * Condition at the entry of _stext:
  *
index 27897798867a40d47e22ca5d2db72c0a2f48205d..03404987528dd083970977dfde5379c2bca67d8c 100644 (file)
@@ -253,14 +253,7 @@ void __init init_IRQ(void)
 #ifdef CONFIG_CPU_HAS_PINT_IRQ
        init_IRQ_pint();
 #endif
-
-#ifdef CONFIG_CPU_HAS_INTC2_IRQ
-       init_IRQ_intc2();
-#endif
-
-#ifdef CONFIG_CPU_HAS_IPR_IRQ
-       init_IRQ_ipr();
-#endif
+       plat_irq_setup();
 
        /* Perform the machine specific initialisation */
        if (sh_mv.mv_init_irq)
index de8e6e2f2c87d3f21e09bcb443c304812b4a60f6..c14a3e95d0b18c52e261a1d93ae8095d06640168 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/kexec.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/page.h>
@@ -78,7 +79,11 @@ static char __initdata command_line[COMMAND_LINE_SIZE] = { 0, };
 static struct resource code_resource = { .name = "Kernel code", };
 static struct resource data_resource = { .name = "Kernel data", };
 
-unsigned long memory_start, memory_end;
+unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
+
+unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
 
 static int __init early_parse_mem(char *p)
 {
index 5b53e10bb9cd3d7fb6809731c30285b152477f0f..d1bcac4fa2690419e3e4855b2ed97760248f7476 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) 2000 Greg Banks, Mitch Davis
  *
  */
-
+#include <linux/module.h>
 #include <asm/sh_bios.h>
 
 #define BIOS_CALL_CONSOLE_WRITE        0
@@ -63,6 +63,7 @@ void sh_bios_gdb_detach(void)
 {
     sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
 }
+EXPORT_SYMBOL(sh_bios_gdb_detach);
 
 void sh_bios_get_node_addr (unsigned char *node_addr)
 {
index c968dcf09eee0610e7aa524f0393c60ab0feb96e..37aef0a85197b7b754998e0f0d126cde9ee9cdbf 100644 (file)
@@ -63,10 +63,43 @@ EXPORT_SYMBOL(__const_udelay);
 /* These symbols are generated by the compiler itself */
 DECLARE_EXPORT(__udivsi3);
 DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__ashrsi3);
+DECLARE_EXPORT(__ashlsi3);
 DECLARE_EXPORT(__ashrdi3);
 DECLARE_EXPORT(__ashldi3);
+DECLARE_EXPORT(__ashiftrt_r4_6);
+DECLARE_EXPORT(__ashiftrt_r4_7);
+DECLARE_EXPORT(__ashiftrt_r4_8);
+DECLARE_EXPORT(__ashiftrt_r4_9);
+DECLARE_EXPORT(__ashiftrt_r4_10);
+DECLARE_EXPORT(__ashiftrt_r4_11);
+DECLARE_EXPORT(__ashiftrt_r4_12);
+DECLARE_EXPORT(__ashiftrt_r4_13);
+DECLARE_EXPORT(__ashiftrt_r4_14);
+DECLARE_EXPORT(__ashiftrt_r4_15);
+DECLARE_EXPORT(__ashiftrt_r4_20);
+DECLARE_EXPORT(__ashiftrt_r4_21);
+DECLARE_EXPORT(__ashiftrt_r4_22);
+DECLARE_EXPORT(__ashiftrt_r4_23);
+DECLARE_EXPORT(__ashiftrt_r4_24);
+DECLARE_EXPORT(__ashiftrt_r4_27);
+DECLARE_EXPORT(__ashiftrt_r4_30);
+DECLARE_EXPORT(__lshrsi3);
 DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__movstrSI8);
+DECLARE_EXPORT(__movstrSI12);
 DECLARE_EXPORT(__movstrSI16);
+DECLARE_EXPORT(__movstrSI20);
+DECLARE_EXPORT(__movstrSI24);
+DECLARE_EXPORT(__movstrSI28);
+DECLARE_EXPORT(__movstrSI32);
+DECLARE_EXPORT(__movstrSI36);
+DECLARE_EXPORT(__movstrSI40);
+DECLARE_EXPORT(__movstrSI44);
+DECLARE_EXPORT(__movstrSI48);
+DECLARE_EXPORT(__movstrSI52);
+DECLARE_EXPORT(__movstrSI56);
+DECLARE_EXPORT(__movstrSI60);
 #if __GNUC__ == 4
 DECLARE_EXPORT(__movmem);
 #else
@@ -115,7 +148,9 @@ EXPORT_SYMBOL(synchronize_irq);
 #endif
 
 EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_generic);
 #ifdef CONFIG_IPV6
 EXPORT_SYMBOL(csum_ipv6_magic);
 #endif
 EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(__clear_user);
index ff5656e60c05c3744c110ca9b770d40bb8efe0e1..91fb7024e06f08626bd4b31efd0043ca6ad69b31 100644 (file)
@@ -358,3 +358,4 @@ ENTRY(sys_call_table)
        .long sys_signalfd
        .long sys_timerfd
        .long sys_eventfd
+       .long sys_fallocate
index 5ba216180b304132f51ccf94a02c02bf5387dbd2..9cb95af7b09013dd25fdfb0da3b1cf6e031bc84a 100644 (file)
@@ -22,6 +22,7 @@ SECTIONS
        *(.empty_zero_page)
        } = 0
   .text : {
+       *(.text.head)
        TEXT_TEXT
        SCHED_TEXT
        LOCK_TEXT
index 28d79a474cde53efbede8072938df4902361c333..70da1c8d407e87c73ffe415a27ffa6206cc884da 100644 (file)
@@ -120,14 +120,14 @@ config CPU_SUBTYPE_SH7712
 config CPU_SUBTYPE_SH7750
        bool "Support SH7750 processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
        help
          Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
 
 config CPU_SUBTYPE_SH7091
        bool "Support SH7091 processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
        help
          Select SH7091 if you have an SH-4 based Sega device (such as
          the Dreamcast, Naomi, and Naomi 2).
@@ -135,17 +135,17 @@ config CPU_SUBTYPE_SH7091
 config CPU_SUBTYPE_SH7750R
        bool "Support SH7750R processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7750S
        bool "Support SH7750S processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7751
        bool "Support SH7751 processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
        help
          Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
          or if you have a HD6417751R CPU.
@@ -153,7 +153,7 @@ config CPU_SUBTYPE_SH7751
 config CPU_SUBTYPE_SH7751R
        bool "Support SH7751R processor"
        select CPU_SH4
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7760
        bool "Support SH7760 processor"
@@ -189,7 +189,7 @@ config CPU_SUBTYPE_SH7770
 config CPU_SUBTYPE_SH7780
        bool "Support SH7780 processor"
        select CPU_SH4A
-       select CPU_HAS_INTC2_IRQ
+       select CPU_HAS_INTC_IRQ
 
 config CPU_SUBTYPE_SH7785
        bool "Support SH7785 processor"
@@ -217,7 +217,7 @@ config CPU_SUBTYPE_SH7722
        bool "Support SH7722 processor"
        select CPU_SH4AL_DSP
        select CPU_SHX2
-       select CPU_HAS_IPR_IRQ
+       select CPU_HAS_INTC_IRQ
        select ARCH_SPARSEMEM_ENABLE
        select SYS_SUPPORTS_NUMA
 
index ed035084b05359f563e7e7b325496732b634dbbd..784434143343f547bf31b9b08b355e2a6e3c7095 100644 (file)
@@ -1,11 +1,12 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc1
-# Mon May 14 08:43:31 2007
+# Linux kernel version: 2.6.22
+# Fri Jul 20 12:28:34 2007
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH64=y
 CONFIG_MMU=y
+CONFIG_QUICKLIST=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
@@ -32,7 +33,7 @@ CONFIG_SWAP=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 # CONFIG_AUDIT is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
@@ -66,19 +67,12 @@ CONFIG_SLAB=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
 # CONFIG_MODULES is not set
-
-#
-# Block layer
-#
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
 
 #
 # IO Schedulers
@@ -156,6 +150,8 @@ CONFIG_FLAT_NODE_MEM_MAP=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 
 #
 # Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -175,7 +171,6 @@ CONFIG_SH_PCIDMA_NONCOHERENT=y
 # Executable file formats
 #
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
 # CONFIG_BINFMT_MISC is not set
 
 #
@@ -225,20 +220,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -274,6 +257,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -288,26 +272,10 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
 # CONFIG_CONNECTOR is not set
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
@@ -323,18 +291,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
-# CONFIG_BLINK is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
 # CONFIG_IDE is not set
 
 #
@@ -342,6 +303,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
@@ -410,13 +372,8 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
 # CONFIG_SCSI_SRP is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
 
 #
@@ -432,30 +389,16 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
 #
 # CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 # CONFIG_MII is not set
 # CONFIG_STNIC is not set
@@ -464,10 +407,6 @@ CONFIG_NET_ETHERNET=y
 # CONFIG_CASSINI is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_SMC91X is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=y
@@ -510,7 +449,6 @@ CONFIG_NETDEV_1000=y
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_VIA_VELOCITY is not set
 # CONFIG_TIGON3 is not set
 # CONFIG_BNX2 is not set
@@ -524,11 +462,6 @@ CONFIG_NETDEV_10000=y
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
 # CONFIG_MLX4_CORE is not set
-CONFIG_MLX4_DEBUG=y
-
-#
-# Token Ring devices
-#
 # CONFIG_TR is not set
 
 #
@@ -546,15 +479,7 @@ CONFIG_MLX4_DEBUG=y
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -562,6 +487,7 @@ CONFIG_MLX4_DEBUG=y
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -638,10 +564,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_WATCHDOG=y
 # CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -658,15 +580,10 @@ CONFIG_WATCHDOG=y
 # CONFIG_PCIPCWATCHDOG is not set
 # CONFIG_WDTPCI is not set
 CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
@@ -676,20 +593,24 @@ CONFIG_DEVPORT=y
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
 # CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
 # CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
 # CONFIG_HWMON_DEBUG_CHIP is not set
 
 #
@@ -739,7 +660,6 @@ CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
-# CONFIG_FB_EPSON1355 is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
@@ -765,6 +685,7 @@ CONFIG_FB_KYRO=y
 #
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -789,16 +710,10 @@ CONFIG_LOGO_SUPERH_CLUT224=y
 # Sound
 #
 # CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -826,16 +741,8 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 #
 # LED Triggers
 #
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
 
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
 #
 # Real Time Clock
 #
@@ -854,6 +761,11 @@ CONFIG_USB_ARCH_HAS_EHCI=y
 # DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
 #
 # File systems
 #
@@ -950,7 +862,6 @@ CONFIG_SUNRPC=y
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
 # CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1001,6 +912,7 @@ CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_DEBUG_SHIRQ is not set
 CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
 CONFIG_SCHEDSTATS=y
 # CONFIG_TIMER_STATS is not set
 # CONFIG_DEBUG_SLAB is not set
@@ -1017,7 +929,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
 # CONFIG_DEBUG_LIST is not set
 CONFIG_FRAME_POINTER=y
 CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_EARLY_PRINTK is not set
 # CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
@@ -1033,10 +944,6 @@ CONFIG_SH64_SR_WATCH=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 # CONFIG_CRYPTO is not set
 
 #
@@ -1047,6 +954,7 @@ CONFIG_BITREVERSE=y
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
index f3740ddbc47190fc99ec05c7cfda8a75c25cebca..186406d3ad9c60561992e6e1682e2730de8df748 100644 (file)
@@ -124,7 +124,7 @@ empty_bad_pte_table:
 fpu_in_use:    .quad   0
 
 
-       .section        .text, "ax"
+       .section        .text.head, "ax"
        .balign L1_CACHE_BYTES
 /*
  * Condition at the entry of __stext:
index 3334f99b5835f0a113514fa3e25dcf886690dbd5..388bb711f1b02ec0c46dac25723dfee1fa3a95df 100644 (file)
@@ -48,7 +48,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
 
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
 {
        return str;
 }
@@ -497,7 +497,7 @@ static int __init pcibios_init(void)
 
 subsys_initcall(pcibios_init);
 
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
        struct pci_dev *dev = bus->self;
        int i;
index a5c680d2938429351a4a7168667ab9ec702a352c..abb94c05d07a7099e285594b6eaecde8ee4dda55 100644 (file)
@@ -378,3 +378,4 @@ sys_call_table:
        .long sys_signalfd
        .long sys_timerfd               /* 350 */
        .long sys_eventfd
+       .long sys_fallocate
index 8ac9c7c5f8487fd31c872a5ebb1ec7e354564b1a..267b4f9af2e18ccc1117f465a4a62406710a4ee4 100644 (file)
@@ -54,6 +54,7 @@ SECTIONS
        } = 0
 
   .text : C_PHYS(.text) {
+       *(.text.head)
        TEXT_TEXT
        *(.text64)
         *(.text..SHmedia32)
index ff26c02511aa6eac58ed79bb284f7bb76604e2f0..990857756d44db11195d23edc5eee4564a8a7556 100644 (file)
@@ -242,7 +242,7 @@ static void shmedia_free_io(struct resource *res)
        release_resource(res);
 }
 
-static void *sh64_get_page(void)
+static __init_refok void *sh64_get_page(void)
 {
        extern int after_bootmem;
        void *page;
index 603d83ad65c8f0012e11c3c300273424d24c1098..9d327ec59759746bf0938f53f89ed2569fba7c44 100644 (file)
@@ -24,6 +24,9 @@ config GENERIC_ISA_DMA
 config ARCH_NO_VIRT_TO_BUS
        def_bool y
 
+config OF
+       def_bool y
+
 source "init/Kconfig"
 
 menu "General machine setup"
index 7bb86b9cdaa338be5c3ab6a54f8ab53bc5ed7938..ac352eb6dff3beb4753cefc885078c87284c053e 100644 (file)
@@ -148,6 +148,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
 {
        const struct linux_prom_registers *regs;
        struct linux_ebus_child *child;
+       struct dev_archdata *sd;
        const int *irqs;
        int i, n, len;
        unsigned long baseaddr;
@@ -234,6 +235,10 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
                }
        }
 
+       sd = &dev->ofdev.dev.archdata;
+       sd->prom_node = dp;
+       sd->op = &dev->ofdev;
+
        dev->ofdev.node = dp;
        dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
        dev->ofdev.dev.bus = &ebus_bus_type;
index fd7f8cb668a3c080ba2642ae265ae59cb57d6808..36383f73d6855a425a92e60884c20f10e4c9f6be 100644 (file)
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
-
-#include <asm/errno.h>
-#include <asm/of_device.h>
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-                                       const struct of_device *dev)
-{
-       if (!dev->node)
-               return NULL;
-       while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-               int match = 1;
-               if (matches->name[0])
-                       match &= dev->node->name
-                               && !strcmp(matches->name, dev->node->name);
-               if (matches->type[0])
-                       match &= dev->node->type
-                               && !strcmp(matches->type, dev->node->type);
-               if (matches->compatible[0])
-                       match &= of_device_is_compatible(dev->node,
-                                                        matches->compatible);
-               if (match)
-                       return matches;
-               matches++;
-       }
-       return NULL;
-}
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-       const struct of_device_id * matches = of_drv->match_table;
-
-       if (!matches)
-               return 0;
-
-       return of_match_device(matches, of_dev) != NULL;
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
-       struct device *tmp;
-
-       if (!dev)
-               return NULL;
-       tmp = get_device(&dev->dev);
-       if (tmp)
-               return to_of_device(tmp);
-       else
-               return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
-       if (dev)
-               put_device(&dev->dev);
-}
-
-
-static int of_device_probe(struct device *dev)
-{
-       int error = -ENODEV;
-       struct of_platform_driver *drv;
-       struct of_device *of_dev;
-       const struct of_device_id *match;
-
-       drv = to_of_platform_driver(dev->driver);
-       of_dev = to_of_device(dev);
-
-       if (!drv->probe)
-               return error;
-
-       of_dev_get(of_dev);
-
-       match = of_match_device(drv->match_table, of_dev);
-       if (match)
-               error = drv->probe(of_dev, match);
-       if (error)
-               of_dev_put(of_dev);
-
-       return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-       if (dev->driver && drv->remove)
-               drv->remove(of_dev);
-       return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->suspend)
-               error = drv->suspend(of_dev, state);
-       return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->resume)
-               error = drv->resume(of_dev);
-       return error;
-}
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 static int node_match(struct device *dev, void *data)
 {
@@ -138,7 +19,7 @@ static int node_match(struct device *dev, void *data)
 
 struct of_device *of_find_device_by_node(struct device_node *dp)
 {
-       struct device *dev = bus_find_device(&of_bus_type, NULL,
+       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
                                             dp, node_match);
 
        if (dev)
@@ -149,38 +30,17 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
 EXPORT_SYMBOL(of_find_device_by_node);
 
 #ifdef CONFIG_PCI
-struct bus_type ebus_bus_type = {
-       .name   = "ebus",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type ebus_bus_type;
 EXPORT_SYMBOL(ebus_bus_type);
 #endif
 
 #ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type = {
-       .name   = "sbus",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type sbus_bus_type;
 EXPORT_SYMBOL(sbus_bus_type);
 #endif
 
-struct bus_type of_bus_type = {
-       .name   = "of",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
-EXPORT_SYMBOL(of_bus_type);
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
 
 static inline u64 of_read_addr(const u32 *cell, int size)
 {
@@ -560,11 +420,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
 {
        struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
        const struct linux_prom_irqs *intr;
+       struct dev_archdata *sd;
        int len, i;
 
        if (!op)
                return NULL;
 
+       sd = &op->dev.archdata;
+       sd->prom_node = dp;
+       sd->op = op;
+
        op->node = dp;
 
        op->clock_freq = of_getintprop_default(dp, "clock-frequency",
@@ -646,7 +511,7 @@ build_resources:
        build_device_resources(op, parent);
 
        op->dev.parent = parent;
-       op->dev.bus = &of_bus_type;
+       op->dev.bus = &of_platform_bus_type;
        if (!parent)
                strcpy(op->dev.bus_id, "root");
        else
@@ -690,14 +555,14 @@ static int __init of_bus_driver_init(void)
 {
        int err;
 
-       err = bus_register(&of_bus_type);
+       err = of_bus_type_init(&of_platform_bus_type, "of");
 #ifdef CONFIG_PCI
        if (!err)
-               err = bus_register(&ebus_bus_type);
+               err = of_bus_type_init(&ebus_bus_type, "ebus");
 #endif
 #ifdef CONFIG_SBUS
        if (!err)
-               err = bus_register(&sbus_bus_type);
+               err = of_bus_type_init(&sbus_bus_type, "sbus");
 #endif
 
        if (!err)
@@ -735,56 +600,6 @@ void of_unregister_driver(struct of_platform_driver *drv)
        driver_unregister(&drv->driver);
 }
 
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct of_device *ofdev;
-
-       ofdev = to_of_device(dev);
-       return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-       struct of_device *ofdev;
-
-        ofdev = to_of_device(dev);
-
-       kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
-       int rc;
-
-       BUG_ON(ofdev->node == NULL);
-
-       rc = device_register(&ofdev->dev);
-       if (rc)
-               return rc;
-
-       rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
-       if (rc)
-               device_unregister(&ofdev->dev);
-
-       return rc;
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
-       device_remove_file(&ofdev->dev, &dev_attr_devspec);
-       device_unregister(&ofdev->dev);
-}
-
 struct of_device* of_platform_device_create(struct device_node *np,
                                            const char *bus_id,
                                            struct device *parent,
@@ -810,12 +625,6 @@ struct of_device* of_platform_device_create(struct device_node *np,
        return dev;
 }
 
-EXPORT_SYMBOL(of_match_device);
 EXPORT_SYMBOL(of_register_driver);
 EXPORT_SYMBOL(of_unregister_driver);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
 EXPORT_SYMBOL(of_platform_device_create);
-EXPORT_SYMBOL(of_release_dev);
index 8c37f8f5adb7f0ef2d49f5910c984f22307b2951..33f7a3ddb1046b374a4804dad958e1c6d429b74c 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/processor.h>
 #include <asm/psr.h>
 #include <asm/elf.h>
+#include <asm/prom.h>
 #include <asm/unistd.h>
 
 /* 
@@ -150,7 +151,7 @@ void machine_halt(void)
        local_irq_enable();
        mdelay(8);
        local_irq_disable();
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        prom_halt();
        panic("Halt failed!");
@@ -166,7 +167,7 @@ void machine_restart(char * cmd)
 
        p = strchr (reboot_command, '\n');
        if (p) *p = 0;
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        if (cmd)
                prom_reboot(cmd);
@@ -179,7 +180,8 @@ void machine_restart(char * cmd)
 void machine_power_off(void)
 {
 #ifdef CONFIG_SUN_AUXIO
-       if (auxio_power_register && (!serial_console || scons_pwroff))
+       if (auxio_power_register &&
+           (strcmp(of_console_device->type, "serial") || scons_pwroff))
                *auxio_power_register |= AUXIO_POWER_OFF;
 #endif
        machine_halt();
index eed140b3c7397caf4abe0bd204df9bbb45dd25df..e3a537650db1e8792c0d7a7978b0e52ab3e7fe2e 100644 (file)
 #include <asm/prom.h>
 #include <asm/oplib.h>
 
-static struct device_node *allnodes;
+extern struct device_node *allnodes;   /* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
-                           const char *compat)
-{
-       const char* cp;
-       int cplen, l;
-
-       cp = of_get_property(device, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
-       struct device_node *np;
-
-       if (!node)
-               return NULL;
-
-       np = node->parent;
-
-       return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
-       struct device_node *prev)
-{
-       struct device_node *next;
-
-       next = prev ? prev->sibling : node->child;
-       for (; next != 0; next = next->sibling) {
-               break;
-       }
-
-       return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
-       struct device_node *np = allnodes;
-
-       for (; np != 0; np = np->allnext) {
-               if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock;  /* temporary while merging */
 
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
@@ -105,81 +41,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
-struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != NULL; np = np->allnext)
-               if (np->name != NULL && strcmp(np->name, name) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext)
-               if (np->type != 0 && strcmp(np->type, type) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compatible)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext) {
-               if (type != NULL
-                   && !(np->type != 0 && strcmp(np->type, type) == 0))
-                       continue;
-               if (of_device_is_compatible(np, compatible))
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(const struct device_node *np,
-                                 const char *name,
-                                 int *lenp)
-{
-       struct property *pp;
-
-       for (pp = np->properties; pp != 0; pp = pp->next) {
-               if (strcasecmp(pp->name, name) == 0) {
-                       if (lenp != 0)
-                               *lenp = pp->length;
-                       break;
-               }
-       }
-       return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
-                           int *lenp)
-{
-       struct property *pp = of_find_property(np,name,lenp);
-       return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 int of_getintprop_default(struct device_node *np, const char *name, int def)
 {
        struct property *prop;
@@ -193,36 +54,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
-int of_n_addr_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#address-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #address-cells property for the root node, default to 2 */
-       return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#size-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #size-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -566,6 +397,135 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
        return dp;
 }
 
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+extern void restore_current(void);
+
+static void __init of_console_init(void)
+{
+       char *msg = "OF stdout device is: %s\n";
+       struct device_node *dp;
+       unsigned long flags;
+       const char *type;
+       phandle node;
+       int skip, fd;
+
+       of_console_path = prom_early_alloc(256);
+
+       switch (prom_vers) {
+       case PROM_V0:
+       case PROM_SUN4:
+               skip = 0;
+               switch (*romvec->pv_stdout) {
+               case PROMDEV_SCREEN:
+                       type = "display";
+                       break;
+
+               case PROMDEV_TTYB:
+                       skip = 1;
+                       /* FALLTHRU */
+
+               case PROMDEV_TTYA:
+                       type = "serial";
+                       break;
+
+               default:
+                       prom_printf("Invalid PROM_V0 stdout value %u\n",
+                                   *romvec->pv_stdout);
+                       prom_halt();
+               }
+
+               for_each_node_by_type(dp, type) {
+                       if (!skip--)
+                               break;
+               }
+               if (!dp) {
+                       prom_printf("Cannot find PROM_V0 console node.\n");
+                       prom_halt();
+               }
+               of_console_device = dp;
+
+               strcpy(of_console_path, dp->full_name);
+               if (!strcmp(type, "serial")) {
+                       strcat(of_console_path,
+                              (skip ? ":b" : ":a"));
+               }
+               break;
+
+       default:
+       case PROM_V2:
+       case PROM_V3:
+               fd = *romvec->pv_v2bootargs.fd_stdout;
+
+               spin_lock_irqsave(&prom_lock, flags);
+               node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
+               restore_current();
+               spin_unlock_irqrestore(&prom_lock, flags);
+
+               if (!node) {
+                       prom_printf("Cannot resolve stdout node from "
+                                   "instance %08x.\n", fd);
+                       prom_halt();
+               }
+               dp = of_find_node_by_phandle(node);
+               type = of_get_property(dp, "device_type", NULL);
+
+               if (!type) {
+                       prom_printf("Console stdout lacks "
+                                   "device_type property.\n");
+                       prom_halt();
+               }
+
+               if (strcmp(type, "display") && strcmp(type, "serial")) {
+                       prom_printf("Console device_type is neither display "
+                                   "nor serial.\n");
+                       prom_halt();
+               }
+
+               of_console_device = dp;
+
+               if (prom_vers == PROM_V2) {
+                       strcpy(of_console_path, dp->full_name);
+                       switch (*romvec->pv_stdout) {
+                       case PROMDEV_TTYA:
+                               strcat(of_console_path, ":a");
+                               break;
+                       case PROMDEV_TTYB:
+                               strcat(of_console_path, ":b");
+                               break;
+                       }
+               } else {
+                       const char *path;
+
+                       dp = of_find_node_by_path("/");
+                       path = of_get_property(dp, "stdout-path", NULL);
+                       if (!path) {
+                               prom_printf("No stdout-path in root node.\n");
+                               prom_halt();
+                       }
+                       strcpy(of_console_path, path);
+               }
+               break;
+       }
+
+       of_console_options = strrchr(of_console_path, ':');
+       if (of_console_options) {
+               of_console_options++;
+               if (*of_console_options == '\0')
+                       of_console_options = NULL;
+       }
+
+       prom_printf(msg, of_console_path);
+       printk(msg, of_console_path);
+}
+
 void __init prom_build_devicetree(void)
 {
        struct device_node **nextp;
@@ -578,6 +538,8 @@ void __init prom_build_devicetree(void)
        allnodes->child = build_tree(allnodes,
                                     prom_getchild(allnodes->node),
                                     &nextp);
+       of_console_init();
+
        printk("PROM: Built device tree with %u bytes of memory.\n",
               prom_early_allocated);
 }
index 64c0ed98820aa8870f7107e09c09c8df69fddd50..f8228383895ac9f38c51709c9af3c76ac13d2ba1 100644 (file)
@@ -146,31 +146,6 @@ static void __init process_switch(char c)
        }
 }
 
-static void __init process_console(char *commands)
-{
-       serial_console = 0;
-       commands += 8;
-       /* Linux-style serial */
-       if (!strncmp(commands, "ttyS", 4))
-               serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
-       else if (!strncmp(commands, "tty", 3)) {
-               char c = *(commands + 3);
-               /* Solaris-style serial */
-               if (c == 'a' || c == 'b')
-                       serial_console = c - 'a' + 1;
-               /* else Linux-style fbcon, not serial */
-       }
-#if defined(CONFIG_PROM_CONSOLE)
-       if (!strncmp(commands, "prom", 4)) {
-               char *p;
-
-               for (p = commands - 8; *p && *p != ' '; p++)
-                       *p = ' ';
-               conswitchp = &prom_con;
-       }
-#endif
-}
-
 static void __init boot_flags_init(char *commands)
 {
        while (*commands) {
@@ -187,9 +162,7 @@ static void __init boot_flags_init(char *commands)
                                process_switch(*commands++);
                        continue;
                }
-               if (!strncmp(commands, "console=", 8)) {
-                       process_console(commands);
-               } else if (!strncmp(commands, "mem=", 4)) {
+               if (!strncmp(commands, "mem=", 4)) {
                        /*
                         * "mem=XXX[kKmM] overrides the PROM-reported
                         * memory size.
@@ -341,41 +314,6 @@ void __init setup_arch(char **cmdline_p)
        smp_setup_cpu_possible_map();
 }
 
-static int __init set_preferred_console(void)
-{
-       int idev, odev;
-
-       /* The user has requested a console so this is already set up. */
-       if (serial_console >= 0)
-               return -EBUSY;
-
-       idev = prom_query_input_device();
-       odev = prom_query_output_device();
-       if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-               serial_console = 0;
-       } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-               serial_console = 1;
-       } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-               serial_console = 2;
-       } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
-               prom_printf("MrCoffee ttya\n");
-               serial_console = 1;
-       } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
-               serial_console = 0;
-               prom_printf("MrCoffee keyboard\n");
-       } else {
-               prom_printf("Confusing console (idev %d, odev %d)\n",
-                   idev, odev);
-               serial_console = 1;
-       }
-
-       if (serial_console)
-               return add_preferred_console("ttyS", serial_console - 1, NULL);
-
-       return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
 extern char *sparc_cpu_type;
 extern char *sparc_fpu_type;
 
@@ -461,7 +399,6 @@ void sun_do_break(void)
        prom_cmdline();
 }
 
-int serial_console = -1;
 int stop_a_enabled = 1;
 
 static int __init topology_init(void)
index 90b52d4dab9a8ce4ec47d18f8ac6b2e188e39c9b..55722840859c89c15df7dc32409cdd902fb7c376 100644 (file)
@@ -1,8 +1,7 @@
-/* $Id: systbls.S,v 1.103 2002/02/08 03:57:14 davem Exp $
- * systbls.S: System call entry point tables for OS compatibility.
+/* systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
  *
  * Based upon preliminary work which is:
  *
@@ -80,7 +79,7 @@ sys_call_table:
 /*295*/        .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
 /*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd
+/*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
 
 #ifdef CONFIG_SUNOS_EMUL
        /* Now the SunOS syscall table. */
@@ -198,6 +197,6 @@ sunos_sys_table:
        .long sunos_nosys, sunos_nosys, sunos_nosys
        .long sunos_nosys
 /*310*/        .long sunos_nosys, sunos_nosys, sunos_nosys
-       .long sunos_nosys
+       .long sunos_nosys, sunos_nosys
 
 #endif
index 7b4612da74a6ff0f830beba61d8eea3142c2b515..f2fdbb3664d37e34d3aaf8a6c19f6733e3c47e1a 100644 (file)
@@ -354,7 +354,7 @@ static struct of_platform_driver clock_driver = {
 /* Probe for the mostek real time clock chip. */
 static int __init clock_init(void)
 {
-       return of_register_driver(&clock_driver, &of_bus_type);
+       return of_register_driver(&clock_driver, &of_platform_bus_type);
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
index 4e6e41d3291d11d75b624c9d7b8f5f2021bae90a..8d1cfb0d5068544205cdda1e516cb65636ed31bc 100644 (file)
@@ -102,119 +102,3 @@ prom_putchar(char c)
        while(prom_nbputchar(c) == -1) ;
        return;
 }
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
-       unsigned long flags;
-       int st_p;
-       char propb[64];
-       char *p;
-       int propl;
-
-       switch(prom_vers) {
-       case PROM_V0:
-       case PROM_V2:
-       case PROM_SUN4:
-       default:
-               switch(*romvec->pv_stdin) {
-               case PROMDEV_KBD:       return PROMDEV_IKBD;
-               case PROMDEV_TTYA:      return PROMDEV_ITTYA;
-               case PROMDEV_TTYB:      return PROMDEV_ITTYB;
-               default:
-                       return PROMDEV_I_UNK;
-               };
-       case PROM_V3:
-               spin_lock_irqsave(&prom_lock, flags);
-               st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
-               restore_current();
-               spin_unlock_irqrestore(&prom_lock, flags);
-               if(prom_node_has_property(st_p, "keyboard"))
-                       return PROMDEV_IKBD;
-               if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) {
-                       if(strncmp(propb, "keyboard", sizeof("serial")) == 0)
-                               return PROMDEV_IKBD;
-               }
-               if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) {
-               if(strncmp(propb, "serial", sizeof("serial")))
-                       return PROMDEV_I_UNK;
-               }
-               propl = prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
-               if(propl > 2) {
-                       p = propb;
-                       while(*p) p++; p -= 2;
-                       if(p[0] == ':') {
-                               if(p[1] == 'a')
-                                       return PROMDEV_ITTYA;
-                               else if(p[1] == 'b')
-                                       return PROMDEV_ITTYB;
-                       }
-               }
-               return PROMDEV_I_UNK;
-       }
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
-       unsigned long flags;
-       int st_p;
-       char propb[64];
-       char *p;
-       int propl;
-
-       switch(prom_vers) {
-       case PROM_V0:
-       case PROM_SUN4:
-               switch(*romvec->pv_stdin) {
-               case PROMDEV_SCREEN:    return PROMDEV_OSCREEN;
-               case PROMDEV_TTYA:      return PROMDEV_OTTYA;
-               case PROMDEV_TTYB:      return PROMDEV_OTTYB;
-               };
-               break;
-       case PROM_V2:
-       case PROM_V3:
-               spin_lock_irqsave(&prom_lock, flags);
-               st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
-               restore_current();
-               spin_unlock_irqrestore(&prom_lock, flags);
-               propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-               if (propl == sizeof("display") &&
-                       strncmp("display", propb, sizeof("display")) == 0)
-               {
-                       return PROMDEV_OSCREEN;
-               }
-               if(prom_vers == PROM_V3) {
-                       if(propl >= 0 &&
-                           strncmp("serial", propb, sizeof("serial")) != 0)
-                               return PROMDEV_O_UNK;
-                       propl = prom_getproperty(prom_root_node, "stdout-path",
-                                                propb, sizeof(propb));
-                       if(propl == CON_SIZE_JMC &&
-                           strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0)
-                               return PROMDEV_OTTYA;
-                       if(propl > 2) {
-                               p = propb;
-                               while(*p) p++; p-= 2;
-                               if(p[0]==':') {
-                                       if(p[1] == 'a')
-                                               return PROMDEV_OTTYA;
-                                       else if(p[1] == 'b')
-                                               return PROMDEV_OTTYB;
-                               }
-                       }
-               } else {
-                       switch(*romvec->pv_stdin) {
-                       case PROMDEV_TTYA:      return PROMDEV_OTTYA;
-                       case PROMDEV_TTYB:      return PROMDEV_OTTYB;
-                       };
-               }
-               break;
-       default:
-               ;
-       };
-       return PROMDEV_O_UNK;
-}
index 1942c7c05cb18d350005ea19bcf043136a9f5755..37cff5f54704aaf205f66689582acb744ca55110 100644 (file)
@@ -58,7 +58,7 @@ prom_cmdline(void)
        extern void install_linux_ticker(void);
        unsigned long flags;
 
-       if(!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        spin_lock_irqsave(&prom_lock, flags);
        install_obp_ticker();
@@ -69,7 +69,7 @@ prom_cmdline(void)
 #ifdef CONFIG_SUN_AUXIO
        set_auxio(AUXIO_LED, 0);
 #endif
-       if(!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (0);
 }
 
index df6ee71894d1f3228a6ddf59a599df3eeced3e9d..f1cc55677ff24b874db671be74d8ba736c727dbf 100644 (file)
@@ -65,6 +65,9 @@ config AUDIT_ARCH
 config ARCH_NO_VIRT_TO_BUS
        def_bool y
 
+config OF
+       def_bool y
+
 choice
        prompt "Kernel page size"
        default SPARC64_PAGE_SIZE_8KB
index 45ebf91a280ce048a812f3350418db966a480242..10e301970a44daa0db1737d6c46c829aee56684f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.22
-# Tue Jul 17 01:19:52 2007
+# Thu Jul 19 21:30:37 2007
 #
 CONFIG_SPARC=y
 CONFIG_SPARC64=y
@@ -16,6 +16,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_AUDIT_ARCH=y
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
 CONFIG_SPARC64_PAGE_SIZE_8KB=y
 # CONFIG_SPARC64_PAGE_SIZE_64KB is not set
 # CONFIG_SPARC64_PAGE_SIZE_512KB is not set
@@ -148,7 +149,6 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
 CONFIG_RESOURCES_64BIT=y
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_NR_QUICK=1
-CONFIG_VIRT_TO_BUS=y
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
 CONFIG_SUN_AUXIO=y
@@ -317,7 +317,6 @@ CONFIG_CONNECTOR=m
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
@@ -470,10 +469,6 @@ CONFIG_ISCSI_TCP=m
 # CONFIG_SCSI_SUNESP is not set
 # CONFIG_SCSI_SRP is not set
 # CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=m
 CONFIG_MD_LINEAR=m
@@ -610,10 +605,6 @@ CONFIG_SLHC=m
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
 # CONFIG_PHONE is not set
 
@@ -782,6 +773,7 @@ CONFIG_I2C_ALGOBIT=y
 CONFIG_HWMON=y
 # CONFIG_HWMON_VID is not set
 # CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
 # CONFIG_SENSORS_AD7418 is not set
 # CONFIG_SENSORS_ADM1021 is not set
 # CONFIG_SENSORS_ADM1025 is not set
@@ -808,11 +800,13 @@ CONFIG_HWMON=y
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
 # CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_MAX6650 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_PC87427 is not set
 # CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_SMSC47M192 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
@@ -906,6 +900,7 @@ CONFIG_FB_RADEON_I2C=y
 # CONFIG_PROM_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -1195,6 +1190,11 @@ CONFIG_USB_STORAGE=m
 # DMA Devices
 #
 
+#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
 #
 # Misc Linux/SPARC drivers
 #
@@ -1385,6 +1385,7 @@ CONFIG_SCHEDSTATS=y
 # CONFIG_DEBUG_MUTEXES is not set
 # CONFIG_DEBUG_LOCK_ALLOC is not set
 # CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 # CONFIG_DEBUG_KOBJECT is not set
@@ -1461,6 +1462,7 @@ CONFIG_CRC_CCITT=m
 CONFIG_CRC16=m
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=m
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
index 826118ee53d5f97f74e3985c4c078a2e63f77a5b..7b379761e9f85fdf398444acc871ff70032aad0c 100644 (file)
@@ -155,7 +155,7 @@ static struct of_platform_driver auxio_driver = {
 
 static int __init auxio_init(void)
 {
-       return of_register_driver(&auxio_driver, &of_bus_type);
+       return of_register_driver(&auxio_driver, &of_platform_bus_type);
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
index fa1f04d756a286381ffb741602774ea546594481..9f472a79d37e04236add3ad9138bc0de33695bd9 100644 (file)
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/kthread.h>
+#include <linux/reboot.h>
 #include <linux/cpu.h>
 
 #include <asm/ldc.h>
 #include <asm/vio.h>
-#include <asm/power.h>
 #include <asm/mdesc.h>
 #include <asm/head.h>
 #include <asm/irq.h>
@@ -124,10 +124,11 @@ struct ds_data_nack {
        __u64                   result;
 };
 
+struct ds_info;
 struct ds_cap_state {
        __u64                   handle;
 
-       void                    (*data)(struct ldc_channel *lp,
+       void                    (*data)(struct ds_info *dp,
                                        struct ds_cap_state *cp,
                                        void *buf, int len);
 
@@ -139,27 +140,27 @@ struct ds_cap_state {
 #define CAP_STATE_REGISTERED   0x02
 };
 
-static void md_update_data(struct ldc_channel *lp, struct ds_cap_state *cp,
+static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp,
                           void *buf, int len);
-static void domain_shutdown_data(struct ldc_channel *lp,
+static void domain_shutdown_data(struct ds_info *dp,
                                 struct ds_cap_state *cp,
                                 void *buf, int len);
-static void domain_panic_data(struct ldc_channel *lp,
+static void domain_panic_data(struct ds_info *dp,
                              struct ds_cap_state *cp,
                              void *buf, int len);
 #ifdef CONFIG_HOTPLUG_CPU
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
                        struct ds_cap_state *cp,
                        void *buf, int len);
 #endif
-static void ds_pri_data(struct ldc_channel *lp,
+static void ds_pri_data(struct ds_info *dp,
                        struct ds_cap_state *cp,
                        void *buf, int len);
-static void ds_var_data(struct ldc_channel *lp,
+static void ds_var_data(struct ds_info *dp,
                        struct ds_cap_state *cp,
                        void *buf, int len);
 
-struct ds_cap_state ds_states[] = {
+struct ds_cap_state ds_states_template[] = {
        {
                .service_id     = "md-update",
                .data           = md_update_data,
@@ -200,30 +201,38 @@ struct ds_info {
 #define DS_HS_START            0x01
 #define DS_HS_DONE             0x02
 
+       u64                     id;
+
        void                    *rcv_buf;
        int                     rcv_buf_len;
+
+       struct ds_cap_state     *ds_states;
+       int                     num_ds_states;
+
+       struct ds_info          *next;
 };
 
-static struct ds_info *ds_info;
+static struct ds_info *ds_info_list;
 
-static struct ds_cap_state *find_cap(u64 handle)
+static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle)
 {
        unsigned int index = handle >> 32;
 
-       if (index >= ARRAY_SIZE(ds_states))
+       if (index >= dp->num_ds_states)
                return NULL;
-       return &ds_states[index];
+       return &dp->ds_states[index];
 }
 
-static struct ds_cap_state *find_cap_by_string(const char *name)
+static struct ds_cap_state *find_cap_by_string(struct ds_info *dp,
+                                              const char *name)
 {
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
-               if (strcmp(ds_states[i].service_id, name))
+       for (i = 0; i < dp->num_ds_states; i++) {
+               if (strcmp(dp->ds_states[i].service_id, name))
                        continue;
 
-               return &ds_states[i];
+               return &dp->ds_states[i];
        }
        return NULL;
 }
@@ -264,10 +273,11 @@ struct ds_md_update_res {
        __u32                           result;
 };
 
-static void md_update_data(struct ldc_channel *lp,
-                          struct ds_cap_state *dp,
+static void md_update_data(struct ds_info *dp,
+                          struct ds_cap_state *cp,
                           void *buf, int len)
 {
+       struct ldc_channel *lp = dp->lp;
        struct ds_data *dpkt = buf;
        struct ds_md_update_req *rp;
        struct {
@@ -277,14 +287,14 @@ static void md_update_data(struct ldc_channel *lp,
 
        rp = (struct ds_md_update_req *) (dpkt + 1);
 
-       printk(KERN_INFO PFX "Machine description update.\n");
+       printk(KERN_INFO "ds-%lu: Machine description update.\n", dp->id);
 
        mdesc_update();
 
        memset(&pkt, 0, sizeof(pkt));
        pkt.data.tag.type = DS_DATA;
        pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-       pkt.data.handle = dp->handle;
+       pkt.data.handle = cp->handle;
        pkt.res.req_num = rp->req_num;
        pkt.res.result = DS_OK;
 
@@ -302,10 +312,11 @@ struct ds_shutdown_res {
        char                            reason[1];
 };
 
-static void domain_shutdown_data(struct ldc_channel *lp,
-                                struct ds_cap_state *dp,
+static void domain_shutdown_data(struct ds_info *dp,
+                                struct ds_cap_state *cp,
                                 void *buf, int len)
 {
+       struct ldc_channel *lp = dp->lp;
        struct ds_data *dpkt = buf;
        struct ds_shutdown_req *rp;
        struct {
@@ -315,20 +326,20 @@ static void domain_shutdown_data(struct ldc_channel *lp,
 
        rp = (struct ds_shutdown_req *) (dpkt + 1);
 
-       printk(KERN_ALERT PFX "Shutdown request from "
-              "LDOM manager received.\n");
+       printk(KERN_ALERT "ds-%lu: Shutdown request from "
+              "LDOM manager received.\n", dp->id);
 
        memset(&pkt, 0, sizeof(pkt));
        pkt.data.tag.type = DS_DATA;
        pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-       pkt.data.handle = dp->handle;
+       pkt.data.handle = cp->handle;
        pkt.res.req_num = rp->req_num;
        pkt.res.result = DS_OK;
        pkt.res.reason[0] = 0;
 
        ds_send(lp, &pkt, sizeof(pkt));
 
-       wake_up_powerd();
+       orderly_poweroff(true);
 }
 
 struct ds_panic_req {
@@ -341,10 +352,11 @@ struct ds_panic_res {
        char                            reason[1];
 };
 
-static void domain_panic_data(struct ldc_channel *lp,
-                             struct ds_cap_state *dp,
+static void domain_panic_data(struct ds_info *dp,
+                             struct ds_cap_state *cp,
                              void *buf, int len)
 {
+       struct ldc_channel *lp = dp->lp;
        struct ds_data *dpkt = buf;
        struct ds_panic_req *rp;
        struct {
@@ -354,13 +366,13 @@ static void domain_panic_data(struct ldc_channel *lp,
 
        rp = (struct ds_panic_req *) (dpkt + 1);
 
-       printk(KERN_ALERT PFX "Panic request from "
-              "LDOM manager received.\n");
+       printk(KERN_ALERT "ds-%lu: Panic request from "
+              "LDOM manager received.\n", dp->id);
 
        memset(&pkt, 0, sizeof(pkt));
        pkt.data.tag.type = DS_DATA;
        pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
-       pkt.data.handle = dp->handle;
+       pkt.data.handle = cp->handle;
        pkt.res.req_num = rp->req_num;
        pkt.res.result = DS_OK;
        pkt.res.reason[0] = 0;
@@ -403,10 +415,11 @@ struct dr_cpu_resp_entry {
        __u32                           str_off;
 };
 
-static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void __dr_cpu_send_error(struct ds_info *dp,
+                               struct ds_cap_state *cp,
+                               struct ds_data *data)
 {
        struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
-       struct ds_info *dp = ds_info;
        struct {
                struct ds_data          data;
                struct dr_cpu_tag       tag;
@@ -428,12 +441,14 @@ static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
        __ds_send(dp->lp, &pkt, msg_len);
 }
 
-static void dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void dr_cpu_send_error(struct ds_info *dp,
+                             struct ds_cap_state *cp,
+                             struct ds_data *data)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&ds_lock, flags);
-       __dr_cpu_send_error(cp, data);
+       __dr_cpu_send_error(dp, cp, data);
        spin_unlock_irqrestore(&ds_lock, flags);
 }
 
@@ -511,7 +526,9 @@ static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus,
        }
 }
 
-static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_configure(struct ds_info *dp,
+                           struct ds_cap_state *cp,
+                           u64 req_num,
                            cpumask_t *mask)
 {
        struct ds_data *resp;
@@ -533,7 +550,8 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
        for_each_cpu_mask(cpu, *mask) {
                int err;
 
-               printk(KERN_INFO PFX "Starting cpu %d...\n", cpu);
+               printk(KERN_INFO "ds-%lu: Starting cpu %d...\n",
+                      dp->id, cpu);
                err = cpu_up(cpu);
                if (err) {
                        __u32 res = DR_CPU_RES_FAILURE;
@@ -548,14 +566,14 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
                                res = DR_CPU_RES_CPU_NOT_RESPONDING;
                        }
 
-                       printk(KERN_INFO PFX "CPU startup failed err=%d\n",
-                              err);
+                       printk(KERN_INFO "ds-%lu: CPU startup failed err=%d\n",
+                              dp->id, err);
                        dr_cpu_mark(resp, cpu, ncpus, res, stat);
                }
        }
 
        spin_lock_irqsave(&ds_lock, flags);
-       __ds_send(ds_info->lp, resp, resp_len);
+       __ds_send(dp->lp, resp, resp_len);
        spin_unlock_irqrestore(&ds_lock, flags);
 
        kfree(resp);
@@ -566,7 +584,9 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
        return 0;
 }
 
-static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_unconfigure(struct ds_info *dp,
+                             struct ds_cap_state *cp,
+                             u64 req_num,
                              cpumask_t *mask)
 {
        struct ds_data *resp;
@@ -586,8 +606,8 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
        for_each_cpu_mask(cpu, *mask) {
                int err;
 
-               printk(KERN_INFO PFX "CPU[%d]: Shutting down cpu %d...\n",
-                      smp_processor_id(), cpu);
+               printk(KERN_INFO "ds-%lu: Shutting down cpu %d...\n",
+                      dp->id, cpu);
                err = cpu_down(cpu);
                if (err)
                        dr_cpu_mark(resp, cpu, ncpus,
@@ -596,7 +616,7 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
        }
 
        spin_lock_irqsave(&ds_lock, flags);
-       __ds_send(ds_info->lp, resp, resp_len);
+       __ds_send(dp->lp, resp, resp_len);
        spin_unlock_irqrestore(&ds_lock, flags);
 
        kfree(resp);
@@ -604,7 +624,7 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
        return 0;
 }
 
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
                        struct ds_cap_state *cp,
                        void *buf, int len)
 {
@@ -623,7 +643,7 @@ static void dr_cpu_data(struct ldc_channel *lp,
                break;
 
        default:
-               dr_cpu_send_error(cp, data);
+               dr_cpu_send_error(dp, cp, data);
                return;
        }
 
@@ -639,12 +659,12 @@ static void dr_cpu_data(struct ldc_channel *lp,
        }
 
        if (tag->type == DR_CPU_CONFIGURE)
-               err = dr_cpu_configure(cp, req_num, &mask);
+               err = dr_cpu_configure(dp, cp, req_num, &mask);
        else
-               err = dr_cpu_unconfigure(cp, req_num, &mask);
+               err = dr_cpu_unconfigure(dp, cp, req_num, &mask);
 
        if (err)
-               dr_cpu_send_error(cp, data);
+               dr_cpu_send_error(dp, cp, data);
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
@@ -656,8 +676,8 @@ struct ds_pri_msg {
 #define DS_PRI_UPDATE                  0x02
 };
 
-static void ds_pri_data(struct ldc_channel *lp,
-                       struct ds_cap_state *dp,
+static void ds_pri_data(struct ds_info *dp,
+                       struct ds_cap_state *cp,
                        void *buf, int len)
 {
        struct ds_data *dpkt = buf;
@@ -665,8 +685,8 @@ static void ds_pri_data(struct ldc_channel *lp,
 
        rp = (struct ds_pri_msg *) (dpkt + 1);
 
-       printk(KERN_INFO PFX "PRI REQ [%lx:%lx], len=%d\n",
-              rp->req_num, rp->type, len);
+       printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n",
+              dp->id, rp->req_num, rp->type, len);
 }
 
 struct ds_var_hdr {
@@ -701,8 +721,8 @@ static DEFINE_MUTEX(ds_var_mutex);
 static int ds_var_doorbell;
 static int ds_var_response;
 
-static void ds_var_data(struct ldc_channel *lp,
-                       struct ds_cap_state *dp,
+static void ds_var_data(struct ds_info *dp,
+                       struct ds_cap_state *cp,
                        void *buf, int len)
 {
        struct ds_data *dpkt = buf;
@@ -721,14 +741,35 @@ static void ds_var_data(struct ldc_channel *lp,
 
 void ldom_set_var(const char *var, const char *value)
 {
-       struct ds_info *dp = ds_info;
        struct ds_cap_state *cp;
+       struct ds_info *dp;
+       unsigned long flags;
 
-       cp = find_cap_by_string("var-config");
-       if (cp->state != CAP_STATE_REGISTERED)
-               cp = find_cap_by_string("var-config-backup");
+       spin_lock_irqsave(&ds_lock, flags);
+       cp = NULL;
+       for (dp = ds_info_list; dp; dp = dp->next) {
+               struct ds_cap_state *tmp;
 
-       if (cp->state == CAP_STATE_REGISTERED) {
+               tmp = find_cap_by_string(dp, "var-config");
+               if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+                       cp = tmp;
+                       break;
+               }
+       }
+       if (!cp) {
+               for (dp = ds_info_list; dp; dp = dp->next) {
+                       struct ds_cap_state *tmp;
+
+                       tmp = find_cap_by_string(dp, "var-config-backup");
+                       if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+                               cp = tmp;
+                               break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&ds_lock, flags);
+
+       if (cp) {
                union {
                        struct {
                                struct ds_data          data;
@@ -736,7 +777,6 @@ void ldom_set_var(const char *var, const char *value)
                        } header;
                        char                    all[512];
                } pkt;
-               unsigned long flags;
                char  *base, *p;
                int msg_len, loops;
 
@@ -777,9 +817,9 @@ void ldom_set_var(const char *var, const char *value)
 
                if (ds_var_doorbell == 0 ||
                    ds_var_response != DS_VAR_SUCCESS)
-                       printk(KERN_ERR PFX "var-config [%s:%s] "
+                       printk(KERN_ERR "ds-%lu: var-config [%s:%s] "
                               "failed, response(%d).\n",
-                              var, value,
+                              dp->id, var, value,
                               ds_var_response);
        } else {
                printk(KERN_ERR PFX "var-config not registered so "
@@ -811,8 +851,8 @@ void ldom_power_off(void)
 
 static void ds_conn_reset(struct ds_info *dp)
 {
-       printk(KERN_ERR PFX "ds_conn_reset() from %p\n",
-              __builtin_return_address(0));
+       printk(KERN_ERR "ds-%lu: ds_conn_reset() from %p\n",
+              dp->id, __builtin_return_address(0));
 }
 
 static int register_services(struct ds_info *dp)
@@ -820,12 +860,12 @@ static int register_services(struct ds_info *dp)
        struct ldc_channel *lp = dp->lp;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
+       for (i = 0; i < dp->num_ds_states; i++) {
                struct {
                        struct ds_reg_req req;
                        u8 id_buf[256];
                } pbuf;
-               struct ds_cap_state *cp = &ds_states[i];
+               struct ds_cap_state *cp = &dp->ds_states[i];
                int err, msg_len;
                u64 new_count;
 
@@ -870,28 +910,26 @@ static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt)
 
        if (pkt->type == DS_REG_ACK) {
                struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
-               struct ds_cap_state *cp = find_cap(ap->handle);
+               struct ds_cap_state *cp = find_cap(dp, ap->handle);
 
                if (!cp) {
-                       printk(KERN_ERR PFX "REG ACK for unknown handle %lx\n",
-                              ap->handle);
+                       printk(KERN_ERR "ds-%lu: REG ACK for unknown "
+                              "handle %lx\n", dp->id, ap->handle);
                        return 0;
                }
-               printk(KERN_INFO PFX "Registered %s service.\n",
-                      cp->service_id);
+               printk(KERN_INFO "ds-%lu: Registered %s service.\n",
+                      dp->id, cp->service_id);
                cp->state = CAP_STATE_REGISTERED;
        } else if (pkt->type == DS_REG_NACK) {
                struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
-               struct ds_cap_state *cp = find_cap(np->handle);
+               struct ds_cap_state *cp = find_cap(dp, np->handle);
 
                if (!cp) {
-                       printk(KERN_ERR PFX "REG NACK for "
+                       printk(KERN_ERR "ds-%lu: REG NACK for "
                               "unknown handle %lx\n",
-                              np->handle);
+                              dp->id, np->handle);
                        return 0;
                }
-               printk(KERN_INFO PFX "Could not register %s service\n",
-                      cp->service_id);
                cp->state = CAP_STATE_UNKNOWN;
        }
 
@@ -922,6 +960,7 @@ static DECLARE_WAIT_QUEUE_HEAD(ds_wait);
 
 struct ds_queue_entry {
        struct list_head                list;
+       struct ds_info                  *dp;
        int                             req_len;
        int                             __pad;
        u64                             req[0];
@@ -930,7 +969,6 @@ struct ds_queue_entry {
 static void process_ds_work(void)
 {
        struct ds_queue_entry *qp, *tmp;
-       static struct ds_info *dp;
        unsigned long flags;
        LIST_HEAD(todo);
 
@@ -939,22 +977,22 @@ static void process_ds_work(void)
        INIT_LIST_HEAD(&ds_work_list);
        spin_unlock_irqrestore(&ds_lock, flags);
 
-       dp = ds_info;
-
        list_for_each_entry_safe(qp, tmp, &todo, list) {
                struct ds_data *dpkt = (struct ds_data *) qp->req;
-               struct ds_cap_state *cp = find_cap(dpkt->handle);
+               struct ds_info *dp = qp->dp;
+               struct ds_cap_state *cp = find_cap(dp, dpkt->handle);
                int req_len = qp->req_len;
 
                if (!cp) {
-                       printk(KERN_ERR PFX "Data for unknown handle %lu\n",
-                              dpkt->handle);
+                       printk(KERN_ERR "ds-%lu: Data for unknown "
+                              "handle %lu\n",
+                              dp->id, dpkt->handle);
 
                        spin_lock_irqsave(&ds_lock, flags);
                        __send_ds_nack(dp, dpkt->handle);
                        spin_unlock_irqrestore(&ds_lock, flags);
                } else {
-                       cp->data(dp->lp, cp, dpkt, req_len);
+                       cp->data(dp, cp, dpkt, req_len);
                }
 
                list_del(&qp->list);
@@ -990,6 +1028,7 @@ static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len)
        if (!qp) {
                __send_ds_nack(dp, dpkt->handle);
        } else {
+               qp->dp = dp;
                memcpy(&qp->req, pkt, len);
                list_add_tail(&qp->list, &ds_work_list);
                wake_up(&ds_wait);
@@ -1019,8 +1058,8 @@ static void ds_reset(struct ds_info *dp)
 
        dp->hs_state = 0;
 
-       for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
-               struct ds_cap_state *cp = &ds_states[i];
+       for (i = 0; i < dp->num_ds_states; i++) {
+               struct ds_cap_state *cp = &dp->ds_states[i];
 
                cp->state = CAP_STATE_UNKNOWN;
        }
@@ -1048,7 +1087,8 @@ static void ds_event(void *arg, int event)
        }
 
        if (event != LDC_EVENT_DATA_READY) {
-               printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+               printk(KERN_WARNING "ds-%lu: Unexpected LDC event %d\n",
+                      dp->id, event);
                spin_unlock_irqrestore(&ds_lock, flags);
                return;
        }
@@ -1099,9 +1139,11 @@ static int __devinit ds_probe(struct vio_dev *vdev,
                .mtu            = 4096,
                .mode           = LDC_MODE_STREAM,
        };
+       struct mdesc_handle *hp;
        struct ldc_channel *lp;
        struct ds_info *dp;
-       int err;
+       const u64 *val;
+       int err, i;
 
        if (ds_version_printed++ == 0)
                printk(KERN_INFO "%s", version);
@@ -1111,19 +1153,37 @@ static int __devinit ds_probe(struct vio_dev *vdev,
        if (!dp)
                goto out_err;
 
+       hp = mdesc_grab();
+       val = mdesc_get_property(hp, vdev->mp, "id", NULL);
+       if (val)
+               dp->id = *val;
+       mdesc_release(hp);
+
        dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
        if (!dp->rcv_buf)
                goto out_free_dp;
 
        dp->rcv_buf_len = 4096;
 
+       dp->ds_states = kzalloc(sizeof(ds_states_template),
+                               GFP_KERNEL);
+       if (!dp->ds_states)
+               goto out_free_rcv_buf;
+
+       memcpy(dp->ds_states, ds_states_template,
+              sizeof(ds_states_template));
+       dp->num_ds_states = ARRAY_SIZE(ds_states_template);
+
+       for (i = 0; i < dp->num_ds_states; i++)
+               dp->ds_states[i].handle = ((u64)i << 32);
+
        ds_cfg.tx_irq = vdev->tx_irq;
        ds_cfg.rx_irq = vdev->rx_irq;
 
        lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
        if (IS_ERR(lp)) {
                err = PTR_ERR(lp);
-               goto out_free_rcv_buf;
+               goto out_free_ds_states;
        }
        dp->lp = lp;
 
@@ -1131,15 +1191,19 @@ static int __devinit ds_probe(struct vio_dev *vdev,
        if (err)
                goto out_free_ldc;
 
-       ds_info = dp;
-
-       start_powerd();
+       spin_lock_irq(&ds_lock);
+       dp->next = ds_info_list;
+       ds_info_list = dp;
+       spin_unlock_irq(&ds_lock);
 
        return err;
 
 out_free_ldc:
        ldc_free(dp->lp);
 
+out_free_ds_states:
+       kfree(dp->ds_states);
+
 out_free_rcv_buf:
        kfree(dp->rcv_buf);
 
@@ -1174,11 +1238,6 @@ static struct vio_driver ds_driver = {
 
 static int __init ds_init(void)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ds_states); i++)
-               ds_states[i].handle = ((u64)i << 32);
-
        kthread_run(ds_thread, NULL, "kldomd");
 
        return vio_register_driver(&ds_driver);
index ad55a9bb50ddedfe6febf63c54e7836b43c18b16..6d2956179cde796006f767d6529cc80ab0694e73 100644 (file)
@@ -362,6 +362,7 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
 static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
 {
        struct linux_ebus_child *child;
+       struct dev_archdata *sd;
        struct of_device *op;
        int i, len;
 
@@ -387,6 +388,10 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de
                        dev->irqs[i] = op->irqs[i];
        }
 
+       sd = &dev->ofdev.dev.archdata;
+       sd->prom_node = dp;
+       sd->op = &dev->ofdev;
+
        dev->ofdev.node = dp;
        dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
        dev->ofdev.dev.bus = &ebus_bus_type;
index 77259526cb152daff39c213176ac02db1cae3346..35feacb6b8ec44d317a195b46c0e3e7dc438c14f 100644 (file)
@@ -458,7 +458,6 @@ tlb_fixup_done:
        or      %g6, %lo(init_thread_union), %g6
        ldx     [%g6 + TI_TASK], %g4
        mov     %sp, %l6
-       mov     %o4, %l7
 
        wr      %g0, ASI_P, %asi
        mov     1, %g1
index 8cb3358674f5257fcaff2ee83448592b1732e3dd..db31bf6b42dbfa569871e9c9d49aec3d0e3f6a9d 100644 (file)
@@ -87,7 +87,11 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY
  */
 #define irq_work(__cpu)        &(trap_block[(__cpu)].irq_worklist)
 
-static unsigned int virt_to_real_irq_table[NR_IRQS];
+static struct {
+       unsigned int irq;
+       unsigned int dev_handle;
+       unsigned int dev_ino;
+} virt_to_real_irq_table[NR_IRQS];
 
 static unsigned char virt_irq_alloc(unsigned int real_irq)
 {
@@ -96,7 +100,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
        BUILD_BUG_ON(NR_IRQS >= 256);
 
        for (ent = 1; ent < NR_IRQS; ent++) {
-               if (!virt_to_real_irq_table[ent])
+               if (!virt_to_real_irq_table[ent].irq)
                        break;
        }
        if (ent >= NR_IRQS) {
@@ -104,7 +108,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
                return 0;
        }
 
-       virt_to_real_irq_table[ent] = real_irq;
+       virt_to_real_irq_table[ent].irq = real_irq;
 
        return ent;
 }
@@ -117,8 +121,8 @@ static void virt_irq_free(unsigned int virt_irq)
        if (virt_irq >= NR_IRQS)
                return;
 
-       real_irq = virt_to_real_irq_table[virt_irq];
-       virt_to_real_irq_table[virt_irq] = 0;
+       real_irq = virt_to_real_irq_table[virt_irq].irq;
+       virt_to_real_irq_table[virt_irq].irq = 0;
 
        __bucket(real_irq)->virt_irq = 0;
 }
@@ -126,7 +130,7 @@ static void virt_irq_free(unsigned int virt_irq)
 
 static unsigned int virt_to_real_irq(unsigned char virt_irq)
 {
-       return virt_to_real_irq_table[virt_irq];
+       return virt_to_real_irq_table[virt_irq].irq;
 }
 
 /*
@@ -336,15 +340,15 @@ static void sun4v_irq_enable(unsigned int virt_irq)
 
                err = sun4v_intr_settarget(ino, cpuid);
                if (err != HV_EOK)
-                       printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
-                              ino, cpuid, err);
+                       printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+                              "err(%d)\n", ino, cpuid, err);
                err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
                if (err != HV_EOK)
-                       printk("sun4v_intr_setstate(%x): "
+                       printk(KERN_ERR "sun4v_intr_setstate(%x): "
                               "err(%d)\n", ino, err);
                err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
                if (err != HV_EOK)
-                       printk("sun4v_intr_setenabled(%x): err(%d)\n",
+                       printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
                               ino, err);
        }
 }
@@ -362,8 +366,8 @@ static void sun4v_set_affinity(unsigned int virt_irq, cpumask_t mask)
 
                err = sun4v_intr_settarget(ino, cpuid);
                if (err != HV_EOK)
-                       printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
-                              ino, cpuid, err);
+                       printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+                              "err(%d)\n", ino, cpuid, err);
        }
 }
 
@@ -377,7 +381,7 @@ static void sun4v_irq_disable(unsigned int virt_irq)
 
                err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
                if (err != HV_EOK)
-                       printk("sun4v_intr_setenabled(%x): "
+                       printk(KERN_ERR "sun4v_intr_setenabled(%x): "
                               "err(%d)\n", ino, err);
        }
 }
@@ -410,7 +414,7 @@ static void sun4v_irq_end(unsigned int virt_irq)
 
                err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
                if (err != HV_EOK)
-                       printk("sun4v_intr_setstate(%x): "
+                       printk(KERN_ERR "sun4v_intr_setstate(%x): "
                               "err(%d)\n", ino, err);
        }
 }
@@ -418,7 +422,6 @@ static void sun4v_irq_end(unsigned int virt_irq)
 static void sun4v_virq_enable(unsigned int virt_irq)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
 
        if (likely(bucket)) {
                unsigned long cpuid, dev_handle, dev_ino;
@@ -426,24 +429,24 @@ static void sun4v_virq_enable(unsigned int virt_irq)
 
                cpuid = irq_choose_cpu(virt_irq);
 
-               dev_handle = ino & IMAP_IGN;
-               dev_ino = ino & IMAP_INO;
+               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
                err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+                       printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
                               "err(%d)\n",
                               dev_handle, dev_ino, cpuid, err);
                err = sun4v_vintr_set_state(dev_handle, dev_ino,
                                            HV_INTR_STATE_IDLE);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
                                "HV_INTR_STATE_IDLE): err(%d)\n",
                               dev_handle, dev_ino, err);
                err = sun4v_vintr_set_valid(dev_handle, dev_ino,
                                            HV_INTR_ENABLED);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
                               "HV_INTR_ENABLED): err(%d)\n",
                               dev_handle, dev_ino, err);
        }
@@ -452,7 +455,6 @@ static void sun4v_virq_enable(unsigned int virt_irq)
 static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
 
        if (likely(bucket)) {
                unsigned long cpuid, dev_handle, dev_ino;
@@ -460,12 +462,12 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
 
                cpuid = irq_choose_cpu(virt_irq);
 
-               dev_handle = ino & IMAP_IGN;
-               dev_ino = ino & IMAP_INO;
+               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
                err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+                       printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
                               "err(%d)\n",
                               dev_handle, dev_ino, cpuid, err);
        }
@@ -474,19 +476,18 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
 static void sun4v_virq_disable(unsigned int virt_irq)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
 
        if (likely(bucket)) {
                unsigned long dev_handle, dev_ino;
                int err;
 
-               dev_handle = ino & IMAP_IGN;
-               dev_ino = ino & IMAP_INO;
+               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
                err = sun4v_vintr_set_valid(dev_handle, dev_ino,
                                            HV_INTR_DISABLED);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
                               "HV_INTR_DISABLED): err(%d)\n",
                               dev_handle, dev_ino, err);
        }
@@ -495,7 +496,6 @@ static void sun4v_virq_disable(unsigned int virt_irq)
 static void sun4v_virq_end(unsigned int virt_irq)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
-       unsigned int ino = bucket - &ivector_table[0];
        struct irq_desc *desc = irq_desc + virt_irq;
 
        if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
@@ -505,13 +505,13 @@ static void sun4v_virq_end(unsigned int virt_irq)
                unsigned long dev_handle, dev_ino;
                int err;
 
-               dev_handle = ino & IMAP_IGN;
-               dev_ino = ino & IMAP_INO;
+               dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+               dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
 
                err = sun4v_vintr_set_state(dev_handle, dev_ino,
                                            HV_INTR_STATE_IDLE);
                if (err != HV_EOK)
-                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                       printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
                                "HV_INTR_STATE_IDLE): err(%d)\n",
                               dev_handle, dev_ino, err);
        }
@@ -700,11 +700,12 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
 unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
 {
        unsigned long sysino, hv_err;
+       unsigned int virq;
 
-       BUG_ON(devhandle & ~IMAP_IGN);
-       BUG_ON(devino & ~IMAP_INO);
+       BUG_ON(devhandle & devino);
 
        sysino = devhandle | devino;
+       BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
 
        hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
        if (hv_err) {
@@ -713,7 +714,12 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
                prom_halt();
        }
 
-       return sun4v_build_common(sysino, &sun4v_virq);
+       virq = sun4v_build_common(sysino, &sun4v_virq);
+
+       virt_to_real_irq_table[virq].dev_handle = devhandle;
+       virt_to_real_irq_table[virq].dev_ino = devino;
+
+       return virq;
 }
 
 #ifdef CONFIG_PCI_MSI
index 6a6882e57ff22ff3c5f1aee779b761d20b493ab6..1a1043fcf97dda26866182a97acd2739e94df3ee 100644 (file)
@@ -79,6 +79,7 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
 
        while (dp) {
                struct sparc_isa_device *isa_dev;
+               struct dev_archdata *sd;
 
                isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
                if (!isa_dev) {
@@ -86,6 +87,10 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
                        return;
                }
 
+               sd = &isa_dev->ofdev.dev.archdata;
+               sd->prom_node = dp;
+               sd->op = &isa_dev->ofdev;
+
                isa_dev->ofdev.node = dp;
                isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
                isa_dev->ofdev.dev.bus = &isa_bus_type;
index 302ba5e5a0bb85d1b8c5f66b938c0177c9e504d2..cce4d0ddf5d5d1c0677544805a042a8acca898ad 100644 (file)
@@ -83,7 +83,7 @@ static void mdesc_handle_init(struct mdesc_handle *hp,
        hp->handle_size = handle_size;
 }
 
-static struct mdesc_handle *mdesc_bootmem_alloc(unsigned int mdesc_size)
+static struct mdesc_handle * __init mdesc_bootmem_alloc(unsigned int mdesc_size)
 {
        struct mdesc_handle *hp;
        unsigned int handle_size, alloc_size;
@@ -123,7 +123,7 @@ static void mdesc_bootmem_free(struct mdesc_handle *hp)
        }
 }
 
-static struct mdesc_mem_ops bootmem_mdesc_memops = {
+static struct mdesc_mem_ops bootmem_mdesc_ops = {
        .alloc = mdesc_bootmem_alloc,
        .free  = mdesc_bootmem_free,
 };
@@ -231,6 +231,25 @@ void mdesc_register_notifier(struct mdesc_notifier_client *client)
        mutex_unlock(&mdesc_mutex);
 }
 
+static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
+{
+       const u64 *id;
+       u64 a;
+
+       id = NULL;
+       mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+               u64 target;
+
+               target = mdesc_arc_target(hp, a);
+               id = mdesc_get_property(hp, target,
+                                       "cfg-handle", NULL);
+               if (id)
+                       break;
+       }
+
+       return id;
+}
+
 /* Run 'func' on nodes which are in A but not in B.  */
 static void invoke_on_missing(const char *name,
                              struct mdesc_handle *a,
@@ -240,13 +259,42 @@ static void invoke_on_missing(const char *name,
        u64 node;
 
        mdesc_for_each_node_by_name(a, node, name) {
-               const u64 *id = mdesc_get_property(a, node, "id", NULL);
-               int found = 0;
+               int found = 0, is_vdc_port = 0;
+               const char *name_prop;
+               const u64 *id;
                u64 fnode;
 
+               name_prop = mdesc_get_property(a, node, "name", NULL);
+               if (name_prop && !strcmp(name_prop, "vdc-port")) {
+                       is_vdc_port = 1;
+                       id = parent_cfg_handle(a, node);
+               } else
+                       id = mdesc_get_property(a, node, "id", NULL);
+
+               if (!id) {
+                       printk(KERN_ERR "MD: Cannot find ID for %s node.\n",
+                              (name_prop ? name_prop : name));
+                       continue;
+               }
+
                mdesc_for_each_node_by_name(b, fnode, name) {
-                       const u64 *fid = mdesc_get_property(b, fnode,
-                                                           "id", NULL);
+                       const u64 *fid;
+
+                       if (is_vdc_port) {
+                               name_prop = mdesc_get_property(b, fnode,
+                                                              "name", NULL);
+                               if (!name_prop ||
+                                   strcmp(name_prop, "vdc-port"))
+                                       continue;
+                               fid = parent_cfg_handle(b, fnode);
+                               if (!fid) {
+                                       printk(KERN_ERR "MD: Cannot find ID "
+                                              "for vdc-port node.\n");
+                                       continue;
+                               }
+                       } else
+                               fid = mdesc_get_property(b, fnode,
+                                                        "id", NULL);
 
                        if (*id == *fid) {
                                found = 1;
@@ -812,7 +860,7 @@ void __init sun4v_mdesc_init(void)
 
        printk("MDESC: Size is %lu bytes.\n", len);
 
-       hp = mdesc_alloc(len, &bootmem_mdesc_memops);
+       hp = mdesc_alloc(len, &bootmem_mdesc_ops);
        if (hp == NULL) {
                prom_printf("MDESC: alloc of %lu bytes failed.\n", len);
                prom_halt();
index 6676b93219dcd51cee5454cb2577854074c4ec80..4cc77485f53602ba54714e88b42d61e1bb062047 100644 (file)
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/of.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
-
-#include <asm/errno.h>
-#include <asm/of_device.h>
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
-                                       const struct of_device *dev)
-{
-       if (!dev->node)
-               return NULL;
-       while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
-               int match = 1;
-               if (matches->name[0])
-                       match &= dev->node->name
-                               && !strcmp(matches->name, dev->node->name);
-               if (matches->type[0])
-                       match &= dev->node->type
-                               && !strcmp(matches->type, dev->node->type);
-               if (matches->compatible[0])
-                       match &= of_device_is_compatible(dev->node,
-                                                        matches->compatible);
-               if (match)
-                       return matches;
-               matches++;
-       }
-       return NULL;
-}
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * of_drv = to_of_platform_driver(drv);
-       const struct of_device_id * matches = of_drv->match_table;
-
-       if (!matches)
-               return 0;
-
-       return of_match_device(matches, of_dev) != NULL;
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
-       struct device *tmp;
-
-       if (!dev)
-               return NULL;
-       tmp = get_device(&dev->dev);
-       if (tmp)
-               return to_of_device(tmp);
-       else
-               return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
-       if (dev)
-               put_device(&dev->dev);
-}
-
-
-static int of_device_probe(struct device *dev)
-{
-       int error = -ENODEV;
-       struct of_platform_driver *drv;
-       struct of_device *of_dev;
-       const struct of_device_id *match;
-
-       drv = to_of_platform_driver(dev->driver);
-       of_dev = to_of_device(dev);
-
-       if (!drv->probe)
-               return error;
-
-       of_dev_get(of_dev);
-
-       match = of_match_device(drv->match_table, of_dev);
-       if (match)
-               error = drv->probe(of_dev, match);
-       if (error)
-               of_dev_put(of_dev);
-
-       return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
-       if (dev->driver && drv->remove)
-               drv->remove(of_dev);
-       return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->suspend)
-               error = drv->suspend(of_dev, state);
-       return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
-       struct of_device * of_dev = to_of_device(dev);
-       struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-       int error = 0;
-
-       if (dev->driver && drv->resume)
-               error = drv->resume(of_dev);
-       return error;
-}
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
 {
@@ -163,7 +44,7 @@ static int node_match(struct device *dev, void *data)
 
 struct of_device *of_find_device_by_node(struct device_node *dp)
 {
-       struct device *dev = bus_find_device(&of_bus_type, NULL,
+       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
                                             dp, node_match);
 
        if (dev)
@@ -174,48 +55,20 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
 EXPORT_SYMBOL(of_find_device_by_node);
 
 #ifdef CONFIG_PCI
-struct bus_type isa_bus_type = {
-       .name   = "isa",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type isa_bus_type;
 EXPORT_SYMBOL(isa_bus_type);
 
-struct bus_type ebus_bus_type = {
-       .name   = "ebus",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type ebus_bus_type;
 EXPORT_SYMBOL(ebus_bus_type);
 #endif
 
 #ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type = {
-       .name   = "sbus",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
+struct bus_type sbus_bus_type;
 EXPORT_SYMBOL(sbus_bus_type);
 #endif
 
-struct bus_type of_bus_type = {
-       .name   = "of",
-       .match  = of_platform_bus_match,
-       .probe  = of_device_probe,
-       .remove = of_device_remove,
-       .suspend        = of_device_suspend,
-       .resume = of_device_resume,
-};
-EXPORT_SYMBOL(of_bus_type);
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
 
 static inline u64 of_read_addr(const u32 *cell, int size)
 {
@@ -899,11 +752,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
 {
        struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
        const unsigned int *irq;
+       struct dev_archdata *sd;
        int len, i;
 
        if (!op)
                return NULL;
 
+       sd = &op->dev.archdata;
+       sd->prom_node = dp;
+       sd->op = op;
+
        op->node = dp;
 
        op->clock_freq = of_getintprop_default(dp, "clock-frequency",
@@ -933,7 +791,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
                op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
 
        op->dev.parent = parent;
-       op->dev.bus = &of_bus_type;
+       op->dev.bus = &of_platform_bus_type;
        if (!parent)
                strcpy(op->dev.bus_id, "root");
        else
@@ -977,16 +835,16 @@ static int __init of_bus_driver_init(void)
 {
        int err;
 
-       err = bus_register(&of_bus_type);
+       err = of_bus_type_init(&of_platform_bus_type, "of");
 #ifdef CONFIG_PCI
        if (!err)
-               err = bus_register(&isa_bus_type);
+               err = of_bus_type_init(&isa_bus_type, "isa");
        if (!err)
-               err = bus_register(&ebus_bus_type);
+               err = of_bus_type_init(&ebus_bus_type, "ebus");
 #endif
 #ifdef CONFIG_SBUS
        if (!err)
-               err = bus_register(&sbus_bus_type);
+               err = of_bus_type_init(&sbus_bus_type, "sbus");
 #endif
 
        if (!err)
@@ -1020,61 +878,13 @@ int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
        /* register with core */
        return driver_register(&drv->driver);
 }
+EXPORT_SYMBOL(of_register_driver);
 
 void of_unregister_driver(struct of_platform_driver *drv)
 {
        driver_unregister(&drv->driver);
 }
-
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct of_device *ofdev;
-
-       ofdev = to_of_device(dev);
-       return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
-       struct of_device *ofdev;
-
-        ofdev = to_of_device(dev);
-
-       kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
-       int rc;
-
-       BUG_ON(ofdev->node == NULL);
-
-       rc = device_register(&ofdev->dev);
-       if (rc)
-               return rc;
-
-       rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
-       if (rc)
-               device_unregister(&ofdev->dev);
-
-       return rc;
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
-       device_remove_file(&ofdev->dev, &dev_attr_devspec);
-       device_unregister(&ofdev->dev);
-}
+EXPORT_SYMBOL(of_unregister_driver);
 
 struct of_device* of_platform_device_create(struct device_node *np,
                                            const char *bus_id,
@@ -1100,13 +910,4 @@ struct of_device* of_platform_device_create(struct device_node *np,
 
        return dev;
 }
-
-EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_register_driver);
-EXPORT_SYMBOL(of_unregister_driver);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
 EXPORT_SYMBOL(of_platform_device_create);
-EXPORT_SYMBOL(of_release_dev);
index 6b3fe2c1d65e990ca95cd6d0eb9eaea1a8700675..639cf06ca37280f3fbe98b97d4f267e23eaaed69 100644 (file)
@@ -1129,7 +1129,7 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
+static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
 {
        struct pci_pbm_info *pbm;
 
@@ -1163,7 +1163,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
        pci_sun4v_msi_init(pbm);
 }
 
-void sun4v_pci_init(struct device_node *dp, char *model_name)
+void __init sun4v_pci_init(struct device_node *dp, char *model_name)
 {
        static int hvapi_negotiated = 0;
        struct pci_controller_info *p;
index 8dd4294ad21ec0bcf0b3345d53f920efe999703c..881a09ee4c4c15ae4a2fac487184fad0a6c8fd06 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/pm.h>
 #include <linux/syscalls.h>
+#include <linux/reboot.h>
 
 #include <asm/system.h>
 #include <asm/auxio.h>
 #include <asm/prom.h>
 #include <asm/of_device.h>
 #include <asm/io.h>
-#include <asm/power.h>
 #include <asm/sstate.h>
 
 #include <linux/unistd.h>
@@ -31,20 +31,9 @@ int scons_pwroff = 1;
 
 static void __iomem *power_reg;
 
-static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
-static int button_pressed;
-
-void wake_up_powerd(void)
-{
-       if (button_pressed == 0) {
-               button_pressed = 1;
-               wake_up(&powerd_wait);
-       }
-}
-
 static irqreturn_t power_handler(int irq, void *dev_id)
 {
-       wake_up_powerd();
+       orderly_poweroff(true);
 
        /* FIXME: Check registers for status... */
        return IRQ_HANDLED;
@@ -57,7 +46,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off;
 void machine_power_off(void)
 {
        sstate_poweroff();
-       if (!serial_console || scons_pwroff) {
+       if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
                if (power_reg) {
                        /* Both register bits seem to have the
                         * same effect, so until I figure out
@@ -77,48 +66,6 @@ void machine_power_off(void)
 void (*pm_power_off)(void) = machine_power_off;
 EXPORT_SYMBOL(pm_power_off);
 
-static int powerd(void *__unused)
-{
-       static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-       char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
-       DECLARE_WAITQUEUE(wait, current);
-
-       daemonize("powerd");
-
-       add_wait_queue(&powerd_wait, &wait);
-
-       for (;;) {
-               set_task_state(current, TASK_INTERRUPTIBLE);
-               if (button_pressed)
-                       break;
-               flush_signals(current);
-               schedule();
-       }
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&powerd_wait, &wait);
-
-       /* Ok, down we go... */
-       button_pressed = 0;
-       if (kernel_execve("/sbin/shutdown", argv, envp) < 0) {
-               printk(KERN_ERR "powerd: shutdown execution failed\n");
-               machine_power_off();
-       }
-       return 0;
-}
-
-int start_powerd(void)
-{
-       int err;
-
-       err = kernel_thread(powerd, NULL, CLONE_FS);
-       if (err < 0)
-               printk(KERN_ERR "power: Failed to start power daemon.\n");
-       else
-               printk(KERN_INFO "power: powerd running.\n");
-
-       return err;
-}
-
 static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
 {
        if (irq == 0xffffffff)
@@ -136,20 +83,15 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
 
        power_reg = of_ioremap(res, 0, 0x4, "power");
 
-       printk("%s: Control reg at %lx ... ",
+       printk(KERN_INFO "%s: Control reg at %lx\n",
               op->node->name, res->start);
 
        poweroff_method = machine_halt;  /* able to use the standard halt */
 
        if (has_button_interrupt(irq, op->node)) {
-               if (start_powerd() < 0)
-                       return 0;
-
                if (request_irq(irq,
                                power_handler, 0, "power", NULL) < 0)
                        printk(KERN_ERR "power: Cannot setup IRQ handler.\n");
-       } else {
-               printk(KERN_INFO "power: Not using powerd.\n");
        }
 
        return 0;
@@ -170,6 +112,6 @@ static struct of_platform_driver power_driver = {
 
 void __init power_init(void)
 {
-       of_register_driver(&power_driver, &of_bus_type);
+       of_register_driver(&power_driver, &of_platform_bus_type);
        return;
 }
index 93557507ec9f76d765783677b800152ef00de20a..fd7899ba1d70bde8edee7211139081fe7bad88f9 100644 (file)
@@ -119,7 +119,7 @@ extern void (*prom_keyboard)(void);
 void machine_halt(void)
 {
        sstate_halt();
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        if (prom_keyboard)
                prom_keyboard();
@@ -130,7 +130,7 @@ void machine_halt(void)
 void machine_alt_power_off(void)
 {
        sstate_poweroff();
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette(1);
        if (prom_keyboard)
                prom_keyboard();
@@ -145,7 +145,7 @@ void machine_restart(char * cmd)
        sstate_reboot();
        p = strchr (reboot_command, '\n');
        if (p) *p = 0;
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette (1);
        if (prom_keyboard)
                prom_keyboard();
index 5d220302cd508709e65a9e32a3ea64cf98c40331..f4e0a9ad9be30b000895d5246d7f5318b1b11453 100644 (file)
 #include <asm/upa.h>
 #include <asm/smp.h>
 
-static struct device_node *allnodes;
+extern struct device_node *allnodes;   /* temporary while merging */
 
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
-                           const char *compat)
-{
-       const char* cp;
-       int cplen, l;
-
-       cp = of_get_property(device, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
-       struct device_node *np;
-
-       if (!node)
-               return NULL;
-
-       np = node->parent;
-
-       return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
-       struct device_node *prev)
-{
-       struct device_node *next;
-
-       next = prev ? prev->sibling : node->child;
-       for (; next != 0; next = next->sibling) {
-               break;
-       }
-
-       return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
-       struct device_node *np = allnodes;
-
-       for (; np != 0; np = np->allnext) {
-               if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock;  /* temporary while merging */
 
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
@@ -110,81 +46,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
 
-struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != NULL; np = np->allnext)
-               if (np->name != NULL && strcmp(np->name, name) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext)
-               if (np->type != 0 && strcmp(np->type, type) == 0)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compatible)
-{
-       struct device_node *np;
-
-       np = from ? from->allnext : allnodes;
-       for (; np != 0; np = np->allnext) {
-               if (type != NULL
-                   && !(np->type != 0 && strcmp(np->type, type) == 0))
-                       continue;
-               if (of_device_is_compatible(np, compatible))
-                       break;
-       }
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(const struct device_node *np,
-                                 const char *name,
-                                 int *lenp)
-{
-       struct property *pp;
-
-       for (pp = np->properties; pp != 0; pp = pp->next) {
-               if (strcasecmp(pp->name, name) == 0) {
-                       if (lenp != 0)
-                               *lenp = pp->length;
-                       break;
-               }
-       }
-       return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
-                     int *lenp)
-{
-       struct property *pp = of_find_property(np,name,lenp);
-       return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
 int of_getintprop_default(struct device_node *np, const char *name, int def)
 {
        struct property *prop;
@@ -198,36 +59,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
-int of_n_addr_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#address-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #address-cells property for the root node, default to 2 */
-       return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
-       const int* ip;
-       do {
-               if (np->parent)
-                       np = np->parent;
-               ip = of_get_property(np, "#size-cells", NULL);
-               if (ip != NULL)
-                       return *ip;
-       } while (np->parent);
-       /* No #size-cells property for the root node, default to 1 */
-       return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -1815,6 +1646,60 @@ static void __init of_fill_in_cpu_data(void)
        smp_fill_in_sib_core_maps();
 }
 
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+static void __init of_console_init(void)
+{
+       char *msg = "OF stdout device is: %s\n";
+       struct device_node *dp;
+       const char *type;
+       phandle node;
+
+       of_console_path = prom_early_alloc(256);
+       if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
+               prom_printf("Cannot obtain path of stdout.\n");
+               prom_halt();
+       }
+       of_console_options = strrchr(of_console_path, ':');
+       if (of_console_options) {
+               of_console_options++;
+               if (*of_console_options == '\0')
+                       of_console_options = NULL;
+       }
+
+       node = prom_inst2pkg(prom_stdout);
+       if (!node) {
+               prom_printf("Cannot resolve stdout node from "
+                           "instance %08x.\n", prom_stdout);
+               prom_halt();
+       }
+
+       dp = of_find_node_by_phandle(node);
+       type = of_get_property(dp, "device_type", NULL);
+       if (!type) {
+               prom_printf("Console stdout lacks device_type property.\n");
+               prom_halt();
+       }
+
+       if (strcmp(type, "display") && strcmp(type, "serial")) {
+               prom_printf("Console device_type is neither display "
+                           "nor serial.\n");
+               prom_halt();
+       }
+
+       of_console_device = dp;
+
+       prom_printf(msg, of_console_path);
+       printk(msg, of_console_path);
+}
+
 void __init prom_build_devicetree(void)
 {
        struct device_node **nextp;
@@ -1827,6 +1712,8 @@ void __init prom_build_devicetree(void)
        allnodes->child = build_tree(allnodes,
                                     prom_getchild(allnodes->node),
                                     &nextp);
+       of_console_init();
+
        printk("PROM: Built device tree with %u bytes of memory.\n",
               prom_early_allocated);
 
index aafde3dd9fd4996af17f88f4d486aec214cdfe63..0f5be828ee92614c8465055552a192e042274d47 100644 (file)
@@ -133,33 +133,6 @@ static void __init process_switch(char c)
        }
 }
 
-static void __init process_console(char *commands)
-{
-       serial_console = 0;
-       commands += 8;
-       /* Linux-style serial */
-       if (!strncmp(commands, "ttyS", 4))
-               serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
-       else if (!strncmp(commands, "tty", 3)) {
-               char c = *(commands + 3);
-               /* Solaris-style serial */
-               if (c == 'a' || c == 'b') {
-                       serial_console = c - 'a' + 1;
-                       prom_printf ("Using /dev/tty%c as console.\n", c);
-               }
-               /* else Linux-style fbcon, not serial */
-       }
-#if defined(CONFIG_PROM_CONSOLE)
-       if (!strncmp(commands, "prom", 4)) {
-               char *p;
-
-               for (p = commands - 8; *p && *p != ' '; p++)
-                       *p = ' ';
-               conswitchp = &prom_con;
-       }
-#endif
-}
-
 static void __init boot_flags_init(char *commands)
 {
        while (*commands) {
@@ -176,9 +149,7 @@ static void __init boot_flags_init(char *commands)
                                process_switch(*commands++);
                        continue;
                }
-               if (!strncmp(commands, "console=", 8)) {
-                       process_console(commands);
-               } else if (!strncmp(commands, "mem=", 4)) {
+               if (!strncmp(commands, "mem=", 4)) {
                        /*
                         * "mem=XXX[kKmM]" overrides the PROM-reported
                         * memory size.
@@ -378,44 +349,6 @@ void __init setup_arch(char **cmdline_p)
        paging_init();
 }
 
-static int __init set_preferred_console(void)
-{
-       int idev, odev;
-
-       /* The user has requested a console so this is already set up. */
-       if (serial_console >= 0)
-               return -EBUSY;
-
-       idev = prom_query_input_device();
-       odev = prom_query_output_device();
-       if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-               serial_console = 0;
-       } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-               serial_console = 1;
-       } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-               serial_console = 2;
-       } else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
-               serial_console = 3;
-       } else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
-               /* sunhv_console_init() doesn't check the serial_console
-                * value anyways...
-                */
-               serial_console = 4;
-               return add_preferred_console("ttyHV", 0, NULL);
-       } else {
-               prom_printf("Inconsistent console: "
-                           "input %d, output %d\n",
-                           idev, odev);
-               prom_halt();
-       }
-
-       if (serial_console)
-               return add_preferred_console("ttyS", serial_console - 1, NULL);
-
-       return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
 /* BUFFER is PAGE_SIZE bytes long. */
 
 extern char *sparc_cpu_type;
@@ -508,5 +441,4 @@ void sun_do_break(void)
        prom_cmdline();
 }
 
-int serial_console = -1;
 int stop_a_enabled = 1;
index 719d676c2ddc5c2875a675f4bf3fe9bacc300b6d..7d36531aa5b98d3e243a1917ceb595a5f870cf7a 100644 (file)
@@ -330,7 +330,6 @@ EXPORT_SYMBOL(VISenter);
 
 /* for input/keybdev */
 EXPORT_SYMBOL(sun_do_break);
-EXPORT_SYMBOL(serial_console);
 EXPORT_SYMBOL(stop_a_enabled);
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
index abd83129b2e73480031791032ea6a698eac26af8..e8dce90d05d45022589b4a75805798d35c6c4dbf 100644 (file)
@@ -1,8 +1,7 @@
-/* $Id: sys_sparc32.c,v 1.184 2002/02/09 19:49:31 davem Exp $
- * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
+/* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
  *
  * These routines maintain argument size conversion between 32bit and 64bit
  * environment.
@@ -1028,3 +1027,10 @@ long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_lo
                                   (nb_high << 32) | nb_low,
                                   flags);
 }
+
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+                                    u32 lenhi, u32 lenlo)
+{
+       return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+                            ((loff_t)lenhi << 32) | lenlo);
+}
index 8765e32155a06c83e21547f3fd30a26d71ac6d91..06d10907d8cee77ed3111a2b87a2a5c6e0bd98cb 100644 (file)
@@ -1,8 +1,7 @@
-/* $Id: systbls.S,v 1.81 2002/02/08 03:57:14 davem Exp $
- * systbls.S: System call entry point tables for OS compatibility.
+/* systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
- * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1996, 2007 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  *
  * Based upon preliminary work which is:
@@ -81,7 +80,7 @@ sys_call_table32:
        .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
 /*300*/        .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
        .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
-/*310*/        .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd
+/*310*/        .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate
 
 #endif /* CONFIG_COMPAT */
 
@@ -153,7 +152,7 @@ sys_call_table:
        .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
 /*300*/        .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
        .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd
+/*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
 
 #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
     defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -272,6 +271,6 @@ sunos_sys_table:
        .word sunos_nosys, sunos_nosys, sunos_nosys
        .word sunos_nosys
 /*310*/        .word sunos_nosys, sunos_nosys, sunos_nosys
-       .word sunos_nosys
+       .word sunos_nosys, sunos_nosys
 
 #endif
index 62e316ab1339a0ed1687728dd5db0f7c89f31ec2..e340eb401fb956642028b4eb8f912989487e2378 100644 (file)
@@ -835,7 +835,7 @@ static int __init clock_init(void)
                return 0;
        }
 
-       return of_register_driver(&clock_driver, &of_bus_type);
+       return of_register_driver(&clock_driver, &of_platform_bus_type);
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
@@ -1434,6 +1434,78 @@ static int bq4802_set_rtc_time(struct rtc_time *time)
 
        return 0;
 }
+
+static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
+{
+       unsigned char ctrl;
+
+       rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+       rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+       rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+       rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+       rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+       rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+       rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
+
+       ctrl = CMOS_READ(RTC_CONTROL);
+       if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+               BCD_TO_BIN(rtc_tm->tm_sec);
+               BCD_TO_BIN(rtc_tm->tm_min);
+               BCD_TO_BIN(rtc_tm->tm_hour);
+               BCD_TO_BIN(rtc_tm->tm_mday);
+               BCD_TO_BIN(rtc_tm->tm_mon);
+               BCD_TO_BIN(rtc_tm->tm_year);
+               BCD_TO_BIN(rtc_tm->tm_wday);
+       }
+
+       if (rtc_tm->tm_year <= 69)
+               rtc_tm->tm_year += 100;
+
+       rtc_tm->tm_mon--;
+}
+
+static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
+{
+       unsigned char mon, day, hrs, min, sec;
+       unsigned char save_control, save_freq_select;
+       unsigned int yrs;
+
+       yrs = rtc_tm->tm_year;
+       mon = rtc_tm->tm_mon + 1;
+       day = rtc_tm->tm_mday;
+       hrs = rtc_tm->tm_hour;
+       min = rtc_tm->tm_min;
+       sec = rtc_tm->tm_sec;
+
+       if (yrs >= 100)
+               yrs -= 100;
+
+       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+               BIN_TO_BCD(sec);
+               BIN_TO_BCD(min);
+               BIN_TO_BCD(hrs);
+               BIN_TO_BCD(day);
+               BIN_TO_BCD(mon);
+               BIN_TO_BCD(yrs);
+       }
+
+       save_control = CMOS_READ(RTC_CONTROL);
+       CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+       save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+       CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+       CMOS_WRITE(yrs, RTC_YEAR);
+       CMOS_WRITE(mon, RTC_MONTH);
+       CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+       CMOS_WRITE(hrs, RTC_HOURS);
+       CMOS_WRITE(min, RTC_MINUTES);
+       CMOS_WRITE(sec, RTC_SECONDS);
+
+       CMOS_WRITE(save_control, RTC_CONTROL);
+       CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+       return 0;
+}
 #endif /* CONFIG_PCI */
 
 struct mini_rtc_ops {
@@ -1456,6 +1528,11 @@ static struct mini_rtc_ops bq4802_rtc_ops = {
        .get_rtc_time = bq4802_get_rtc_time,
        .set_rtc_time = bq4802_set_rtc_time,
 };
+
+static struct mini_rtc_ops cmos_rtc_ops = {
+       .get_rtc_time = cmos_get_rtc_time,
+       .set_rtc_time = cmos_set_rtc_time,
+};
 #endif /* CONFIG_PCI */
 
 static struct mini_rtc_ops *mini_rtc_ops;
@@ -1583,6 +1660,8 @@ static int __init rtc_mini_init(void)
 #ifdef CONFIG_PCI
        else if (bq4802_regs)
                mini_rtc_ops = &bq4802_rtc_ops;
+       else if (ds1287_regs)
+               mini_rtc_ops = &cmos_rtc_ops;
 #endif /* CONFIG_PCI */
        else
                return -ENODEV;
index 8d3cc4fdb557018740e1f38076ef6a09b9a2f265..3685daf5157f369a1d3257e7cd8bf97aa12b84b9 100644 (file)
@@ -103,9 +103,9 @@ static ssize_t devspec_show(struct device *dev,
        struct vio_dev *vdev = to_vio_dev(dev);
        const char *str = "none";
 
-       if (!strcmp(vdev->type, "network"))
+       if (!strcmp(vdev->type, "vnet-port"))
                str = "vnet";
-       else if (!strcmp(vdev->type, "block"))
+       else if (!strcmp(vdev->type, "vdc-port"))
                str = "vdisk";
 
        return sprintf(buf, "%s\n", str);
@@ -205,7 +205,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
        struct device_node *dp;
        struct vio_dev *vdev;
        int err, tlen, clen;
-       const u64 *id;
+       const u64 *id, *cfg_handle;
+       u64 a;
 
        type = mdesc_get_property(hp, mp, "device-type", &tlen);
        if (!type) {
@@ -221,6 +222,19 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
                return NULL;
        }
 
+       id = mdesc_get_property(hp, mp, "id", NULL);
+
+       cfg_handle = NULL;
+       mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+               u64 target;
+
+               target = mdesc_arc_target(hp, a);
+               cfg_handle = mdesc_get_property(hp, target,
+                                               "cfg-handle", NULL);
+               if (cfg_handle)
+                       break;
+       }
+
        bus_id_name = type;
        if (!strcmp(type, "domain-services-port"))
                bus_id_name = "ds";
@@ -260,13 +274,19 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
 
        vio_fill_channel_info(hp, mp, vdev);
 
-       id = mdesc_get_property(hp, mp, "id", NULL);
-       if (!id)
+       if (!id) {
                snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
                         bus_id_name);
-       else
+               vdev->dev_no = ~(u64)0;
+       } else if (!cfg_handle) {
                snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
                         bus_id_name, *id);
+               vdev->dev_no = *id;
+       } else {
+               snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu-%lu",
+                        bus_id_name, *cfg_handle, *id);
+               vdev->dev_no = *cfg_handle;
+       }
 
        vdev->dev.parent = parent;
        vdev->dev.bus = &vio_bus_type;
index 7c25c54cefdc77e04ef4ea2470bff043195654fa..3fafa9a8b50bb3d541ebbc0a9814379b292dcbd2 100644 (file)
@@ -73,88 +73,3 @@ prom_puts(const char *s, int len)
                           P1275_INOUT(3,1),
                           prom_stdout, s, P1275_SIZE(len));
 }
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
-       int st_p;
-       char propb[64];
-
-       st_p = prom_inst2pkg(prom_stdin);
-       if(prom_node_has_property(st_p, "keyboard"))
-               return PROMDEV_IKBD;
-       prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-       if(strncmp(propb, "serial", 6))
-               return PROMDEV_I_UNK;
-       /* FIXME: Is there any better way how to find out? */   
-       memset(propb, 0, sizeof(propb));
-       st_p = prom_finddevice ("/options");
-       prom_getproperty(st_p, "input-device", propb, sizeof(propb));
-
-       /*
-        * If we get here with propb == 'keyboard', we are on ttya, as
-        * the PROM defaulted to this due to 'no input device'.
-        */
-       if (!strncmp(propb, "keyboard", 8))
-               return PROMDEV_ITTYA;
-
-       if (!strncmp (propb, "rsc", 3))
-               return PROMDEV_IRSC;
-
-       if (!strncmp (propb, "virtual-console", 3))
-               return PROMDEV_IVCONS;
-
-       if (strncmp (propb, "tty", 3) || !propb[3])
-               return PROMDEV_I_UNK;
-
-       switch (propb[3]) {
-               case 'a': return PROMDEV_ITTYA;
-               case 'b': return PROMDEV_ITTYB;
-               default: return PROMDEV_I_UNK;
-       }
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
-       int st_p;
-       char propb[64];
-       int propl;
-
-       st_p = prom_inst2pkg(prom_stdout);
-       propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
-       if (propl >= 0 && propl == sizeof("display") &&
-           strncmp("display", propb, sizeof("display")) == 0)
-               return PROMDEV_OSCREEN;
-       if(strncmp("serial", propb, 6))
-               return PROMDEV_O_UNK;
-       /* FIXME: Is there any better way how to find out? */   
-       memset(propb, 0, sizeof(propb));
-       st_p = prom_finddevice ("/options");
-       prom_getproperty(st_p, "output-device", propb, sizeof(propb));
-
-       /*
-        * If we get here with propb == 'screen', we are on ttya, as
-        * the PROM defaulted to this due to 'no input device'.
-        */
-       if (!strncmp(propb, "screen", 6))
-               return PROMDEV_OTTYA;
-
-       if (!strncmp (propb, "rsc", 3))
-               return PROMDEV_ORSC;
-
-       if (!strncmp (propb, "virtual-console", 3))
-               return PROMDEV_OVCONS;
-
-       if (strncmp (propb, "tty", 3) || !propb[3])
-               return PROMDEV_O_UNK;
-
-       switch (propb[3]) {
-               case 'a': return PROMDEV_OTTYA;
-               case 'b': return PROMDEV_OTTYB;
-               default: return PROMDEV_O_UNK;
-       }
-}
index 33c5b7da31e5522906855441953caa933d5ec835..68c83ad04ad958651654e6439657206284ae5df8 100644 (file)
@@ -72,7 +72,7 @@ void prom_cmdline(void)
 
        local_irq_save(flags);
 
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette(1);
 
 #ifdef CONFIG_SMP
@@ -85,7 +85,7 @@ void prom_cmdline(void)
        smp_release();
 #endif
 
-       if (!serial_console && prom_palette)
+       if (prom_palette)
                prom_palette(0);
 
        local_irq_restore(flags);
index 17b7ecfe7ca95aed84232c40020509a50f48ddf6..b2c5b12c9818ad57f5602491865f84b2898c970e 100644 (file)
@@ -304,3 +304,11 @@ prom_pathtoinode(const char *path)
        if (node == -1) return 0;
        return node;
 }
+
+int prom_ihandle2path(int handle, char *buffer, int bufsize)
+{
+       return p1275_cmd("instance-to-path",
+                        P1275_ARG(1,P1275_ARG_OUT_BUF)|
+                        P1275_INOUT(3, 1),
+                        handle, buffer, P1275_SIZE(bufsize));
+}
index 9755a3cfad26e7f3ed50e2dbff15adaec15c4470..d148ccbc36d17efa03e93d5af68340a77e4db532 100644 (file)
@@ -92,7 +92,11 @@ struct cfq_data {
        struct cfq_queue *active_queue;
        struct cfq_io_context *active_cic;
 
-       struct cfq_queue *async_cfqq[IOPRIO_BE_NR];
+       /*
+        * async queue for each priority case
+        */
+       struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR];
+       struct cfq_queue *async_idle_cfqq;
 
        struct timer_list idle_class_timer;
 
@@ -111,9 +115,6 @@ struct cfq_data {
        unsigned int cfq_slice_idle;
 
        struct list_head cic_list;
-
-       sector_t new_seek_mean;
-       u64 new_seek_total;
 };
 
 /*
@@ -153,8 +154,6 @@ struct cfq_queue {
 
        /* various state flags, see below */
        unsigned int flags;
-
-       sector_t last_request_pos;
 };
 
 enum cfqq_state_flags {
@@ -1414,24 +1413,44 @@ out:
        return cfqq;
 }
 
+static struct cfq_queue **
+cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
+{
+       switch(ioprio_class) {
+       case IOPRIO_CLASS_RT:
+               return &cfqd->async_cfqq[0][ioprio];
+       case IOPRIO_CLASS_BE:
+               return &cfqd->async_cfqq[1][ioprio];
+       case IOPRIO_CLASS_IDLE:
+               return &cfqd->async_idle_cfqq;
+       default:
+               BUG();
+       }
+}
+
 static struct cfq_queue *
 cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
              gfp_t gfp_mask)
 {
        const int ioprio = task_ioprio(tsk);
+       const int ioprio_class = task_ioprio_class(tsk);
+       struct cfq_queue **async_cfqq = NULL;
        struct cfq_queue *cfqq = NULL;
 
-       if (!is_sync)
-               cfqq = cfqd->async_cfqq[ioprio];
+       if (!is_sync) {
+               async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio);
+               cfqq = *async_cfqq;
+       }
+
        if (!cfqq)
                cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask);
 
        /*
         * pin the queue now that it's allocated, scheduler exit will prune it
         */
-       if (!is_sync && !cfqd->async_cfqq[ioprio]) {
+       if (!is_sync && !(*async_cfqq)) {
                atomic_inc(&cfqq->ref);
-               cfqd->async_cfqq[ioprio] = cfqq;
+               *async_cfqq = cfqq;
        }
 
        atomic_inc(&cfqq->ref);
@@ -1597,11 +1616,6 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
        else
                sdist = cic->last_request_pos - rq->sector;
 
-       if (!cic->seek_samples) {
-               cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
-               cfqd->new_seek_mean = cfqd->new_seek_total / 256;
-       }
-
        /*
         * Don't allow the seek distance to get too large from the
         * odd fragment, pagein, etc
@@ -1737,7 +1751,6 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
        cfq_update_idle_window(cfqd, cfqq, cic);
 
        cic->last_request_pos = rq->sector + rq->nr_sectors;
-       cfqq->last_request_pos = cic->last_request_pos;
 
        if (cfqq == cfqd->active_queue) {
                /*
@@ -2042,11 +2055,24 @@ static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
        blk_sync_queue(cfqd->queue);
 }
 
+static void cfq_put_async_queues(struct cfq_data *cfqd)
+{
+       int i;
+
+       for (i = 0; i < IOPRIO_BE_NR; i++) {
+               if (cfqd->async_cfqq[0][i])
+                       cfq_put_queue(cfqd->async_cfqq[0][i]);
+               if (cfqd->async_cfqq[1][i])
+                       cfq_put_queue(cfqd->async_cfqq[1][i]);
+               if (cfqd->async_idle_cfqq)
+                       cfq_put_queue(cfqd->async_idle_cfqq);
+       }
+}
+
 static void cfq_exit_queue(elevator_t *e)
 {
        struct cfq_data *cfqd = e->elevator_data;
        request_queue_t *q = cfqd->queue;
-       int i;
 
        cfq_shutdown_timer_wq(cfqd);
 
@@ -2063,12 +2089,7 @@ static void cfq_exit_queue(elevator_t *e)
                __cfq_exit_single_io_context(cfqd, cic);
        }
 
-       /*
-        * Put the async queues
-        */
-       for (i = 0; i < IOPRIO_BE_NR; i++)
-               if (cfqd->async_cfqq[i])        
-                       cfq_put_queue(cfqd->async_cfqq[i]);
+       cfq_put_async_queues(cfqd);
 
        spin_unlock_irq(q->queue_lock);
 
index a973f4ef897d8cb369920f5c301a1e83e9b540e1..047e533fcc5ba249977895ea1c3969f6a6b0be2e 100644 (file)
@@ -36,7 +36,6 @@
  * @offset: offset in pages to start transaction
  * @len: length in bytes
  * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
- *     ASYNC_TX_KMAP_SRC, ASYNC_TX_KMAP_DST
  * @depend_tx: memcpy depends on the result of this transaction
  * @cb_fn: function to call when the memcpy completes
  * @cb_param: parameter to pass to the callback routine
@@ -88,23 +87,13 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
                                        __FUNCTION__);
                }
 
-               if (flags & ASYNC_TX_KMAP_DST)
-                       dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset;
-               else
-                       dest_buf = page_address(dest) + dest_offset;
-
-               if (flags & ASYNC_TX_KMAP_SRC)
-                       src_buf = kmap_atomic(src, KM_USER0) + src_offset;
-               else
-                       src_buf = page_address(src) + src_offset;
+               dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset;
+               src_buf = kmap_atomic(src, KM_USER1) + src_offset;
 
                memcpy(dest_buf, src_buf, len);
 
-               if (flags & ASYNC_TX_KMAP_DST)
-                       kunmap_atomic(dest_buf, KM_USER0);
-
-               if (flags & ASYNC_TX_KMAP_SRC)
-                       kunmap_atomic(src_buf, KM_USER0);
+               kunmap_atomic(dest_buf, KM_USER0);
+               kunmap_atomic(src_buf, KM_USER1);
 
                async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
        }
index 707650ab77a76cae4983a6d6f56494e84bc24972..3e1c442deff9b7a4f67fada30120a162288b8f87 100644 (file)
@@ -8,6 +8,8 @@ source "drivers/connector/Kconfig"
 
 source "drivers/mtd/Kconfig"
 
+source "drivers/of/Kconfig"
+
 source "drivers/parport/Kconfig"
 
 source "drivers/pnp/Kconfig"
index 0ea8e3237c0d0cbf381621841ae6fde722bb58cd..a9e4c5f922a041b094d219b5581398e8035ef1e4 100644 (file)
@@ -86,3 +86,4 @@ obj-$(CONFIG_GENERIC_TIME)    += clocksource/
 obj-$(CONFIG_DMA_ENGINE)       += dma/
 obj-$(CONFIG_HID)              += hid/
 obj-$(CONFIG_PPC_PS3)          += ps3/
+obj-$(CONFIG_OF)               += of/
index 80ffc782991631492d08c2dea2837972698e5193..bb5d23be42607fe4ebb3c91c6dd118287242131b 100644 (file)
@@ -475,7 +475,7 @@ static void acpi_processor_idle(void)
                /* Get end time (ticks) */
                t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
                /* TSC halts in C2, so notify users */
                mark_tsc_unstable("possible TSC halt in C2");
 #endif
@@ -517,7 +517,7 @@ static void acpi_processor_idle(void)
                        acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
                }
 
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
                /* TSC halts in C3, so notify users */
                mark_tsc_unstable("TSC halts in C3");
 #endif
index 11e4eb9f304e92bd97498313c6600a3e7dceffe8..06f212ff2b4f2093e6d954c169c8c2454136dbb7 100644 (file)
@@ -99,6 +99,7 @@ enum {
        HOST_CAP_SSC            = (1 << 14), /* Slumber capable */
        HOST_CAP_CLO            = (1 << 24), /* Command List Override support */
        HOST_CAP_SSS            = (1 << 27), /* Staggered Spin-up */
+       HOST_CAP_SNTF           = (1 << 29), /* SNotification register */
        HOST_CAP_NCQ            = (1 << 30), /* Native Command Queueing */
        HOST_CAP_64             = (1 << 31), /* PCI DAC (64-bit DMA) support */
 
@@ -113,11 +114,11 @@ enum {
        PORT_TFDATA             = 0x20, /* taskfile data */
        PORT_SIG                = 0x24, /* device TF signature */
        PORT_CMD_ISSUE          = 0x38, /* command issue */
-       PORT_SCR                = 0x28, /* SATA phy register block */
        PORT_SCR_STAT           = 0x28, /* SATA phy register: SStatus */
        PORT_SCR_CTL            = 0x2c, /* SATA phy register: SControl */
        PORT_SCR_ERR            = 0x30, /* SATA phy register: SError */
        PORT_SCR_ACT            = 0x34, /* SATA phy register: SActive */
+       PORT_SCR_NTF            = 0x3c, /* SATA phy register: SNotification */
 
        /* PORT_IRQ_{STAT,MASK} bits */
        PORT_IRQ_COLD_PRES      = (1 << 31), /* cold presence detect */
@@ -216,8 +217,8 @@ struct ahci_port_priv {
        unsigned int            ncq_saw_sdb:1;
 };
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static void ahci_irq_clear(struct ata_port *ap);
@@ -417,7 +418,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
 
        /* ATI */
        { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
-       { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 */
+       { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 IDE */
+       { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700 AHCI */
+       { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700 nraid5 */
+       { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700 raid5 */
 
        /* VIA */
        { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
@@ -545,13 +549,19 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
        hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
        hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
 
-       /* some chips lie about 64bit support */
+       /* some chips have errata preventing 64bit use */
        if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
                dev_printk(KERN_INFO, &pdev->dev,
                           "controller can't do 64bit DMA, forcing 32bit\n");
                cap &= ~HOST_CAP_64;
        }
 
+       if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+               dev_printk(KERN_INFO, &pdev->dev,
+                          "controller can't do NCQ, turning off CAP_NCQ\n");
+               cap &= ~HOST_CAP_NCQ;
+       }
+
        /* fixup zero port_map */
        if (!port_map) {
                port_map = (1 << ahci_nr_ports(cap)) - 1;
@@ -625,38 +635,45 @@ static void ahci_restore_initial_config(struct ata_host *host)
        (void) readl(mmio + HOST_PORTS_IMPL);   /* flush */
 }
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
 {
-       unsigned int sc_reg;
-
-       switch (sc_reg_in) {
-       case SCR_STATUS:        sc_reg = 0; break;
-       case SCR_CONTROL:       sc_reg = 1; break;
-       case SCR_ERROR:         sc_reg = 2; break;
-       case SCR_ACTIVE:        sc_reg = 3; break;
-       default:
-               return 0xffffffffU;
-       }
+       static const int offset[] = {
+               [SCR_STATUS]            = PORT_SCR_STAT,
+               [SCR_CONTROL]           = PORT_SCR_CTL,
+               [SCR_ERROR]             = PORT_SCR_ERR,
+               [SCR_ACTIVE]            = PORT_SCR_ACT,
+               [SCR_NOTIFICATION]      = PORT_SCR_NTF,
+       };
+       struct ahci_host_priv *hpriv = ap->host->private_data;
 
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       if (sc_reg < ARRAY_SIZE(offset) &&
+           (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+               return offset[sc_reg];
+       return 0;
 }
 
-
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
-                              u32 val)
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
-       unsigned int sc_reg;
-
-       switch (sc_reg_in) {
-       case SCR_STATUS:        sc_reg = 0; break;
-       case SCR_CONTROL:       sc_reg = 1; break;
-       case SCR_ERROR:         sc_reg = 2; break;
-       case SCR_ACTIVE:        sc_reg = 3; break;
-       default:
-               return;
+       void __iomem *port_mmio = ahci_port_base(ap);
+       int offset = ahci_scr_offset(ap, sc_reg);
+
+       if (offset) {
+               *val = readl(port_mmio + offset);
+               return 0;
        }
+       return -EINVAL;
+}
 
-       writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+       void __iomem *port_mmio = ahci_port_base(ap);
+       int offset = ahci_scr_offset(ap, sc_reg);
+
+       if (offset) {
+               writel(val, port_mmio + offset);
+               return 0;
+       }
+       return -EINVAL;
 }
 
 static void ahci_start_engine(struct ata_port *ap)
@@ -948,37 +965,87 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
        pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
 }
 
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
 {
        void __iomem *port_mmio = ap->ioaddr.cmd_addr;
        struct ahci_host_priv *hpriv = ap->host->private_data;
        u32 tmp;
+       int busy, rc;
+
+       /* do we need to kick the port? */
+       busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+       if (!busy && !force_restart)
+               return 0;
+
+       /* stop engine */
+       rc = ahci_stop_engine(ap);
+       if (rc)
+               goto out_restart;
 
-       if (!(hpriv->cap & HOST_CAP_CLO))
-               return -EOPNOTSUPP;
+       /* need to do CLO? */
+       if (!busy) {
+               rc = 0;
+               goto out_restart;
+       }
 
+       if (!(hpriv->cap & HOST_CAP_CLO)) {
+               rc = -EOPNOTSUPP;
+               goto out_restart;
+       }
+
+       /* perform CLO */
        tmp = readl(port_mmio + PORT_CMD);
        tmp |= PORT_CMD_CLO;
        writel(tmp, port_mmio + PORT_CMD);
 
+       rc = 0;
        tmp = ata_wait_register(port_mmio + PORT_CMD,
                                PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
        if (tmp & PORT_CMD_CLO)
-               return -EIO;
+               rc = -EIO;
 
-       return 0;
+       /* restart engine */
+ out_restart:
+       ahci_start_engine(ap);
+       return rc;
 }
 
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
-                         unsigned long deadline)
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+                               struct ata_taskfile *tf, int is_cmd, u16 flags,
+                               unsigned long timeout_msec)
 {
+       const u32 cmd_fis_len = 5; /* five dwords */
        struct ahci_port_priv *pp = ap->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
-       const u32 cmd_fis_len = 5; /* five dwords */
+       u8 *fis = pp->cmd_tbl;
+       u32 tmp;
+
+       /* prep the command */
+       ata_tf_to_fis(tf, pmp, is_cmd, fis);
+       ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+       /* issue & wait */
+       writel(1, port_mmio + PORT_CMD_ISSUE);
+
+       if (timeout_msec) {
+               tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+                                       1, timeout_msec);
+               if (tmp & 0x1) {
+                       ahci_kick_engine(ap, 1);
+                       return -EBUSY;
+               }
+       } else
+               readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
+
+       return 0;
+}
+
+static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+                            int pmp, unsigned long deadline)
+{
        const char *reason = NULL;
+       unsigned long now, msecs;
        struct ata_taskfile tf;
-       u32 tmp;
-       u8 *fis;
        int rc;
 
        DPRINTK("ENTER\n");
@@ -990,43 +1057,22 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
        }
 
        /* prepare for SRST (AHCI-1.1 10.4.1) */
-       rc = ahci_stop_engine(ap);
-       if (rc) {
-               reason = "failed to stop engine";
-               goto fail_restart;
-       }
-
-       /* check BUSY/DRQ, perform Command List Override if necessary */
-       if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
-               rc = ahci_clo(ap);
-
-               if (rc == -EOPNOTSUPP) {
-                       reason = "port busy but CLO unavailable";
-                       goto fail_restart;
-               } else if (rc) {
-                       reason = "port busy but CLO failed";
-                       goto fail_restart;
-               }
-       }
-
-       /* restart engine */
-       ahci_start_engine(ap);
+       rc = ahci_kick_engine(ap, 1);
+       if (rc)
+               ata_port_printk(ap, KERN_WARNING,
+                               "failed to reset engine (errno=%d)", rc);
 
        ata_tf_init(ap->device, &tf);
-       fis = pp->cmd_tbl;
 
        /* issue the first D2H Register FIS */
-       ahci_fill_cmd_slot(pp, 0,
-                          cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+       msecs = 0;
+       now = jiffies;
+       if (time_after(now, deadline))
+               msecs = jiffies_to_msecs(deadline - now);
 
        tf.ctl |= ATA_SRST;
-       ata_tf_to_fis(&tf, fis, 0);
-       fis[1] &= ~(1 << 7);    /* turn off Command FIS bit */
-
-       writel(1, port_mmio + PORT_CMD_ISSUE);
-
-       tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
-       if (tmp & 0x1) {
+       if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
+                                AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
                rc = -EIO;
                reason = "1st FIS failed";
                goto fail;
@@ -1036,14 +1082,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
        msleep(1);
 
        /* issue the second D2H Register FIS */
-       ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
        tf.ctl &= ~ATA_SRST;
-       ata_tf_to_fis(&tf, fis, 0);
-       fis[1] &= ~(1 << 7);    /* turn off Command FIS bit */
-
-       writel(1, port_mmio + PORT_CMD_ISSUE);
-       readl(port_mmio + PORT_CMD_ISSUE);      /* flush */
+       ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
 
        /* spec mandates ">= 2ms" before checking status.
         * We wait 150ms, because that was the magic delay used for
@@ -1066,13 +1106,17 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
        DPRINTK("EXIT, class=%u\n", *class);
        return 0;
 
- fail_restart:
-       ahci_start_engine(ap);
  fail:
        ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
        return rc;
 }
 
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+                         unsigned long deadline)
+{
+       return ahci_do_softreset(ap, class, 0, deadline);
+}
+
 static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
                          unsigned long deadline)
 {
@@ -1088,7 +1132,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
        /* clear D2H reception area to properly wait for D2H FIS */
        ata_tf_init(ap->device, &tf);
        tf.command = 0x80;
-       ata_tf_to_fis(&tf, d2h_fis, 0);
+       ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
        rc = sata_std_hardreset(ap, class, deadline);
 
@@ -1106,6 +1150,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
 static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
                                 unsigned long deadline)
 {
+       u32 serror;
        int rc;
 
        DPRINTK("ENTER\n");
@@ -1116,7 +1161,8 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
                                 deadline);
 
        /* vt8251 needs SError cleared for the port to operate */
-       ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
+       ahci_scr_read(ap, SCR_ERROR, &serror);
+       ahci_scr_write(ap, SCR_ERROR, serror);
 
        ahci_start_engine(ap);
 
@@ -1205,7 +1251,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
         */
        cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
 
-       ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+       ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
        if (is_atapi) {
                memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
                memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1238,7 +1284,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        ata_ehi_clear_desc(ehi);
 
        /* AHCI needs SError cleared; otherwise, it might lock up */
-       serror = ahci_scr_read(ap, SCR_ERROR);
+       ahci_scr_read(ap, SCR_ERROR, &serror);
        ahci_scr_write(ap, SCR_ERROR, serror);
 
        /* analyze @irq_stat */
@@ -1262,12 +1308,12 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
        if (irq_stat & PORT_IRQ_IF_ERR) {
                err_mask |= AC_ERR_ATA_BUS;
                action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi, "interface fatal error");
+               ata_ehi_push_desc(ehi, "interface fatal error");
        }
 
        if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
                ata_ehi_hotplugged(ehi);
-               ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
+               ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
                        "connection status changed" : "PHY RDY changed");
        }
 
@@ -1276,7 +1322,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 
                err_mask |= AC_ERR_HSM;
                action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
+               ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
                                  unk[0], unk[1], unk[2], unk[3]);
        }
 
@@ -1512,11 +1558,17 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
 {
        struct ata_port *ap = qc->ap;
 
-       if (qc->flags & ATA_QCFLAG_FAILED) {
-               /* make DMA engine forget about the failed command */
-               ahci_stop_engine(ap);
-               ahci_start_engine(ap);
-       }
+       /* make DMA engine forget about the failed command */
+       if (qc->flags & ATA_QCFLAG_FAILED)
+               ahci_kick_engine(ap, 1);
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+       ahci_power_up(ap);
+       ahci_start_port(ap);
+
+       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -1536,14 +1588,6 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
        return rc;
 }
 
-static int ahci_port_resume(struct ata_port *ap)
-{
-       ahci_power_up(ap);
-       ahci_start_port(ap);
-
-       return 0;
-}
-
 static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
        struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -1734,12 +1778,13 @@ static void ahci_print_info(struct ata_host *host)
 
        dev_printk(KERN_INFO, &pdev->dev,
                "flags: "
-               "%s%s%s%s%s%s"
-               "%s%s%s%s%s%s%s\n"
+               "%s%s%s%s%s%s%s"
+               "%s%s%s%s%s%s%s\n"
                ,
 
                cap & (1 << 31) ? "64bit " : "",
                cap & (1 << 30) ? "ncq " : "",
+               cap & (1 << 29) ? "sntf " : "",
                cap & (1 << 28) ? "ilck " : "",
                cap & (1 << 27) ? "stag " : "",
                cap & (1 << 26) ? "pm " : "",
@@ -1794,7 +1839,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        ahci_save_initial_config(pdev, &pi, hpriv);
 
        /* prepare host */
-       if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+       if (hpriv->cap & HOST_CAP_NCQ)
                pi.flags |= ATA_FLAG_NCQ;
 
        host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
@@ -1808,10 +1853,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                void __iomem *port_mmio = ahci_port_base(ap);
 
                /* standard SATA port setup */
-               if (hpriv->port_map & (1 << i)) {
+               if (hpriv->port_map & (1 << i))
                        ap->ioaddr.cmd_addr = port_mmio;
-                       ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
-               }
 
                /* disabled/not-implemented port */
                else
index 88e2dd0983b536cc31c3dfd6d44ffafa1f2854fc..6001aae0b8841b88acdb90c4250ce2e5e5d71861 100644 (file)
@@ -111,8 +111,9 @@ MODULE_VERSION(DRV_VERSION);
 /**
  *     ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
  *     @tf: Taskfile to convert
- *     @fis: Buffer into which data will output
  *     @pmp: Port multiplier port
+ *     @is_cmd: This FIS is for command
+ *     @fis: Buffer into which data will output
  *
  *     Converts a standard ATA taskfile to a Serial ATA
  *     FIS structure (Register - Host to Device).
@@ -120,12 +121,13 @@ MODULE_VERSION(DRV_VERSION);
  *     LOCKING:
  *     Inherited from caller.
  */
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
 {
-       fis[0] = 0x27;  /* Register - Host to Device FIS */
-       fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
-                                           bit 7 indicates Command FIS */
+       fis[0] = 0x27;                  /* Register - Host to Device FIS */
+       fis[1] = pmp & 0xf;             /* Port multiplier number*/
+       if (is_cmd)
+               fis[1] |= (1 << 7);     /* bit 7 indicates Command FIS */
+
        fis[2] = tf->command;
        fis[3] = tf->feature;
 
@@ -2387,21 +2389,35 @@ int sata_down_spd_limit(struct ata_port *ap)
        u32 sstatus, spd, mask;
        int rc, highbit;
 
+       if (!sata_scr_valid(ap))
+               return -EOPNOTSUPP;
+
+       /* If SCR can be read, use it to determine the current SPD.
+        * If not, use cached value in ap->sata_spd.
+        */
        rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
-       if (rc)
-               return rc;
+       if (rc == 0)
+               spd = (sstatus >> 4) & 0xf;
+       else
+               spd = ap->sata_spd;
 
        mask = ap->sata_spd_limit;
        if (mask <= 1)
                return -EINVAL;
+
+       /* unconditionally mask off the highest bit */
        highbit = fls(mask) - 1;
        mask &= ~(1 << highbit);
 
-       spd = (sstatus >> 4) & 0xf;
-       if (spd <= 1)
-               return -EINVAL;
-       spd--;
-       mask &= (1 << spd) - 1;
+       /* Mask off all speeds higher than or equal to the current
+        * one.  Force 1.5Gbps if current SPD is not available.
+        */
+       if (spd > 1)
+               mask &= (1 << (spd - 1)) - 1;
+       else
+               mask &= 1;
+
+       /* were we already at the bottom? */
        if (!mask)
                return -EINVAL;
 
@@ -3251,9 +3267,11 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
                last = cur;
                last_jiffies = jiffies;
 
-               /* check deadline */
+               /* Check deadline.  If debouncing failed, return
+                * -EPIPE to tell upper layer to lower link speed.
+                */
                if (time_after(jiffies, deadline))
-                       return -EBUSY;
+                       return -EPIPE;
        }
 }
 
@@ -3769,6 +3787,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
        { "WDC WD740ADFD-00NLR1", NULL,         ATA_HORKAGE_NONCQ, },
        { "FUJITSU MHV2080BH",  "00840028",     ATA_HORKAGE_NONCQ, },
+       { "ST9160821AS",        "3.CLF",        ATA_HORKAGE_NONCQ, },
 
        /* Devices with NCQ limits */
 
@@ -5729,10 +5748,8 @@ int sata_scr_valid(struct ata_port *ap)
  */
 int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
 {
-       if (sata_scr_valid(ap)) {
-               *val = ap->ops->scr_read(ap, reg);
-               return 0;
-       }
+       if (sata_scr_valid(ap))
+               return ap->ops->scr_read(ap, reg, val);
        return -EOPNOTSUPP;
 }
 
@@ -5754,10 +5771,8 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
  */
 int sata_scr_write(struct ata_port *ap, int reg, u32 val)
 {
-       if (sata_scr_valid(ap)) {
-               ap->ops->scr_write(ap, reg, val);
-               return 0;
-       }
+       if (sata_scr_valid(ap))
+               return ap->ops->scr_write(ap, reg, val);
        return -EOPNOTSUPP;
 }
 
@@ -5778,10 +5793,13 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val)
  */
 int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
 {
+       int rc;
+
        if (sata_scr_valid(ap)) {
-               ap->ops->scr_write(ap, reg, val);
-               ap->ops->scr_read(ap, reg);
-               return 0;
+               rc = ap->ops->scr_write(ap, reg, val);
+               if (rc == 0)
+                       rc = ap->ops->scr_read(ap, reg, &val);
+               return rc;
        }
        return -EOPNOTSUPP;
 }
@@ -5993,6 +6011,7 @@ void ata_dev_init(struct ata_device *dev)
 
        /* SATA spd limit is bound to the first device */
        ap->sata_spd_limit = ap->hw_sata_spd_limit;
+       ap->sata_spd = 0;
 
        /* High bits of dev->flags are used to record warm plug
         * requests which occur asynchronously.  Synchronize using
@@ -6058,6 +6077,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
        INIT_LIST_HEAD(&ap->eh_done_q);
        init_waitqueue_head(&ap->eh_wait_q);
+       init_timer_deferrable(&ap->fastdrain_timer);
+       ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
+       ap->fastdrain_timer.data = (unsigned long)ap;
 
        ap->cbl = ATA_CBL_NONE;
 
@@ -6434,7 +6456,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        for (i = 0; i < host->n_ports; i++) {
                struct ata_port *ap = host->ports[i];
 
-               ata_scsi_scan_host(ap);
+               ata_scsi_scan_host(ap, 1);
        }
 
        return 0;
@@ -6942,6 +6964,9 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
+EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
 EXPORT_SYMBOL_GPL(ata_port_abort);
index 9aa62a0754f6946349a4c72d142f2f68eec0077e..ac6ceed4bb602082037b3cc844eef9470a6b6adb 100644 (file)
@@ -56,6 +56,7 @@ enum {
  */
 enum {
        ATA_EH_PRERESET_TIMEOUT         = 10 * HZ,
+       ATA_EH_FASTDRAIN_INTERVAL       = 3 * HZ,
 };
 
 /* The following table determines how we sequence resets.  Each entry
@@ -85,6 +86,71 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
 { }
 #endif /* CONFIG_PM */
 
+static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt,
+                                va_list args)
+{
+       ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len,
+                                    ATA_EH_DESC_LEN - ehi->desc_len,
+                                    fmt, args);
+}
+
+/**
+ *     __ata_ehi_push_desc - push error description without adding separator
+ *     @ehi: target EHI
+ *     @fmt: printf format string
+ *
+ *     Format string according to @fmt and append it to @ehi->desc.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       __ata_ehi_pushv_desc(ehi, fmt, args);
+       va_end(args);
+}
+
+/**
+ *     ata_ehi_push_desc - push error description with separator
+ *     @ehi: target EHI
+ *     @fmt: printf format string
+ *
+ *     Format string according to @fmt and append it to @ehi->desc.
+ *     If @ehi->desc is not empty, ", " is added in-between.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+       va_list args;
+
+       if (ehi->desc_len)
+               __ata_ehi_push_desc(ehi, ", ");
+
+       va_start(args, fmt);
+       __ata_ehi_pushv_desc(ehi, fmt, args);
+       va_end(args);
+}
+
+/**
+ *     ata_ehi_clear_desc - clean error description
+ *     @ehi: target EHI
+ *
+ *     Clear @ehi->desc.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+void ata_ehi_clear_desc(struct ata_eh_info *ehi)
+{
+       ehi->desc[0] = '\0';
+       ehi->desc_len = 0;
+}
+
 static void ata_ering_record(struct ata_ering *ering, int is_io,
                             unsigned int err_mask)
 {
@@ -296,6 +362,9 @@ void ata_scsi_error(struct Scsi_Host *host)
  repeat:
        /* invoke error handler */
        if (ap->ops->error_handler) {
+               /* kill fast drain timer */
+               del_timer_sync(&ap->fastdrain_timer);
+
                /* process port resume request */
                ata_eh_handle_port_resume(ap);
 
@@ -511,6 +580,94 @@ void ata_eng_timeout(struct ata_port *ap)
        DPRINTK("EXIT\n");
 }
 
+static int ata_eh_nr_in_flight(struct ata_port *ap)
+{
+       unsigned int tag;
+       int nr = 0;
+
+       /* count only non-internal commands */
+       for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++)
+               if (ata_qc_from_tag(ap, tag))
+                       nr++;
+
+       return nr;
+}
+
+void ata_eh_fastdrain_timerfn(unsigned long arg)
+{
+       struct ata_port *ap = (void *)arg;
+       unsigned long flags;
+       int cnt;
+
+       spin_lock_irqsave(ap->lock, flags);
+
+       cnt = ata_eh_nr_in_flight(ap);
+
+       /* are we done? */
+       if (!cnt)
+               goto out_unlock;
+
+       if (cnt == ap->fastdrain_cnt) {
+               unsigned int tag;
+
+               /* No progress during the last interval, tag all
+                * in-flight qcs as timed out and freeze the port.
+                */
+               for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) {
+                       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+                       if (qc)
+                               qc->err_mask |= AC_ERR_TIMEOUT;
+               }
+
+               ata_port_freeze(ap);
+       } else {
+               /* some qcs have finished, give it another chance */
+               ap->fastdrain_cnt = cnt;
+               ap->fastdrain_timer.expires =
+                       jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+               add_timer(&ap->fastdrain_timer);
+       }
+
+ out_unlock:
+       spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ *     ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
+ *     @ap: target ATA port
+ *     @fastdrain: activate fast drain
+ *
+ *     Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
+ *     is non-zero and EH wasn't pending before.  Fast drain ensures
+ *     that EH kicks in in timely manner.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ */
+static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
+{
+       int cnt;
+
+       /* already scheduled? */
+       if (ap->pflags & ATA_PFLAG_EH_PENDING)
+               return;
+
+       ap->pflags |= ATA_PFLAG_EH_PENDING;
+
+       if (!fastdrain)
+               return;
+
+       /* do we have in-flight qcs? */
+       cnt = ata_eh_nr_in_flight(ap);
+       if (!cnt)
+               return;
+
+       /* activate fast drain */
+       ap->fastdrain_cnt = cnt;
+       ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+       add_timer(&ap->fastdrain_timer);
+}
+
 /**
  *     ata_qc_schedule_eh - schedule qc for error handling
  *     @qc: command to schedule error handling for
@@ -528,7 +685,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
        WARN_ON(!ap->ops->error_handler);
 
        qc->flags |= ATA_QCFLAG_FAILED;
-       qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
+       ata_eh_set_pending(ap, 1);
 
        /* The following will fail if timeout has already expired.
         * ata_scsi_error() takes care of such scmds on EH entry.
@@ -555,7 +712,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
        if (ap->pflags & ATA_PFLAG_INITIALIZING)
                return;
 
-       ap->pflags |= ATA_PFLAG_EH_PENDING;
+       ata_eh_set_pending(ap, 1);
        scsi_schedule_eh(ap->scsi_host);
 
        DPRINTK("port EH scheduled\n");
@@ -579,6 +736,9 @@ int ata_port_abort(struct ata_port *ap)
 
        WARN_ON(!ap->ops->error_handler);
 
+       /* we're gonna abort all commands, no need for fast drain */
+       ata_eh_set_pending(ap, 0);
+
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
                struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
 
@@ -1130,7 +1290,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
        /* we've got the perpetrator, condemn it */
        qc = __ata_qc_from_tag(ap, tag);
        memcpy(&qc->result_tf, &tf, sizeof(tf));
-       qc->err_mask |= AC_ERR_DEV;
+       qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
        ehc->i.err_mask &= ~AC_ERR_DEV;
 }
 
@@ -1413,8 +1573,12 @@ static void ata_eh_autopsy(struct ata_port *ap)
        if (rc == 0) {
                ehc->i.serror |= serror;
                ata_eh_analyze_serror(ap);
-       } else if (rc != -EOPNOTSUPP)
+       } else if (rc != -EOPNOTSUPP) {
+               /* SError read failed, force hardreset and probing */
+               ata_ehi_schedule_probe(&ehc->i);
                ehc->i.action |= ATA_EH_HARDRESET;
+               ehc->i.err_mask |= AC_ERR_OTHER;
+       }
 
        /* analyze NCQ failure */
        ata_eh_analyze_ncq_error(ap);
@@ -1524,14 +1688,14 @@ static void ata_eh_report(struct ata_port *ap)
                               ehc->i.err_mask, ap->sactive, ehc->i.serror,
                               ehc->i.action, frozen);
                if (desc)
-                       ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+                       ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
        } else {
                ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
                                "SAct 0x%x SErr 0x%x action 0x%x%s\n",
                                ehc->i.err_mask, ap->sactive, ehc->i.serror,
                                ehc->i.action, frozen);
                if (desc)
-                       ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+                       ata_port_printk(ap, KERN_ERR, "%s\n", desc);
        }
 
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
@@ -1551,7 +1715,7 @@ static void ata_eh_report(struct ata_port *ap)
                        "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
                        "tag %d cdb 0x%x data %u %s\n         "
                        "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
-                       "Emask 0x%x (%s)\n",
+                       "Emask 0x%x (%s)%s\n",
                        cmd->command, cmd->feature, cmd->nsect,
                        cmd->lbal, cmd->lbam, cmd->lbah,
                        cmd->hob_feature, cmd->hob_nsect,
@@ -1562,7 +1726,8 @@ static void ata_eh_report(struct ata_port *ap)
                        res->lbal, res->lbam, res->lbah,
                        res->hob_feature, res->hob_nsect,
                        res->hob_lbal, res->hob_lbam, res->hob_lbah,
-                       res->device, qc->err_mask, ata_err_string(qc->err_mask));
+                       res->device, qc->err_mask, ata_err_string(qc->err_mask),
+                       qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
        }
 }
 
@@ -1648,7 +1813,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                        } else
                                ata_port_printk(ap, KERN_ERR,
                                        "prereset failed (errno=%d)\n", rc);
-                       return rc;
+                       goto out;
                }
        }
 
@@ -1661,7 +1826,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                /* prereset told us not to reset, bang classes and return */
                for (i = 0; i < ATA_MAX_DEVICES; i++)
                        classes[i] = ATA_DEV_NONE;
-               return 0;
+               rc = 0;
+               goto out;
        }
 
        /* did prereset() screw up?  if so, fix up to avoid oopsing */
@@ -1697,7 +1863,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                        ata_port_printk(ap, KERN_ERR,
                                        "follow-up softreset required "
                                        "but no softreset avaliable\n");
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto out;
                }
 
                ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
@@ -1707,7 +1874,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                    classes[0] == ATA_DEV_UNKNOWN) {
                        ata_port_printk(ap, KERN_ERR,
                                        "classification failed\n");
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto out;
                }
        }
 
@@ -1724,7 +1892,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                        schedule_timeout_uninterruptible(delta);
                }
 
-               if (reset == hardreset &&
+               if (rc == -EPIPE ||
                    try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
                        sata_down_spd_limit(ap);
                if (hardreset)
@@ -1733,12 +1901,18 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
        }
 
        if (rc == 0) {
+               u32 sstatus;
+
                /* After the reset, the device state is PIO 0 and the
                 * controller state is undefined.  Record the mode.
                 */
                for (i = 0; i < ATA_MAX_DEVICES; i++)
                        ap->device[i].pio_mode = XFER_PIO_0;
 
+               /* record current link speed */
+               if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0)
+                       ap->sata_spd = (sstatus >> 4) & 0xf;
+
                if (postreset)
                        postreset(ap, classes);
 
@@ -1746,7 +1920,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
                ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
                ehc->i.action |= ATA_EH_REVALIDATE;
        }
-
+ out:
+       /* clear hotplug flag */
+       ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
        return rc;
 }
 
index cfde22da07ac9aa3537e22b88935c4f56bf57e70..12ac0b511f7947a52d12804311382f072552a331 100644 (file)
@@ -2947,17 +2947,22 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
        return rc;
 }
 
-void ata_scsi_scan_host(struct ata_port *ap)
+void ata_scsi_scan_host(struct ata_port *ap, int sync)
 {
+       int tries = 5;
+       struct ata_device *last_failed_dev = NULL;
+       struct ata_device *dev;
        unsigned int i;
 
        if (ap->flags & ATA_FLAG_DISABLED)
                return;
 
+ repeat:
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
                struct scsi_device *sdev;
 
+               dev = &ap->device[i];
+
                if (!ata_dev_enabled(dev) || dev->sdev)
                        continue;
 
@@ -2967,6 +2972,45 @@ void ata_scsi_scan_host(struct ata_port *ap)
                        scsi_device_put(sdev);
                }
        }
+
+       /* If we scanned while EH was in progress or allocation
+        * failure occurred, scan would have failed silently.  Check
+        * whether all devices are attached.
+        */
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               dev = &ap->device[i];
+               if (ata_dev_enabled(dev) && !dev->sdev)
+                       break;
+       }
+       if (i == ATA_MAX_DEVICES)
+               return;
+
+       /* we're missing some SCSI devices */
+       if (sync) {
+               /* If caller requested synchrnous scan && we've made
+                * any progress, sleep briefly and repeat.
+                */
+               if (dev != last_failed_dev) {
+                       msleep(100);
+                       last_failed_dev = dev;
+                       goto repeat;
+               }
+
+               /* We might be failing to detect boot device, give it
+                * a few more chances.
+                */
+               if (--tries) {
+                       msleep(100);
+                       goto repeat;
+               }
+
+               ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
+                               "failed without making any progress,\n"
+                               "                  switching to async\n");
+       }
+
+       queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+                          round_jiffies_relative(HZ));
 }
 
 /**
@@ -3093,20 +3137,7 @@ void ata_scsi_hotplug(struct work_struct *work)
        }
 
        /* scan for new ones */
-       ata_scsi_scan_host(ap);
-
-       /* If we scanned while EH was in progress, scan would have
-        * failed silently.  Requeue if there are enabled but
-        * unattached devices.
-        */
-       for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               struct ata_device *dev = &ap->device[i];
-               if (ata_dev_enabled(dev) && !dev->sdev) {
-                       queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
-                               round_jiffies_relative(HZ));
-                       break;
-               }
-       }
+       ata_scsi_scan_host(ap, 0);
 
        DPRINTK("EXIT\n");
 }
index ca7d2245d6840b2580141ceae2b81542366a3d6e..6c289c7b13224119d2ff13756ad556bcbff11fcf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  libata-bmdma.c - helper library for PCI IDE BMDMA
+ *  libata-sff.c - helper library for PCI IDE BMDMA
  *
  *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
  *                 Please ALWAYS copy linux-ide@vger.kernel.org
@@ -211,6 +211,8 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
                tf->hob_lbal = ioread8(ioaddr->lbal_addr);
                tf->hob_lbam = ioread8(ioaddr->lbam_addr);
                tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+               iowrite8(tf->ctl, ioaddr->ctl_addr);
+               ap->last_ctl = tf->ctl;
        }
 }
 
index ba17fc5f2e998a1601993494cafc2b1d766c9468..564cd234c805335999bf40fefe0b00eab1f061d1 100644 (file)
@@ -112,7 +112,7 @@ static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
 /* libata-scsi.c */
 extern int ata_scsi_add_hosts(struct ata_host *host,
                              struct scsi_host_template *sht);
-extern void ata_scsi_scan_host(struct ata_port *ap);
+extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
 extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
@@ -151,6 +151,7 @@ extern int ata_bus_probe(struct ata_port *ap);
 extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
+extern void ata_eh_fastdrain_timerfn(unsigned long arg);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
 
 /* libata-sff.c */
index 6bf037d82b5aa9b0a324c37c4c627bc32b38ff27..7dc76e71bd55070b4fc177eae62b3e0c57f8e2eb 100644 (file)
@@ -275,7 +275,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
 
        for (i = 0; i < 2; i++) {
                static const int irq[] = { 14, 15 };
-               struct ata_port *ap = host->ports[0];
+               struct ata_port *ap = host->ports[i];
 
                if (ata_port_is_dummy(ap))
                        continue;
index 79f841bca593defac6f1e1926145f92a36a59d06..a909f793ffc1327dbdbf3b7c9137ab80a928ca04 100644 (file)
@@ -213,8 +213,9 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
        pata_platform_setup_port(&ap->ioaddr, pp_info);
 
        /* activate */
-       return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
-                                pp_info->irq_flags, &pata_platform_sht);
+       return ata_host_activate(host, platform_get_irq(pdev, 0),
+                                ata_interrupt, pp_info ? pp_info->irq_flags
+                                : 0, &pata_platform_sht);
 }
 
 /**
index c55667e0eb65a5978f2b786707afad88f5c30e6e..36cdbd2b0bd50c963df8253925f856328be0579e 100644 (file)
@@ -238,12 +238,6 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
        else
                offset = 0;     /* 100MHz */
 
-       /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
-       if (adev->class == ATA_DEV_ATAPI && speed > XFER_UDMA_4) {
-               printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
-               speed = XFER_UDMA_4;
-       }
-
        if (speed >= XFER_UDMA_0)
                idx = speed - XFER_UDMA_0;
        else
@@ -264,6 +258,17 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
                 JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
 }
 
+unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+       /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
+       if (adev->class == ATA_DEV_ATAPI &&
+           (mask & (0xE0 << ATA_SHIFT_UDMA))) {
+               printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
+               mask &= ~(0xE0 << ATA_SHIFT_UDMA);
+       }
+       return ata_pci_default_filter(adev, mask);
+}
+
 /**
  *     scc_tf_load - send taskfile registers to host controller
  *     @ap: Port to which output is sent
@@ -358,6 +363,8 @@ static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf)
                tf->hob_lbal = in_be32(ioaddr->lbal_addr);
                tf->hob_lbam = in_be32(ioaddr->lbam_addr);
                tf->hob_lbah = in_be32(ioaddr->lbah_addr);
+               out_be32(ioaddr->ctl_addr, tf->ctl);
+               ap->last_ctl = tf->ctl;
        }
 }
 
@@ -741,7 +748,7 @@ static u8 scc_bmdma_status (struct ata_port *ap)
                return host_stat;
 
        /* errata A252,A308 workaround: Step4 */
-       if (ata_altstatus(ap) & ATA_ERR && int_status & INTSTS_INTRQ)
+       if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
                return (host_stat | ATA_DMA_INTR);
 
        /* errata A308 workaround Step5 */
@@ -752,11 +759,11 @@ static u8 scc_bmdma_status (struct ata_port *ap)
                if ((qc->tf.protocol == ATA_PROT_DMA &&
                     qc->dev->xfer_mode > XFER_UDMA_4)) {
                        if (!(int_status & INTSTS_ACTEINT)) {
-                               printk(KERN_WARNING "ata%u: data lost occurred. (ACTEINT==0, retry:%d)\n",
-                                      ap->print_id, retry);
+                               printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
+                                      ap->print_id);
                                host_stat |= ATA_DMA_ERR;
                                if (retry++)
-                                       ap->udma_mask >>= 1;
+                                       ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
                        } else
                                retry = 0;
                }
@@ -1016,7 +1023,7 @@ static const struct ata_port_operations scc_pata_ops = {
        .port_disable           = ata_port_disable,
        .set_piomode            = scc_set_piomode,
        .set_dmamode            = scc_set_dmamode,
-       .mode_filter            = ata_pci_default_filter,
+       .mode_filter            = scc_mode_filter,
 
        .tf_load                = scc_tf_load,
        .tf_read                = scc_tf_read,
index 3de183461c3c42a9f46c1500fe32b4e8c4610ffa..a9c948d7604af602632ed3fba4c5772ad456e3ea 100644 (file)
@@ -190,34 +190,34 @@ static void inic_reset_port(void __iomem *port_base)
        writew(ctl, idma_ctl);
 }
 
-static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
 {
        void __iomem *scr_addr = ap->ioaddr.scr_addr;
        void __iomem *addr;
-       u32 val;
 
        if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
-               return 0xffffffffU;
+               return -EINVAL;
 
        addr = scr_addr + scr_map[sc_reg] * 4;
-       val = readl(scr_addr + scr_map[sc_reg] * 4);
+       *val = readl(scr_addr + scr_map[sc_reg] * 4);
 
        /* this controller has stuck DIAG.N, ignore it */
        if (sc_reg == SCR_ERROR)
-               val &= ~SERR_PHYRDY_CHG;
-       return val;
+               *val &= ~SERR_PHYRDY_CHG;
+       return 0;
 }
 
-static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
 {
        void __iomem *scr_addr = ap->ioaddr.scr_addr;
        void __iomem *addr;
 
        if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
-               return;
+               return -EINVAL;
 
        addr = scr_addr + scr_map[sc_reg] * 4;
        writel(val, scr_addr + scr_map[sc_reg] * 4);
+       return 0;
 }
 
 /*
index fb8a749423ca6634f3f8dff199db09841a24d497..8ec520885b959557d0dc8d6bc3d80407cda3460f 100644 (file)
@@ -35,8 +35,6 @@
 
   6) Add port multiplier support (intermediate)
 
-  7) Test and verify 3.0 Gbps support
-
   8) Develop a low-power-consumption strategy, and implement it.
 
   9) [Experiment, low priority] See if ATAPI can be supported using
@@ -227,26 +225,26 @@ enum {
 
        EDMA_ERR_IRQ_CAUSE_OFS  = 0x8,
        EDMA_ERR_IRQ_MASK_OFS   = 0xc,
-       EDMA_ERR_D_PAR          = (1 << 0),
-       EDMA_ERR_PRD_PAR        = (1 << 1),
-       EDMA_ERR_DEV            = (1 << 2),
-       EDMA_ERR_DEV_DCON       = (1 << 3),
-       EDMA_ERR_DEV_CON        = (1 << 4),
-       EDMA_ERR_SERR           = (1 << 5),
+       EDMA_ERR_D_PAR          = (1 << 0),     /* UDMA data parity err */
+       EDMA_ERR_PRD_PAR        = (1 << 1),     /* UDMA PRD parity err */
+       EDMA_ERR_DEV            = (1 << 2),     /* device error */
+       EDMA_ERR_DEV_DCON       = (1 << 3),     /* device disconnect */
+       EDMA_ERR_DEV_CON        = (1 << 4),     /* device connected */
+       EDMA_ERR_SERR           = (1 << 5),     /* SError bits [WBDST] raised */
        EDMA_ERR_SELF_DIS       = (1 << 7),     /* Gen II/IIE self-disable */
        EDMA_ERR_SELF_DIS_5     = (1 << 8),     /* Gen I self-disable */
-       EDMA_ERR_BIST_ASYNC     = (1 << 8),
+       EDMA_ERR_BIST_ASYNC     = (1 << 8),     /* BIST FIS or Async Notify */
        EDMA_ERR_TRANS_IRQ_7    = (1 << 8),     /* Gen IIE transprt layer irq */
-       EDMA_ERR_CRBQ_PAR       = (1 << 9),
-       EDMA_ERR_CRPB_PAR       = (1 << 10),
-       EDMA_ERR_INTRL_PAR      = (1 << 11),
-       EDMA_ERR_IORDY          = (1 << 12),
-       EDMA_ERR_LNK_CTRL_RX    = (0xf << 13),
+       EDMA_ERR_CRQB_PAR       = (1 << 9),     /* CRQB parity error */
+       EDMA_ERR_CRPB_PAR       = (1 << 10),    /* CRPB parity error */
+       EDMA_ERR_INTRL_PAR      = (1 << 11),    /* internal parity error */
+       EDMA_ERR_IORDY          = (1 << 12),    /* IORdy timeout */
+       EDMA_ERR_LNK_CTRL_RX    = (0xf << 13),  /* link ctrl rx error */
        EDMA_ERR_LNK_CTRL_RX_2  = (1 << 15),
-       EDMA_ERR_LNK_DATA_RX    = (0xf << 17),
-       EDMA_ERR_LNK_CTRL_TX    = (0x1f << 21),
-       EDMA_ERR_LNK_DATA_TX    = (0x1f << 26),
-       EDMA_ERR_TRANS_PROTO    = (1 << 31),
+       EDMA_ERR_LNK_DATA_RX    = (0xf << 17),  /* link data rx error */
+       EDMA_ERR_LNK_CTRL_TX    = (0x1f << 21), /* link ctrl tx error */
+       EDMA_ERR_LNK_DATA_TX    = (0x1f << 26), /* link data tx error */
+       EDMA_ERR_TRANS_PROTO    = (1 << 31),    /* transport protocol error */
        EDMA_ERR_OVERRUN_5      = (1 << 5),
        EDMA_ERR_UNDERRUN_5     = (1 << 6),
        EDMA_EH_FREEZE          = EDMA_ERR_D_PAR |
@@ -255,7 +253,7 @@ enum {
                                  EDMA_ERR_DEV_CON |
                                  EDMA_ERR_SERR |
                                  EDMA_ERR_SELF_DIS |
-                                 EDMA_ERR_CRBQ_PAR |
+                                 EDMA_ERR_CRQB_PAR |
                                  EDMA_ERR_CRPB_PAR |
                                  EDMA_ERR_INTRL_PAR |
                                  EDMA_ERR_IORDY |
@@ -270,7 +268,7 @@ enum {
                                  EDMA_ERR_OVERRUN_5 |
                                  EDMA_ERR_UNDERRUN_5 |
                                  EDMA_ERR_SELF_DIS_5 |
-                                 EDMA_ERR_CRBQ_PAR |
+                                 EDMA_ERR_CRQB_PAR |
                                  EDMA_ERR_CRPB_PAR |
                                  EDMA_ERR_INTRL_PAR |
                                  EDMA_ERR_IORDY,
@@ -286,10 +284,10 @@ enum {
        EDMA_RSP_Q_OUT_PTR_OFS  = 0x24,         /* also contains BASE_LO */
        EDMA_RSP_Q_PTR_SHIFT    = 3,
 
-       EDMA_CMD_OFS            = 0x28,
-       EDMA_EN                 = (1 << 0),
-       EDMA_DS                 = (1 << 1),
-       ATA_RST                 = (1 << 2),
+       EDMA_CMD_OFS            = 0x28,         /* EDMA command register */
+       EDMA_EN                 = (1 << 0),     /* enable EDMA */
+       EDMA_DS                 = (1 << 1),     /* disable EDMA; self-negated */
+       ATA_RST                 = (1 << 2),     /* reset trans/link/phy */
 
        EDMA_IORDY_TMOUT        = 0x34,
        EDMA_ARB_CFG            = 0x38,
@@ -301,14 +299,13 @@ enum {
        MV_HP_ERRATA_60X1B2     = (1 << 3),
        MV_HP_ERRATA_60X1C0     = (1 << 4),
        MV_HP_ERRATA_XX42A0     = (1 << 5),
-       MV_HP_GEN_I             = (1 << 6),
-       MV_HP_GEN_II            = (1 << 7),
-       MV_HP_GEN_IIE           = (1 << 8),
+       MV_HP_GEN_I             = (1 << 6),     /* Generation I: 50xx */
+       MV_HP_GEN_II            = (1 << 7),     /* Generation II: 60xx */
+       MV_HP_GEN_IIE           = (1 << 8),     /* Generation IIE: 6042/7042 */
 
        /* Port private flags (pp_flags) */
-       MV_PP_FLAG_EDMA_EN      = (1 << 0),
-       MV_PP_FLAG_EDMA_DS_ACT  = (1 << 1),
-       MV_PP_FLAG_HAD_A_RESET  = (1 << 2),
+       MV_PP_FLAG_EDMA_EN      = (1 << 0),     /* is EDMA engine enabled? */
+       MV_PP_FLAG_HAD_A_RESET  = (1 << 2),     /* 1st hard reset complete? */
 };
 
 #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -318,8 +315,12 @@ enum {
 enum {
        MV_DMA_BOUNDARY         = 0xffffffffU,
 
+       /* mask of register bits containing lower 32 bits
+        * of EDMA request queue DMA address
+        */
        EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
 
+       /* ditto, for response queue */
        EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
 };
 
@@ -403,10 +404,10 @@ struct mv_host_priv {
 };
 
 static void mv_irq_clear(struct ata_port *ap);
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
 static int mv_port_start(struct ata_port *ap);
 static void mv_port_stop(struct ata_port *ap);
 static void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -823,7 +824,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
 }
 
 /**
- *      mv_stop_dma - Disable eDMA engine
+ *      __mv_stop_dma - Disable eDMA engine
  *      @ap: ATA channel to manipulate
  *
  *      Verify the local cache of the eDMA state is accurate with a
@@ -832,7 +833,7 @@ static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_stop_dma(struct ata_port *ap)
+static int __mv_stop_dma(struct ata_port *ap)
 {
        void __iomem *port_mmio = mv_ap_base(ap);
        struct mv_port_priv *pp = ap->private_data;
@@ -865,6 +866,18 @@ static int mv_stop_dma(struct ata_port *ap)
        return err;
 }
 
+static int mv_stop_dma(struct ata_port *ap)
+{
+       unsigned long flags;
+       int rc;
+
+       spin_lock_irqsave(&ap->host->lock, flags);
+       rc = __mv_stop_dma(ap);
+       spin_unlock_irqrestore(&ap->host->lock, flags);
+
+       return rc;
+}
+
 #ifdef ATA_DEBUG
 static void mv_dump_mem(void __iomem *start, unsigned bytes)
 {
@@ -961,22 +974,26 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
        return ofs;
 }
 
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
        unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-       if (0xffffffffU != ofs)
-               return readl(mv_ap_base(ap) + ofs);
-       else
-               return (u32) ofs;
+       if (ofs != 0xffffffffU) {
+               *val = readl(mv_ap_base(ap) + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
        unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-       if (0xffffffffU != ofs)
+       if (ofs != 0xffffffffU) {
                writelfl(val, mv_ap_base(ap) + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
 static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
@@ -1029,6 +1046,7 @@ static int mv_port_start(struct ata_port *ap)
        void __iomem *port_mmio = mv_ap_base(ap);
        void *mem;
        dma_addr_t mem_dma;
+       unsigned long flags;
        int rc;
 
        pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
@@ -1067,10 +1085,14 @@ static int mv_port_start(struct ata_port *ap)
        pp->sg_tbl = mem;
        pp->sg_tbl_dma = mem_dma;
 
+       spin_lock_irqsave(&ap->host->lock, flags);
+
        mv_edma_cfg(ap, hpriv, port_mmio);
 
        mv_set_edma_ptrs(port_mmio, hpriv, pp);
 
+       spin_unlock_irqrestore(&ap->host->lock, flags);
+
        /* Don't turn on EDMA here...do it before DMA commands only.  Else
         * we'll be unable to send non-data, PIO, etc due to restricted access
         * to shadow regs.
@@ -1090,11 +1112,7 @@ static int mv_port_start(struct ata_port *ap)
  */
 static void mv_port_stop(struct ata_port *ap)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ap->host->lock, flags);
        mv_stop_dma(ap);
-       spin_unlock_irqrestore(&ap->host->lock, flags);
 }
 
 /**
@@ -1325,7 +1343,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
                 * port.  Turn off EDMA so there won't be problems accessing
                 * shadow block, etc registers.
                 */
-               mv_stop_dma(ap);
+               __mv_stop_dma(ap);
                return ata_qc_issue_prot(qc);
        }
 
@@ -1393,16 +1411,16 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
        if (edma_err_cause & EDMA_ERR_DEV)
                err_mask |= AC_ERR_DEV;
        if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
-                       EDMA_ERR_CRBQ_PAR | EDMA_ERR_CRPB_PAR |
+                       EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
                        EDMA_ERR_INTRL_PAR)) {
                err_mask |= AC_ERR_ATA_BUS;
                action |= ATA_EH_HARDRESET;
-               ata_ehi_push_desc(ehi, "parity error");
+               ata_ehi_push_desc(ehi, "parity error");
        }
        if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
                ata_ehi_hotplugged(ehi);
                ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
-                       ", dev disconnect" : ", dev connect");
+                       "dev disconnect" : "dev connect");
        }
 
        if (IS_GEN_I(hpriv)) {
@@ -1411,7 +1429,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
                        struct mv_port_priv *pp = ap->private_data;
                        pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-                       ata_ehi_push_desc(ehi, "EDMA self-disable");
+                       ata_ehi_push_desc(ehi, "EDMA self-disable");
                }
        } else {
                eh_freeze_mask = EDMA_EH_FREEZE;
@@ -1419,7 +1437,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
                if (edma_err_cause & EDMA_ERR_SELF_DIS) {
                        struct mv_port_priv *pp = ap->private_data;
                        pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-                       ata_ehi_push_desc(ehi, "EDMA self-disable");
+                       ata_ehi_push_desc(ehi, "EDMA self-disable");
                }
 
                if (edma_err_cause & EDMA_ERR_SERR) {
@@ -1489,33 +1507,30 @@ static void mv_intr_edma(struct ata_port *ap)
 
        while (1) {
                u16 status;
+               unsigned int tag;
 
                /* get s/w response queue last-read pointer, and compare */
                out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
                if (in_index == out_index)
                        break;
 
-                
                /* 50xx: get active ATA command */
-               if (IS_GEN_I(hpriv)) 
-                       qc = ata_qc_from_tag(ap, ap->active_tag);
+               if (IS_GEN_I(hpriv))
+                       tag = ap->active_tag;
 
-               /* 60xx: get active ATA command via tag, to enable support
-                * for queueing.  this works transparently for queued and
-                * non-queued modes.
+               /* Gen II/IIE: get active ATA command via tag, to enable
+                * support for queueing.  this works transparently for
+                * queued and non-queued modes.
                 */
-               else {
-                       unsigned int tag;
+               else if (IS_GEN_II(hpriv))
+                       tag = (le16_to_cpu(pp->crpb[out_index].id)
+                               >> CRPB_IOID_SHIFT_6) & 0x3f;
 
-                       if (IS_GEN_II(hpriv))
-                               tag = (le16_to_cpu(pp->crpb[out_index].id)
-                                       >> CRPB_IOID_SHIFT_6) & 0x3f;
-                       else
-                               tag = (le16_to_cpu(pp->crpb[out_index].id)
-                                       >> CRPB_IOID_SHIFT_7) & 0x3f;
+               else /* IS_GEN_IIE */
+                       tag = (le16_to_cpu(pp->crpb[out_index].id)
+                               >> CRPB_IOID_SHIFT_7) & 0x3f;
 
-                       qc = ata_qc_from_tag(ap, tag);
-               }
+               qc = ata_qc_from_tag(ap, tag);
 
                /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
                 * bits (WARNING: might not necessarily be associated
@@ -1535,7 +1550,7 @@ static void mv_intr_edma(struct ata_port *ap)
                        ata_qc_complete(qc);
                }
 
-               /* advance software response queue pointer, to 
+               /* advance software response queue pointer, to
                 * indicate (after the loop completes) to hardware
                 * that we have consumed a response queue entry.
                 */
@@ -1741,26 +1756,30 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
        return ofs;
 }
 
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
        void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-       if (ofs != 0xffffffffU)
-               return readl(addr + ofs);
-       else
-               return (u32) ofs;
+       if (ofs != 0xffffffffU) {
+               *val = readl(addr + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
        void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
        void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
        unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-       if (ofs != 0xffffffffU)
+       if (ofs != 0xffffffffU) {
                writelfl(val, addr + ofs);
+               return 0;
+       } else
+               return -EINVAL;
 }
 
 static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
@@ -2138,9 +2157,17 @@ static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
 
        VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
 
-       DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
-               "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-               mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+       {
+               u32 sstatus, serror, scontrol;
+
+               mv_scr_read(ap, SCR_STATUS, &sstatus);
+               mv_scr_read(ap, SCR_ERROR, &serror);
+               mv_scr_read(ap, SCR_CONTROL, &scontrol);
+               DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+                       "SCtrl 0x%08x\n", status, serror, scontrol);
+       }
+#endif
 
        /* Issue COMRESET via SControl */
 comreset_retry:
@@ -2164,9 +2191,17 @@ comreset_retry:
            (retry-- > 0))
                goto comreset_retry;
 
-       DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
-               "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-               mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+       {
+               u32 sstatus, serror, scontrol;
+
+               mv_scr_read(ap, SCR_STATUS, &sstatus);
+               mv_scr_read(ap, SCR_ERROR, &serror);
+               mv_scr_read(ap, SCR_CONTROL, &scontrol);
+               DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+                       "SCtrl 0x%08x\n", sstatus, serror, scontrol);
+       }
+#endif
 
        if (ata_port_offline(ap)) {
                *class = ATA_DEV_NONE;
@@ -2209,7 +2244,7 @@ static int mv_prereset(struct ata_port *ap, unsigned long deadline)
        struct mv_port_priv *pp = ap->private_data;
        struct ata_eh_context *ehc = &ap->eh_context;
        int rc;
-       
+
        rc = mv_stop_dma(ap);
        if (rc)
                ehc->i.action |= ATA_EH_HARDRESET;
index db81e3efa5ec4f03c3d8ab7888a07bd632cb3589..0b58c4df6fd2a800c23dfe59390abb8d1055ca2b 100644 (file)
@@ -236,8 +236,8 @@ static void nv_ck804_host_stop(struct ata_host *host);
 static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static void nv_nf2_freeze(struct ata_port *ap);
 static void nv_nf2_thaw(struct ata_port *ap);
@@ -715,19 +715,20 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
                int freeze = 0;
 
                ata_ehi_clear_desc(ehi);
-               ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+               __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags );
                if (flags & NV_CPB_RESP_ATA_ERR) {
-                       ata_ehi_push_desc(ehi, "ATA error");
+                       ata_ehi_push_desc(ehi, "ATA error");
                        ehi->err_mask |= AC_ERR_DEV;
                } else if (flags & NV_CPB_RESP_CMD_ERR) {
-                       ata_ehi_push_desc(ehi, "CMD error");
+                       ata_ehi_push_desc(ehi, "CMD error");
                        ehi->err_mask |= AC_ERR_DEV;
                } else if (flags & NV_CPB_RESP_CPB_ERR) {
-                       ata_ehi_push_desc(ehi, "CPB error");
+                       ata_ehi_push_desc(ehi, "CPB error");
                        ehi->err_mask |= AC_ERR_SYSTEM;
                        freeze = 1;
                } else {
                        /* notifier error, but no error in CPB flags? */
+                       ata_ehi_push_desc(ehi, "unknown");
                        ehi->err_mask |= AC_ERR_OTHER;
                        freeze = 1;
                }
@@ -854,20 +855,21 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                                struct ata_eh_info *ehi = &ap->eh_info;
 
                                ata_ehi_clear_desc(ehi);
-                               ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
+                               __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
                                if (status & NV_ADMA_STAT_TIMEOUT) {
                                        ehi->err_mask |= AC_ERR_SYSTEM;
-                                       ata_ehi_push_desc(ehi, "timeout");
+                                       ata_ehi_push_desc(ehi, "timeout");
                                } else if (status & NV_ADMA_STAT_HOTPLUG) {
                                        ata_ehi_hotplugged(ehi);
-                                       ata_ehi_push_desc(ehi, "hotplug");
+                                       ata_ehi_push_desc(ehi, "hotplug");
                                } else if (status & NV_ADMA_STAT_HOTUNPLUG) {
                                        ata_ehi_hotplugged(ehi);
-                                       ata_ehi_push_desc(ehi, "hot unplug");
+                                       ata_ehi_push_desc(ehi, "hot unplug");
                                } else if (status & NV_ADMA_STAT_SERROR) {
                                        /* let libata analyze SError and figure out the cause */
-                                       ata_ehi_push_desc(ehi, ": SError");
-                               }
+                                       ata_ehi_push_desc(ehi, "SError");
+                               } else
+                                       ata_ehi_push_desc(ehi, "unknown");
                                ata_port_freeze(ap);
                                continue;
                        }
@@ -1391,20 +1393,22 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
        return ret;
 }
 
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
+               return -EINVAL;
 
-       return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+       *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
 
        iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 static void nv_nf2_freeze(struct ata_port *ap)
index d2fcb9a6bec2a024ef4a2dcbb9369cf592618d31..d39ebc23c4a9e45ec0ac24474af5142f0cfb130e 100644 (file)
@@ -128,8 +128,8 @@ struct pdc_port_priv {
        dma_addr_t              pkt_dma;
 };
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int pdc_common_port_start(struct ata_port *ap);
 static int pdc_sata_port_start(struct ata_port *ap);
@@ -427,19 +427,20 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
        return ATA_CBL_SATA;
 }
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+               return -EINVAL;
+       *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-                              u32 val)
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
@@ -642,8 +643,12 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
                           | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
                ac_err_mask |= AC_ERR_HOST_BUS;
 
-       if (sata_scr_valid(ap))
-               ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+       if (sata_scr_valid(ap)) {
+               u32 serror;
+
+               pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+               ehi->serror |= serror;
+       }
 
        qc->err_mask |= ac_err_mask;
 
index 9ab554da89bfd89301521a8deb1ec17306b0ff3f..c8f9242e7f44b04670a458291c2d101191e3f9f8 100644 (file)
@@ -111,8 +111,8 @@ struct qs_port_priv {
        qs_state_t              state;
 };
 
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int qs_port_start(struct ata_port *ap);
 static void qs_host_stop(struct ata_host *host);
@@ -255,18 +255,20 @@ static void qs_eng_timeout(struct ata_port *ap)
        ata_eng_timeout(ap);
 }
 
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return ~0U;
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+               return -EINVAL;
+       *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+       return 0;
 }
 
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+       return 0;
 }
 
 static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
@@ -337,7 +339,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
        buf[28] = dflags;
 
        /* frame information structure (FIS) */
-       ata_tf_to_fis(&qc->tf, &buf[32], 0);
+       ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
 }
 
 static inline void qs_packet_start(struct ata_queued_cmd *qc)
index 2a86dc4598d04b479e1d2654f256ee49656a393b..db67637589520c02b3289421ae79579f4e84d4a8 100644 (file)
@@ -115,8 +115,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int sil_pci_device_resume(struct pci_dev *pdev);
 #endif
 static void sil_dev_config(struct ata_device *dev);
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
@@ -350,19 +350,26 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re
        return NULL;
 }
 
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        void __iomem *mmio = sil_scr_addr(ap, sc_reg);
-       if (mmio)
-               return readl(mmio);
-       return 0xffffffffU;
+
+       if (mmio) {
+               *val = readl(mmio);
+               return 0;
+       }
+       return -EINVAL;
 }
 
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        void __iomem *mmio = sil_scr_addr(ap, sc_reg);
-       if (mmio)
+
+       if (mmio) {
                writel(val, mmio);
+               return 0;
+       }
+       return -EINVAL;
 }
 
 static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
@@ -378,7 +385,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
                 * controllers continue to assert IRQ as long as
                 * SError bits are pending.  Clear SError immediately.
                 */
-               serror = sil_scr_read(ap, SCR_ERROR);
+               sil_scr_read(ap, SCR_ERROR, &serror);
                sil_scr_write(ap, SCR_ERROR, serror);
 
                /* Trigger hotplug and accumulate SError only if the
index ac43a30ebe2925095e330a9dbc26347e83dddbcf..46fbbe7f121c2da1ca115a383800ee9f3525da5c 100644 (file)
@@ -326,8 +326,8 @@ struct sil24_port_priv {
 
 static void sil24_dev_config(struct ata_device *dev);
 static u8 sil24_check_status(struct ata_port *ap);
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
@@ -464,15 +464,15 @@ static void sil24_dev_config(struct ata_device *dev)
                writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
 }
 
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
 {
-       struct sil24_port_priv *pp = ap->private_data;
        void __iomem *port = ap->ioaddr.cmd_addr;
-       struct sil24_prb __iomem *prb = port;
+       struct sil24_prb __iomem *prb;
        u8 fis[6 * 4];
 
-       memcpy_fromio(fis, prb->fis, 6 * 4);
-       ata_tf_from_fis(fis, &pp->tf);
+       prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
+       memcpy_fromio(fis, prb->fis, sizeof(fis));
+       ata_tf_from_fis(fis, tf);
 }
 
 static u8 sil24_check_status(struct ata_port *ap)
@@ -488,25 +488,30 @@ static int sil24_scr_map[] = {
        [SCR_ACTIVE]    = 3,
 };
 
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
 {
        void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
        if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
                void __iomem *addr;
                addr = scr_addr + sil24_scr_map[sc_reg] * 4;
-               return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+               *val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+               return 0;
        }
-       return 0xffffffffU;
+       return -EINVAL;
 }
 
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
 {
        void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
        if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
                void __iomem *addr;
                addr = scr_addr + sil24_scr_map[sc_reg] * 4;
                writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
+               return 0;
        }
+       return -EINVAL;
 }
 
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -531,15 +536,60 @@ static int sil24_init_port(struct ata_port *ap)
        return 0;
 }
 
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
-                          unsigned long deadline)
+static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
+                                const struct ata_taskfile *tf,
+                                int is_cmd, u32 ctrl,
+                                unsigned long timeout_msec)
 {
        void __iomem *port = ap->ioaddr.cmd_addr;
        struct sil24_port_priv *pp = ap->private_data;
        struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
        dma_addr_t paddr = pp->cmd_block_dma;
-       u32 mask, irq_stat;
+       u32 irq_enabled, irq_mask, irq_stat;
+       int rc;
+
+       prb->ctrl = cpu_to_le16(ctrl);
+       ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
+
+       /* temporarily plug completion and error interrupts */
+       irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
+       writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+
+       writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+       writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+       irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+       irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+                                    10, timeout_msec);
+
+       writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
+       irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+       if (irq_stat & PORT_IRQ_COMPLETE)
+               rc = 0;
+       else {
+               /* force port into known state */
+               sil24_init_port(ap);
+
+               if (irq_stat & PORT_IRQ_ERROR)
+                       rc = -EIO;
+               else
+                       rc = -EBUSY;
+       }
+
+       /* restore IRQ enabled */
+       writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
+
+       return rc;
+}
+
+static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
+                             int pmp, unsigned long deadline)
+{
+       unsigned long timeout_msec = 0;
+       struct ata_taskfile tf;
        const char *reason;
+       int rc;
 
        DPRINTK("ENTER\n");
 
@@ -556,29 +606,22 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
        }
 
        /* do SRST */
-       prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
-       prb->fis[1] = 0; /* no PMP yet */
-
-       writel((u32)paddr, port + PORT_CMD_ACTIVATE);
-       writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
-       mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
-       irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
-                                    100, jiffies_to_msecs(deadline - jiffies));
-
-       writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
-       irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
-       if (!(irq_stat & PORT_IRQ_COMPLETE)) {
-               if (irq_stat & PORT_IRQ_ERROR)
-                       reason = "SRST command error";
-               else
-                       reason = "timeout";
+       if (time_after(deadline, jiffies))
+               timeout_msec = jiffies_to_msecs(deadline - jiffies);
+
+       ata_tf_init(ap->device, &tf);   /* doesn't really matter */
+       rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
+                                  timeout_msec);
+       if (rc == -EBUSY) {
+               reason = "timeout";
+               goto err;
+       } else if (rc) {
+               reason = "SRST command error";
                goto err;
        }
 
-       sil24_update_tf(ap);
-       *class = ata_dev_classify(&pp->tf);
+       sil24_read_tf(ap, 0, &tf);
+       *class = ata_dev_classify(&tf);
 
        if (*class == ATA_DEV_UNKNOWN)
                *class = ATA_DEV_NONE;
@@ -592,6 +635,12 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
        return -EIO;
 }
 
+static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+                          unsigned long deadline)
+{
+       return sil24_do_softreset(ap, class, 0, deadline);
+}
+
 static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
                           unsigned long deadline)
 {
@@ -699,7 +748,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
        }
 
        prb->ctrl = cpu_to_le16(ctrl);
-       ata_tf_to_fis(&qc->tf, prb->fis, 0);
+       ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
 
        if (qc->flags & ATA_QCFLAG_DMAMAP)
                sil24_fill_sg(qc, sge);
@@ -754,6 +803,7 @@ static void sil24_thaw(struct ata_port *ap)
 static void sil24_error_intr(struct ata_port *ap)
 {
        void __iomem *port = ap->ioaddr.cmd_addr;
+       struct sil24_port_priv *pp = ap->private_data;
        struct ata_eh_info *ehi = &ap->eh_info;
        int freeze = 0;
        u32 irq_stat;
@@ -769,16 +819,16 @@ static void sil24_error_intr(struct ata_port *ap)
 
        if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
                ata_ehi_hotplugged(ehi);
-               ata_ehi_push_desc(ehi, "%s",
-                              irq_stat & PORT_IRQ_PHYRDY_CHG ?
-                              "PHY RDY changed" : "device exchanged");
+               ata_ehi_push_desc(ehi, "%s",
+                                 irq_stat & PORT_IRQ_PHYRDY_CHG ?
+                                 "PHY RDY changed" : "device exchanged");
                freeze = 1;
        }
 
        if (irq_stat & PORT_IRQ_UNK_FIS) {
                ehi->err_mask |= AC_ERR_HSM;
                ehi->action |= ATA_EH_SOFTRESET;
-               ata_ehi_push_desc(ehi , ", unknown FIS");
+               ata_ehi_push_desc(ehi, "unknown FIS");
                freeze = 1;
        }
 
@@ -797,18 +847,18 @@ static void sil24_error_intr(struct ata_port *ap)
                if (ci && ci->desc) {
                        err_mask |= ci->err_mask;
                        action |= ci->action;
-                       ata_ehi_push_desc(ehi, "%s", ci->desc);
+                       ata_ehi_push_desc(ehi, "%s", ci->desc);
                } else {
                        err_mask |= AC_ERR_OTHER;
                        action |= ATA_EH_SOFTRESET;
-                       ata_ehi_push_desc(ehi, "unknown command error %d",
+                       ata_ehi_push_desc(ehi, "unknown command error %d",
                                          cerr);
                }
 
                /* record error info */
                qc = ata_qc_from_tag(ap, ap->active_tag);
                if (qc) {
-                       sil24_update_tf(ap);
+                       sil24_read_tf(ap, qc->tag, &pp->tf);
                        qc->err_mask |= err_mask;
                } else
                        ehi->err_mask |= err_mask;
@@ -825,8 +875,11 @@ static void sil24_error_intr(struct ata_port *ap)
 
 static void sil24_finish_qc(struct ata_queued_cmd *qc)
 {
+       struct ata_port *ap = qc->ap;
+       struct sil24_port_priv *pp = ap->private_data;
+
        if (qc->flags & ATA_QCFLAG_RESULT_TF)
-               sil24_update_tf(qc->ap);
+               sil24_read_tf(ap, qc->tag, &pp->tf);
 }
 
 static inline void sil24_host_intr(struct ata_port *ap)
index 33716b00c6b7ec1de843a36772303a035e52ed31..31a2f55aae666c137d8b7bbf8bf556e84978ef0e 100644 (file)
@@ -64,8 +64,8 @@ enum {
 };
 
 static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id sis_pci_tbl[] = {
        { PCI_VDEVICE(SI, 0x0180), sis_180 },           /* SiS 964/180 */
@@ -207,36 +207,37 @@ static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val
                pci_write_config_dword(pdev, cfg_addr+0x10, val);
 }
 
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-       u32 val, val2 = 0;
        u8 pmr;
 
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
+               return -EINVAL;
 
        if (ap->flags & SIS_FLAG_CFGSCR)
                return sis_scr_cfg_read(ap, sc_reg);
 
        pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
-       val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+       *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
 
        if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
            (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
-               val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+               *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+
+       *val &= 0xfffffffb;
 
-       return (val | val2) &  0xfffffffb;
+       return 0;
 }
 
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host->dev);
        u8 pmr;
 
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
 
        pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
@@ -248,6 +249,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
                    (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
                        iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
        }
+       return 0;
 }
 
 static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
index 63fe99afd59f3a782cb45a869fcbc36c96cde9ad..92e8770750375d35ed129131fc96bd710235ef93 100644 (file)
@@ -103,20 +103,21 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
        return 0;
 }
 
-static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+               return -EINVAL;
+       *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 
-static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-                              u32 val)
+static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 
index b52f83ab056ac30256ef2b9c6d75831fdf9efc52..78c28512f01c634e2050256a976fe45721f531fb 100644 (file)
@@ -57,8 +57,8 @@ struct uli_priv {
 };
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id uli_pci_tbl[] = {
        { PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -164,20 +164,22 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
        pci_write_config_dword(pdev, cfg_addr, val);
 }
 
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
+               return -EINVAL;
 
-       return uli_scr_cfg_read(ap, sc_reg);
+       *val = uli_scr_cfg_read(ap, sc_reg);
+       return 0;
 }
 
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)       //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
-               return;
+               return -EINVAL;
 
        uli_scr_cfg_write(ap, sc_reg, val);
+       return 0;
 }
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
index c4124475f754f101fc427a63934901d59de9083b..86b7bfc173244a203bf11977eba1fbe268db7799 100644 (file)
@@ -72,8 +72,8 @@ enum {
 };
 
 static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void svia_noop_freeze(struct ata_port *ap);
 static void vt6420_error_handler(struct ata_port *ap);
 static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -249,18 +249,20 @@ MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
-       return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+               return -EINVAL;
+       *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+       return 0;
 }
 
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+       return 0;
 }
 
 static void svia_noop_freeze(struct ata_port *ap)
@@ -305,18 +307,19 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
 
        /* Resume phy.  This is the old SATA resume sequence */
        svia_scr_write(ap, SCR_CONTROL, 0x300);
-       svia_scr_read(ap, SCR_CONTROL); /* flush */
+       svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
 
        /* wait for phy to become ready, if necessary */
        do {
                msleep(200);
-               if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+               svia_scr_read(ap, SCR_STATUS, &sstatus);
+               if ((sstatus & 0xf) != 1)
                        break;
        } while (time_before(jiffies, timeout));
 
        /* open code sata_print_link_status() */
-       sstatus = svia_scr_read(ap, SCR_STATUS);
-       scontrol = svia_scr_read(ap, SCR_CONTROL);
+       svia_scr_read(ap, SCR_STATUS, &sstatus);
+       svia_scr_read(ap, SCR_CONTROL, &scontrol);
 
        online = (sstatus & 0xf) == 0x3;
 
@@ -325,7 +328,7 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
                        online ? "up" : "down", sstatus, scontrol);
 
        /* SStatus is read one more time */
-       svia_scr_read(ap, SCR_STATUS);
+       svia_scr_read(ap, SCR_STATUS, &sstatus);
 
        if (!online) {
                /* tell EH to bail */
index 1b5d81faa10248c740694adcdc4e62c83c1363dd..24344d0d0575b10dc394ad501c22fd15f653e04e 100644 (file)
@@ -98,20 +98,21 @@ enum {
                              VSC_SATA_INT_PHY_CHANGE),
 };
 
-static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
        if (sc_reg > SCR_CONTROL)
-               return 0xffffffffU;
-       return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+               return -EINVAL;
+       *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 
-static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-                              u32 val)
+static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
        if (sc_reg > SCR_CONTROL)
-               return;
+               return -EINVAL;
        writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+       return 0;
 }
 
 
index 2288b55d916f9e12fc3ea2332acf40c3dfe67dff..d50b82381155d1990ee5434cc41bf7da59c60a24 100644 (file)
@@ -64,7 +64,6 @@ struct vdc_port {
        u64                     operations;
        u32                     vdisk_size;
        u8                      vdisk_type;
-       u8                      dev_no;
 
        char                    disk_name[32];
 
@@ -703,7 +702,7 @@ static int probe_disk(struct vdc_port *port)
        blk_queue_max_phys_segments(q, port->ring_cookies);
        blk_queue_max_sectors(q, port->max_xfer_size);
        g->major = vdc_major;
-       g->first_minor = port->dev_no << PARTITION_SHIFT;
+       g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
        strcpy(g->disk_name, port->disk_name);
 
        g->fops = &vdc_fops;
@@ -747,21 +746,16 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
 {
        struct mdesc_handle *hp;
        struct vdc_port *port;
-       const u64 *port_id;
        int err;
 
        print_version();
 
        hp = mdesc_grab();
 
-       port_id = mdesc_get_property(hp, vdev->mp, "id", NULL);
        err = -ENODEV;
-       if (!port_id) {
-               printk(KERN_ERR PFX "Port lacks id property.\n");
-               goto err_out_release_mdesc;
-       }
-       if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
-               printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
+       if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+               printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+                      vdev->dev_no);
                goto err_out_release_mdesc;
        }
 
@@ -772,16 +766,14 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
                goto err_out_release_mdesc;
        }
 
-       port->dev_no = *port_id;
-
-       if (port->dev_no >= 26)
+       if (vdev->dev_no >= 26)
                snprintf(port->disk_name, sizeof(port->disk_name),
                         VDCBLK_NAME "%c%c",
-                        'a' + (port->dev_no / 26) - 1,
-                        'a' + (port->dev_no % 26));
+                        'a' + ((int)vdev->dev_no / 26) - 1,
+                        'a' + ((int)vdev->dev_no % 26));
        else
                snprintf(port->disk_name, sizeof(port->disk_name),
-                        VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
+                        VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
 
        err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
                              vdc_versions, ARRAY_SIZE(vdc_versions),
@@ -849,7 +841,7 @@ static struct vio_device_id vdc_port_match[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(vio, vdc_match);
+MODULE_DEVICE_TABLE(vio, vdc_port_match);
 
 static struct vio_driver vdc_port_driver = {
        .id_table       = vdc_port_match,
index 9e8f21410d2d06a3f499c5d22397a45fb5ff0472..c8dfd18bea443b9cb76f5c9fe84a88b5a834f5a1 100644 (file)
@@ -185,7 +185,7 @@ config ESPSERIAL
 
 config MOXA_INTELLIO
        tristate "Moxa Intellio support"
-       depends on SERIAL_NONSTANDARD
+       depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
        help
          Say Y here if you have a Moxa Intellio multiport serial card.
 
@@ -241,7 +241,7 @@ config SYNCLINK
 
 config SYNCLINKMP
        tristate "SyncLink Multiport support"
-       depends on SERIAL_NONSTANDARD
+       depends on SERIAL_NONSTANDARD && PCI
        help
          Enable support for the SyncLink Multiport (2 or 4 ports)
          serial adapter, running asynchronous and HDLC communications up
@@ -726,7 +726,7 @@ config NVRAM
 
 config RTC
        tristate "Enhanced Real Time Clock Support"
-       depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
+       depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC64 && (!SPARC32 || PCI) && !FRV && !ARM && !SUPERH && !S390
        ---help---
          If you say Y here and create a character special file /dev/rtc with
          major number 10 and minor number 135 using mknod ("man mknod"), you
index 0be700f4e8fd7acdceaec7dd3acf0acdf63a00d3..ba0e74ad74bbbc778eb485ed95ae089b15cab6a1 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/bcd.h>
 #include <linux/seq_file.h>
 #include <linux/bitops.h>
+#include <linux/clocksource.h>
 
 #include <asm/current.h>
 #include <asm/uaccess.h>
 
 #define HPET_RANGE_SIZE                1024    /* from HPET spec */
 
+#if BITS_PER_LONG == 64
+#define        write_counter(V, MC)    writeq(V, MC)
+#define        read_counter(MC)        readq(MC)
+#else
+#define        write_counter(V, MC)    writel(V, MC)
+#define        read_counter(MC)        readl(MC)
+#endif
+
 static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
 
+static void __iomem *hpet_mctr;
+
+static cycle_t read_hpet(void)
+{
+       return (cycle_t)read_counter((void __iomem *)hpet_mctr);
+}
+
+static struct clocksource clocksource_hpet = {
+        .name           = "hpet",
+        .rating         = 250,
+        .read           = read_hpet,
+        .mask           = 0xffffffffffffffff,
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 10,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+static struct clocksource *hpet_clocksource;
+
 /* A lock for concurrent access by app and isr hpet activity. */
 static DEFINE_SPINLOCK(hpet_lock);
 /* A lock for concurrent intermodule access to hpet and isr hpet activity. */
@@ -79,7 +106,7 @@ struct hpets {
        struct hpets *hp_next;
        struct hpet __iomem *hp_hpet;
        unsigned long hp_hpet_phys;
-       struct time_interpolator *hp_interpolator;
+       struct clocksource *hp_clocksource;
        unsigned long long hp_tick_freq;
        unsigned long hp_delta;
        unsigned int hp_ntimer;
@@ -94,13 +121,6 @@ static struct hpets *hpets;
 #define        HPET_PERIODIC           0x0004
 #define        HPET_SHARED_IRQ         0x0008
 
-#if BITS_PER_LONG == 64
-#define        write_counter(V, MC)    writeq(V, MC)
-#define        read_counter(MC)        readq(MC)
-#else
-#define        write_counter(V, MC)    writel(V, MC)
-#define        read_counter(MC)        readl(MC)
-#endif
 
 #ifndef readq
 static inline unsigned long long readq(void __iomem *addr)
@@ -737,27 +757,6 @@ static ctl_table dev_root[] = {
 
 static struct ctl_table_header *sysctl_header;
 
-static void hpet_register_interpolator(struct hpets *hpetp)
-{
-#ifdef CONFIG_TIME_INTERPOLATION
-       struct time_interpolator *ti;
-
-       ti = kzalloc(sizeof(*ti), GFP_KERNEL);
-       if (!ti)
-               return;
-
-       ti->source = TIME_SOURCE_MMIO64;
-       ti->shift = 10;
-       ti->addr = &hpetp->hp_hpet->hpet_mc;
-       ti->frequency = hpetp->hp_tick_freq;
-       ti->drift = HPET_DRIFT;
-       ti->mask = -1;
-
-       hpetp->hp_interpolator = ti;
-       register_time_interpolator(ti);
-#endif
-}
-
 /*
  * Adjustment for when arming the timer with
  * initial conditions.  That is, main counter
@@ -909,7 +908,16 @@ int hpet_alloc(struct hpet_data *hdp)
        }
 
        hpetp->hp_delta = hpet_calibrate(hpetp);
-       hpet_register_interpolator(hpetp);
+
+       if (!hpet_clocksource) {
+               hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
+               CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
+               clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
+                                               clocksource_hpet.shift);
+               clocksource_register(&clocksource_hpet);
+               hpetp->hp_clocksource = &clocksource_hpet;
+               hpet_clocksource = &clocksource_hpet;
+       }
 
        return 0;
 }
@@ -995,7 +1003,7 @@ static int hpet_acpi_add(struct acpi_device *device)
 
 static int hpet_acpi_remove(struct acpi_device *device, int type)
 {
-       /* XXX need to unregister interpolator, dealloc mem, etc */
+       /* XXX need to unregister clocksource, dealloc mem, etc */
        return -EINVAL;
 }
 
index 22cf7aa56cc470f6b04d464547c0cfc8a716efdf..30c3f54c7666ee5f7e666ec38ff125acfd0f2eeb 100644 (file)
 #include <asm/hpet.h>
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 #include <linux/pci.h>
 #include <asm/ebus.h>
-#ifdef __sparc_v9__
-#include <asm/isa.h>
-#endif
 
 static unsigned long rtc_port;
 static int rtc_irq = PCI_IRQ_NONE;
@@ -930,13 +927,9 @@ static int __init rtc_init(void)
        unsigned int year, ctrl;
        char *guess = NULL;
 #endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
        struct linux_ebus *ebus;
        struct linux_ebus_device *edev;
-#ifdef __sparc_v9__
-       struct sparc_isa_bridge *isa_br;
-       struct sparc_isa_device *isa_dev;
-#endif
 #else
        void *r;
 #ifdef RTC_IRQ
@@ -944,7 +937,7 @@ static int __init rtc_init(void)
 #endif
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
        for_each_ebus(ebus) {
                for_each_ebusdev(edev, ebus) {
                        if(strcmp(edev->prom_node->name, "rtc") == 0) {
@@ -954,17 +947,6 @@ static int __init rtc_init(void)
                        }
                }
        }
-#ifdef __sparc_v9__
-       for_each_isa(isa_br) {
-               for_each_isadev(isa_dev, isa_br) {
-                       if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
-                               rtc_port = isa_dev->resource.start;
-                               rtc_irq = isa_dev->irq;
-                               goto found;
-                       }
-               }
-       }
-#endif
        rtc_has_irq = 0;
        printk(KERN_ERR "rtc_init: no PC rtc found\n");
        return -EIO;
@@ -1020,7 +1002,7 @@ no_irq:
 
 #endif
 
-#endif /* __sparc__ vs. others */
+#endif /* CONFIG_SPARC32 vs. others */
 
        if (misc_register(&rtc_dev)) {
 #ifdef RTC_IRQ
@@ -1105,7 +1087,7 @@ static void __exit rtc_exit (void)
        remove_proc_entry ("driver/rtc", NULL);
        misc_deregister(&rtc_dev);
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
        if (rtc_has_irq)
                free_irq (rtc_irq, &rtc_port);
 #else
@@ -1117,7 +1099,7 @@ static void __exit rtc_exit (void)
        if (rtc_has_irq)
                free_irq (RTC_IRQ, NULL);
 #endif
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC32 */
 }
 
 module_init(rtc_init);
index c585b4738f86c2b670a46e54c4b5a154a2c5ed5d..f1497cecffd815248a7eb374a0346e4e8fb88e2f 100644 (file)
@@ -2573,16 +2573,10 @@ static struct tty_driver *serial167_console_device(struct console *c,
        return cy_serial_driver;
 }
 
-static int __init serial167_console_setup(struct console *co, char *options)
-{
-       return 0;
-}
-
 static struct console sercons = {
        .name = "ttyS",
        .write = serial167_console_write,
        .device = serial167_console_device,
-       .setup = serial167_console_setup,
        .flags = CON_PRINTBUFFER,
        .index = -1,
 };
index 4eba32b23b297c2f15bd942292c754bcc4d7708b..8677fc6a545eebe543d6ac26846879325e97bde5 100644 (file)
@@ -427,7 +427,7 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
                return -ENOMEM;
 
        if ((err = read_log(log)))
-               return err;
+               goto out_free;
 
        /* now register seq file */
        err = seq_open(file, &tpm_ascii_b_measurments_seqops);
@@ -435,10 +435,15 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
                seq = file->private_data;
                seq->private = log;
        } else {
-               kfree(log->bios_event_log);
-               kfree(log);
+               goto out_free;
        }
+
+out:
        return err;
+out_free:
+       kfree(log->bios_event_log);
+       kfree(log);
+       goto out;
 }
 
 const struct file_operations tpm_ascii_bios_measurements_ops = {
@@ -460,7 +465,7 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
                return -ENOMEM;
 
        if ((err = read_log(log)))
-               return err;
+               goto out_free;
 
        /* now register seq file */
        err = seq_open(file, &tpm_binary_b_measurments_seqops);
@@ -468,10 +473,15 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
                seq = file->private_data;
                seq->private = log;
        } else {
-               kfree(log->bios_event_log);
-               kfree(log);
+               goto out_free;
        }
+
+out:
        return err;
+out_free:
+       kfree(log->bios_event_log);
+       kfree(log);
+       goto out;
 }
 
 const struct file_operations tpm_binary_bios_measurements_ops = {
index bef6d886d4fb2f6e3e2ea3b69ee1da3e29673b0c..e122a0e87bb0b8a53984262ae29bc5d0d3e34e63 100644 (file)
@@ -1013,18 +1013,10 @@ static struct tty_driver *scc_console_device(struct console *c, int *index)
        return scc_driver;
 }
 
-
-static int __init scc_console_setup(struct console *co, char *options)
-{
-       return 0;
-}
-
-
 static struct console sercons = {
        .name           = "ttyS",
        .write          = scc_console_write,
        .device         = scc_console_device,
-       .setup          = scc_console_setup,
        .flags          = CON_PRINTBUFFER,
        .index          = -1,
 };
index 2f48ba329961ae6eb7537609709e72e412d0aa8d..ad5cc5f6862fdff08746a91d5068dad490124c8b 100644 (file)
@@ -602,7 +602,7 @@ config ZVM_WATCHDOG
 
 config SH_WDT
        tristate "SuperH Watchdog"
-       depends on SUPERH
+       depends on SUPERH && (CPU_SH3 || CPU_SH4)
        help
          This driver adds watchdog support for the integrated watchdog in the
          SuperH processors. If you have one of these processors and wish
index e1e9d9d6893fdd82990abdf124ae049c4e23c681..f0829b83e970db20c5f7a500eee860bf1aa484a2 100644 (file)
@@ -8,6 +8,7 @@
  *  more details.
  */
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
@@ -54,6 +55,7 @@ static int falconide_offsets[IDE_NR_PORTS] __initdata = {
      */
 
 int falconide_intr_lock;
+EXPORT_SYMBOL(falconide_intr_lock);
 
 
     /*
index 75b4d2a83dd99ff842308e1a96400cd809aac383..5fe7555866230509e48f3a0526858704de27b5b9 100644 (file)
@@ -471,37 +471,16 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
        return 0;
 }
 
-static struct list_head *list_get_nth_element(struct list_head *list, loff_t *pos)
-{
-       struct list_head *node;
-       loff_t i = 0;
-
-       list_for_each(node, list)
-               if (i++ == *pos)
-                       return node;
-
-       return NULL;
-}
-
-static struct list_head *list_get_next_element(struct list_head *list, struct list_head *element, loff_t *pos)
-{
-       if (element->next == list)
-               return NULL;
-
-       ++(*pos);
-       return element->next;
-}
-
 static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
 {
        /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
 
-       return list_get_nth_element(&input_dev_list, pos);
+       return seq_list_start(&input_dev_list, *pos);
 }
 
 static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-       return list_get_next_element(&input_dev_list, v, pos);
+       return seq_list_next(v, &input_dev_list, pos);
 }
 
 static void input_devices_seq_stop(struct seq_file *seq, void *v)
@@ -592,13 +571,13 @@ static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
 {
        /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
        seq->private = (void *)(unsigned long)*pos;
-       return list_get_nth_element(&input_handler_list, pos);
+       return seq_list_start(&input_handler_list, *pos);
 }
 
 static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        seq->private = (void *)(unsigned long)(*pos + 1);
-       return list_get_next_element(&input_handler_list, v, pos);
+       return seq_list_next(v, &input_handler_list, pos);
 }
 
 static void input_handlers_seq_stop(struct seq_file *seq, void *v)
index 12db72d83ea0b254e048de0d68016010b153228d..e2abe18e575df2d89e2de4189124f2fbb4abb35f 100644 (file)
@@ -275,4 +275,11 @@ config JOYSTICK_XPAD_FF
        ---help---
          Say Y here if you want to take advantage of xbox 360 rumble features.
 
+config JOYSTICK_XPAD_LEDS
+       bool "LED Support for Xbox360 controller 'BigX' LED"
+       depends on LEDS_CLASS && JOYSTICK_XPAD
+       ---help---
+         This option enables support for the LED which surrounds the Big X on
+         XBox 360 controller.
+
 endif
index 244089c52650f1af2eae67185f05c3277abdfe3a..28080395899c21aacbc08accda1631c98637a286 100644 (file)
@@ -191,13 +191,18 @@ struct usb_xpad {
        unsigned char *idata;           /* input data */
        dma_addr_t idata_dma;
 
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
        struct urb *irq_out;            /* urb for interrupt out report */
        unsigned char *odata;           /* output data */
        dma_addr_t odata_dma;
+       struct mutex odata_mutex;
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+       struct xpad_led *led;
 #endif
 
-       char phys[65];                  /* physical device path */
+       char phys[64];                  /* physical device path */
 
        int dpad_mapping;               /* map d-pad to buttons or to axes */
        int xtype;                      /* type of xbox device */
@@ -349,7 +354,7 @@ exit:
                     __FUNCTION__, retval);
 }
 
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
 static void xpad_irq_out(struct urb *urb)
 {
        int retval;
@@ -376,29 +381,7 @@ exit:
                   __FUNCTION__, retval);
 }
 
-static int xpad_play_effect(struct input_dev *dev, void *data,
-                           struct ff_effect *effect)
-{
-       struct usb_xpad *xpad = input_get_drvdata(dev);
-
-       if (effect->type == FF_RUMBLE) {
-               __u16 strong = effect->u.rumble.strong_magnitude;
-               __u16 weak = effect->u.rumble.weak_magnitude;
-               xpad->odata[0] = 0x00;
-               xpad->odata[1] = 0x08;
-               xpad->odata[2] = 0x00;
-               xpad->odata[3] = strong / 256;
-               xpad->odata[4] = weak / 256;
-               xpad->odata[5] = 0x00;
-               xpad->odata[6] = 0x00;
-               xpad->odata[7] = 0x00;
-               usb_submit_urb(xpad->irq_out, GFP_KERNEL);
-       }
-
-       return 0;
-}
-
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
 {
        struct usb_endpoint_descriptor *ep_irq_out;
        int error = -ENOMEM;
@@ -411,6 +394,8 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
        if (!xpad->odata)
                goto fail1;
 
+       mutex_init(&xpad->odata_mutex);
+
        xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
        if (!xpad->irq_out)
                goto fail2;
@@ -423,25 +408,19 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
        xpad->irq_out->transfer_dma = xpad->odata_dma;
        xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-       input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
-
-       error = input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
-       if (error)
-               goto fail2;
-
        return 0;
 
  fail2:        usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
  fail1:        return error;
 }
 
-static void xpad_stop_ff(struct usb_xpad *xpad)
+static void xpad_stop_output(struct usb_xpad *xpad)
 {
        if (xpad->xtype == XTYPE_XBOX360)
                usb_kill_urb(xpad->irq_out);
 }
 
-static void xpad_deinit_ff(struct usb_xpad *xpad)
+static void xpad_deinit_output(struct usb_xpad *xpad)
 {
        if (xpad->xtype == XTYPE_XBOX360) {
                usb_free_urb(xpad->irq_out);
@@ -449,13 +428,130 @@ static void xpad_deinit_ff(struct usb_xpad *xpad)
                                xpad->odata, xpad->odata_dma);
        }
 }
+#else
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
+static void xpad_deinit_output(struct usb_xpad *xpad) {}
+static void xpad_stop_output(struct usb_xpad *xpad) {}
+#endif
+
+#ifdef CONFIG_JOYSTICK_XPAD_FF
+static int xpad_play_effect(struct input_dev *dev, void *data,
+                           struct ff_effect *effect)
+{
+       struct usb_xpad *xpad = input_get_drvdata(dev);
 
+       if (effect->type == FF_RUMBLE) {
+               __u16 strong = effect->u.rumble.strong_magnitude;
+               __u16 weak = effect->u.rumble.weak_magnitude;
+               xpad->odata[0] = 0x00;
+               xpad->odata[1] = 0x08;
+               xpad->odata[2] = 0x00;
+               xpad->odata[3] = strong / 256;
+               xpad->odata[4] = weak / 256;
+               xpad->odata[5] = 0x00;
+               xpad->odata[6] = 0x00;
+               xpad->odata[7] = 0x00;
+               usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+       }
+
+       return 0;
+}
+
+static int xpad_init_ff(struct usb_xpad *xpad)
+{
+       input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
+
+       return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
+}
+
+#else
+static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+#include <linux/leds.h>
+
+struct xpad_led {
+       char name[16];
+       struct led_classdev led_cdev;
+       struct usb_xpad *xpad;
+};
+
+static void xpad_send_led_command(struct usb_xpad *xpad, int command)
+{
+       if (command >= 0 && command < 14) {
+               mutex_lock(&xpad->odata_mutex);
+               xpad->odata[0] = 0x01;
+               xpad->odata[1] = 0x03;
+               xpad->odata[2] = command;
+               usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+               mutex_unlock(&xpad->odata_mutex);
+       }
+}
+
+static void xpad_led_set(struct led_classdev *led_cdev,
+                        enum led_brightness value)
+{
+       struct xpad_led *xpad_led = container_of(led_cdev,
+                                                struct xpad_led, led_cdev);
+
+       xpad_send_led_command(xpad_led->xpad, value);
+}
+
+static int xpad_led_probe(struct usb_xpad *xpad)
+{
+       static atomic_t led_seq = ATOMIC_INIT(0);
+       long led_no;
+       struct xpad_led *led;
+       struct led_classdev *led_cdev;
+       int error;
+
+       if (xpad->xtype != XTYPE_XBOX360)
+               return 0;
+
+       xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL);
+       if (!led)
+               return -ENOMEM;
+
+       led_no = (long)atomic_inc_return(&led_seq) - 1;
+
+       snprintf(led->name, sizeof(led->name), "xpad%ld", led_no);
+       led->xpad = xpad;
+
+       led_cdev = &led->led_cdev;
+       led_cdev->name = led->name;
+       led_cdev->brightness_set = xpad_led_set;
+
+       error = led_classdev_register(&xpad->udev->dev, led_cdev);
+       if (error) {
+               kfree(led);
+               xpad->led = NULL;
+               return error;
+       }
+
+       /*
+        * Light up the segment corresponding to controller number
+        */
+       xpad_send_led_command(xpad, (led_no % 4) + 2);
+
+       return 0;
+}
+
+static void xpad_led_disconnect(struct usb_xpad *xpad)
+{
+       struct xpad_led *xpad_led = xpad->led;
+
+       if (xpad_led) {
+               led_classdev_unregister(&xpad_led->led_cdev);
+               kfree(xpad_led->name);
+       }
+}
 #else
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
-static void xpad_stop_ff(struct usb_xpad *xpad) { }
-static void xpad_deinit_ff(struct usb_xpad *xpad) { }
+static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
+static void xpad_led_disconnect(struct usb_xpad *xpad) { }
 #endif
 
+
 static int xpad_open(struct input_dev *dev)
 {
        struct usb_xpad *xpad = input_get_drvdata(dev);
@@ -472,7 +568,7 @@ static void xpad_close(struct input_dev *dev)
        struct usb_xpad *xpad = input_get_drvdata(dev);
 
        usb_kill_urb(xpad->irq_in);
-       xpad_stop_ff(xpad);
+       xpad_stop_output(xpad);
 }
 
 static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
@@ -564,10 +660,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
                for (i = 0; xpad_abs_pad[i] >= 0; i++)
                    xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
 
-       error = xpad_init_ff(intf, xpad);
+       error = xpad_init_output(intf, xpad);
        if (error)
                goto fail2;
 
+       error = xpad_init_ff(xpad);
+       if (error)
+               goto fail3;
+
+       error = xpad_led_probe(xpad);
+       if (error)
+               goto fail3;
+
        ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
        usb_fill_int_urb(xpad->irq_in, udev,
                         usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
@@ -578,12 +682,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        error = input_register_device(xpad->dev);
        if (error)
-               goto fail3;
+               goto fail4;
 
        usb_set_intfdata(intf, xpad);
        return 0;
 
- fail3:        usb_free_urb(xpad->irq_in);
+ fail4:        usb_free_urb(xpad->irq_in);
+ fail3:        xpad_deinit_output(xpad);
  fail2:        usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
  fail1:        input_free_device(input_dev);
        kfree(xpad);
@@ -597,8 +702,9 @@ static void xpad_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
        if (xpad) {
+               xpad_led_disconnect(xpad);
                input_unregister_device(xpad->dev);
-               xpad_deinit_ff(xpad);
+               xpad_deinit_output(xpad);
                usb_free_urb(xpad->irq_in);
                usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
                                xpad->idata, xpad->idata_dma);
index e3215267db112dcc89818ff41b0f5ca601c30151..2bea1b2c631c81274b80304f3e4be11216013068 100644 (file)
@@ -155,6 +155,8 @@ struct atp {
        int                     xy_acc[ATP_XSENSORS + ATP_YSENSORS];
        int                     overflowwarn;   /* overflow warning printed? */
        int                     datalen;        /* size of an USB urb transfer */
+       int                     idlecount;      /* number of empty packets */
+       struct work_struct      work;
 };
 
 #define dbg_dump(msg, tab) \
@@ -208,6 +210,55 @@ static inline int atp_is_geyser_3(struct atp *dev)
                (productId == GEYSER4_JIS_PRODUCT_ID);
 }
 
+/*
+ * By default Geyser 3 device sends standard USB HID mouse
+ * packets (Report ID 2). This code changes device mode, so it
+ * sends raw sensor reports (Report ID 5).
+ */
+static int atp_geyser3_init(struct usb_device *udev)
+{
+       char data[8];
+       int size;
+
+       size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                       ATP_GEYSER3_MODE_READ_REQUEST_ID,
+                       USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       ATP_GEYSER3_MODE_REQUEST_VALUE,
+                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+       if (size != 8) {
+               err("Could not do mode read request from device"
+                   " (Geyser 3 mode)");
+               return -EIO;
+       }
+
+       /* Apply the mode switch */
+       data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+       size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       ATP_GEYSER3_MODE_REQUEST_VALUE,
+                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+       if (size != 8) {
+               err("Could not do mode write request to device"
+                   " (Geyser 3 mode)");
+               return -EIO;
+       }
+       return 0;
+}
+
+/* Reinitialise the device if it's a geyser 3 */
+static void atp_reinit(struct work_struct *work)
+{
+       struct atp *dev = container_of(work, struct atp, work);
+       struct usb_device *udev = dev->udev;
+
+       dev->idlecount = 0;
+       atp_geyser3_init(udev);
+}
+
 static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
                             int *z, int *fingers)
 {
@@ -439,8 +490,8 @@ static void atp_complete(struct urb* urb)
                }
                dev->x_old = x;
                dev->y_old = y;
-       }
-       else if (!x && !y) {
+
+       else if (!x && !y) {
 
                dev->x_old = dev->y_old = -1;
                input_report_key(dev->input, BTN_TOUCH, 0);
@@ -449,11 +500,21 @@ static void atp_complete(struct urb* urb)
 
                /* reset the accumulator on release */
                memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
-       }
 
-       input_report_key(dev->input, BTN_LEFT,
-                        !!dev->data[dev->datalen - 1]);
+               /* Geyser 3 will continue to send packets continually after
+                  the first touch unless reinitialised. Do so if it's been
+                  idle for a while in order to avoid waking the kernel up
+                  several hundred times a second */
+               if (atp_is_geyser_3(dev)) {
+                       dev->idlecount++;
+                       if (dev->idlecount == 10) {
+                               dev->valid = 0;
+                               schedule_work(&dev->work);
+                       }
+               }
+       }
 
+       input_report_key(dev->input, BTN_LEFT, dev->data[dev->datalen - 1] & 1);
        input_sync(dev->input);
 
 exit:
@@ -480,6 +541,7 @@ static void atp_close(struct input_dev *input)
        struct atp *dev = input_get_drvdata(input);
 
        usb_kill_urb(dev->urb);
+       cancel_work_sync(&dev->work);
        dev->open = 0;
 }
 
@@ -528,40 +590,10 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
                dev->datalen = 81;
 
        if (atp_is_geyser_3(dev)) {
-               /*
-                * By default Geyser 3 device sends standard USB HID mouse
-                * packets (Report ID 2). This code changes device mode, so it
-                * sends raw sensor reports (Report ID 5).
-                */
-               char data[8];
-               int size;
-
-               size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                       ATP_GEYSER3_MODE_READ_REQUEST_ID,
-                       USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       ATP_GEYSER3_MODE_REQUEST_VALUE,
-                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
-               if (size != 8) {
-                       err("Could not do mode read request from device"
-                                                       " (Geyser 3 mode)");
+               /* switch to raw sensor mode */
+               if (atp_geyser3_init(udev))
                        goto err_free_devs;
-               }
-
-               /* Apply the mode switch */
-               data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
-
-               size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                       ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       ATP_GEYSER3_MODE_REQUEST_VALUE,
-                       ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
 
-               if (size != 8) {
-                       err("Could not do mode write request to device"
-                                                       " (Geyser 3 mode)");
-                       goto err_free_devs;
-               }
                printk("appletouch Geyser 3 inited.\n");
        }
 
@@ -636,6 +668,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
        /* save our data pointer in this interface device */
        usb_set_intfdata(iface, dev);
 
+       INIT_WORK(&dev->work, atp_reinit);
+
        return 0;
 
  err_free_buffer:
@@ -669,14 +703,17 @@ static void atp_disconnect(struct usb_interface *iface)
 static int atp_suspend(struct usb_interface *iface, pm_message_t message)
 {
        struct atp *dev = usb_get_intfdata(iface);
+
        usb_kill_urb(dev->urb);
        dev->valid = 0;
+
        return 0;
 }
 
 static int atp_resume(struct usb_interface *iface)
 {
        struct atp *dev = usb_get_intfdata(iface);
+
        if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
                return -EIO;
 
index 1740cadd95942aac53487629ec485644cf9a3d02..91109b49fde1475d30d2489eff29d8c8b0d42eb3 100644 (file)
@@ -109,7 +109,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
 {
        struct lifebook_data *priv = psmouse->private;
        struct input_dev *dev1 = psmouse->dev;
-       struct input_dev *dev2 = priv->dev2;
+       struct input_dev *dev2 = priv ? priv->dev2 : NULL;
        unsigned char *packet = psmouse->packet;
        int relative_packet = packet[0] & 0x08;
 
index 4fca1e7f26781e1ce874f98f0cf5941a483c0ae3..702a526cf45b9d8c43cc6d4dc33ba17fd5c3c3fb 100644 (file)
@@ -366,6 +366,7 @@ static void i8042_pnp_exit(void)
 static int __init i8042_pnp_init(void)
 {
        char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
+       int pnp_data_busted = 0;
        int err;
 
        if (i8042_nopnp) {
@@ -413,27 +414,48 @@ static int __init i8042_pnp_init(void)
 #endif
 
        if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
-             i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) {
-               printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
+             i8042_pnp_data_reg != i8042_data_reg) ||
+           !i8042_pnp_data_reg) {
+               printk(KERN_WARNING
+                       "PNP: PS/2 controller has invalid data port %#x; "
+                       "using default %#x\n",
                        i8042_pnp_data_reg, i8042_data_reg);
                i8042_pnp_data_reg = i8042_data_reg;
+               pnp_data_busted = 1;
        }
 
        if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
-             i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) {
-               printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
+             i8042_pnp_command_reg != i8042_command_reg) ||
+           !i8042_pnp_command_reg) {
+               printk(KERN_WARNING
+                       "PNP: PS/2 controller has invalid command port %#x; "
+                       "using default %#x\n",
                        i8042_pnp_command_reg, i8042_command_reg);
                i8042_pnp_command_reg = i8042_command_reg;
+               pnp_data_busted = 1;
        }
 
        if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
-               printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %d\n", i8042_kbd_irq);
+               printk(KERN_WARNING
+                       "PNP: PS/2 controller doesn't have KBD irq; "
+                       "using default %d\n", i8042_kbd_irq);
                i8042_pnp_kbd_irq = i8042_kbd_irq;
+               pnp_data_busted = 1;
        }
 
        if (!i8042_noaux && !i8042_pnp_aux_irq) {
-               printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %d\n", i8042_aux_irq);
-               i8042_pnp_aux_irq = i8042_aux_irq;
+               if (!pnp_data_busted && i8042_pnp_kbd_irq) {
+                       printk(KERN_WARNING
+                               "PNP: PS/2 appears to have AUX port disabled, "
+                               "if this is incorrect please boot with "
+                               "i8042.nopnp\n");
+                       i8042_noaux = 1;
+               } else {
+                       printk(KERN_WARNING
+                               "PNP: PS/2 controller doesn't have AUX irq; "
+                               "using default %d\n", i8042_aux_irq);
+                       i8042_pnp_aux_irq = i8042_aux_irq;
+               }
        }
 
        i8042_data_reg = i8042_pnp_data_reg;
index 69371779806ac57182548230a9513e2754efd064..f929fcdbae2e75cb640dded83d2e33c33b1d8d24 100644 (file)
@@ -54,6 +54,19 @@ config TOUCHSCREEN_CORGI
          To compile this driver as a module, choose M here: the
          module will be called corgi_ts.
 
+config TOUCHSCREEN_FUJITSU
+       tristate "Fujitsu serial touchscreen"
+       select SERIO
+       help
+         Say Y here if you have the Fujitsu touchscreen (such as one
+         installed in Lifebook P series laptop) connected to your
+         system.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called fujitsu-ts.
+
 config TOUCHSCREEN_GUNZE
        tristate "Gunze AHL-51S touchscreen"
        select SERIO
index 2f86d6ad06d3a193fedcdd01b2a4dd7dbb498491..5de8933c49936ecbda73bb2da6e05c5dcb62cd41 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY)         += h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_CORGI)                += corgi_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)                += gunze.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)          += elo.o
+obj-$(CONFIG_TOUCHSCREEN_FUJITSU)      += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MTOUCH)       += mtouch.o
 obj-$(CONFIG_TOUCHSCREEN_MK712)                += mk712.o
 obj-$(CONFIG_TOUCHSCREEN_HP600)                += hp680_ts_input.o
index 1c9069cd3bae4228fe1ed142c8c6543b4467ad11..96581d08774f8b55aa9bfc86e099de666b7be906 100644 (file)
@@ -95,7 +95,7 @@ struct ads7846 {
        u16                     dummy;          /* for the pwrdown read */
        struct ts_event         tc;
 
-       struct spi_transfer     xfer[10];
+       struct spi_transfer     xfer[18];
        struct spi_message      msg[5];
        struct spi_message      *last_msg;
        int                     msg_idx;
@@ -107,6 +107,8 @@ struct ads7846 {
        u16                     debounce_tol;
        u16                     debounce_rep;
 
+       u16                     penirq_recheck_delay_usecs;
+
        spinlock_t              lock;
        struct hrtimer          timer;
        unsigned                pendown:1;      /* P: lock */
@@ -553,6 +555,15 @@ static void ads7846_rx(void *ads)
                return;
        }
 
+       /* Maybe check the pendown state before reporting. This discards
+        * false readings when the pen is lifted.
+        */
+       if (ts->penirq_recheck_delay_usecs) {
+               udelay(ts->penirq_recheck_delay_usecs);
+               if (!ts->get_pendown_state())
+                       Rt = 0;
+       }
+
        /* NOTE: We can't rely on the pressure to determine the pen down
         * state, even this controller has a pressure sensor.  The pressure
         * value can fluctuate for quite a while after lifting the pen and
@@ -896,6 +907,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                ts->filter = ads7846_no_filter;
        ts->get_pendown_state = pdata->get_pendown_state;
 
+       if (pdata->penirq_recheck_delay_usecs)
+               ts->penirq_recheck_delay_usecs =
+                               pdata->penirq_recheck_delay_usecs;
+
        snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
 
        input_dev->name = "ADS784x Touchscreen";
@@ -936,6 +951,24 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
+       /* the first sample after switching drivers can be low quality;
+        * optionally discard it, using a second one after the signals
+        * have had enough time to stabilize.
+        */
+       if (pdata->settle_delay_usecs) {
+               x->delay_usecs = pdata->settle_delay_usecs;
+
+               x++;
+               x->tx_buf = &ts->read_y;
+               x->len = 1;
+               spi_message_add_tail(x, m);
+
+               x++;
+               x->rx_buf = &ts->tc.y;
+               x->len = 2;
+               spi_message_add_tail(x, m);
+       }
+
        m->complete = ads7846_rx_val;
        m->context = ts;
 
@@ -954,6 +987,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
        x->len = 2;
        spi_message_add_tail(x, m);
 
+       /* ... maybe discard first sample ... */
+       if (pdata->settle_delay_usecs) {
+               x->delay_usecs = pdata->settle_delay_usecs;
+
+               x++;
+               x->tx_buf = &ts->read_x;
+               x->len = 1;
+               spi_message_add_tail(x, m);
+
+               x++;
+               x->rx_buf = &ts->tc.x;
+               x->len = 2;
+               spi_message_add_tail(x, m);
+       }
+
        m->complete = ads7846_rx_val;
        m->context = ts;
 
@@ -973,6 +1021,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
+               /* ... maybe discard first sample ... */
+               if (pdata->settle_delay_usecs) {
+                       x->delay_usecs = pdata->settle_delay_usecs;
+
+                       x++;
+                       x->tx_buf = &ts->read_z1;
+                       x->len = 1;
+                       spi_message_add_tail(x, m);
+
+                       x++;
+                       x->rx_buf = &ts->tc.z1;
+                       x->len = 2;
+                       spi_message_add_tail(x, m);
+               }
+
                m->complete = ads7846_rx_val;
                m->context = ts;
 
@@ -990,6 +1053,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
                x->len = 2;
                spi_message_add_tail(x, m);
 
+               /* ... maybe discard first sample ... */
+               if (pdata->settle_delay_usecs) {
+                       x->delay_usecs = pdata->settle_delay_usecs;
+
+                       x++;
+                       x->tx_buf = &ts->read_z2;
+                       x->len = 1;
+                       spi_message_add_tail(x, m);
+
+                       x++;
+                       x->rx_buf = &ts->tc.z2;
+                       x->len = 2;
+                       spi_message_add_tail(x, m);
+               }
+
                m->complete = ads7846_rx_val;
                m->context = ts;
        }
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
new file mode 100644 (file)
index 0000000..daf7a4a
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Fujitsu serial touchscreen driver
+ *
+ * Copyright (c) Dmitry Torokhov <dtor@mail.ru>
+ */
+
+/*
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC    "Fujitsu serial touchscreen driver"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define FUJITSU_LENGTH 5
+
+/*
+ * Per-touchscreen data.
+ */
+struct fujitsu {
+       struct input_dev *dev;
+       struct serio *serio;
+       int idx;
+       unsigned char data[FUJITSU_LENGTH];
+       char phys[32];
+};
+
+/*
+ * Decode serial data (5 bytes per packet)
+ * First byte
+ * 1 C 0 0 R S S S
+ * Where C is 1 while in calibration mode (which we don't use)
+ * R is 1 when no coordinate corection was done.
+ * S are button state
+ */
+static irqreturn_t fujitsu_interrupt(struct serio *serio,
+                                    unsigned char data, unsigned int flags)
+{
+       struct fujitsu *fujitsu = serio_get_drvdata(serio);
+       struct input_dev *dev = fujitsu->dev;
+
+       if (fujitsu->idx == 0) {
+               /* resync skip until start of frame */
+               if ((data & 0xf0) != 0x80)
+                       return IRQ_HANDLED;
+       } else {
+               /* resync skip garbage */
+               if (data & 0x80) {
+                       fujitsu->idx = 0;
+                       return IRQ_HANDLED;
+               }
+       }
+
+       fujitsu->data[fujitsu->idx++] = data;
+       if (fujitsu->idx == FUJITSU_LENGTH) {
+               input_report_abs(dev, ABS_X,
+                                (fujitsu->data[2] << 7) | fujitsu->data[1]);
+               input_report_abs(dev, ABS_Y,
+                                (fujitsu->data[4] << 7) | fujitsu->data[3]);
+               input_report_key(dev, BTN_TOUCH,
+                                (fujitsu->data[0] & 0x03) != 2);
+               input_sync(dev);
+               fujitsu->idx = 0;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * fujitsu_disconnect() is the opposite of fujitsu_connect()
+ */
+static void fujitsu_disconnect(struct serio *serio)
+{
+       struct fujitsu *fujitsu = serio_get_drvdata(serio);
+
+       input_get_device(fujitsu->dev);
+       input_unregister_device(fujitsu->dev);
+       serio_close(serio);
+       serio_set_drvdata(serio, NULL);
+       input_put_device(fujitsu->dev);
+       kfree(fujitsu);
+}
+
+/*
+ * fujitsu_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Fujitsu protocol and registers it
+ * as input device.
+ */
+static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
+{
+       struct fujitsu *fujitsu;
+       struct input_dev *input_dev;
+       int err;
+
+       fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!fujitsu || !input_dev) {
+               err = -ENOMEM;
+               goto fail1;
+       }
+
+       fujitsu->serio = serio;
+       fujitsu->dev = input_dev;
+       snprintf(fujitsu->phys, sizeof(fujitsu->phys),
+                "%s/input0", serio->phys);
+
+       input_dev->name = "Fujitsu Serial Touchscreen";
+       input_dev->phys = fujitsu->phys;
+       input_dev->id.bustype = BUS_RS232;
+       input_dev->id.vendor = SERIO_FUJITSU;
+       input_dev->id.product = 0;
+       input_dev->id.version = 0x0100;
+       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+       input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
+       serio_set_drvdata(serio, fujitsu);
+
+       err = serio_open(serio, drv);
+       if (err)
+               goto fail2;
+
+       err = input_register_device(fujitsu->dev);
+       if (err)
+               goto fail3;
+
+       return 0;
+
+ fail3:
+       serio_close(serio);
+ fail2:
+       serio_set_drvdata(serio, NULL);
+ fail1:
+       input_free_device(input_dev);
+       kfree(fujitsu);
+       return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+static struct serio_device_id fujitsu_serio_ids[] = {
+       {
+               .type   = SERIO_RS232,
+               .proto  = SERIO_FUJITSU,
+               .id     = SERIO_ANY,
+               .extra  = SERIO_ANY,
+       },
+       { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids);
+
+static struct serio_driver fujitsu_drv = {
+       .driver         = {
+               .name   = "fujitsu_ts",
+       },
+       .description    = DRIVER_DESC,
+       .id_table       = fujitsu_serio_ids,
+       .interrupt      = fujitsu_interrupt,
+       .connect        = fujitsu_connect,
+       .disconnect     = fujitsu_disconnect,
+};
+
+static int __init fujitsu_init(void)
+{
+       return serio_register_driver(&fujitsu_drv);
+}
+
+static void __exit fujitsu_exit(void)
+{
+       serio_unregister_driver(&fujitsu_drv);
+}
+
+module_init(fujitsu_init);
+module_exit(fujitsu_exit);
index a7c5e6bee034e0b9d178f6cda5122756112d319b..3ac9cbce3369f31c7ae48bde1cd9a593be1393bd 100644 (file)
@@ -121,7 +121,7 @@ struct kvm_pte_chain {
  *   bits 4:7 - page table level for this shadow (1-4)
  *   bits 8:9 - page table quadrant for 2-level guests
  *   bit   16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- *   bits 17:18 - "access" - the user and writable bits of a huge page pde
+ *   bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
  */
 union kvm_mmu_page_role {
        unsigned word;
@@ -131,7 +131,7 @@ union kvm_mmu_page_role {
                unsigned quadrant : 2;
                unsigned pad_for_nice_hex_output : 6;
                unsigned metaphysical : 1;
-               unsigned hugepage_access : 2;
+               unsigned hugepage_access : 3;
        };
 };
 
@@ -535,8 +535,8 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu);
 int kvm_mmu_setup(struct kvm_vcpu *vcpu);
 
 int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
+void kvm_mmu_zap_all(struct kvm *kvm);
 
 hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
 #define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
@@ -569,6 +569,8 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
 unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
 void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
                     unsigned long *rflags);
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 
 struct x86_emulate_ctxt;
 
index 1b206f197c6b5a4d2cd015ea57fcf554ef1a772b..bcbe6835beb4316be933f037f728f92d2df60e3d 100644 (file)
@@ -238,23 +238,6 @@ static void vcpu_load(struct kvm_vcpu *vcpu)
        kvm_arch_ops->vcpu_load(vcpu);
 }
 
-/*
- * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL
- * if the slot is not populated.
- */
-static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot)
-{
-       struct kvm_vcpu *vcpu = &kvm->vcpus[slot];
-
-       mutex_lock(&vcpu->mutex);
-       if (!vcpu->vmcs) {
-               mutex_unlock(&vcpu->mutex);
-               return NULL;
-       }
-       kvm_arch_ops->vcpu_load(vcpu);
-       return vcpu;
-}
-
 static void vcpu_put(struct kvm_vcpu *vcpu)
 {
        kvm_arch_ops->vcpu_put(vcpu);
@@ -663,13 +646,6 @@ void fx_init(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(fx_init);
 
-static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
-{
-       spin_lock(&vcpu->kvm->lock);
-       kvm_mmu_slot_remove_write_access(vcpu, slot);
-       spin_unlock(&vcpu->kvm->lock);
-}
-
 /*
  * Allocate some memory and give it an address in the guest physical address
  * space.
@@ -792,19 +768,10 @@ raced:
        *memslot = new;
        ++kvm->memory_config_version;
 
-       spin_unlock(&kvm->lock);
-
-       for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-               struct kvm_vcpu *vcpu;
+       kvm_mmu_slot_remove_write_access(kvm, mem->slot);
+       kvm_flush_remote_tlbs(kvm);
 
-               vcpu = vcpu_load_slot(kvm, i);
-               if (!vcpu)
-                       continue;
-               if (new.flags & KVM_MEM_LOG_DIRTY_PAGES)
-                       do_remove_write_access(vcpu, mem->slot);
-               kvm_mmu_reset_context(vcpu);
-               vcpu_put(vcpu);
-       }
+       spin_unlock(&kvm->lock);
 
        kvm_free_physmem_slot(&old, &new);
        return 0;
@@ -826,7 +793,6 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
        struct kvm_memory_slot *memslot;
        int r, i;
        int n;
-       int cleared;
        unsigned long any = 0;
 
        spin_lock(&kvm->lock);
@@ -855,23 +821,11 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
        if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
                goto out;
 
-       if (any) {
-               cleared = 0;
-               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-                       struct kvm_vcpu *vcpu;
-
-                       vcpu = vcpu_load_slot(kvm, i);
-                       if (!vcpu)
-                               continue;
-                       if (!cleared) {
-                               do_remove_write_access(vcpu, log->slot);
-                               memset(memslot->dirty_bitmap, 0, n);
-                               cleared = 1;
-                       }
-                       kvm_arch_ops->tlb_flush(vcpu);
-                       vcpu_put(vcpu);
-               }
-       }
+       spin_lock(&kvm->lock);
+       kvm_mmu_slot_remove_write_access(kvm, log->slot);
+       kvm_flush_remote_tlbs(kvm);
+       memset(memslot->dirty_bitmap, 0, n);
+       spin_unlock(&kvm->lock);
 
        r = 0;
 
@@ -920,13 +874,9 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
                        break;
        kvm->naliases = n;
 
-       spin_unlock(&kvm->lock);
+       kvm_mmu_zap_all(kvm);
 
-       vcpu_load(&kvm->vcpus[0]);
-       spin_lock(&kvm->lock);
-       kvm_mmu_zap_all(&kvm->vcpus[0]);
        spin_unlock(&kvm->lock);
-       vcpu_put(&kvm->vcpus[0]);
 
        return 0;
 
@@ -1567,7 +1517,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common);
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 {
        return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
 }
@@ -1645,7 +1595,7 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
        return kvm_arch_ops->set_msr(vcpu, msr_index, data);
 }
@@ -2183,7 +2133,7 @@ static __init void kvm_init_msr_list(void)
  */
 static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
 {
-       return set_msr(vcpu, index, *data);
+       return kvm_set_msr(vcpu, index, *data);
 }
 
 /*
@@ -2667,7 +2617,7 @@ static long kvm_vcpu_ioctl(struct file *filp,
                break;
        }
        case KVM_GET_MSRS:
-               r = msr_io(vcpu, argp, get_msr, 1);
+               r = msr_io(vcpu, argp, kvm_get_msr, 1);
                break;
        case KVM_SET_MSRS:
                r = msr_io(vcpu, argp, do_set_msr, 0);
index 1199d3f32ac3c296ca4973b6a38a29e979fe8b24..d99d2fe53dcaa2f081ef714cf1130e41f1434657 100644 (file)
@@ -154,7 +154,6 @@ struct kvm_rmap_desc {
 
 static struct kmem_cache *pte_chain_cache;
 static struct kmem_cache *rmap_desc_cache;
-static struct kmem_cache *mmu_page_cache;
 static struct kmem_cache *mmu_page_header_cache;
 
 static int is_write_protection(struct kvm_vcpu *vcpu)
@@ -225,6 +224,29 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
                kfree(mc->objects[--mc->nobjs]);
 }
 
+static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
+                                      int min, gfp_t gfp_flags)
+{
+       struct page *page;
+
+       if (cache->nobjs >= min)
+               return 0;
+       while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
+               page = alloc_page(gfp_flags);
+               if (!page)
+                       return -ENOMEM;
+               set_page_private(page, 0);
+               cache->objects[cache->nobjs++] = page_address(page);
+       }
+       return 0;
+}
+
+static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
+{
+       while (mc->nobjs)
+               __free_page(mc->objects[--mc->nobjs]);
+}
+
 static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
 {
        int r;
@@ -237,8 +259,7 @@ static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
                                   rmap_desc_cache, 1, gfp_flags);
        if (r)
                goto out;
-       r = mmu_topup_memory_cache(&vcpu->mmu_page_cache,
-                                  mmu_page_cache, 4, gfp_flags);
+       r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
        if (r)
                goto out;
        r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
@@ -266,7 +287,7 @@ static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
 {
        mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
        mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
-       mmu_free_memory_cache(&vcpu->mmu_page_cache);
+       mmu_free_memory_cache_page(&vcpu->mmu_page_cache);
        mmu_free_memory_cache(&vcpu->mmu_page_header_cache);
 }
 
@@ -281,24 +302,15 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
        return p;
 }
 
-static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj)
-{
-       if (mc->nobjs < KVM_NR_MEM_OBJS)
-               mc->objects[mc->nobjs++] = obj;
-       else
-               kfree(obj);
-}
-
 static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
 {
        return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache,
                                      sizeof(struct kvm_pte_chain));
 }
 
-static void mmu_free_pte_chain(struct kvm_vcpu *vcpu,
-                              struct kvm_pte_chain *pc)
+static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
 {
-       mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc);
+       kfree(pc);
 }
 
 static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
@@ -307,10 +319,9 @@ static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
                                      sizeof(struct kvm_rmap_desc));
 }
 
-static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu,
-                              struct kvm_rmap_desc *rd)
+static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
 {
-       mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd);
+       kfree(rd);
 }
 
 /*
@@ -355,8 +366,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte)
        }
 }
 
-static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
-                                  struct page *page,
+static void rmap_desc_remove_entry(struct page *page,
                                   struct kvm_rmap_desc *desc,
                                   int i,
                                   struct kvm_rmap_desc *prev_desc)
@@ -376,10 +386,10 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
                        prev_desc->more = desc->more;
                else
                        set_page_private(page,(unsigned long)desc->more | 1);
-       mmu_free_rmap_desc(vcpu, desc);
+       mmu_free_rmap_desc(desc);
 }
 
-static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
+static void rmap_remove(u64 *spte)
 {
        struct page *page;
        struct kvm_rmap_desc *desc;
@@ -407,7 +417,7 @@ static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
                while (desc) {
                        for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
                                if (desc->shadow_ptes[i] == spte) {
-                                       rmap_desc_remove_entry(vcpu, page,
+                                       rmap_desc_remove_entry(page,
                                                               desc, i,
                                                               prev_desc);
                                        return;
@@ -442,7 +452,7 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
                BUG_ON(!(*spte & PT_PRESENT_MASK));
                BUG_ON(!(*spte & PT_WRITABLE_MASK));
                rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
-               rmap_remove(vcpu, spte);
+               rmap_remove(spte);
                set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
                kvm_flush_remote_tlbs(vcpu->kvm);
        }
@@ -464,14 +474,14 @@ static int is_empty_shadow_page(u64 *spt)
 }
 #endif
 
-static void kvm_mmu_free_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_free_page(struct kvm *kvm,
                              struct kvm_mmu_page *page_head)
 {
        ASSERT(is_empty_shadow_page(page_head->spt));
        list_del(&page_head->link);
-       mmu_memory_cache_free(&vcpu->mmu_page_cache, page_head->spt);
-       mmu_memory_cache_free(&vcpu->mmu_page_header_cache, page_head);
-       ++vcpu->kvm->n_free_mmu_pages;
+       __free_page(virt_to_page(page_head->spt));
+       kfree(page_head);
+       ++kvm->n_free_mmu_pages;
 }
 
 static unsigned kvm_page_table_hashfn(gfn_t gfn)
@@ -537,8 +547,7 @@ static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu,
        pte_chain->parent_ptes[0] = parent_pte;
 }
 
-static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
-                                      struct kvm_mmu_page *page,
+static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page,
                                       u64 *parent_pte)
 {
        struct kvm_pte_chain *pte_chain;
@@ -565,7 +574,7 @@ static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
                        pte_chain->parent_ptes[i] = NULL;
                        if (i == 0) {
                                hlist_del(&pte_chain->link);
-                               mmu_free_pte_chain(vcpu, pte_chain);
+                               mmu_free_pte_chain(pte_chain);
                                if (hlist_empty(&page->parent_ptes)) {
                                        page->multimapped = 0;
                                        page->parent_pte = NULL;
@@ -643,7 +652,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
        return page;
 }
 
-static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
+static void kvm_mmu_page_unlink_children(struct kvm *kvm,
                                         struct kvm_mmu_page *page)
 {
        unsigned i;
@@ -655,10 +664,10 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
        if (page->role.level == PT_PAGE_TABLE_LEVEL) {
                for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
                        if (pt[i] & PT_PRESENT_MASK)
-                               rmap_remove(vcpu, &pt[i]);
+                               rmap_remove(&pt[i]);
                        pt[i] = 0;
                }
-               kvm_flush_remote_tlbs(vcpu->kvm);
+               kvm_flush_remote_tlbs(kvm);
                return;
        }
 
@@ -669,19 +678,18 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
                if (!(ent & PT_PRESENT_MASK))
                        continue;
                ent &= PT64_BASE_ADDR_MASK;
-               mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]);
+               mmu_page_remove_parent_pte(page_header(ent), &pt[i]);
        }
-       kvm_flush_remote_tlbs(vcpu->kvm);
+       kvm_flush_remote_tlbs(kvm);
 }
 
-static void kvm_mmu_put_page(struct kvm_vcpu *vcpu,
-                            struct kvm_mmu_page *page,
+static void kvm_mmu_put_page(struct kvm_mmu_page *page,
                             u64 *parent_pte)
 {
-       mmu_page_remove_parent_pte(vcpu, page, parent_pte);
+       mmu_page_remove_parent_pte(page, parent_pte);
 }
 
-static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_zap_page(struct kvm *kvm,
                             struct kvm_mmu_page *page)
 {
        u64 *parent_pte;
@@ -697,15 +705,15 @@ static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
                        parent_pte = chain->parent_ptes[0];
                }
                BUG_ON(!parent_pte);
-               kvm_mmu_put_page(vcpu, page, parent_pte);
+               kvm_mmu_put_page(page, parent_pte);
                set_shadow_pte(parent_pte, 0);
        }
-       kvm_mmu_page_unlink_children(vcpu, page);
+       kvm_mmu_page_unlink_children(kvm, page);
        if (!page->root_count) {
                hlist_del(&page->hash_link);
-               kvm_mmu_free_page(vcpu, page);
+               kvm_mmu_free_page(kvm, page);
        } else
-               list_move(&page->link, &vcpu->kvm->active_mmu_pages);
+               list_move(&page->link, &kvm->active_mmu_pages);
 }
 
 static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -724,7 +732,7 @@ static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
                if (page->gfn == gfn && !page->role.metaphysical) {
                        pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
                                 page->role.word);
-                       kvm_mmu_zap_page(vcpu, page);
+                       kvm_mmu_zap_page(vcpu->kvm, page);
                        r = 1;
                }
        return r;
@@ -737,7 +745,7 @@ static void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn)
        while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
                pgprintk("%s: zap %lx %x\n",
                         __FUNCTION__, gfn, page->role.word);
-               kvm_mmu_zap_page(vcpu, page);
+               kvm_mmu_zap_page(vcpu->kvm, page);
        }
 }
 
@@ -1089,10 +1097,10 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
        pte = *spte;
        if (is_present_pte(pte)) {
                if (page->role.level == PT_PAGE_TABLE_LEVEL)
-                       rmap_remove(vcpu, spte);
+                       rmap_remove(spte);
                else {
                        child = page_header(pte & PT64_BASE_ADDR_MASK);
-                       mmu_page_remove_parent_pte(vcpu, child, spte);
+                       mmu_page_remove_parent_pte(child, spte);
                }
        }
        *spte = 0;
@@ -1161,7 +1169,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
                         */
                        pgprintk("misaligned: gpa %llx bytes %d role %x\n",
                                 gpa, bytes, page->role.word);
-                       kvm_mmu_zap_page(vcpu, page);
+                       kvm_mmu_zap_page(vcpu->kvm, page);
                        continue;
                }
                page_offset = offset;
@@ -1207,7 +1215,7 @@ void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 
                page = container_of(vcpu->kvm->active_mmu_pages.prev,
                                    struct kvm_mmu_page, link);
-               kvm_mmu_zap_page(vcpu, page);
+               kvm_mmu_zap_page(vcpu->kvm, page);
        }
 }
 EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages);
@@ -1219,7 +1227,7 @@ static void free_mmu_pages(struct kvm_vcpu *vcpu)
        while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
                page = container_of(vcpu->kvm->active_mmu_pages.next,
                                    struct kvm_mmu_page, link);
-               kvm_mmu_zap_page(vcpu, page);
+               kvm_mmu_zap_page(vcpu->kvm, page);
        }
        free_page((unsigned long)vcpu->mmu.pae_root);
 }
@@ -1277,9 +1285,8 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
        mmu_free_memory_caches(vcpu);
 }
 
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
 {
-       struct kvm *kvm = vcpu->kvm;
        struct kvm_mmu_page *page;
 
        list_for_each_entry(page, &kvm->active_mmu_pages, link) {
@@ -1293,27 +1300,20 @@ void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
                for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
                        /* avoid RMW */
                        if (pt[i] & PT_WRITABLE_MASK) {
-                               rmap_remove(vcpu, &pt[i]);
+                               rmap_remove(&pt[i]);
                                pt[i] &= ~PT_WRITABLE_MASK;
                        }
        }
 }
 
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
+void kvm_mmu_zap_all(struct kvm *kvm)
 {
-       destroy_kvm_mmu(vcpu);
-
-       while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
-               struct kvm_mmu_page *page;
+       struct kvm_mmu_page *page, *node;
 
-               page = container_of(vcpu->kvm->active_mmu_pages.next,
-                                   struct kvm_mmu_page, link);
-               kvm_mmu_zap_page(vcpu, page);
-       }
+       list_for_each_entry_safe(page, node, &kvm->active_mmu_pages, link)
+               kvm_mmu_zap_page(kvm, page);
 
-       mmu_free_memory_caches(vcpu);
-       kvm_flush_remote_tlbs(vcpu->kvm);
-       init_kvm_mmu(vcpu);
+       kvm_flush_remote_tlbs(kvm);
 }
 
 void kvm_mmu_module_exit(void)
@@ -1322,8 +1322,6 @@ void kvm_mmu_module_exit(void)
                kmem_cache_destroy(pte_chain_cache);
        if (rmap_desc_cache)
                kmem_cache_destroy(rmap_desc_cache);
-       if (mmu_page_cache)
-               kmem_cache_destroy(mmu_page_cache);
        if (mmu_page_header_cache)
                kmem_cache_destroy(mmu_page_header_cache);
 }
@@ -1341,12 +1339,6 @@ int kvm_mmu_module_init(void)
        if (!rmap_desc_cache)
                goto nomem;
 
-       mmu_page_cache = kmem_cache_create("kvm_mmu_page",
-                                          PAGE_SIZE,
-                                          PAGE_SIZE, 0, NULL);
-       if (!mmu_page_cache)
-               goto nomem;
-
        mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
                                                  sizeof(struct kvm_mmu_page),
                                                  0, 0, NULL);
index a7c5cb0319ea8ae70a18dce47b3c3cafe580662d..4b5391c717f8d4ddece1a84883cfb12b2efe3656 100644 (file)
@@ -366,6 +366,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
                        metaphysical = 1;
                        hugepage_access = *guest_ent;
                        hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
+                       if (*guest_ent & PT64_NX_MASK)
+                               hugepage_access |= (1 << 2);
                        hugepage_access >>= PT_WRITABLE_SHIFT;
                        table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
                                >> PAGE_SHIFT;
index f60012d626104c45c449cd2c0055468cd835f189..1b800fc00342c55dbdb47c21935345330b49c4ef 100644 (file)
@@ -163,7 +163,7 @@ static u16 twobyte_table[256] = {
        ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x30 - 0x3F */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x40 - 0x47 */
        DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
        DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -486,6 +486,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        unsigned long modrm_ea;
        int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
        int no_wb = 0;
+       u64 msr_data;
 
        /* Shadow copy of register state. Committed on successful emulation. */
        unsigned long _regs[NR_VCPU_REGS];
@@ -1344,6 +1345,29 @@ twobyte_special_insn:
                        goto cannot_emulate;
                realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
                break;
+       case 0x30:
+               /* wrmsr */
+               msr_data = (u32)_regs[VCPU_REGS_RAX]
+                       | ((u64)_regs[VCPU_REGS_RDX] << 32);
+               rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
+               if (rc) {
+                       kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+                       _eip = ctxt->vcpu->rip;
+               }
+               rc = X86EMUL_CONTINUE;
+               break;
+       case 0x32:
+               /* rdmsr */
+               rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
+               if (rc) {
+                       kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+                       _eip = ctxt->vcpu->rip;
+               } else {
+                       _regs[VCPU_REGS_RAX] = (u32)msr_data;
+                       _regs[VCPU_REGS_RDX] = msr_data >> 32;
+               }
+               rc = X86EMUL_CONTINUE;
+               break;
        case 0xc7:              /* Grp9 (cmpxchg8b) */
                {
                        u64 old, new;
index d9de5bbc613f3e06431ddbbe5e7dc4d257f370f3..bee029bb2c7bf543912f97d1fa798739569e2606 100644 (file)
@@ -38,12 +38,12 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
                ss = lg->regs->ss;
        }
 
-       /* We use IF bit in eflags to indicate whether irqs were disabled
-          (it's always 0, since irqs are enabled when guest is running). */
+       /* We use IF bit in eflags to indicate whether irqs were enabled
+          (it's always 1, since irqs are enabled when guest is running). */
        eflags = lg->regs->eflags;
-       if (get_user(irq_enable, &lg->lguest_data->irq_enabled))
-               irq_enable = 0;
-       eflags |= (irq_enable & X86_EFLAGS_IF);
+       if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
+           && !(irq_enable & X86_EFLAGS_IF))
+               eflags &= ~X86_EFLAGS_IF;
 
        push_guest_stack(lg, &gstack, eflags);
        push_guest_stack(lg, &gstack, lg->regs->cs);
index 06bdba2337ef4ba634fe325673fc3f833c765384..c8eb79266991efb68d34e077de859295e8f8edcb 100644 (file)
@@ -187,7 +187,7 @@ static u32 copy_data(struct lguest *srclg,
                /* FIXME: This is not completely portable, since
                   archs do different things for copy_to_user_page. */
                if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
-                                  (void *__user)src->addr[si], len) != 0) {
+                                  (void __user *)src->addr[si], len) != 0) {
                        kill_guest(srclg, "bad address in sending DMA");
                        totlen = 0;
                        break;
index b9a58b78c9903c7b4c4cd4049fd6691fb954fe9e..434fea1e82f7626dc7933bfe9668d4a788fd395d 100644 (file)
@@ -39,7 +39,6 @@
 #include <asm/e820.h>
 #include <asm/mce.h>
 #include <asm/io.h>
-//#include <asm/sched-clock.h>
 
 /* Declarations for definitions in lguest_guest.S */
 extern char lguest_noirq_start[], lguest_noirq_end[];
@@ -57,6 +56,7 @@ struct lguest_data lguest_data = {
        .blocked_interrupts = { 1 }, /* Block timer interrupts */
 };
 struct lguest_device_desc *lguest_devices;
+static cycle_t clock_base;
 
 static enum paravirt_lazy_mode lazy_mode;
 static void lguest_lazy_mode(enum paravirt_lazy_mode mode)
@@ -363,6 +363,11 @@ static struct clocksource lguest_clock = {
        .read           = lguest_clock_read,
 };
 
+static unsigned long long lguest_sched_clock(void)
+{
+       return cyc2ns(&lguest_clock, lguest_clock_read() - clock_base);
+}
+
 /* We also need a "struct clock_event_device": Linux asks us to set it to go
  * off some time in the future.  Actually, James Morris figured all this out, I
  * just applied the patch. */
@@ -439,6 +444,7 @@ static void lguest_time_init(void)
                lguest_clock.mult = (((u64)NSEC_PER_SEC<<8)/ACTHZ) << 8;
                lguest_clock.mask = CLOCKSOURCE_MASK(32);
        }
+       clock_base = lguest_clock_read();
        clocksource_register(&lguest_clock);
 
        /* We can't set cpumask in the initializer: damn C limitations! */
@@ -584,6 +590,7 @@ __init void lguest_init(void *boot)
        paravirt_ops.time_init = lguest_time_init;
        paravirt_ops.set_lazy_mode = lguest_lazy_mode;
        paravirt_ops.wbinvd = lguest_wbinvd;
+       paravirt_ops.sched_clock = lguest_sched_clock;
 
        hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
 
index 00046c57b5bad69ac3b9dc983dbea71efd488ccb..a3dbf22ee365a86d11b85792e1163f8256e9cdda 100644 (file)
@@ -2,9 +2,7 @@
 #include <linux/lguest.h>
 #include <asm/asm-offsets.h>
 #include <asm/thread_info.h>
-
-/* FIXME: Once asm/processor-flags.h goes in, include that */
-#define X86_EFLAGS_IF 0x00000200
+#include <asm/processor-flags.h>
 
 /*
  * This is where we begin: we have a magic signature which the launcher looks
index c8dfdb302916aa81e10f2c82e55198e8daaf4f01..d90ee145effeb8d841061fda1b394eabe3eae385 100644 (file)
@@ -493,12 +493,12 @@ async_copy_data(int frombio, struct bio *bio, struct page *page,
                        if (frombio)
                                tx = async_memcpy(page, bio_page, page_offset,
                                        b_offset, clen,
-                                       ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_SRC,
+                                       ASYNC_TX_DEP_ACK,
                                        tx, NULL, NULL);
                        else
                                tx = async_memcpy(bio_page, page, b_offset,
                                        page_offset, clen,
-                                       ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_DST,
+                                       ASYNC_TX_DEP_ACK,
                                        tx, NULL, NULL);
                }
                if (clen < len) /* hit end of page */
index fe447a06e24efd9ad3961a8c07e056f6ff3feda0..a3292e955aaaa136822a0ed5b863cd1f1b3c5508 100644 (file)
@@ -345,8 +345,8 @@ void ir_rc5_timer_end(unsigned long data)
                        }
 
                        /* Set/reset key-up timer */
-                       timeout = current_jiffies + (500 + ir->rc5_key_timeout
-                                                    * HZ) / 1000;
+                       timeout = current_jiffies +
+                                 msecs_to_jiffies(ir->rc5_key_timeout);
                        mod_timer(&ir->timer_keyup, timeout);
 
                        /* Save code for repeat test */
index 2cee9e3bd29f8c33cb4b73e1c1f7d156cf7b3d8d..8178832d14a809dd55b3866df2088571a1a36ef5 100644 (file)
@@ -2267,7 +2267,7 @@ static int frontend_init(struct av7110 *av7110)
                FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
                FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
                FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
-               FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+               FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage);
                FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
                FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
 
index ce940b1b787f346d442d58fedd978aaf07249bfa..f0a67e93d7fd0765a38baece496b3eadc18b2b3a 100644 (file)
@@ -63,7 +63,7 @@ struct rt_device
 static void sleep_delay(long n)
 {
        /* Sleep nicely for 'n' uS */
-       int d=n/(1000000/HZ);
+       int d=n/msecs_to_jiffies(1000);
        if(!d)
                udelay(n);
        else
index 8cf2e9df5c8aa0ae5365d2293b1e53c9c417669e..34e317ced5a346243de25cf65e62577cbd6181bc 100644 (file)
@@ -329,7 +329,7 @@ cadet_handler(unsigned long data)
        init_timer(&readtimer);
        readtimer.function=cadet_handler;
        readtimer.data=(unsigned long)0;
-       readtimer.expires=jiffies+(HZ/20);
+       readtimer.expires=jiffies+msecs_to_jiffies(50);
        add_timer(&readtimer);
 }
 
@@ -349,7 +349,7 @@ cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
                init_timer(&readtimer);
                readtimer.function=cadet_handler;
                readtimer.data=(unsigned long)0;
-               readtimer.expires=jiffies+(HZ/20);
+               readtimer.expires=jiffies+msecs_to_jiffies(50);
                add_timer(&readtimer);
        }
        if(rdsin==rdsout) {
index 4db05b2b1b6eb919735591090ca05ff302d238fa..99a3231313332b5736e43dd218352a9a15454115 100644 (file)
@@ -94,7 +94,6 @@ struct gemtek_pci_card {
 
        u32 iobase;
        u32 length;
-       u16 model;
 
        u32 current_frequency;
        u8  mute;
@@ -413,8 +412,6 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
                goto err_pci;
        }
 
-       pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
-
        pci_set_drvdata( pci_dev, card );
 
        if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
index 2e4cf1efdd21f94d7c9b24ed4d75215a2d4393ab..b767b098d14bb677b9c9b7e6393825c61cedff38 100644 (file)
@@ -257,7 +257,7 @@ static int bt866_write(struct bt866 *encoder,
                printk(KERN_WARNING "%s: I/O error #%d "
                       "(write 0x%02x/0x%02x)\n",
                       encoder->i2c->name, err, encoder->addr, subaddr);
-               schedule_timeout_interruptible(HZ/10);
+               schedule_timeout_interruptible(msecs_to_jiffies(100));
        }
        if (err == 3) {
                printk(KERN_WARNING "%s: giving up\n",
index 2aea09c720937962fa8613c2f887cfcd9a3723bc..387cb2122d4f0061d1e964d0c7ecf8ce3fa42839 100644 (file)
@@ -4209,7 +4209,7 @@ static int tea5757_read(struct bttv *btv)
        bus_low(btv,btv->mbox_clk);
 
        udelay(10);
-       timeout= jiffies + HZ;
+       timeout= jiffies + msecs_to_jiffies(1000);
 
        /* wait for DATA line to go low; error if it doesn't */
        while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
index 94a13d0ee61484d994f142da2d49d188ccf28d61..4201552bc3c0689393e127ddaacfe51dfec0baef 100644 (file)
@@ -153,7 +153,7 @@ static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
 {
        if (ir->polling) {
                setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
-               ir->timer.expires  = jiffies + HZ;
+               ir->timer.expires  = jiffies + msecs_to_jiffies(1000);
                add_timer(&ir->timer);
        } else if (ir->rc5_gpio) {
                /* set timer_end for code completion */
index bd85f6d0fbe3f32d03f28fe103a9698138877998..5b25faca150411f7b227622b8e9327d77d2bfc89 100644 (file)
@@ -284,8 +284,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
 #define d2printk if (bttv_debug >= 2) printk
 
 #define BTTV_MAX_FBUF   0x208000
-#define BTTV_TIMEOUT    (HZ/2) /* 0.5 seconds */
-#define BTTV_FREE_IDLE  (HZ)   /* one second */
+#define BTTV_TIMEOUT    msecs_to_jiffies(500)    /* 0.5 seconds */
+#define BTTV_FREE_IDLE  msecs_to_jiffies(1000)   /* one second */
 
 
 struct bttv_pll_info {
index 925ff17efbbcbedea434bef38134ef0c1a5ecae2..f76c6a6c37667cd40564654346d18814f245186a 100644 (file)
@@ -95,7 +95,7 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
        unsigned long oldjiffies = jiffies;
        unsigned int i;
 
-       for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+       for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
                if (qcam_ready1(qcam) == value)
                        return 0;
 
@@ -120,7 +120,7 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
        unsigned long oldjiffies = jiffies;
        unsigned int i;
 
-       for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+       for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
                if (qcam_ready2(qcam) == value)
                        return 0;
 
index 98fa35421bdd4d3da05be0b0ad6bdfdcbb9804f5..06b233a7b20bfc3dce4860f6c6d9392ac8759ca0 100644 (file)
@@ -1881,8 +1881,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
        mutex_unlock(&core->lock);
 
        /* start tvaudio thread */
-       if (core->tuner_type != TUNER_ABSENT)
+       if (core->tuner_type != TUNER_ABSENT) {
                core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
+               if (IS_ERR(core->kthread)) {
+                       err = PTR_ERR(core->kthread);
+                       printk(KERN_ERR "Failed to create cx88 audio thread, err=%d\n",
+                              err);
+               }
+       }
        return 0;
 
 fail_unreg:
index c4f656ec46b04b1faeaf09ddc7342135f0d4a371..809126866a3e7dedae36de969c3543b9e448e18f 100644 (file)
@@ -259,7 +259,7 @@ struct cx88_subid {
 #define RESOURCE_VIDEO         2
 #define RESOURCE_VBI           4
 
-#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
 /* buffer for one video frame */
 struct cx88_buffer {
index 1aaeaa02f158ec0efdcb32df39d3f0ad269a4fea..e43beb2c9cbfd345081758185cb6c544dcda35f3 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_IVTV
        tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
        depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+       select I2C_ALGOBIT
        select FW_LOADER
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
@@ -16,11 +17,11 @@ config VIDEO_IVTV
        select VIDEO_UPD64031A
        select VIDEO_UPD64083
        ---help---
-         This is a video4linux driver for Conexant cx23416 or cx23416 based
+         This is a video4linux driver for Conexant cx23416 or cx23415 based
          PCI personal video recorder devices.
 
          This is used in devices such as the Hauppauge PVR-150/250/350/500
-         cards.
+         cards. There is a driver homepage at <http://www.ivtvdriver.org>.
 
          To compile this driver as a module, choose M here: the
          module will be called ivtv.
index 4c93466a89e52402ce32fb17a18293a910691c01..d73d433a4ff6ff59dbd0c4679295855aa5b08870 100644 (file)
@@ -56,7 +56,6 @@
 #include "ivtv-gpio.h"
 #include "ivtv-yuv.h"
 
-#include <linux/vermagic.h>
 #include <media/tveeprom.h>
 #include <media/v4l2-chip-ident.h>
 
@@ -276,9 +275,10 @@ int ivtv_waitq(wait_queue_head_t *waitq)
 }
 
 /* Generic utility functions */
-int ivtv_sleep_timeout(int timeout, int intr)
+int ivtv_msleep_timeout(unsigned int msecs, int intr)
 {
        int ret;
+       int timeout = msecs_to_jiffies(msecs);
 
        do {
                set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
@@ -427,7 +427,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
        if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) {
                itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0;
                if (itv->options.newi2c) {
-                   IVTV_INFO("reopen i2c bus for IR-blaster support\n");
+                   IVTV_INFO("Reopen i2c bus for IR-blaster support\n");
                    exit_ivtv_i2c(itv);
                    init_ivtv_i2c(itv);
                }
@@ -951,7 +951,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
 
        /* Make sure we've got a place for this card */
        if (ivtv_cards_active == IVTV_MAX_CARDS) {
-               printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d).\n",
+               printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d)\n",
                              ivtv_cards_active);
                spin_unlock(&ivtv_cards_lock);
                return -ENOMEM;
@@ -966,9 +966,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        itv->dev = dev;
        itv->num = ivtv_cards_active++;
        snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
-       if (itv->num) {
-               printk(KERN_INFO "ivtv:  ======================  NEXT CARD  ======================\n");
-       }
+       IVTV_INFO("Initializing card #%d\n", itv->num);
 
        spin_unlock(&ivtv_cards_lock);
 
@@ -1215,7 +1213,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
        if (itv->has_cx23415)
                ivtv_set_osd_alpha(itv);
 
-       IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num);
+       IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
 
        return 0;
 
@@ -1248,15 +1246,15 @@ static void ivtv_remove(struct pci_dev *pci_dev)
 {
        struct ivtv *itv = pci_get_drvdata(pci_dev);
 
-       IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num);
+       IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
 
        /* Stop all captures */
-       IVTV_DEBUG_INFO(" Stopping all streams.\n");
+       IVTV_DEBUG_INFO("Stopping all streams\n");
        if (atomic_read(&itv->capturing) > 0)
                ivtv_stop_all_captures(itv);
 
        /* Stop all decoding */
-       IVTV_DEBUG_INFO(" Stopping decoding.\n");
+       IVTV_DEBUG_INFO("Stopping decoding\n");
        if (atomic_read(&itv->decoding) > 0) {
                int type;
 
@@ -1269,30 +1267,30 @@ static void ivtv_remove(struct pci_dev *pci_dev)
        }
 
        /* Interrupts */
-       IVTV_DEBUG_INFO(" Disabling interrupts.\n");
+       IVTV_DEBUG_INFO("Disabling interrupts\n");
        ivtv_set_irq_mask(itv, 0xffffffff);
        del_timer_sync(&itv->dma_timer);
 
        /* Stop all Work Queues */
-       IVTV_DEBUG_INFO(" Stop Work Queues.\n");
+       IVTV_DEBUG_INFO("Stop Work Queues\n");
        flush_workqueue(itv->irq_work_queues);
        destroy_workqueue(itv->irq_work_queues);
 
-       IVTV_DEBUG_INFO(" Stopping Firmware.\n");
+       IVTV_DEBUG_INFO("Stopping Firmware\n");
        ivtv_halt_firmware(itv);
 
-       IVTV_DEBUG_INFO(" Unregistering v4l devices.\n");
+       IVTV_DEBUG_INFO("Unregistering v4l devices\n");
        ivtv_streams_cleanup(itv);
-       IVTV_DEBUG_INFO(" Freeing dma resources.\n");
+       IVTV_DEBUG_INFO("Freeing dma resources\n");
        ivtv_udma_free(itv);
 
        exit_ivtv_i2c(itv);
 
-       IVTV_DEBUG_INFO(" Releasing irq.\n");
+       IVTV_DEBUG_INFO(" Releasing irq\n");
        free_irq(itv->dev->irq, (void *)itv);
        ivtv_iounmap(itv);
 
-       IVTV_DEBUG_INFO(" Releasing mem.\n");
+       IVTV_DEBUG_INFO(" Releasing mem\n");
        release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
        release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
        if (itv->has_cx23415)
@@ -1313,28 +1311,27 @@ static struct pci_driver ivtv_pci_driver = {
 
 static int module_start(void)
 {
-       printk(KERN_INFO "ivtv:  ==================== START INIT IVTV ====================\n");
-       printk(KERN_INFO "ivtv:  version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION);
+       printk(KERN_INFO "ivtv:  Start initialization, version %s\n", IVTV_VERSION);
 
        memset(ivtv_cards, 0, sizeof(ivtv_cards));
 
        /* Validate parameters */
        if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
-               printk(KERN_ERR "ivtv:  ivtv_first_minor must be between 0 and %d. Exiting...\n",
+               printk(KERN_ERR "ivtv:  Exiting, ivtv_first_minor must be between 0 and %d\n",
                     IVTV_MAX_CARDS - 1);
                return -1;
        }
 
        if (ivtv_debug < 0 || ivtv_debug > 1023) {
                ivtv_debug = 0;
-               printk(KERN_INFO "ivtv:  debug value must be >= 0 and <= 1023!\n");
+               printk(KERN_INFO "ivtv:  Debug value must be >= 0 and <= 1023\n");
        }
 
        if (pci_register_driver(&ivtv_pci_driver)) {
                printk(KERN_ERR "ivtv:  Error detecting PCI card\n");
                return -ENODEV;
        }
-       printk(KERN_INFO "ivtv:  ====================  END INIT IVTV  ====================\n");
+       printk(KERN_INFO "ivtv:  End initialization\n");
        return 0;
 }
 
index 6c1a85f1ee1b966daea6ff93321a6ce37481ce10..91b588d261ae2a2f81189ba08c14aa7631567573 100644 (file)
@@ -848,7 +848,7 @@ int ivtv_set_output_mode(struct ivtv *itv, int mode);
 struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv);
 
 /* Return non-zero if a signal is pending */
-int ivtv_sleep_timeout(int timeout, int intr);
+int ivtv_msleep_timeout(unsigned int msecs, int intr);
 
 /* Wait on queue, returns -EINTR if interrupted */
 int ivtv_waitq(wait_queue_head_t *waitq);
index ee7e884e9c4f2606498eabe0686bcdf635baab95..8e97a938398f729fa7386da8bde213d1ecaa30e8 100644 (file)
@@ -218,7 +218,7 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
                        /* Process pending program info updates and pending VBI data */
                        ivtv_update_pgm_info(itv);
 
-                       if (jiffies - itv->dualwatch_jiffies > HZ) {
+                       if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
                                itv->dualwatch_jiffies = jiffies;
                                ivtv_dualwatch(itv);
                        }
@@ -832,7 +832,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
        if (itv == NULL) {
                /* Couldn't find a device registered
                   on that minor, shouldn't happen! */
-               printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor);
+               printk(KERN_WARNING "ivtv:  No ivtv device found on minor %d\n", minor);
                return -ENXIO;
        }
 
@@ -924,7 +924,7 @@ void ivtv_unmute(struct ivtv *itv)
        if (atomic_read(&itv->capturing) == 0)
                ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
 
-       ivtv_sleep_timeout(HZ / 10, 0);
+       ivtv_msleep_timeout(100, 0);
 
        if (atomic_read(&itv->capturing)) {
                ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
index 2b6208a6a108dd5c9b0a66970491cfb2300a8094..d0feabf9308023e3f2632cda4b27b10988e1daf3 100644 (file)
@@ -36,7 +36,7 @@
 #define IVTV_CMD_SPU_STOP              0x00000001
 #define IVTV_CMD_SDRAM_PRECHARGE_INIT  0x0000001A
 #define IVTV_CMD_SDRAM_REFRESH_INIT    0x80000640
-#define IVTV_SDRAM_SLEEPTIME           (60 * HZ / 100) /* 600 ms */
+#define IVTV_SDRAM_SLEEPTIME           600
 
 #define IVTV_DECODE_INIT_MPEG_FILENAME         "v4l-cx2341x-init.mpg"
 #define IVTV_DECODE_INIT_MPEG_SIZE     (152*1024)
@@ -61,7 +61,7 @@ retry:
                           the wrong file was sometimes loaded. So we check filesizes to
                           see if at least the right-sized file was loaded. If not, then we
                           retry. */
-                       IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+                       IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
                        release_firmware(fw);
                        retries--;
                        goto retry;
@@ -73,11 +73,11 @@ retry:
                        src++;
                }
                release_firmware(fw);
-               IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+               IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
                return size;
        }
-       IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size);
-       IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n");
+       IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
+       IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
        return -ENOMEM;
 }
 
@@ -89,7 +89,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
        if (itv->enc_mbox.mbox)
                ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
 
-       ivtv_sleep_timeout(HZ / 100, 0);
+       ivtv_msleep_timeout(10, 0);
        itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
 
        IVTV_DEBUG_INFO("Stopping VDM\n");
@@ -113,7 +113,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
        IVTV_DEBUG_INFO("Stopping SPU\n");
        write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
 
-       ivtv_sleep_timeout(HZ / 100, 0);
+       ivtv_msleep_timeout(10, 0);
 
        IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
        write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
@@ -129,9 +129,8 @@ void ivtv_halt_firmware(struct ivtv *itv)
                write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
        }
 
-       IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n",
-                  (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ));
-       ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+       IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
+       ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
 }
 
 void ivtv_firmware_versions(struct ivtv *itv)
@@ -204,12 +203,12 @@ int ivtv_firmware_init(struct ivtv *itv)
 
        /* start firmware */
        write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
-       ivtv_sleep_timeout(HZ / 10, 0);
+       ivtv_msleep_timeout(100, 0);
        if (itv->has_cx23415)
                write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
        else
                write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
-       ivtv_sleep_timeout(HZ / 10, 0);
+       ivtv_msleep_timeout(100, 0);
 
        /* find mailboxes and ping firmware */
        itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
@@ -264,7 +263,7 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
                                IVTV_DECODE_INIT_MPEG_FILENAME);
        } else {
                ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
-               ivtv_sleep_timeout(HZ / 10, 0);
+               ivtv_msleep_timeout(100, 0);
        }
        ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
 }
index 676418cbaaad14b909fd44c22441766d4f90b52a..6a5a7aa6697621648bad6d7f019d0062cd385e64 100644 (file)
@@ -130,7 +130,7 @@ int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr)
 
        if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028)
                return -EINVAL;
-       IVTV_INFO("Resetting tuner.\n");
+       IVTV_INFO("Resetting tuner\n");
        curout = read_reg(IVTV_REG_GPIO_OUT);
        curdir = read_reg(IVTV_REG_GPIO_DIR);
        curdir |= (1 << 12);  /* GPIO bit 12 */
index 50624c6a62a515a4ce45f369f89de6ef3ce7c924..b3557435456db70d0cf170cb942f70c81a72f28a 100644 (file)
@@ -144,7 +144,7 @@ static int attach_inform(struct i2c_client *client)
                }
        }
        if (i == I2C_CLIENTS_MAX) {
-               IVTV_ERR("insufficient room for new I2C client!\n");
+               IVTV_ERR("Insufficient room for new I2C client\n");
        }
        return 0;
 }
@@ -236,7 +236,7 @@ static int ivtv_ack(struct ivtv *itv)
        int ret = 0;
 
        if (ivtv_getscl(itv) == 1) {
-               IVTV_DEBUG_I2C("SCL was high starting an ack\n");
+               IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n");
                ivtv_setscl(itv, 0);
                if (!ivtv_waitscl(itv, 0)) {
                        IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n");
@@ -263,7 +263,7 @@ static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte)
 {
        int i, bit;
 
-       IVTV_DEBUG_I2C("write %x\n",byte);
+       IVTV_DEBUG_HI_I2C("write %x\n",byte);
        for (i = 0; i < 8; ++i, byte<<=1) {
                ivtv_setscl(itv, 0);
                if (!ivtv_waitscl(itv, 0)) {
@@ -318,7 +318,7 @@ static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack)
        ivtv_scldelay(itv);
        ivtv_setscl(itv, 0);
        ivtv_scldelay(itv);
-       IVTV_DEBUG_I2C("read %x\n",*byte);
+       IVTV_DEBUG_HI_I2C("read %x\n",*byte);
        return 0;
 }
 
@@ -330,7 +330,7 @@ static int ivtv_start(struct ivtv *itv)
 
        sda = ivtv_getsda(itv);
        if (sda != 1) {
-               IVTV_DEBUG_I2C("SDA was low at start\n");
+               IVTV_DEBUG_HI_I2C("SDA was low at start\n");
                ivtv_setsda(itv, 1);
                if (!ivtv_waitsda(itv, 1)) {
                        IVTV_DEBUG_I2C("SDA stuck low\n");
@@ -355,7 +355,7 @@ static int ivtv_stop(struct ivtv *itv)
        int i;
 
        if (ivtv_getscl(itv) != 0) {
-               IVTV_DEBUG_I2C("SCL not low when stopping\n");
+               IVTV_DEBUG_HI_I2C("SCL not low when stopping\n");
                ivtv_setscl(itv, 0);
                if (!ivtv_waitscl(itv, 0)) {
                        IVTV_DEBUG_I2C("SCL could not be set low\n");
@@ -569,7 +569,7 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg
                }
        }
        if (cmd != VIDIOC_G_CHIP_IDENT)
-               IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd);
+               IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
        return -ENODEV;
 }
 
@@ -640,7 +640,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg)
 
        addr = ivtv_i2c_hw_addr(itv, hw);
        if (addr < 0) {
-               IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n",
+               IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
                               hw, ivtv_i2c_hw_name(hw), cmd);
                return addr;
        }
@@ -655,7 +655,7 @@ int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg)
        addr = ivtv_i2c_id_addr(itv, id);
        if (addr < 0) {
                if (cmd != VIDIOC_G_CHIP_IDENT)
-                       IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n",
+                       IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
                                id, ivtv_i2c_id_name(id), cmd);
                return addr;
        }
@@ -696,7 +696,7 @@ int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg)
 void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
 {
        if (itv->i2c_adap.algo == NULL) {
-               IVTV_ERR("adapter is not set");
+               IVTV_ERR("Adapter is not set");
                return;
        }
        i2c_clients_command(&itv->i2c_adap, cmd, arg);
index 1a3ee464a826297d7c5245f33c5d5495ba9cb08b..fcd6e7f5f121b0cb78c471cdfc82e9cb0249a790 100644 (file)
@@ -403,6 +403,11 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
        /* Mark last buffer size for Interrupt flag */
        s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
 
+       if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+               set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+       else
+               clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+
        if (ivtv_use_pio(s)) {
                for (i = 0; i < s->SG_length; i++) {
                        s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src);
@@ -420,7 +425,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
                write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
                set_bit(IVTV_F_I_DMA, &itv->i_flags);
                itv->cur_dma_stream = s->type;
-               itv->dma_timer.expires = jiffies + HZ / 10;
+               itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
                add_timer(&itv->dma_timer);
        }
 }
@@ -437,7 +442,7 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
        write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
        set_bit(IVTV_F_I_DMA, &itv->i_flags);
        itv->cur_dma_stream = s->type;
-       itv->dma_timer.expires = jiffies + HZ / 10;
+       itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
        add_timer(&itv->dma_timer);
 }
 
@@ -597,7 +602,6 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
                                data[0], data[1], data[2]);
                return;
        }
-       clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
        s = &itv->streams[ivtv_stream_map[data[0]]];
        if (!stream_enc_dma_append(s, data)) {
                set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
@@ -634,7 +638,6 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
           then start a DMA request for just the VBI data. */
        if (!stream_enc_dma_append(s, data) &&
                        !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
-               set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
                set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
        }
 }
index 6ae42a3b03cc824fa35b07cd9ba6e2ee60bc5936..814a673712b386e3d79e245ddd9e5d733c42b50c 100644 (file)
@@ -37,6 +37,7 @@
 #define API_RESULT      (1 << 1)       /* Allow 1 second for this cmd to end */
 #define API_FAST_RESULT         (3 << 1)       /* Allow 0.1 second for this cmd to end */
 #define API_DMA         (1 << 3)       /* DMA mailbox, has special handling */
+#define API_HIGH_VOL    (1 << 5)       /* High volume command (i.e. called during encoding or decoding) */
 #define API_NO_WAIT_MB          (1 << 4)       /* Command may not wait for a free mailbox */
 #define API_NO_WAIT_RES         (1 << 5)       /* Command may not wait for the result */
 
@@ -77,11 +78,11 @@ static const struct ivtv_api_info api_info[256] = {
        API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE,       API_CACHE),
        API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10,  API_FAST_RESULT),
        API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9,   API_FAST_RESULT),
-       API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST,        API_DMA),
+       API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST,        API_DMA | API_HIGH_VOL),
        API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT,         API_RESULT),
        API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE,      API_CACHE),
        API_ENTRY(CX2341X_ENC_PAUSE_ENCODER,            API_RESULT),
-       API_ENTRY(CX2341X_ENC_REFRESH_INPUT,            API_NO_WAIT_MB),
+       API_ENTRY(CX2341X_ENC_REFRESH_INPUT,            API_NO_WAIT_MB | API_HIGH_VOL),
        API_ENTRY(CX2341X_ENC_SET_COPYRIGHT,            API_CACHE),
        API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION,   API_RESULT),
        API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES,      API_CACHE),
@@ -102,7 +103,7 @@ static const struct ivtv_api_info api_info[256] = {
        API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE,       API_CACHE),
        API_ENTRY(CX2341X_DEC_GET_XFER_INFO,            API_FAST_RESULT),
        API_ENTRY(CX2341X_DEC_GET_DMA_STATUS,           API_FAST_RESULT),
-       API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST,      API_DMA),
+       API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST,      API_DMA | API_HIGH_VOL),
        API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK,           API_RESULT),
        API_ENTRY(CX2341X_DEC_HALT_FW,                  API_FAST_RESULT),
        API_ENTRY(CX2341X_DEC_SET_STANDARD,             API_CACHE),
@@ -175,9 +176,9 @@ static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int f
 
                /* Sleep before a retry, if not atomic */
                if (!(flags & API_NO_WAIT_MB)) {
-                       if (jiffies - then > retries * HZ / 100)
+                       if (jiffies - then > msecs_to_jiffies(10*retries))
                               break;
-                       ivtv_sleep_timeout(HZ / 100, 0);
+                       ivtv_msleep_timeout(10, 0);
                }
        }
        return -ENODEV;
@@ -212,7 +213,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
 {
        struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
        volatile struct ivtv_mailbox __iomem *mbox;
-       int api_timeout = HZ;
+       int api_timeout = msecs_to_jiffies(1000);
        int flags, mb, i;
        unsigned long then;
 
@@ -227,7 +228,12 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
                return -EINVAL;
        }
 
-       IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+       if (api_info[cmd].flags & API_HIGH_VOL) {
+           IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name);
+       }
+       else {
+           IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+       }
 
        /* clear possibly uninitialized part of data array */
        for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
@@ -237,7 +243,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
           data, then just return 0 as there is no need to issue this command again.
           Just an optimization to prevent unnecessary use of mailboxes. */
        if (itv->api_cache[cmd].last_jiffies &&
-           jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 &&
+           jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
            !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
                itv->api_cache[cmd].last_jiffies = jiffies;
                return 0;
@@ -262,7 +268,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
        }
 
        if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
-               api_timeout = HZ / 10;
+               api_timeout = msecs_to_jiffies(100);
 
        mb = get_mailbox(itv, mbdata, flags);
        if (mb < 0) {
@@ -295,11 +301,12 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
                if (flags & API_NO_WAIT_RES)
                        mdelay(1);
                else
-                       ivtv_sleep_timeout(HZ / 100, 0);
+                       ivtv_msleep_timeout(10, 0);
        }
-       if (jiffies - then > HZ / 10)
-               IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n",
-                               api_info[cmd].name, jiffies - then, HZ);
+       if (jiffies - then > msecs_to_jiffies(100))
+               IVTV_DEBUG_WARN("%s took %u jiffies\n",
+                               api_info[cmd].name,
+                               jiffies_to_msecs(jiffies - then));
 
        for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
                data[i] = readl(&mbox->data[i]);
index 287117187499776bebc43b8cc1951e2641c303a7..322b347b67c28905ccf00091a1a189dfe1c800bb 100644 (file)
@@ -565,7 +565,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                /* Initialize Digitizer for Capture */
                ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
 
-               ivtv_sleep_timeout(HZ / 10, 0);
+               ivtv_msleep_timeout(100, 0);
        }
 
        /* begin_capture */
@@ -781,8 +781,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                        set_current_state(TASK_INTERRUPTIBLE);
 
                        /* wait 2s for EOS interrupt */
-                       while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) {
-                               schedule_timeout(HZ / 100);
+                       while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
+                               jiffies < then + msecs_to_jiffies (2000)) {
+                               schedule_timeout(msecs_to_jiffies(10));
                        }
 
                        /* To convert jiffies to ms, we must multiply by 1000
@@ -821,7 +822,8 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
                        } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
                                break;
                        }
-               } while (!ivtv_sleep_timeout(HZ / 100, 1) && then + HZ * 2 > jiffies);
+               } while (!ivtv_msleep_timeout(10, 1) &&
+                        then + msecs_to_jiffies(2000) > jiffies);
 
                set_current_state(TASK_RUNNING);
                remove_wait_queue(&s->waitq, &wait);
@@ -892,7 +894,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
                                        break;
                                tmp = data[3];
                        }
-                       if (ivtv_sleep_timeout(HZ/10, 1))
+                       if (ivtv_msleep_timeout(100, 1))
                                break;
                }
        }
index f2a2f34cd6261cf6e909d2fc9c278c5eed584a4b..17f1e2e9a66b16c3031fe9e7b29573765da8f86e 100644 (file)
@@ -86,9 +86,9 @@ static const int disp_modes[8][3] =
 
 
 
-#define PAGE_WAIT (300*HZ/1000)                        /* Time between requesting page and */
+#define PAGE_WAIT    msecs_to_jiffies(300)     /* Time between requesting page and */
                                                /* checking status bits */
-#define PGBUF_EXPIRE (15*HZ)                   /* Time to wait before retransmitting */
+#define PGBUF_EXPIRE msecs_to_jiffies(15000)   /* Time to wait before retransmitting */
                                                /* page regardless of infobits */
 typedef struct {
        u8 pgbuf[VTX_VIRTUALSIZE];              /* Page-buffer */
@@ -115,8 +115,8 @@ struct saa5249_device
 #define CCTWR 34               /* I²C write/read-address of vtx-chip */
 #define CCTRD 35
 #define NOACK_REPEAT 10                /* Retry access this many times on failure */
-#define CLEAR_DELAY (HZ/20)    /* Time required to clear a page */
-#define READY_TIMEOUT (30*HZ/1000)     /* Time to wait for ready signal of I²C-bus interface */
+#define CLEAR_DELAY   msecs_to_jiffies(50)     /* Time required to clear a page */
+#define READY_TIMEOUT msecs_to_jiffies(30)     /* Time to wait for ready signal of I2C-bus interface */
 #define INIT_DELAY 500         /* Time in usec to wait at initialization of CEA interface */
 #define START_DELAY 10         /* Time in usec to wait before starting write-cycle (CEA) */
 
index 676b9970eb2e2cd6d1d596064b6940e47528c78e..061134a7ba9fe7ce69cdf91f6937710a7a459b82 100644 (file)
@@ -208,7 +208,7 @@ determine_norm (struct i2c_client *client)
        saa7110_write_block(client, initseq, sizeof(initseq));
        saa7110_selmux(client, decoder->input);
        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ/4);
+       schedule_timeout(msecs_to_jiffies(250));
        finish_wait(&decoder->wq, &wait);
        status = saa7110_read(client);
        if (status & 0x40) {
@@ -249,7 +249,7 @@ determine_norm (struct i2c_client *client)
        //saa7110_write(client,0x2E,0x9A);
 
        prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
-       schedule_timeout(HZ/4);
+       schedule_timeout(msecs_to_jiffies(250));
        finish_wait(&decoder->wq, &wait);
 
        status = saa7110_read(client);
index d32a856192d742a0dfe2adcf2fce18104f30f68e..346255468dad2f478795f41ebfef86002f80e658 100644 (file)
@@ -314,7 +314,7 @@ struct saa7134_board {
 #define INTERLACE_ON           1
 #define INTERLACE_OFF          2
 
-#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
 struct saa7134_dev;
 struct saa7134_dma;
index 9da338dc4f3b5830d50eeecd9a8ad4e6bee0fbbf..cffb011590e3bb0418561ba0e54646d9e85bd1d5 100644 (file)
@@ -290,7 +290,7 @@ static int chip_thread(void *data)
                desc->checkmode(chip);
 
                /* schedule next check */
-               mod_timer(&chip->wt, jiffies+2*HZ);
+               mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
        }
 
        v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
@@ -1770,7 +1770,7 @@ static int chip_command(struct i2c_client *client,
                        desc->setmode(chip,VIDEO_SOUND_MONO);
                        if (chip->prevmode != VIDEO_SOUND_MONO)
                                chip->prevmode = -1; /* reset previous mode */
-                       mod_timer(&chip->wt, jiffies+2*HZ);
+                       mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
                        /* the thread will call checkmode() later */
                }
                break;
index 13ee550d3215d7d93d3989611da2648d8a4c135d..d2915d3530ead3d53499188504435cc884d643c1 100644 (file)
@@ -939,16 +939,25 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
    When no more controls are available 0 is returned. */
 u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
 {
-       u32 ctrl_class;
+       u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
        const u32 *pctrl;
 
-       /* if no query is desired, then just return the control ID */
-       if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
-               return id;
        if (ctrl_classes == NULL)
                return 0;
+
+       /* if no query is desired, then check if the ID is part of ctrl_classes */
+       if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
+               /* find class */
+               while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
+                       ctrl_classes++;
+               if (*ctrl_classes == NULL)
+                       return 0;
+               pctrl = *ctrl_classes;
+               /* find control ID */
+               while (*pctrl && *pctrl != id) pctrl++;
+               return *pctrl ? id : 0;
+       }
        id &= V4L2_CTRL_ID_MASK;
-       ctrl_class = V4L2_CTRL_ID2CLASS(id);
        id++;   /* select next control */
        /* find first class that matches (or is greater than) the class of
           the ID */
index e94a9a6036f59d59723bc07a799318653f716c61..a0c1647a2ba460b95a03fa3161aefde5a206c272 100644 (file)
@@ -2080,7 +2080,7 @@ static int vino_wait_for_frame(struct vino_channel_settings *vcs)
 
        /* to ensure that schedule_timeout will return immediately
         * if VINO interrupt was triggered meanwhile */
-       schedule_timeout_interruptible(HZ / 10);
+       schedule_timeout_interruptible(msecs_to_jiffies(100));
 
        if (signal_pending(current))
                err = -EINTR;
index 8f6741a28a4768455628733013fd41f51cd02895..1bf4cbec6a87a7a738a7334db4dbfd4104d6ac8b 100644 (file)
@@ -321,12 +321,14 @@ static int wm8739_probe(struct i2c_adapter *adapter)
 
 static int wm8739_detach(struct i2c_client *client)
 {
+       struct wm8739_state *state = i2c_get_clientdata(client);
        int err;
 
        err = i2c_detach_client(client);
        if (err)
                return err;
 
+       kfree(state);
        kfree(client);
        return 0;
 }
index 4df5d30d4d09bf7a00a3a795d0a0880e6e511933..9f7e894ef962cdc4d76baec111aacb99fa700261 100644 (file)
@@ -222,12 +222,14 @@ static int wm8775_probe(struct i2c_adapter *adapter)
 
 static int wm8775_detach(struct i2c_client *client)
 {
+       struct wm8775_state *state = i2c_get_clientdata(client);
        int err;
 
        err = i2c_detach_client(client);
        if (err) {
                return err;
        }
+       kfree(state);
        kfree(client);
 
        return 0;
index 26a3b45a4a349e86f8072118969f3d89b2697fb4..62c1c6262febea4261c97bf79d61383bb687401b 100644 (file)
@@ -608,7 +608,7 @@ module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
 MODULE_LICENSE("GPL");
 
-int
+int __init
 init_module(void)
 {
        net_debug = debug;
index a2f32151559e4e05c56293dd566059e1485419a0..13f08a390e1f599e304b112d10ab428a495958c5 100644 (file)
@@ -692,6 +692,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 {
        struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
        u16 reg;
+       u32 rx_reg;
        int i;
        const u8 *addr = hw->dev[port]->dev_addr;
 
@@ -768,11 +769,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 
        /* Configure Rx MAC FIFO */
        sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
-       reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+       rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
        if (hw->chip_id == CHIP_ID_YUKON_EX)
-               reg |= GMF_RX_OVER_ON;
+               rx_reg |= GMF_RX_OVER_ON;
 
-       sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+       sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
 
        /* Flush Rx MAC FIFO on any flow control or error */
        sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
index b801e3b3a11a002907d602560e3abfec4cd5234a..61f98251feab04f428e4769c112ac8c4059e33be 100644 (file)
@@ -459,6 +459,22 @@ static int vnet_nack(struct vnet_port *port, void *msgbuf)
        return 0;
 }
 
+static int handle_mcast(struct vnet_port *port, void *msgbuf)
+{
+       struct vio_net_mcast_info *pkt = msgbuf;
+
+       if (pkt->tag.stype != VIO_SUBTYPE_ACK)
+               printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
+                      "[%02x:%02x:%04x:%08x]\n",
+                      port->vp->dev->name,
+                      pkt->tag.type,
+                      pkt->tag.stype,
+                      pkt->tag.stype_env,
+                      pkt->tag.sid);
+
+       return 0;
+}
+
 static void maybe_tx_wakeup(struct vnet *vp)
 {
        struct net_device *dev = vp->dev;
@@ -544,7 +560,10 @@ static void vnet_event(void *arg, int event)
                                err = vnet_nack(port, &msgbuf);
                        }
                } else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
-                       err = vio_control_pkt_engine(vio, &msgbuf);
+                       if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
+                               err = handle_mcast(port, &msgbuf);
+                       else
+                               err = vio_control_pkt_engine(vio, &msgbuf);
                        if (err)
                                break;
                } else {
@@ -731,9 +750,122 @@ static int vnet_close(struct net_device *dev)
        return 0;
 }
 
+static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
+{
+       struct vnet_mcast_entry *m;
+
+       for (m = vp->mcast_list; m; m = m->next) {
+               if (!memcmp(m->addr, addr, ETH_ALEN))
+                       return m;
+       }
+       return NULL;
+}
+
+static void __update_mc_list(struct vnet *vp, struct net_device *dev)
+{
+       struct dev_addr_list *p;
+
+       for (p = dev->mc_list; p; p = p->next) {
+               struct vnet_mcast_entry *m;
+
+               m = __vnet_mc_find(vp, p->dmi_addr);
+               if (m) {
+                       m->hit = 1;
+                       continue;
+               }
+
+               if (!m) {
+                       m = kzalloc(sizeof(*m), GFP_ATOMIC);
+                       if (!m)
+                               continue;
+                       memcpy(m->addr, p->dmi_addr, ETH_ALEN);
+                       m->hit = 1;
+
+                       m->next = vp->mcast_list;
+                       vp->mcast_list = m;
+               }
+       }
+}
+
+static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
+{
+       struct vio_net_mcast_info info;
+       struct vnet_mcast_entry *m, **pp;
+       int n_addrs;
+
+       memset(&info, 0, sizeof(info));
+
+       info.tag.type = VIO_TYPE_CTRL;
+       info.tag.stype = VIO_SUBTYPE_INFO;
+       info.tag.stype_env = VNET_MCAST_INFO;
+       info.tag.sid = vio_send_sid(&port->vio);
+       info.set = 1;
+
+       n_addrs = 0;
+       for (m = vp->mcast_list; m; m = m->next) {
+               if (m->sent)
+                       continue;
+               m->sent = 1;
+               memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+                      m->addr, ETH_ALEN);
+               if (++n_addrs == VNET_NUM_MCAST) {
+                       info.count = n_addrs;
+
+                       (void) vio_ldc_send(&port->vio, &info,
+                                           sizeof(info));
+                       n_addrs = 0;
+               }
+       }
+       if (n_addrs) {
+               info.count = n_addrs;
+               (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+       }
+
+       info.set = 0;
+
+       n_addrs = 0;
+       pp = &vp->mcast_list;
+       while ((m = *pp) != NULL) {
+               if (m->hit) {
+                       m->hit = 0;
+                       pp = &m->next;
+                       continue;
+               }
+
+               memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+                      m->addr, ETH_ALEN);
+               if (++n_addrs == VNET_NUM_MCAST) {
+                       info.count = n_addrs;
+                       (void) vio_ldc_send(&port->vio, &info,
+                                           sizeof(info));
+                       n_addrs = 0;
+               }
+
+               *pp = m->next;
+               kfree(m);
+       }
+       if (n_addrs) {
+               info.count = n_addrs;
+               (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+       }
+}
+
 static void vnet_set_rx_mode(struct net_device *dev)
 {
-       /* XXX Implement multicast support XXX */
+       struct vnet *vp = netdev_priv(dev);
+       struct vnet_port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&vp->lock, flags);
+       if (!list_empty(&vp->port_list)) {
+               port = list_entry(vp->port_list.next, struct vnet_port, list);
+
+               if (port->switch_port) {
+                       __update_mc_list(vp, dev);
+                       __send_mc_list(vp, port);
+               }
+       }
+       spin_unlock_irqrestore(&vp->lock, flags);
 }
 
 static int vnet_change_mtu(struct net_device *dev, int new_mtu)
@@ -1070,6 +1202,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
        switch_port = 0;
        if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
                switch_port = 1;
+       port->switch_port = switch_port;
 
        spin_lock_irqsave(&vp->lock, flags);
        if (switch_port)
@@ -1136,7 +1269,7 @@ static struct vio_device_id vnet_port_match[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(vio, vnet_match);
+MODULE_DEVICE_TABLE(vio, vnet_port_match);
 
 static struct vio_driver vnet_port_driver = {
        .id_table       = vnet_port_match,
index 7d3a0cac727b5a06bdda3dd4932c76df01760c85..d347a5bf24b00d1f69e50dc78106086ae3e99eac 100644 (file)
@@ -30,6 +30,8 @@ struct vnet_port {
 
        struct hlist_node       hash;
        u8                      raddr[ETH_ALEN];
+       u8                      switch_port;
+       u8                      __pad;
 
        struct vnet             *vp;
 
@@ -53,6 +55,13 @@ static inline unsigned int vnet_hashfn(u8 *mac)
        return val & (VNET_PORT_HASH_MASK);
 }
 
+struct vnet_mcast_entry {
+       u8                      addr[ETH_ALEN];
+       u8                      sent;
+       u8                      hit;
+       struct vnet_mcast_entry *next;
+};
+
 struct vnet {
        /* Protects port_list and port_hash.  */
        spinlock_t              lock;
@@ -65,6 +74,8 @@ struct vnet {
 
        struct hlist_head       port_hash[VNET_PORT_HASH_SIZE];
 
+       struct vnet_mcast_entry *mcast_list;
+
        struct list_head        list;
        u64                     local_mac;
 };
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
new file mode 100644 (file)
index 0000000..c03072b
--- /dev/null
@@ -0,0 +1,3 @@
+config OF_DEVICE
+       def_bool y
+       depends on OF && (SPARC || PPC_OF)
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
new file mode 100644 (file)
index 0000000..ab9be5d
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y = base.o
+obj-$(CONFIG_OF_DEVICE) += device.o platform.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
new file mode 100644 (file)
index 0000000..9377f3b
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras      August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com
+ *
+ *  Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ *  Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+struct device_node *allnodes;
+
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+DEFINE_RWLOCK(devtree_lock);
+
+int of_n_addr_cells(struct device_node *np)
+{
+       const int *ip;
+
+       do {
+               if (np->parent)
+                       np = np->parent;
+               ip = of_get_property(np, "#address-cells", NULL);
+               if (ip)
+                       return *ip;
+       } while (np->parent);
+       /* No #address-cells property for the root node */
+       return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+       const int *ip;
+
+       do {
+               if (np->parent)
+                       np = np->parent;
+               ip = of_get_property(np, "#size-cells", NULL);
+               if (ip)
+                       return *ip;
+       } while (np->parent);
+       /* No #size-cells property for the root node */
+       return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+struct property *of_find_property(const struct device_node *np,
+                                 const char *name,
+                                 int *lenp)
+{
+       struct property *pp;
+
+       read_lock(&devtree_lock);
+       for (pp = np->properties; pp != 0; pp = pp->next) {
+               if (of_prop_cmp(pp->name, name) == 0) {
+                       if (lenp != 0)
+                               *lenp = pp->length;
+                       break;
+               }
+       }
+       read_unlock(&devtree_lock);
+
+       return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+                        int *lenp)
+{
+       struct property *pp = of_find_property(np, name, lenp);
+
+       return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+               const char *compat)
+{
+       const char* cp;
+       int cplen, l;
+
+       cp = of_get_property(device, "compatible", &cplen);
+       if (cp == NULL)
+               return 0;
+       while (cplen > 0) {
+               if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+                       return 1;
+               l = strlen(cp) + 1;
+               cp += l;
+               cplen -= l;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+/**
+ *     of_get_parent - Get a node's parent if any
+ *     @node:  Node to get parent
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_get_parent(const struct device_node *node)
+{
+       struct device_node *np;
+
+       if (!node)
+               return NULL;
+
+       read_lock(&devtree_lock);
+       np = of_node_get(node->parent);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+/**
+ *     of_get_next_child - Iterate a node childs
+ *     @node:  parent node
+ *     @prev:  previous child of the parent node, or NULL to get first
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_get_next_child(const struct device_node *node,
+       struct device_node *prev)
+{
+       struct device_node *next;
+
+       read_lock(&devtree_lock);
+       next = prev ? prev->sibling : node->child;
+       for (; next; next = next->sibling)
+               if (of_node_get(next))
+                       break;
+       of_node_put(prev);
+       read_unlock(&devtree_lock);
+       return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+/**
+ *     of_find_node_by_path - Find a node matching a full OF path
+ *     @path:  The full path to match
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+       struct device_node *np = allnodes;
+
+       read_lock(&devtree_lock);
+       for (; np; np = np->allnext) {
+               if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
+                   && of_node_get(np))
+                       break;
+       }
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+/**
+ *     of_find_node_by_name - Find a node by its "name" property
+ *     @from:  The node to start searching from or NULL, the node
+ *             you pass will not be searched, only the next one
+ *             will; typically, you pass what the previous call
+ *             returned. of_node_put() will be called on it
+ *     @name:  The name string to match against
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_name(struct device_node *from,
+       const char *name)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = from ? from->allnext : allnodes;
+       for (; np; np = np->allnext)
+               if (np->name && (of_node_cmp(np->name, name) == 0)
+                   && of_node_get(np))
+                       break;
+       of_node_put(from);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+/**
+ *     of_find_node_by_type - Find a node by its "device_type" property
+ *     @from:  The node to start searching from, or NULL to start searching
+ *             the entire device tree. The node you pass will not be
+ *             searched, only the next one will; typically, you pass
+ *             what the previous call returned. of_node_put() will be
+ *             called on from for you.
+ *     @type:  The type string to match against
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+       const char *type)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = from ? from->allnext : allnodes;
+       for (; np; np = np->allnext)
+               if (np->type && (of_node_cmp(np->type, type) == 0)
+                   && of_node_get(np))
+                       break;
+       of_node_put(from);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+/**
+ *     of_find_compatible_node - Find a node based on type and one of the
+ *                                tokens in its "compatible" property
+ *     @from:          The node to start searching from or NULL, the node
+ *                     you pass will not be searched, only the next one
+ *                     will; typically, you pass what the previous call
+ *                     returned. of_node_put() will be called on it
+ *     @type:          The type string to match "device_type" or NULL to ignore
+ *     @compatible:    The string to match to one of the tokens in the device
+ *                     "compatible" list.
+ *
+ *     Returns a node pointer with refcount incremented, use
+ *     of_node_put() on it when done.
+ */
+struct device_node *of_find_compatible_node(struct device_node *from,
+       const char *type, const char *compatible)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       np = from ? from->allnext : allnodes;
+       for (; np; np = np->allnext) {
+               if (type
+                   && !(np->type && (of_node_cmp(np->type, type) == 0)))
+                       continue;
+               if (of_device_is_compatible(np, compatible) && of_node_get(np))
+                       break;
+       }
+       of_node_put(from);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
diff --git a/drivers/of/device.c b/drivers/of/device.c
new file mode 100644 (file)
index 0000000..6245f06
--- /dev/null
@@ -0,0 +1,131 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @ids: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+                                        const struct device_node *node)
+{
+       while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+               int match = 1;
+               if (matches->name[0])
+                       match &= node->name
+                               && !strcmp(matches->name, node->name);
+               if (matches->type[0])
+                       match &= node->type
+                               && !strcmp(matches->type, node->type);
+               if (matches->compatible[0])
+                       match &= of_device_is_compatible(node,
+                                               matches->compatible);
+               if (match)
+                       return matches;
+               matches++;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(of_match_node);
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+                                       const struct of_device *dev)
+{
+       if (!dev->node)
+               return NULL;
+       return of_match_node(matches, dev->node);
+}
+EXPORT_SYMBOL(of_match_device);
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+       struct device *tmp;
+
+       if (!dev)
+               return NULL;
+       tmp = get_device(&dev->dev);
+       if (tmp)
+               return to_of_device(tmp);
+       else
+               return NULL;
+}
+EXPORT_SYMBOL(of_dev_get);
+
+void of_dev_put(struct of_device *dev)
+{
+       if (dev)
+               put_device(&dev->dev);
+}
+EXPORT_SYMBOL(of_dev_put);
+
+static ssize_t dev_show_devspec(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct of_device *ofdev;
+
+       ofdev = to_of_device(dev);
+       return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+       struct of_device *ofdev;
+
+       ofdev = to_of_device(dev);
+       of_node_put(ofdev->node);
+       kfree(ofdev);
+}
+EXPORT_SYMBOL(of_release_dev);
+
+int of_device_register(struct of_device *ofdev)
+{
+       int rc;
+
+       BUG_ON(ofdev->node == NULL);
+
+       rc = device_register(&ofdev->dev);
+       if (rc)
+               return rc;
+
+       rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
+       if (rc)
+               device_unregister(&ofdev->dev);
+
+       return rc;
+}
+EXPORT_SYMBOL(of_device_register);
+
+void of_device_unregister(struct of_device *ofdev)
+{
+       device_remove_file(&ofdev->dev, &dev_attr_devspec);
+       device_unregister(&ofdev->dev);
+}
+EXPORT_SYMBOL(of_device_unregister);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
new file mode 100644 (file)
index 0000000..864f09f
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *                      <benh@kernel.crashing.org>
+ *    and               Arnd Bergmann, IBM Corp.
+ *    Merged from powerpc/kernel/of_platform.c and
+ *    sparc{,64}/kernel/of_device.c by Stephen Rothwell
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *of_drv = to_of_platform_driver(drv);
+       const struct of_device_id *matches = of_drv->match_table;
+
+       if (!matches)
+               return 0;
+
+       return of_match_device(matches, of_dev) != NULL;
+}
+
+static int of_platform_device_probe(struct device *dev)
+{
+       int error = -ENODEV;
+       struct of_platform_driver *drv;
+       struct of_device *of_dev;
+       const struct of_device_id *match;
+
+       drv = to_of_platform_driver(dev->driver);
+       of_dev = to_of_device(dev);
+
+       if (!drv->probe)
+               return error;
+
+       of_dev_get(of_dev);
+
+       match = of_match_device(drv->match_table, of_dev);
+       if (match)
+               error = drv->probe(of_dev, match);
+       if (error)
+               of_dev_put(of_dev);
+
+       return error;
+}
+
+static int of_platform_device_remove(struct device *dev)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+       if (dev->driver && drv->remove)
+               drv->remove(of_dev);
+       return 0;
+}
+
+static int of_platform_device_suspend(struct device *dev, pm_message_t state)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+       int error = 0;
+
+       if (dev->driver && drv->suspend)
+               error = drv->suspend(of_dev, state);
+       return error;
+}
+
+static int of_platform_device_resume(struct device * dev)
+{
+       struct of_device *of_dev = to_of_device(dev);
+       struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+       int error = 0;
+
+       if (dev->driver && drv->resume)
+               error = drv->resume(of_dev);
+       return error;
+}
+
+int of_bus_type_init(struct bus_type *bus, const char *name)
+{
+       bus->name = name;
+       bus->match = of_platform_bus_match;
+       bus->probe = of_platform_device_probe;
+       bus->remove = of_platform_device_remove;
+       bus->suspend = of_platform_device_suspend;
+       bus->resume = of_platform_device_resume;
+       return bus_register(bus);
+}
index edd6de9957260abb4f631b22090903d916fc8b34..8134c7e198a5b1a197a77b4faed123c15327650a 100644 (file)
@@ -26,8 +26,9 @@
 #include <linux/profile.h>
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/oprofile.h>
 #include <linux/sched.h>
+
 #include "oprofile_stats.h"
 #include "event_buffer.h"
 #include "cpu_buffer.h"
index 9b6a4ebd03e39c65a3ba0cdcf6c336f023109a37..5076ed1ebd8feff23e3df134a808eb211e2cdfc7 100644 (file)
@@ -19,28 +19,10 @@ void free_event_buffer(void);
  
 /* wake up the process sleeping on the event file */
 void wake_up_buffer_waiter(void);
-/* Each escaped entry is prefixed by ESCAPE_CODE
- * then one of the following codes, then the
- * relevant data.
- */
-#define ESCAPE_CODE                    ~0UL
-#define CTX_SWITCH_CODE                1
-#define CPU_SWITCH_CODE                2
-#define COOKIE_SWITCH_CODE             3
-#define KERNEL_ENTER_SWITCH_CODE       4
-#define KERNEL_EXIT_SWITCH_CODE                5
-#define MODULE_LOADED_CODE             6
-#define CTX_TGID_CODE                  7
-#define TRACE_BEGIN_CODE               8
-#define TRACE_END_CODE                 9
+
 #define INVALID_COOKIE ~0UL
 #define NO_COOKIE 0UL
 
-/* add data to the event buffer */
-void add_event_entry(unsigned long data);
 extern const struct file_operations event_buffer_fops;
  
 /* mutex between sync_cpu_buffers() and the
index e5162a64018b58e6f7133eef49a55fb652f89450..2c645170f06e49a80da62f740445fcea96592c62 100644 (file)
@@ -53,9 +53,24 @@ int oprofile_setup(void)
         * us missing task deaths and eventually oopsing
         * when trying to process the event buffer.
         */
+       if (oprofile_ops.sync_start) {
+               int sync_ret = oprofile_ops.sync_start();
+               switch (sync_ret) {
+               case 0:
+                       goto post_sync;
+               case 1:
+                       goto do_generic;
+               case -1:
+                       goto out3;
+               default:
+                       goto out3;
+               }
+       }
+do_generic:
        if ((err = sync_start()))
                goto out3;
 
+post_sync:
        is_setup = 1;
        mutex_unlock(&start_mutex);
        return 0;
@@ -118,7 +133,20 @@ out:
 void oprofile_shutdown(void)
 {
        mutex_lock(&start_mutex);
+       if (oprofile_ops.sync_stop) {
+               int sync_ret = oprofile_ops.sync_stop();
+               switch (sync_ret) {
+               case 0:
+                       goto post_sync;
+               case 1:
+                       goto do_generic;
+               default:
+                       goto post_sync;
+               }
+       }
+do_generic:
        sync_stop();
+post_sync:
        if (oprofile_ops.shutdown)
                oprofile_ops.shutdown();
        is_setup = 0;
index 09c93ff932b15453d316df1d12b7844697d9ca22..d449b150930ea7aedeb0b8ad0cb43a1140575391 100644 (file)
@@ -35,7 +35,7 @@ if PARPORT
 
 config PARPORT_PC
        tristate "PC-style hardware"
-       depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV
+       depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && (!M68K || ISA)
        ---help---
          You should say Y here if you have a PC-style parallel port. All
          IBM PC compatible computers and some Alphas have PC-style
index cea401feb0f3151a7e5e032ce494621ba3ef3c80..35f34665e3c44f06e01c103226462023cdaa5aab 100644 (file)
@@ -394,7 +394,7 @@ config RTC_DRV_SA1100
 
 config RTC_DRV_SH
        tristate "SuperH On-Chip RTC"
-       depends on RTC_CLASS && SUPERH
+       depends on RTC_CLASS && SUPERH && (CPU_SH3 || CPU_SH4)
        help
          Say Y here to enable support for the on-chip RTC found in
          most SuperH processors.
index 002643392d424accdbeb33a79f546bbe5c5d8543..2553629ec15db76dc364ec7cee2373783cdfe6e4 100644 (file)
@@ -33,6 +33,7 @@ struct sbus_bus *sbus_root;
 
 static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
 {
+       struct dev_archdata *sd;
        unsigned long base;
        const void *pval;
        int len, err;
@@ -67,6 +68,10 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde
 
        sbus_fill_device_irq(sdev);
 
+       sd = &sdev->ofdev.dev.archdata;
+       sd->prom_node = dp;
+       sd->op = &sdev->ofdev;
+
        sdev->ofdev.node = dp;
        if (sdev->parent)
                sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
index 372723161c97b8278c594220ff0c949076bdcd55..a947257b89646d8d7e99e5320ab0eaa04fbd62ab 100644 (file)
@@ -483,7 +483,7 @@ source "drivers/scsi/aic94xx/Kconfig"
 # All the I2O code and drivers do not seem to be 64bit safe.
 config SCSI_DPT_I2O
        tristate "Adaptec I2O RAID support "
-       depends on !64BIT && SCSI && PCI
+       depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
        help
          This driver supports all of Adaptec's I2O based RAID controllers as 
          well as the DPT SmartRaid V cards.  This is an Adaptec maintained
index 773d11dd995394843d4d072238395a3608d7fc24..79b4df1581400691d1b9bbf9676b732a01586167 100644 (file)
@@ -95,6 +95,8 @@ enum {
 /* The master ring of all esp hosts we are managing in this driver. */
 static struct NCR_ESP *espchain;
 int nesps = 0, esps_in_use = 0, esps_running = 0;
+EXPORT_SYMBOL(nesps);
+EXPORT_SYMBOL(esps_running);
 
 irqreturn_t esp_intr(int irq, void *dev_id);
 
@@ -524,6 +526,7 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
        /* Eat any bitrot in the chip and we are done... */
        trash = esp_read(eregs->esp_intrpt);
 }
+EXPORT_SYMBOL(esp_bootup_reset);
 
 /* Allocate structure and insert basic data such as SCSI chip frequency
  * data and a pointer to the device
@@ -772,6 +775,7 @@ const char *esp_info(struct Scsi_Host *host)
                panic("Bogon ESP revision");
        };
 }
+EXPORT_SYMBOL(esp_info);
 
 /* From Wolfgang Stanglmeier's NCR scsi driver. */
 struct info_str
@@ -902,6 +906,7 @@ int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t off
                *start = buffer;
        return esp_host_info(esp, buffer, offset, length);
 }
+EXPORT_SYMBOL(esp_proc_info);
 
 static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
@@ -3535,6 +3540,7 @@ state_machine:
        if(esp->dma_irq_exit)
                esp->dma_irq_exit(esp);
 }
+EXPORT_SYMBOL(esp_handle);
 
 #ifndef CONFIG_SMP
 irqreturn_t esp_intr(int irq, void *dev_id)
@@ -3631,6 +3637,7 @@ void esp_release(void)
        esps_in_use--;
        esps_running = esps_in_use;
 }
+EXPORT_SYMBOL(esp_release);
 #endif
 
 EXPORT_SYMBOL(esp_abort);
index aebcd5fcdc5518e012bf0ff425616ffcb7cd8cfe..7829ab1e2fb46d5bf350c9c6d54d0ff9dec4a01a 100644 (file)
@@ -1885,7 +1885,7 @@ static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
        struct sockaddr_in *sin;
        int rc = 0, len;
 
-       addr = kmalloc(GFP_KERNEL, sizeof(*addr));
+       addr = kmalloc(sizeof(*addr), GFP_KERNEL);
        if (!addr)
                return -ENOMEM;
 
index b45ba5392dd362941e12770edcf12c5671e590b2..70a09a3d5af0ee6999b98a57d766f4420688d94c 100644 (file)
 #include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/serial_core.h>
 #include <linux/init.h>
 
-#include <asm/oplib.h>
+#include <asm/prom.h>
 
 #include "suncore.h"
 
@@ -26,92 +27,60 @@ int sunserial_current_minor = 64;
 
 EXPORT_SYMBOL(sunserial_current_minor);
 
-void
-sunserial_console_termios(struct console *con)
+int sunserial_console_match(struct console *con, struct device_node *dp,
+                           struct uart_driver *drv, int line)
 {
-       char mode[16], buf[16], *s;
-       char mode_prop[] = "ttyX-mode";
-       char cd_prop[]   = "ttyX-ignore-cd";
-       char dtr_prop[]  = "ttyX-rts-dtr-off";
-       char *ssp_console_modes_prop = "ssp-console-modes";
-       int baud, bits, stop, cflag;
-       char parity;
-       int carrier = 0;
-       int rtsdtr = 1;
-       int topnd, nd;
-
-       if (!serial_console)
-               return;
-
-       switch (serial_console) {
-       case PROMDEV_OTTYA:
-               mode_prop[3] = 'a';
-               cd_prop[3] = 'a';
-               dtr_prop[3] = 'a';
-               break;
-
-       case PROMDEV_OTTYB:
-               mode_prop[3] = 'b';
-               cd_prop[3] = 'b';
-               dtr_prop[3] = 'b';
-               break;
-
-       case PROMDEV_ORSC:
-
-               nd = prom_pathtoinode("rsc");
-               if (!nd) {
-                       strcpy(mode, "115200,8,n,1,-");
-                       goto no_options;
-               }
+       int off;
 
-               if (!prom_node_has_property(nd, ssp_console_modes_prop)) {
-                       strcpy(mode, "115200,8,n,1,-");
-                       goto no_options;
-               }
+       if (!con || of_console_device != dp)
+               return 0;
 
-               memset(mode, 0, sizeof(mode));
-               prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode));
-               goto no_options;
+       off = 0;
+       if (of_console_options &&
+           *of_console_options == 'b')
+               off = 1;
 
-       default:
-               strcpy(mode, "9600,8,n,1,-");
-               goto no_options;
-       }
+       if ((line & 1) != off)
+               return 0;
 
-       topnd = prom_getchild(prom_root_node);
-       nd = prom_searchsiblings(topnd, "options");
-       if (!nd) {
-               strcpy(mode, "9600,8,n,1,-");
-               goto no_options;
-       }
-
-       if (!prom_node_has_property(nd, mode_prop)) {
-               strcpy(mode, "9600,8,n,1,-");
-               goto no_options;
-       }
+       con->index = line;
+       drv->cons = con;
+       add_preferred_console(con->name, line, NULL);
 
-       memset(mode, 0, sizeof(mode));
-       prom_getstring(nd, mode_prop, mode, sizeof(mode));
-
-       if (prom_node_has_property(nd, cd_prop)) {
-               memset(buf, 0, sizeof(buf));
-               prom_getstring(nd, cd_prop, buf, sizeof(buf));
-               if (!strcmp(buf, "false"))
-                       carrier = 1;
-
-               /* XXX: this is unused below. */
-       }
+       return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
 
-       if (prom_node_has_property(nd, dtr_prop)) {
-               memset(buf, 0, sizeof(buf));
-               prom_getstring(nd, dtr_prop, buf, sizeof(buf));
-               if (!strcmp(buf, "false"))
-                       rtsdtr = 0;
+void
+sunserial_console_termios(struct console *con)
+{
+       struct device_node *dp;
+       const char *od, *mode, *s;
+       char mode_prop[] = "ttyX-mode";
+       int baud, bits, stop, cflag;
+       char parity;
 
-               /* XXX: this is unused below. */
+       dp = of_find_node_by_path("/options");
+       od = of_get_property(dp, "output-device", NULL);
+       if (!strcmp(od, "rsc")) {
+               mode = of_get_property(of_console_device,
+                                      "ssp-console-modes", NULL);
+               if (!mode)
+                       mode = "115200,8,n,1,-";
+       } else {
+               char c;
+
+               c = 'a';
+               if (of_console_options)
+                       c = *of_console_options;
+
+               mode_prop[3] = c;
+
+               mode = of_get_property(dp, mode_prop, NULL);
+               if (!mode)
+                       mode = "9600,8,n,1,-";
        }
 
-no_options:
        cflag = CREAD | HUPCL | CLOCAL;
 
        s = mode;
index 513916a8ce376f4f25796be7ac8bd942f38ef4ef..829d7d65d6dbf4dec55e8992a8d77a795b0b02d2 100644 (file)
@@ -24,6 +24,8 @@ extern int suncore_mouse_baud_detection(unsigned char, int);
 
 extern int sunserial_current_minor;
 
+extern int sunserial_console_match(struct console *, struct device_node *,
+                                  struct uart_driver *, int);
 extern void sunserial_console_termios(struct console *);
 
 #endif /* !(_SERIAL_SUN_H) */
index d82be42ff29acf2f17b490f93beefc00f40fff54..8ff900b098116ebc7c54f4b5ec676223fe4cf54b 100644 (file)
@@ -520,16 +520,6 @@ static struct console sunhv_console = {
        .data   =       &sunhv_reg,
 };
 
-static inline struct console *SUNHV_CONSOLE(void)
-{
-       if (con_is_present())
-               return NULL;
-
-       sunhv_console.index = 0;
-
-       return &sunhv_console;
-}
-
 static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct uart_port *port;
@@ -582,7 +572,8 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
        sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
        sunserial_current_minor += 1;
 
-       sunhv_reg.cons = SUNHV_CONSOLE();
+       sunserial_console_match(&sunhv_console, op->node,
+                               &sunhv_reg, port->line);
 
        err = uart_add_one_port(&sunhv_reg, port);
        if (err)
index 8a0f9e4408d4a78976040178885efc1571b7a184..bca57bb949393275c902f5f31e35e1abe9527d1a 100644 (file)
@@ -968,22 +968,6 @@ static struct console sunsab_console = {
 
 static inline struct console *SUNSAB_CONSOLE(void)
 {
-       int i;
-
-       if (con_is_present())
-               return NULL;
-
-       for (i = 0; i < num_channels; i++) {
-               int this_minor = sunsab_reg.minor + i;
-
-               if ((this_minor - 64) == (serial_console - 1))
-                       break;
-       }
-       if (i == num_channels)
-               return NULL;
-
-       sunsab_console.index = i;
-
        return &sunsab_console;
 }
 #else
@@ -1080,7 +1064,12 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
                return err;
        }
 
+       sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+                               &sunsab_reg, up[0].port.line);
        uart_add_one_port(&sunsab_reg, &up[0].port);
+
+       sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+                               &sunsab_reg, up[1].port.line);
        uart_add_one_port(&sunsab_reg, &up[1].port);
 
        dev_set_drvdata(&op->dev, &up[0]);
@@ -1164,7 +1153,6 @@ static int __init sunsab_init(void)
                }
 
                sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
-               sunsab_reg.cons = SUNSAB_CONSOLE();
                sunserial_current_minor += num_channels;
        }
 
index 26d720baf88c17619577d09420b50cade271e09d..79b13685bdfa45b7dc12f583f1486492f06c7992 100644 (file)
@@ -1371,28 +1371,12 @@ static struct console sunsu_console = {
  *     Register console.
  */
 
-static inline struct console *SUNSU_CONSOLE(int num_uart)
+static inline struct console *SUNSU_CONSOLE(void)
 {
-       int i;
-
-       if (con_is_present())
-               return NULL;
-
-       for (i = 0; i < num_uart; i++) {
-               int this_minor = sunsu_reg.minor + i;
-
-               if ((this_minor - 64) == (serial_console - 1))
-                       break;
-       }
-       if (i == num_uart)
-               return NULL;
-
-       sunsu_console.index = i;
-
        return &sunsu_console;
 }
 #else
-#define SUNSU_CONSOLE(num_uart)                (NULL)
+#define SUNSU_CONSOLE()                        (NULL)
 #define sunsu_serial_console_init()    do { } while (0)
 #endif
 
@@ -1482,6 +1466,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
 
        up->port.ops = &sunsu_pops;
 
+       sunserial_console_match(SUNSU_CONSOLE(), dp,
+                               &sunsu_reg, up->port.line);
        err = uart_add_one_port(&sunsu_reg, &up->port);
        if (err)
                goto out_unmap;
@@ -1572,7 +1558,6 @@ static int __init sunsu_init(void)
                        return err;
                sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
                sunserial_current_minor += num_uart;
-               sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
        }
 
        err = of_register_driver(&su_driver, &of_bus_type);
index 0a3e10a4a35dec59485e1455b5ee8f30a0277c25..1d262c0c613fadbebddde44548d167eb9ec322ce 100644 (file)
@@ -1226,23 +1226,6 @@ static struct console sunzilog_console_ops = {
 
 static inline struct console *SUNZILOG_CONSOLE(void)
 {
-       int i;
-
-       if (con_is_present())
-               return NULL;
-
-       for (i = 0; i < NUM_CHANNELS; i++) {
-               int this_minor = sunzilog_reg.minor + i;
-
-               if ((this_minor - 64) == (serial_console - 1))
-                       break;
-       }
-       if (i == NUM_CHANNELS)
-               return NULL;
-
-       sunzilog_console_ops.index = i;
-       sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
-
        return &sunzilog_console_ops;
 }
 
@@ -1428,12 +1411,18 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
        sunzilog_init_hw(&up[1]);
 
        if (!keyboard_mouse) {
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+                                           &sunzilog_reg, up[0].port.line))
+                       up->flags |= SUNZILOG_FLAG_IS_CONS;
                err = uart_add_one_port(&sunzilog_reg, &up[0].port);
                if (err) {
                        of_iounmap(&op->resource[0],
                                   rp, sizeof(struct zilog_layout));
                        return err;
                }
+               if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+                                           &sunzilog_reg, up[1].port.line))
+                       up->flags |= SUNZILOG_FLAG_IS_CONS;
                err = uart_add_one_port(&sunzilog_reg, &up[1].port);
                if (err) {
                        uart_remove_one_port(&sunzilog_reg, &up[0].port);
@@ -1531,7 +1520,6 @@ static int __init sunzilog_init(void)
                        goto out_free_tables;
 
                sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
-               sunzilog_reg.cons = SUNZILOG_CONSOLE();
 
                sunserial_current_minor += uart_count;
        }
index 1bc884051e0f490dbae657df3bd085b5b8e568de..02c52f8d5dbf2b097af0b5f9e6b0a389afa7af6a 100644 (file)
@@ -456,7 +456,7 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
                                 int* actual_length)
 {
        struct timer_list timer;
-       int status;
+       int status = urb->status;
 
        init_timer(&timer);
        timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
@@ -464,7 +464,6 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
        timer.function = cxacru_timeout_kill;
        add_timer(&timer);
        wait_for_completion(done);
-       status = urb->status;
        del_timer_sync(&timer);
 
        if (actual_length)
index 638b8009b3bc2be1b78d9029d4a64980d94943e9..eb0615abff68a819f4dae10ff2a0010a637dbaaa 100644 (file)
@@ -612,7 +612,8 @@ static void speedtch_handle_int(struct urb *int_urb)
        struct speedtch_instance_data *instance = int_urb->context;
        struct usbatm_data *usbatm = instance->usbatm;
        unsigned int count = int_urb->actual_length;
-       int ret = int_urb->status;
+       int status = int_urb->status;
+       int ret;
 
        /* The magic interrupt for "up state" */
        static const unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
@@ -621,8 +622,8 @@ static void speedtch_handle_int(struct urb *int_urb)
 
        atm_dbg(usbatm, "%s entered\n", __func__);
 
-       if (ret < 0) {
-               atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
+       if (status < 0) {
+               atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status);
                goto fail;
        }
 
index 8f046659b4e947990036968cc836bf69e8bc73e1..a1a1c9d467e028157c84289a9d92ccd0fe97c4b9 100644 (file)
@@ -1308,11 +1308,13 @@ static void uea_intr(struct urb *urb)
 {
        struct uea_softc *sc = urb->context;
        struct intr_pkt *intr = urb->transfer_buffer;
+       int status = urb->status;
+
        uea_enters(INS_TO_USBDEV(sc));
 
-       if (unlikely(urb->status < 0)) {
+       if (unlikely(status < 0)) {
                uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",
-                      urb->status);
+                      status);
                return;
        }
 
index 11e9b15ca45a35fb7c37e84fef91e07c54b2b507..e717f5b1caeeedeadbf51634726356311faa4c95 100644 (file)
@@ -257,9 +257,10 @@ static void usbatm_complete(struct urb *urb)
 {
        struct usbatm_channel *channel = urb->context;
        unsigned long flags;
+       int status = urb->status;
 
        vdbg("%s: urb 0x%p, status %d, actual_length %d",
-            __func__, urb, urb->status, urb->actual_length);
+            __func__, urb, status, urb->actual_length);
 
        /* usually in_interrupt(), but not always */
        spin_lock_irqsave(&channel->lock, flags);
@@ -269,16 +270,16 @@ static void usbatm_complete(struct urb *urb)
 
        spin_unlock_irqrestore(&channel->lock, flags);
 
-       if (unlikely(urb->status) &&
+       if (unlikely(status) &&
                        (!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
-                        urb->status != -EILSEQ ))
+                        status != -EILSEQ ))
        {
-               if (urb->status == -ESHUTDOWN)
+               if (status == -ESHUTDOWN)
                        return;
 
                if (printk_ratelimit())
                        atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
-                               __func__, urb, urb->status);
+                               __func__, urb, status);
                /* throttle processing in case of an error */
                mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
        } else
index cd51520c7e72e10286017998bf00081c8d8571cc..fe940e0536e03488016d1171da3866ce8bb6dd00 100644 (file)
@@ -257,9 +257,10 @@ static void acm_ctrl_irq(struct urb *urb)
        struct usb_cdc_notification *dr = urb->transfer_buffer;
        unsigned char *data;
        int newctrl;
-       int status;
+       int retval;
+       int status = urb->status;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                /* success */
                break;
@@ -267,10 +268,10 @@ static void acm_ctrl_irq(struct urb *urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
                return;
        default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+               dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
                goto exit;
        }
 
@@ -311,10 +312,10 @@ static void acm_ctrl_irq(struct urb *urb)
                        break;
        }
 exit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
-       if (status)
+       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       if (retval)
                err ("%s - usb_submit_urb failed with result %d",
-                    __FUNCTION__, status);
+                    __FUNCTION__, retval);
 }
 
 /* data interface returns incoming bytes, or we got unthrottled */
@@ -324,7 +325,8 @@ static void acm_read_bulk(struct urb *urb)
        struct acm_ru *rcv = urb->context;
        struct acm *acm = rcv->instance;
        int status = urb->status;
-       dbg("Entering acm_read_bulk with status %d", urb->status);
+
+       dbg("Entering acm_read_bulk with status %d", status);
 
        if (!ACM_READY(acm))
                return;
index 9a1478972bf5aee1cf75c5f70434d4e68c5fa83c..5192cd9356def4c3b23fb58783ca0ab379e75f14 100644 (file)
@@ -289,16 +289,17 @@ static int proto_bias = -1;
 static void usblp_bulk_read(struct urb *urb)
 {
        struct usblp *usblp = urb->context;
+       int status = urb->status;
 
        if (usblp->present && usblp->used) {
-               if (urb->status)
+               if (status)
                        printk(KERN_WARNING "usblp%d: "
                            "nonzero read bulk status received: %d\n",
-                           usblp->minor, urb->status);
+                           usblp->minor, status);
        }
        spin_lock(&usblp->lock);
-       if (urb->status < 0)
-               usblp->rstatus = urb->status;
+       if (status < 0)
+               usblp->rstatus = status;
        else
                usblp->rstatus = urb->actual_length;
        usblp->rcomplete = 1;
@@ -311,16 +312,17 @@ static void usblp_bulk_read(struct urb *urb)
 static void usblp_bulk_write(struct urb *urb)
 {
        struct usblp *usblp = urb->context;
+       int status = urb->status;
 
        if (usblp->present && usblp->used) {
-               if (urb->status)
+               if (status)
                        printk(KERN_WARNING "usblp%d: "
                            "nonzero write bulk status received: %d\n",
-                           usblp->minor, urb->status);
+                           usblp->minor, status);
        }
        spin_lock(&usblp->lock);
-       if (urb->status < 0)
-               usblp->wstatus = urb->status;
+       if (status < 0)
+               usblp->wstatus = status;
        else
                usblp->wstatus = urb->actual_length;
        usblp->wcomplete = 1;
@@ -741,10 +743,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
                 */
                rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
                if (rv < 0) {
-                       /*
-                        * If interrupted, we simply leave the URB to dangle,
-                        * so the ->release will call usb_kill_urb().
-                        */
+                       if (rv == -EAGAIN) {
+                               /* Presume that it's going to complete well. */
+                               writecount += transfer_length;
+                       }
+                       /* Leave URB dangling, to be cleaned on close. */
                        goto collect_error;
                }
 
index 963520fbef9061db3a42f12d624840bab9976e92..42ef1d5f6c8ad07c78416bdbaa2c3e9c60e7516e 100644 (file)
@@ -99,12 +99,17 @@ EXPORT_SYMBOL_GPL (usb_bus_list_lock);
 /* used for controlling access to virtual root hubs */
 static DEFINE_SPINLOCK(hcd_root_hub_lock);
 
-/* used when updating hcd data */
-static DEFINE_SPINLOCK(hcd_data_lock);
+/* used when updating an endpoint's URB list */
+static DEFINE_SPINLOCK(hcd_urb_list_lock);
 
 /* wait queue for synchronous unlinks */
 DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
 
+static inline int is_root_hub(struct usb_device *udev)
+{
+       return (udev->parent == NULL);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -906,14 +911,13 @@ EXPORT_SYMBOL (usb_calc_bus_time);
 static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
 {
        unsigned long           flags;
-       int at_root_hub = (urb->dev == hcd->self.root_hub);
 
        /* clear all state linking urb to this dev (and hcd) */
-       spin_lock_irqsave (&hcd_data_lock, flags);
+       spin_lock_irqsave(&hcd_urb_list_lock, flags);
        list_del_init (&urb->urb_list);
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
+       spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
 
-       if (hcd->self.uses_dma && !at_root_hub) {
+       if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
                if (usb_pipecontrol (urb->pipe)
                        && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
                        dma_unmap_single (hcd->self.controller, urb->setup_dma,
@@ -955,7 +959,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
 
        // FIXME:  verify that quiescing hc works right (RH cleans up)
 
-       spin_lock_irqsave (&hcd_data_lock, flags);
+       spin_lock_irqsave(&hcd_urb_list_lock, flags);
        ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
                        [usb_pipeendpoint(urb->pipe)];
        if (unlikely (!ep))
@@ -972,7 +976,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
                status = -ESHUTDOWN;
                break;
        }
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
+       spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
        if (status) {
                INIT_LIST_HEAD (&urb->urb_list);
                usbmon_urb_submit_error(&hcd->self, urb, status);
@@ -986,7 +990,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
        urb = usb_get_urb (urb);
        atomic_inc (&urb->use_count);
 
-       if (urb->dev == hcd->self.root_hub) {
+       if (is_root_hub(urb->dev)) {
                /* NOTE:  requirement on hub callers (usbfs and the hub
                 * driver, for now) that URBs' urb->transfer_buffer be
                 * valid and usb_buffer_{sync,unmap}() not be needed, since
@@ -1033,18 +1037,6 @@ done:
 
 /*-------------------------------------------------------------------------*/
 
-/* called in any context */
-int usb_hcd_get_frame_number (struct usb_device *udev)
-{
-       struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
-
-       if (!HC_IS_RUNNING (hcd->state))
-               return -ESHUTDOWN;
-       return hcd->driver->get_frame_number (hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
 /* this makes the hcd giveback() the urb more quickly, by kicking it
  * off hardware queues (which may take a while) and returning it as
  * soon as practical.  we've already set up the urb's return status,
@@ -1055,7 +1047,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
 {
        int             value;
 
-       if (urb->dev == hcd->self.root_hub)
+       if (is_root_hub(urb->dev))
                value = usb_rh_urb_dequeue (hcd, urb);
        else {
 
@@ -1103,11 +1095,11 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
         * that it was submitted.  But as a rule it can't know whether or
         * not it's already been unlinked ... so we respect the reversed
         * lock sequence needed for the usb_hcd_giveback_urb() code paths
-        * (urb lock, then hcd_data_lock) in case some other CPU is now
+        * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
         * unlinking it.
         */
        spin_lock_irqsave (&urb->lock, flags);
-       spin_lock (&hcd_data_lock);
+       spin_lock(&hcd_urb_list_lock);
 
        sys = &urb->dev->dev;
        hcd = bus_to_hcd(urb->dev->bus);
@@ -1139,17 +1131,16 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
         * finish unlinking the initial failed usb_set_address()
         * or device descriptor fetch.
         */
-       if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags)
-           && hcd->self.root_hub != urb->dev) {
+       if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+                       !is_root_hub(urb->dev)) {
                dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
-                       "Controller is probably using the wrong IRQ."
-                       "\n");
+                       "Controller is probably using the wrong IRQ.\n");
                set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
        }
 
        urb->status = status;
 
-       spin_unlock (&hcd_data_lock);
+       spin_unlock(&hcd_urb_list_lock);
        spin_unlock_irqrestore (&urb->lock, flags);
 
        retval = unlink1 (hcd, urb);
@@ -1158,7 +1149,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
        return retval;
 
 done:
-       spin_unlock (&hcd_data_lock);
+       spin_unlock(&hcd_urb_list_lock);
        spin_unlock_irqrestore (&urb->lock, flags);
        if (retval != -EIDRM && sys && sys->driver)
                dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
@@ -1167,6 +1158,35 @@ done:
 
 /*-------------------------------------------------------------------------*/
 
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function.  The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv).  It also released all HCD locks;
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ */
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+{
+       urb_unlink(hcd, urb);
+       usbmon_urb_complete (&hcd->self, urb);
+       usb_unanchor_urb(urb);
+
+       /* pass ownership to the completion handler */
+       urb->complete (urb);
+       atomic_dec (&urb->use_count);
+       if (unlikely (urb->reject))
+               wake_up (&usb_kill_urb_queue);
+       usb_put_urb (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
+
+/*-------------------------------------------------------------------------*/
+
 /* disables the endpoint: cancels any pending urbs, then synchronizes with
  * the hcd to make sure all endpoint state is gone from hardware, and then
  * waits until the endpoint's queue is completely drained. use for
@@ -1186,7 +1206,7 @@ void usb_hcd_endpoint_disable (struct usb_device *udev,
 
        /* ep is already gone from udev->ep_{in,out}[]; no more submits */
 rescan:
-       spin_lock (&hcd_data_lock);
+       spin_lock(&hcd_urb_list_lock);
        list_for_each_entry (urb, &ep->urb_list, urb_list) {
                int     tmp;
 
@@ -1194,7 +1214,7 @@ rescan:
                if (urb->status != -EINPROGRESS)
                        continue;
                usb_get_urb (urb);
-               spin_unlock (&hcd_data_lock);
+               spin_unlock(&hcd_urb_list_lock);
 
                spin_lock (&urb->lock);
                tmp = urb->status;
@@ -1223,7 +1243,7 @@ rescan:
                /* list contents may have changed */
                goto rescan;
        }
-       spin_unlock (&hcd_data_lock);
+       spin_unlock(&hcd_urb_list_lock);
        local_irq_enable ();
 
        /* synchronize with the hardware, so old configuration state
@@ -1240,7 +1260,7 @@ rescan:
         * endpoint_disable methods.
         */
        while (!list_empty (&ep->urb_list)) {
-               spin_lock_irq (&hcd_data_lock);
+               spin_lock_irq(&hcd_urb_list_lock);
 
                /* The list may have changed while we acquired the spinlock */
                urb = NULL;
@@ -1249,7 +1269,7 @@ rescan:
                                        urb_list);
                        usb_get_urb (urb);
                }
-               spin_unlock_irq (&hcd_data_lock);
+               spin_unlock_irq(&hcd_urb_list_lock);
 
                if (urb) {
                        usb_kill_urb (urb);
@@ -1260,6 +1280,18 @@ rescan:
 
 /*-------------------------------------------------------------------------*/
 
+/* called in any context */
+int usb_hcd_get_frame_number (struct usb_device *udev)
+{
+       struct usb_hcd  *hcd = bus_to_hcd(udev->bus);
+
+       if (!HC_IS_RUNNING (hcd->state))
+               return -ESHUTDOWN;
+       return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
 #ifdef CONFIG_PM
 
 int hcd_bus_suspend(struct usb_device *rhdev)
@@ -1394,35 +1426,6 @@ EXPORT_SYMBOL (usb_bus_start_enum);
 
 /*-------------------------------------------------------------------------*/
 
-/**
- * usb_hcd_giveback_urb - return URB from HCD to device driver
- * @hcd: host controller returning the URB
- * @urb: urb being returned to the USB device driver.
- * Context: in_interrupt()
- *
- * This hands the URB from HCD to its USB device driver, using its
- * completion function.  The HCD has freed all per-urb resources
- * (and is done using urb->hcpriv).  It also released all HCD locks;
- * the device driver won't cause problems if it frees, modifies,
- * or resubmits this URB.
- */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
-{
-       urb_unlink(hcd, urb);
-       usbmon_urb_complete (&hcd->self, urb);
-       usb_unanchor_urb(urb);
-
-       /* pass ownership to the completion handler */
-       urb->complete (urb);
-       atomic_dec (&urb->use_count);
-       if (unlikely (urb->reject))
-               wake_up (&usb_kill_urb_queue);
-       usb_put_urb (urb);
-}
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
-
-/*-------------------------------------------------------------------------*/
-
 /**
  * usb_hcd_irq - hook IRQs to HCD framework (bus glue)
  * @irq: the IRQ being raised
index fd74c50b18049b71f85256fa47a62d6199bc2098..e341a1da517fe8589c7153b0bf7811f84c435e51 100644 (file)
@@ -1335,6 +1335,10 @@ int usb_new_device(struct usb_device *udev)
        udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
                        (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
 
+       /* Increment the parent's count of unsuspended children */
+       if (udev->parent)
+               usb_autoresume_device(udev->parent);
+
        /* Register the device.  The device driver is responsible
         * for adding the device files to sysfs and for configuring
         * the device.
@@ -1342,13 +1346,11 @@ int usb_new_device(struct usb_device *udev)
        err = device_add(&udev->dev);
        if (err) {
                dev_err(&udev->dev, "can't device_add, error %d\n", err);
+               if (udev->parent)
+                       usb_autosuspend_device(udev->parent);
                goto fail;
        }
 
-       /* Increment the parent's count of unsuspended children */
-       if (udev->parent)
-               usb_autoresume_device(udev->parent);
-
 exit:
        return err;
 
index 530e854961ce99785291b399d92253151c626d9e..25f63f1096b43d4d9a6da4e266e212cf09d48549 100644 (file)
@@ -34,13 +34,14 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
 { 
        struct completion done;
        unsigned long expire;
-       int status;
+       int retval;
+       int status = urb->status;
 
        init_completion(&done);         
        urb->context = &done;
        urb->actual_length = 0;
-       status = usb_submit_urb(urb, GFP_NOIO);
-       if (unlikely(status))
+       retval = usb_submit_urb(urb, GFP_NOIO);
+       if (unlikely(retval))
                goto out;
 
        expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
@@ -55,15 +56,15 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
                        urb->transfer_buffer_length);
 
                usb_kill_urb(urb);
-               status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
+               retval = status == -ENOENT ? -ETIMEDOUT : status;
        } else
-               status = urb->status;
+               retval = status;
 out:
        if (actual_length)
                *actual_length = urb->actual_length;
 
        usb_free_urb(urb);
-       return status;
+       return retval;
 }
 
 /*-------------------------------------------------------------------*/
@@ -250,6 +251,7 @@ static void sg_clean (struct usb_sg_request *io)
 static void sg_complete (struct urb *urb)
 {
        struct usb_sg_request   *io = urb->context;
+       int status = urb->status;
 
        spin_lock (&io->lock);
 
@@ -265,21 +267,21 @@ static void sg_complete (struct urb *urb)
         */
        if (io->status
                        && (io->status != -ECONNRESET
-                               || urb->status != -ECONNRESET)
+                               || status != -ECONNRESET)
                        && urb->actual_length) {
                dev_err (io->dev->bus->controller,
                        "dev %s ep%d%s scatterlist error %d/%d\n",
                        io->dev->devpath,
                        usb_pipeendpoint (urb->pipe),
                        usb_pipein (urb->pipe) ? "in" : "out",
-                       urb->status, io->status);
+                       status, io->status);
                // BUG ();
        }
 
-       if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {
-               int             i, found, status;
+       if (io->status == 0 && status && status != -ECONNRESET) {
+               int i, found, retval;
 
-               io->status = urb->status;
+               io->status = status;
 
                /* the previous urbs, and this one, completed already.
                 * unlink pending urbs so they won't rx/tx bad data.
@@ -290,13 +292,13 @@ static void sg_complete (struct urb *urb)
                        if (!io->urbs [i] || !io->urbs [i]->dev)
                                continue;
                        if (found) {
-                               status = usb_unlink_urb (io->urbs [i]);
-                               if (status != -EINPROGRESS
-                                               && status != -ENODEV
-                                               && status != -EBUSY)
+                               retval = usb_unlink_urb (io->urbs [i]);
+                               if (retval != -EINPROGRESS &&
+                                   retval != -ENODEV &&
+                                   retval != -EBUSY)
                                        dev_err (&io->dev->dev,
                                                "%s, unlink --> %d\n",
-                                               __FUNCTION__, status);
+                                               __FUNCTION__, retval);
                        } else if (urb == io->urbs [i])
                                found = 1;
                }
index d47ae89154a7e7b4a2d9ab40e4e733eaebe124be..2ab222be8fd164f58bff7245005ab4f621433a1d 100644 (file)
@@ -441,6 +441,54 @@ static struct attribute_group dev_attr_grp = {
        .attrs = dev_attrs,
 };
 
+/* Binary descriptors */
+
+static ssize_t
+read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct usb_device *udev = to_usb_device(
+                       container_of(kobj, struct device, kobj));
+       size_t nleft = count;
+       size_t srclen, n;
+
+       usb_lock_device(udev);
+
+       /* The binary attribute begins with the device descriptor */
+       srclen = sizeof(struct usb_device_descriptor);
+       if (off < srclen) {
+               n = min_t(size_t, nleft, srclen - off);
+               memcpy(buf, off + (char *) &udev->descriptor, n);
+               nleft -= n;
+               buf += n;
+               off = 0;
+       } else {
+               off -= srclen;
+       }
+
+       /* Then follows the raw descriptor entry for the current
+        * configuration (config plus subsidiary descriptors).
+        */
+       if (udev->actconfig) {
+               int cfgno = udev->actconfig - udev->config;
+
+               srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength);
+               if (off < srclen) {
+                       n = min_t(size_t, nleft, srclen - off);
+                       memcpy(buf, off + udev->rawdescriptors[cfgno], n);
+                       nleft -= n;
+               }
+       }
+       usb_unlock_device(udev);
+       return count - nleft;
+}
+
+static struct bin_attribute dev_bin_attr_descriptors = {
+       .attr = {.name = "descriptors", .mode = 0444},
+       .read = read_descriptors,
+       .size = 18 + 65535,     /* dev descr + max-size raw descriptor */
+};
+
 int usb_create_sysfs_dev_files(struct usb_device *udev)
 {
        struct device *dev = &udev->dev;
@@ -450,6 +498,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
        if (retval)
                return retval;
 
+       retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
+       if (retval)
+               goto error;
+
        retval = add_persist_attributes(dev);
        if (retval)
                goto error;
@@ -492,6 +544,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
        device_remove_file(dev, &dev_attr_serial);
        remove_power_attributes(dev);
        remove_persist_attributes(dev);
+       device_remove_bin_file(dev, &dev_bin_attr_descriptors);
        sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 }
 
index 52ec44b828f3530dd8dfdb33e8452be6aa2a819f..be630228461c046d06fe5232ea91466ad75e861d 100644 (file)
@@ -440,55 +440,57 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
  * @urb: pointer to urb describing a previously submitted request,
  *     may be NULL
  *
- * This routine cancels an in-progress request.  URBs complete only
- * once per submission, and may be canceled only once per submission.
- * Successful cancellation means the requests's completion handler will
- * be called with a status code indicating that the request has been
- * canceled (rather than any other code) and will quickly be removed
- * from host controller data structures.
- *
- * This request is always asynchronous.
- * Success is indicated by returning -EINPROGRESS,
- * at which time the URB will normally have been unlinked but not yet
- * given back to the device driver.  When it is called, the completion
- * function will see urb->status == -ECONNRESET.  Failure is indicated
- * by any other return value.  Unlinking will fail when the URB is not
- * currently "linked" (i.e., it was never submitted, or it was unlinked
- * before, or the hardware is already finished with it), even if the
- * completion handler has not yet run.
+ * This routine cancels an in-progress request.  URBs complete only once
+ * per submission, and may be canceled only once per submission.
+ * Successful cancellation means termination of @urb will be expedited
+ * and the completion handler will be called with a status code
+ * indicating that the request has been canceled (rather than any other
+ * code).
+ *
+ * This request is always asynchronous.  Success is indicated by
+ * returning -EINPROGRESS, at which time the URB will probably not yet
+ * have been given back to the device driver.  When it is eventually
+ * called, the completion function will see @urb->status == -ECONNRESET.
+ * Failure is indicated by usb_unlink_urb() returning any other value.
+ * Unlinking will fail when @urb is not currently "linked" (i.e., it was
+ * never submitted, or it was unlinked before, or the hardware is already
+ * finished with it), even if the completion handler has not yet run.
  *
  * Unlinking and Endpoint Queues:
  *
+ * [The behaviors and guarantees described below do not apply to virtual
+ * root hubs but only to endpoint queues for physical USB devices.]
+ *
  * Host Controller Drivers (HCDs) place all the URBs for a particular
  * endpoint in a queue.  Normally the queue advances as the controller
  * hardware processes each request.  But when an URB terminates with an
- * error its queue stops, at least until that URB's completion routine
- * returns.  It is guaranteed that the queue will not restart until all
- * its unlinked URBs have been fully retired, with their completion
- * routines run, even if that's not until some time after the original
- * completion handler returns.  Normally the same behavior and guarantees
- * apply when an URB terminates because it was unlinked; however if an
- * URB is unlinked before the hardware has started to execute it, then
- * its queue is not guaranteed to stop until all the preceding URBs have
- * completed.
- *
- * This means that USB device drivers can safely build deep queues for
- * large or complex transfers, and clean them up reliably after any sort
- * of aborted transfer by unlinking all pending URBs at the first fault.
- *
- * Note that an URB terminating early because a short packet was received
- * will count as an error if and only if the URB_SHORT_NOT_OK flag is set.
- * Also, that all unlinks performed in any URB completion handler must
- * be asynchronous.
- *
- * Queues for isochronous endpoints are treated differently, because they
- * advance at fixed rates.  Such queues do not stop when an URB is unlinked.
- * An unlinked URB may leave a gap in the stream of packets.  It is undefined
- * whether such gaps can be filled in.
- *
- * When a control URB terminates with an error, it is likely that the
- * status stage of the transfer will not take place, even if it is merely
- * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
+ * error its queue generally stops (see below), at least until that URB's
+ * completion routine returns.  It is guaranteed that a stopped queue
+ * will not restart until all its unlinked URBs have been fully retired,
+ * with their completion routines run, even if that's not until some time
+ * after the original completion handler returns.  The same behavior and
+ * guarantee apply when an URB terminates because it was unlinked.
+ *
+ * Bulk and interrupt endpoint queues are guaranteed to stop whenever an
+ * URB terminates with any sort of error, including -ECONNRESET, -ENOENT,
+ * and -EREMOTEIO.  Control endpoint queues behave the same way except
+ * that they are not guaranteed to stop for -EREMOTEIO errors.  Queues
+ * for isochronous endpoints are treated differently, because they must
+ * advance at fixed rates.  Such queues do not stop when an URB
+ * encounters an error or is unlinked.  An unlinked isochronous URB may
+ * leave a gap in the stream of packets; it is undefined whether such
+ * gaps can be filled in.
+ *
+ * Note that early termination of an URB because a short packet was
+ * received will generate a -EREMOTEIO error if and only if the
+ * URB_SHORT_NOT_OK flag is set.  By setting this flag, USB device
+ * drivers can build deep queues for large or complex bulk transfers
+ * and clean them up reliably after any sort of aborted transfer by
+ * unlinking all pending URBs at the first fault.
+ *
+ * When a control URB terminates with an error other than -EREMOTEIO, it
+ * is quite likely that the status stage of the transfer will not take
+ * place.
  */
 int usb_unlink_urb(struct urb *urb)
 {
index 45e01e289455376b68e5f5ceca8ca3a3a2937ec3..767aed5b4bea015938d7d8164c0c1e121942c994 100644 (file)
@@ -82,6 +82,27 @@ choice
           Many controller drivers are platform-specific; these
           often need board-specific hooks.
 
+config USB_GADGET_AMD5536UDC
+       boolean "AMD5536 UDC"
+       depends on PCI
+       select USB_GADGET_DUALSPEED
+       help
+          The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
+          It is a USB Highspeed DMA capable USB device controller. Beside ep0
+          it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+          The UDC port supports OTG operation, and may be used as a host port
+          if it's not being used to implement peripheral or OTG roles.
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "amd5536udc" and force all
+          gadget drivers to also be dynamically linked.
+
+config USB_AMD5536UDC
+       tristate
+       depends on USB_GADGET_AMD5536UDC
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_FSL_USB2
        boolean "Freescale Highspeed USB DR Peripheral Controller"
        depends on MPC834x || PPC_MPC831x
@@ -156,6 +177,24 @@ config USB_PXA2XX_SMALL
        default y if USB_ETH
        default y if USB_G_SERIAL
 
+config USB_GADGET_M66592
+       boolean "Renesas M66592 USB Peripheral Controller"
+       select USB_GADGET_DUALSPEED
+       help
+          M66592 is a discrete USB peripheral controller chip that
+          supports both full and high speed USB 2.0 data transfers.
+          It has seven configurable endpoints, and endpoint zero.
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "m66592_udc" and force all
+          gadget drivers to also be dynamically linked.
+
+config USB_M66592
+       tristate
+       depends on USB_GADGET_M66592
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_GOKU
        boolean "Toshiba TC86C001 'Goku-S'"
        depends on PCI
@@ -261,24 +300,6 @@ config USB_AT91
        depends on USB_GADGET_AT91
        default USB_GADGET
 
-config USB_GADGET_M66592
-       boolean "M66592 driver"
-       select USB_GADGET_DUALSPEED
-       help
-          M66592 is a USB 2.0 peripheral controller.
-
-          It has seven configurable endpoints, and endpoint zero.
-
-          Say "y" to link the driver statically, or "m" to build a
-          dynamically linked module called "m66592_udc" and force all
-          gadget drivers to also be dynamically linked.
-
-config USB_M66592
-       tristate
-       depends on USB_GADGET_M66592
-       default USB_GADGET
-       select USB_GADGET_SELECTED
-
 config USB_GADGET_DUMMY_HCD
        boolean "Dummy HCD (DEVELOPMENT)"
        depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
index 8ae76f7386355074ffba6b3d1fb1a326e323becd..1bc0f03550cea0df21f0f21e3c6cd7fdf7fdff7d 100644 (file)
@@ -7,6 +7,7 @@ endif
 
 obj-$(CONFIG_USB_DUMMY_HCD)    += dummy_hcd.o
 obj-$(CONFIG_USB_NET2280)      += net2280.o
+obj-$(CONFIG_USB_AMD5536UDC)   += amd5536udc.o
 obj-$(CONFIG_USB_PXA2XX)       += pxa2xx_udc.o
 obj-$(CONFIG_USB_GOKU)         += goku_udc.o
 obj-$(CONFIG_USB_OMAP)         += omap_udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
new file mode 100644 (file)
index 0000000..714156c
--- /dev/null
@@ -0,0 +1,3454 @@
+/*
+ * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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
+ */
+
+/*
+ * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
+ * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
+ * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ *
+ * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
+ * be used as host port) and UOC bits PAD_EN and APU are set (should be done
+ * by BIOS init).
+ *
+ * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
+ * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
+ * can be used with gadget ether.
+ */
+
+/* debug control */
+/* #define UDC_VERBOSE */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION            "AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING      "01.00.0206 - $Revision: #3 $"
+
+/* system */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct udc *dev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+                               unsigned long buf_len, gfp_t gfp_flags);
+static int udc_remote_wakeup(struct udc *dev);
+static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_pci_remove(struct pci_dev *pdev);
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "amd5536udc";
+
+/* structure to hold endpoint function pointers */
+static const struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+static DEFINE_SPINLOCK(udc_irq_spinlock);
+/* stall spin lock */
+static DEFINE_SPINLOCK(udc_stall_spinlock);
+
+/*
+* slave mode: pending bytes in rx fifo after nyet,
+* used if EPIN irq came but no req was available
+*/
+static unsigned int udc_rxfifo_pending;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+
+/* set_rde -- Is used to control enabling of RX DMA. Problem is
+ * that UDC has only one bit (RDE) to enable/disable RX DMA for
+ * all OUT endpoints. So we have to handle race conditions like
+ * when OUT data reaches the fifo but no request was queued yet.
+ * This cannot be solved by letting the RX DMA disabled until a
+ * request gets queued because there may be other OUT packets
+ * in the FIFO (important for not blocking control traffic).
+ * The value of set_rde controls the correspondig timer.
+ *
+ * set_rde -1 == not used, means it is alloed to be set to 0 or 1
+ * set_rde  0 == do not touch RDE, do no start the RDE timer
+ * set_rde  1 == timer function will look whether FIFO has data
+ * set_rde  2 == set by timer function to enable RX DMA on next call
+ */
+static int set_rde = -1;
+
+static DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+static DECLARE_COMPLETION(on_pollstall_exit);
+
+/* tasklet for usb disconnect */
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+               (unsigned long) &udc);
+
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+       ep0_string,
+       "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
+       "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
+       "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
+       "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
+       "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
+       "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
+       "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* full speed only mode */
+static int use_fullspeed;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+       "true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*---------------------------------------------------------------------------*/
+/* Prints UDC device registers and endpoint irq registers */
+static void print_regs(struct udc *dev)
+{
+       DBG(dev, "------- Device registers -------\n");
+       DBG(dev, "dev config     = %08x\n", readl(&dev->regs->cfg));
+       DBG(dev, "dev control    = %08x\n", readl(&dev->regs->ctl));
+       DBG(dev, "dev status     = %08x\n", readl(&dev->regs->sts));
+       DBG(dev, "\n");
+       DBG(dev, "dev int's      = %08x\n", readl(&dev->regs->irqsts));
+       DBG(dev, "dev intmask    = %08x\n", readl(&dev->regs->irqmsk));
+       DBG(dev, "\n");
+       DBG(dev, "dev ep int's   = %08x\n", readl(&dev->regs->ep_irqsts));
+       DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
+       DBG(dev, "\n");
+       DBG(dev, "USE DMA        = %d\n", use_dma);
+       if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+               DBG(dev, "DMA mode       = PPBNDU (packet per buffer "
+                       "WITHOUT desc. update)\n");
+               dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+       } else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+               DBG(dev, "DMA mode       = PPBDU (packet per buffer "
+                       "WITH desc. update)\n");
+               dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+       }
+       if (use_dma && use_dma_bufferfill_mode) {
+               DBG(dev, "DMA mode       = BF (buffer fill mode)\n");
+               dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+       }
+       if (!use_dma) {
+               dev_info(&dev->pdev->dev, "FIFO mode\n");
+       }
+       DBG(dev, "-------------------------------------------------------\n");
+}
+
+/* Masks unused interrupts */
+static int udc_mask_unused_interrupts(struct udc *dev)
+{
+       u32 tmp;
+
+       /* mask all dev interrupts */
+       tmp =   AMD_BIT(UDC_DEVINT_SVC) |
+               AMD_BIT(UDC_DEVINT_ENUM) |
+               AMD_BIT(UDC_DEVINT_US) |
+               AMD_BIT(UDC_DEVINT_UR) |
+               AMD_BIT(UDC_DEVINT_ES) |
+               AMD_BIT(UDC_DEVINT_SI) |
+               AMD_BIT(UDC_DEVINT_SOF)|
+               AMD_BIT(UDC_DEVINT_SC);
+       writel(tmp, &dev->regs->irqmsk);
+
+       /* mask all ep interrupts */
+       writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+       return 0;
+}
+
+/* Enables endpoint 0 interrupts */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+       u32 tmp;
+
+       DBG(dev, "udc_enable_ep0_interrupts()\n");
+
+       /* read irq mask */
+       tmp = readl(&dev->regs->ep_irqmsk);
+       /* enable ep0 irq's */
+       tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+               & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+       writel(tmp, &dev->regs->ep_irqmsk);
+
+       return 0;
+}
+
+/* Enables device interrupts for SET_INTF and SET_CONFIG */
+static int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+       u32 tmp;
+
+       DBG(dev, "enable device interrupts for setup data\n");
+
+       /* read irq mask */
+       tmp = readl(&dev->regs->irqmsk);
+
+       /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+       tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+               & AMD_UNMASK_BIT(UDC_DEVINT_SC)
+               & AMD_UNMASK_BIT(UDC_DEVINT_UR)
+               & AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+               & AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+       writel(tmp, &dev->regs->irqmsk);
+
+       return 0;
+}
+
+/* Calculates fifo start of endpoint based on preceeding endpoints */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+       struct udc      *dev;
+       u32 tmp;
+       int i;
+
+       if (!ep || !(ep->in))
+               return -EINVAL;
+
+       dev = ep->dev;
+       ep->txfifo = dev->txfifo;
+
+       /* traverse ep's */
+       for (i = 0; i < ep->num; i++) {
+               if (dev->ep[i].regs) {
+                       /* read fifo size */
+                       tmp = readl(&dev->ep[i].regs->bufin_framenum);
+                       tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+                       ep->txfifo += tmp;
+               }
+       }
+       return 0;
+}
+
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending;
+
+static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
+{
+       if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
+               DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
+               cnak_pending |= 1 << (num);
+               ep->naking = 1;
+       } else
+               cnak_pending = cnak_pending & (~(1 << (num)));
+}
+
+
+/* Enables endpoint, is called by gadget driver */
+static int
+udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+       struct udc_ep           *ep;
+       struct udc              *dev;
+       u32                     tmp;
+       unsigned long           iflags;
+       u8 udc_csr_epix;
+
+       if (!usbep
+                       || usbep->name == ep0_string
+                       || !desc
+                       || desc->bDescriptorType != USB_DT_ENDPOINT)
+               return -EINVAL;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       dev = ep->dev;
+
+       DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
+
+       if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+               return -ESHUTDOWN;
+
+       spin_lock_irqsave(&dev->lock, iflags);
+       ep->desc = desc;
+
+       ep->halted = 0;
+
+       /* set traffic type */
+       tmp = readl(&dev->ep[ep->num].regs->ctl);
+       tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+       writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+       /* set max packet size */
+       tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+       tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+       ep->ep.maxpacket = desc->wMaxPacketSize;
+       writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+       /* IN ep */
+       if (ep->in) {
+
+               /* ep ix in UDC CSR register space */
+               udc_csr_epix = ep->num;
+
+               /* set buffer size (tx fifo entries) */
+               tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+               /* double buffering: fifo size = 2 x max packet size */
+               tmp = AMD_ADDBITS(
+                               tmp,
+                               desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT
+                                               / UDC_DWORD_BYTES,
+                               UDC_EPIN_BUFF_SIZE);
+               writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+               /* calc. tx fifo base addr */
+               udc_set_txfifo_addr(ep);
+
+               /* flush fifo */
+               tmp = readl(&ep->regs->ctl);
+               tmp |= AMD_BIT(UDC_EPCTL_F);
+               writel(tmp, &ep->regs->ctl);
+
+       /* OUT ep */
+       } else {
+               /* ep ix in UDC CSR register space */
+               udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+               /* set max packet size UDC CSR  */
+               tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+               tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize,
+                                       UDC_CSR_NE_MAX_PKT);
+               writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+               if (use_dma && !ep->in) {
+                       /* alloc and init BNA dummy request */
+                       ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
+                       ep->bna_occurred = 0;
+               }
+
+               if (ep->num != UDC_EP0OUT_IX)
+                       dev->data_ep_enabled = 1;
+       }
+
+       /* set ep values */
+       tmp = readl(&dev->csr->ne[udc_csr_epix]);
+       /* max packet */
+       tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+       /* ep number */
+       tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+       /* ep direction */
+       tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+       /* ep type */
+       tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+       /* ep config */
+       tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+       /* ep interface */
+       tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+       /* ep alt */
+       tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+       /* write reg */
+       writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+       /* enable ep irq */
+       tmp = readl(&dev->regs->ep_irqmsk);
+       tmp &= AMD_UNMASK_BIT(ep->num);
+       writel(tmp, &dev->regs->ep_irqmsk);
+
+       /*
+        * clear NAK by writing CNAK
+        * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
+        */
+       if (!use_dma || ep->in) {
+               tmp = readl(&ep->regs->ctl);
+               tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+               writel(tmp, &ep->regs->ctl);
+               ep->naking = 0;
+               UDC_QUEUE_CNAK(ep, ep->num);
+       }
+       tmp = desc->bEndpointAddress;
+       DBG(dev, "%s enabled\n", usbep->name);
+
+       spin_unlock_irqrestore(&dev->lock, iflags);
+       return 0;
+}
+
+/* Resets endpoint */
+static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
+{
+       u32             tmp;
+
+       VDBG(ep->dev, "ep-%d reset\n", ep->num);
+       ep->desc = NULL;
+       ep->ep.ops = &udc_ep_ops;
+       INIT_LIST_HEAD(&ep->queue);
+
+       ep->ep.maxpacket = (u16) ~0;
+       /* set NAK */
+       tmp = readl(&ep->regs->ctl);
+       tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+       writel(tmp, &ep->regs->ctl);
+       ep->naking = 1;
+
+       /* disable interrupt */
+       tmp = readl(&regs->ep_irqmsk);
+       tmp |= AMD_BIT(ep->num);
+       writel(tmp, &regs->ep_irqmsk);
+
+       if (ep->in) {
+               /* unset P and IN bit of potential former DMA */
+               tmp = readl(&ep->regs->ctl);
+               tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+               writel(tmp, &ep->regs->ctl);
+
+               tmp = readl(&ep->regs->sts);
+               tmp |= AMD_BIT(UDC_EPSTS_IN);
+               writel(tmp, &ep->regs->sts);
+
+               /* flush the fifo */
+               tmp = readl(&ep->regs->ctl);
+               tmp |= AMD_BIT(UDC_EPCTL_F);
+               writel(tmp, &ep->regs->ctl);
+
+       }
+       /* reset desc pointer */
+       writel(0, &ep->regs->desptr);
+}
+
+/* Disables endpoint, is called by gadget driver */
+static int udc_ep_disable(struct usb_ep *usbep)
+{
+       struct udc_ep   *ep = NULL;
+       unsigned long   iflags;
+
+       if (!usbep)
+               return -EINVAL;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       if (usbep->name == ep0_string || !ep->desc)
+               return -EINVAL;
+
+       DBG(ep->dev, "Disable ep-%d\n", ep->num);
+
+       spin_lock_irqsave(&ep->dev->lock, iflags);
+       udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
+       empty_req_queue(ep);
+       ep_init(ep->dev->regs, ep);
+       spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+       return 0;
+}
+
+/* Allocates request packet, called by gadget driver */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+       struct udc_request      *req;
+       struct udc_data_dma     *dma_desc;
+       struct udc_ep   *ep;
+
+       if (!usbep)
+               return NULL;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+
+       VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
+       req = kzalloc(sizeof(struct udc_request), gfp);
+       if (!req)
+               return NULL;
+
+       req->req.dma = DMA_DONT_USE;
+       INIT_LIST_HEAD(&req->queue);
+
+       if (ep->dma) {
+               /* ep0 in requests are allocated from data pool here */
+               dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+                                               &req->td_phys);
+               if (!dma_desc) {
+                       kfree(req);
+                       return NULL;
+               }
+
+               VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
+                               "td_phys = %lx\n",
+                               req, dma_desc,
+                               (unsigned long)req->td_phys);
+               /* prevent from using desc. - set HOST BUSY */
+               dma_desc->status = AMD_ADDBITS(dma_desc->status,
+                                               UDC_DMA_STP_STS_BS_HOST_BUSY,
+                                               UDC_DMA_STP_STS_BS);
+               dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
+               req->td_data = dma_desc;
+               req->td_data_last = NULL;
+               req->chain_len = 1;
+       }
+
+       return &req->req;
+}
+
+/* Frees request packet, called by gadget driver */
+static void
+udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+       struct udc_ep   *ep;
+       struct udc_request      *req;
+
+       if (!usbep || !usbreq)
+               return;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       req = container_of(usbreq, struct udc_request, req);
+       VDBG(ep->dev, "free_req req=%p\n", req);
+       BUG_ON(!list_empty(&req->queue));
+       if (req->td_data) {
+               VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
+
+               /* free dma chain if created */
+               if (req->chain_len > 1) {
+                       udc_free_dma_chain(ep->dev, req);
+               }
+
+               pci_pool_free(ep->dev->data_requests, req->td_data,
+                                                       req->td_phys);
+       }
+       kfree(req);
+}
+
+/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
+static void udc_init_bna_dummy(struct udc_request *req)
+{
+       if (req) {
+               /* set last bit */
+               req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+               /* set next pointer to itself */
+               req->td_data->next = req->td_phys;
+               /* set HOST BUSY */
+               req->td_data->status
+                       = AMD_ADDBITS(req->td_data->status,
+                                       UDC_DMA_STP_STS_BS_DMA_DONE,
+                                       UDC_DMA_STP_STS_BS);
+#ifdef UDC_VERBOSE
+               pr_debug("bna desc = %p, sts = %08x\n",
+                       req->td_data, req->td_data->status);
+#endif
+       }
+}
+
+/* Allocate BNA dummy descriptor */
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
+{
+       struct udc_request *req = NULL;
+       struct usb_request *_req = NULL;
+
+       /* alloc the dummy request */
+       _req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
+       if (_req) {
+               req = container_of(_req, struct udc_request, req);
+               ep->bna_dummy_req = req;
+               udc_init_bna_dummy(req);
+       }
+       return req;
+}
+
+/* Write data to TX fifo for IN packets */
+static void
+udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+       u8                      *req_buf;
+       u32                     *buf;
+       int                     i, j;
+       unsigned                bytes = 0;
+       unsigned                remaining = 0;
+
+       if (!req || !ep)
+               return;
+
+       req_buf = req->buf + req->actual;
+       prefetch(req_buf);
+       remaining = req->length - req->actual;
+
+       buf = (u32 *) req_buf;
+
+       bytes = ep->ep.maxpacket;
+       if (bytes > remaining)
+               bytes = remaining;
+
+       /* dwords first */
+       for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+               writel(*(buf + i), ep->txfifo);
+       }
+
+       /* remaining bytes must be written by byte access */
+       for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+               writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+                                                       ep->txfifo);
+       }
+
+       /* dummy write confirm */
+       writel(0, &ep->regs->confirm);
+}
+
+/* Read dwords from RX fifo for OUT transfers */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
+{
+       int i;
+
+       VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
+
+       for (i = 0; i < dwords; i++) {
+               *(buf + i) = readl(dev->rxfifo);
+       }
+       return 0;
+}
+
+/* Read bytes from RX fifo for OUT transfers */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
+{
+       int i, j;
+       u32 tmp;
+
+       VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
+
+       /* dwords first */
+       for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+               *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
+       }
+
+       /* remaining bytes must be read by byte access */
+       if (bytes % UDC_DWORD_BYTES) {
+               tmp = readl(dev->rxfifo);
+               for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+                       *(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
+                       tmp = tmp >> UDC_BITS_PER_BYTE;
+               }
+       }
+
+       return 0;
+}
+
+/* Read data from RX fifo for OUT transfers */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+       u8 *buf;
+       unsigned buf_space;
+       unsigned bytes = 0;
+       unsigned finished = 0;
+
+       /* received number bytes */
+       bytes = readl(&ep->regs->sts);
+       bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+       buf_space = req->req.length - req->req.actual;
+       buf = req->req.buf + req->req.actual;
+       if (bytes > buf_space) {
+               if ((buf_space % ep->ep.maxpacket) != 0) {
+                       DBG(ep->dev,
+                               "%s: rx %d bytes, rx-buf space = %d bytesn\n",
+                               ep->ep.name, bytes, buf_space);
+                       req->req.status = -EOVERFLOW;
+               }
+               bytes = buf_space;
+       }
+       req->req.actual += bytes;
+
+       /* last packet ? */
+       if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
+               || ((req->req.actual == req->req.length) && !req->req.zero))
+               finished = 1;
+
+       /* read rx fifo bytes */
+       VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+       udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+       return finished;
+}
+
+/* create/re-init a DMA descriptor or a DMA descriptor chain */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
+{
+       int     retval = 0;
+       u32     tmp;
+
+       VDBG(ep->dev, "prep_dma\n");
+       VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
+                       ep->num, req->td_data);
+
+       /* set buffer pointer */
+       req->td_data->bufptr = req->req.dma;
+
+       /* set last bit */
+       req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+       /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+       if (use_dma_ppb) {
+
+               retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+               if (retval != 0) {
+                       if (retval == -ENOMEM)
+                               DBG(ep->dev, "Out of DMA memory\n");
+                       return retval;
+               }
+               if (ep->in) {
+                       if (req->req.length == ep->ep.maxpacket) {
+                               /* write tx bytes */
+                               req->td_data->status =
+                                       AMD_ADDBITS(req->td_data->status,
+                                               ep->ep.maxpacket,
+                                               UDC_DMA_IN_STS_TXBYTES);
+
+                       }
+               }
+
+       }
+
+       if (ep->in) {
+               VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
+                               "maxpacket=%d ep%d\n",
+                               use_dma_ppb, req->req.length,
+                               ep->ep.maxpacket, ep->num);
+               /*
+                * if bytes < max packet then tx bytes must
+                * be written in packet per buffer mode
+                */
+               if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+                               || ep->num == UDC_EP0OUT_IX
+                               || ep->num == UDC_EP0IN_IX) {
+                       /* write tx bytes */
+                       req->td_data->status =
+                               AMD_ADDBITS(req->td_data->status,
+                                               req->req.length,
+                                               UDC_DMA_IN_STS_TXBYTES);
+                       /* reset frame num */
+                       req->td_data->status =
+                               AMD_ADDBITS(req->td_data->status,
+                                               0,
+                                               UDC_DMA_IN_STS_FRAMENUM);
+               }
+               /* set HOST BUSY */
+               req->td_data->status =
+                       AMD_ADDBITS(req->td_data->status,
+                               UDC_DMA_STP_STS_BS_HOST_BUSY,
+                               UDC_DMA_STP_STS_BS);
+       } else {
+               VDBG(ep->dev, "OUT set host ready\n");
+               /* set HOST READY */
+               req->td_data->status =
+                       AMD_ADDBITS(req->td_data->status,
+                               UDC_DMA_STP_STS_BS_HOST_READY,
+                               UDC_DMA_STP_STS_BS);
+
+
+                       /* clear NAK by writing CNAK */
+                       if (ep->naking) {
+                               tmp = readl(&ep->regs->ctl);
+                               tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                               writel(tmp, &ep->regs->ctl);
+                               ep->naking = 0;
+                               UDC_QUEUE_CNAK(ep, ep->num);
+                       }
+
+       }
+
+       return retval;
+}
+
+/* Completes request packet ... caller MUST hold lock */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+__releases(ep->dev->lock)
+__acquires(ep->dev->lock)
+{
+       struct udc              *dev;
+       unsigned                halted;
+
+       VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
+
+       dev = ep->dev;
+       /* unmap DMA */
+       if (req->dma_mapping) {
+               if (ep->in)
+                       pci_unmap_single(dev->pdev,
+                                       req->req.dma,
+                                       req->req.length,
+                                       PCI_DMA_TODEVICE);
+               else
+                       pci_unmap_single(dev->pdev,
+                                       req->req.dma,
+                                       req->req.length,
+                                       PCI_DMA_FROMDEVICE);
+               req->dma_mapping = 0;
+               req->req.dma = DMA_DONT_USE;
+       }
+
+       halted = ep->halted;
+       ep->halted = 1;
+
+       /* set new status if pending */
+       if (req->req.status == -EINPROGRESS)
+               req->req.status = sts;
+
+       /* remove from ep queue */
+       list_del_init(&req->queue);
+
+       VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
+               &req->req, req->req.length, ep->ep.name, sts);
+
+       spin_unlock(&dev->lock);
+       req->req.complete(&ep->ep, &req->req);
+       spin_lock(&dev->lock);
+       ep->halted = halted;
+}
+
+/* frees pci pool descriptors of a DMA chain */
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+
+       int ret_val = 0;
+       struct udc_data_dma     *td;
+       struct udc_data_dma     *td_last = NULL;
+       unsigned int i;
+
+       DBG(dev, "free chain req = %p\n", req);
+
+       /* do not free first desc., will be done by free for request */
+       td_last = req->td_data;
+       td = phys_to_virt(td_last->next);
+
+       for (i = 1; i < req->chain_len; i++) {
+
+               pci_pool_free(dev->data_requests, td,
+                               (dma_addr_t) td_last->next);
+               td_last = td;
+               td = phys_to_virt(td_last->next);
+       }
+
+       return ret_val;
+}
+
+/* Iterates to the end of a DMA chain and returns last descriptor */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+       struct udc_data_dma     *td;
+
+       td = req->td_data;
+       while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+               td = phys_to_virt(td->next);
+       }
+
+       return td;
+
+}
+
+/* Iterates to the end of a DMA chain and counts bytes received */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+       struct udc_data_dma     *td;
+       u32 count;
+
+       td = req->td_data;
+       /* received number bytes */
+       count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+       while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+               td = phys_to_virt(td->next);
+               /* received number bytes */
+               if (td) {
+                       count += AMD_GETBITS(td->status,
+                               UDC_DMA_OUT_STS_RXBYTES);
+               }
+       }
+
+       return count;
+
+}
+
+/* Creates or re-inits a DMA chain */
+static int udc_create_dma_chain(
+       struct udc_ep *ep,
+       struct udc_request *req,
+       unsigned long buf_len, gfp_t gfp_flags
+)
+{
+       unsigned long bytes = req->req.length;
+       unsigned int i;
+       dma_addr_t dma_addr;
+       struct udc_data_dma     *td = NULL;
+       struct udc_data_dma     *last = NULL;
+       unsigned long txbytes;
+       unsigned create_new_chain = 0;
+       unsigned len;
+
+       VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
+                       bytes, buf_len);
+       dma_addr = DMA_DONT_USE;
+
+       /* unset L bit in first desc for OUT */
+       if (!ep->in) {
+               req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+       }
+
+       /* alloc only new desc's if not already available */
+       len = req->req.length / ep->ep.maxpacket;
+       if (req->req.length % ep->ep.maxpacket) {
+               len++;
+       }
+
+       if (len > req->chain_len) {
+               /* shorter chain already allocated before */
+               if (req->chain_len > 1) {
+                       udc_free_dma_chain(ep->dev, req);
+               }
+               req->chain_len = len;
+               create_new_chain = 1;
+       }
+
+       td = req->td_data;
+       /* gen. required number of descriptors and buffers */
+       for (i = buf_len; i < bytes; i += buf_len) {
+               /* create or determine next desc. */
+               if (create_new_chain) {
+
+                       td = pci_pool_alloc(ep->dev->data_requests,
+                                       gfp_flags, &dma_addr);
+                       if (!td)
+                               return -ENOMEM;
+
+                       td->status = 0;
+               } else if (i == buf_len) {
+                       /* first td */
+                       td = (struct udc_data_dma *) phys_to_virt(
+                                               req->td_data->next);
+                       td->status = 0;
+               } else {
+                       td = (struct udc_data_dma *) phys_to_virt(last->next);
+                       td->status = 0;
+               }
+
+
+               if (td)
+                       td->bufptr = req->req.dma + i; /* assign buffer */
+               else
+                       break;
+
+               /* short packet ? */
+               if ((bytes - i) >= buf_len) {
+                       txbytes = buf_len;
+               } else {
+                       /* short packet */
+                       txbytes = bytes - i;
+               }
+
+               /* link td and assign tx bytes */
+               if (i == buf_len) {
+                       if (create_new_chain) {
+                               req->td_data->next = dma_addr;
+                       } else {
+                               /* req->td_data->next = virt_to_phys(td); */
+                       }
+                       /* write tx bytes */
+                       if (ep->in) {
+                               /* first desc */
+                               req->td_data->status =
+                                       AMD_ADDBITS(req->td_data->status,
+                                                       ep->ep.maxpacket,
+                                                       UDC_DMA_IN_STS_TXBYTES);
+                               /* second desc */
+                               td->status = AMD_ADDBITS(td->status,
+                                                       txbytes,
+                                                       UDC_DMA_IN_STS_TXBYTES);
+                       }
+               } else {
+                       if (create_new_chain) {
+                               last->next = dma_addr;
+                       } else {
+                               /* last->next = virt_to_phys(td); */
+                       }
+                       if (ep->in) {
+                               /* write tx bytes */
+                               td->status = AMD_ADDBITS(td->status,
+                                                       txbytes,
+                                                       UDC_DMA_IN_STS_TXBYTES);
+                       }
+               }
+               last = td;
+       }
+       /* set last bit */
+       if (td) {
+               td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+               /* last desc. points to itself */
+               req->td_data_last = td;
+       }
+
+       return 0;
+}
+
+/* Enabling RX DMA */
+static void udc_set_rde(struct udc *dev)
+{
+       u32 tmp;
+
+       VDBG(dev, "udc_set_rde()\n");
+       /* stop RDE timer */
+       if (timer_pending(&udc_timer)) {
+               set_rde = 0;
+               mod_timer(&udc_timer, jiffies - 1);
+       }
+       /* set RDE */
+       tmp = readl(&dev->regs->ctl);
+       tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+       writel(tmp, &dev->regs->ctl);
+}
+
+/* Queues a request packet, called by gadget driver */
+static int
+udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+{
+       int                     retval = 0;
+       u8                      open_rxfifo = 0;
+       unsigned long           iflags;
+       struct udc_ep           *ep;
+       struct udc_request      *req;
+       struct udc              *dev;
+       u32                     tmp;
+
+       /* check the inputs */
+       req = container_of(usbreq, struct udc_request, req);
+
+       if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+                       || !list_empty(&req->queue))
+               return -EINVAL;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+               return -EINVAL;
+
+       VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+       dev = ep->dev;
+
+       if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+               return -ESHUTDOWN;
+
+       /* map dma (usually done before) */
+       if (ep->dma && usbreq->length != 0
+                       && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+               VDBG(dev, "DMA map req %p\n", req);
+               if (ep->in)
+                       usbreq->dma = pci_map_single(dev->pdev,
+                                               usbreq->buf,
+                                               usbreq->length,
+                                               PCI_DMA_TODEVICE);
+               else
+                       usbreq->dma = pci_map_single(dev->pdev,
+                                               usbreq->buf,
+                                               usbreq->length,
+                                               PCI_DMA_FROMDEVICE);
+               req->dma_mapping = 1;
+       }
+
+       VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
+                       usbep->name, usbreq, usbreq->length,
+                       req->td_data, usbreq->buf);
+
+       spin_lock_irqsave(&dev->lock, iflags);
+       usbreq->actual = 0;
+       usbreq->status = -EINPROGRESS;
+       req->dma_done = 0;
+
+       /* on empty queue just do first transfer */
+       if (list_empty(&ep->queue)) {
+               /* zlp */
+               if (usbreq->length == 0) {
+                       /* IN zlp's are handled by hardware */
+                       complete_req(ep, req, 0);
+                       VDBG(dev, "%s: zlp\n", ep->ep.name);
+                       /*
+                        * if set_config or set_intf is waiting for ack by zlp
+                        * then set CSR_DONE
+                        */
+                       if (dev->set_cfg_not_acked) {
+                               tmp = readl(&dev->regs->ctl);
+                               tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+                               writel(tmp, &dev->regs->ctl);
+                               dev->set_cfg_not_acked = 0;
+                       }
+                       /* setup command is ACK'ed now by zlp */
+                       if (dev->waiting_zlp_ack_ep0in) {
+                               /* clear NAK by writing CNAK in EP0_IN */
+                               tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+                               tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                               writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+                               dev->ep[UDC_EP0IN_IX].naking = 0;
+                               UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+                                                       UDC_EP0IN_IX);
+                               dev->waiting_zlp_ack_ep0in = 0;
+                       }
+                       goto finished;
+               }
+               if (ep->dma) {
+                       retval = prep_dma(ep, req, gfp);
+                       if (retval != 0)
+                               goto finished;
+                       /* write desc pointer to enable DMA */
+                       if (ep->in) {
+                               /* set HOST READY */
+                               req->td_data->status =
+                                       AMD_ADDBITS(req->td_data->status,
+                                               UDC_DMA_IN_STS_BS_HOST_READY,
+                                               UDC_DMA_IN_STS_BS);
+                       }
+
+                       /* disabled rx dma while descriptor update */
+                       if (!ep->in) {
+                               /* stop RDE timer */
+                               if (timer_pending(&udc_timer)) {
+                                       set_rde = 0;
+                                       mod_timer(&udc_timer, jiffies - 1);
+                               }
+                               /* clear RDE */
+                               tmp = readl(&dev->regs->ctl);
+                               tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+                               writel(tmp, &dev->regs->ctl);
+                               open_rxfifo = 1;
+
+                               /*
+                                * if BNA occurred then let BNA dummy desc.
+                                * point to current desc.
+                                */
+                               if (ep->bna_occurred) {
+                                       VDBG(dev, "copy to BNA dummy desc.\n");
+                                       memcpy(ep->bna_dummy_req->td_data,
+                                               req->td_data,
+                                               sizeof(struct udc_data_dma));
+                               }
+                       }
+                       /* write desc pointer */
+                       writel(req->td_phys, &ep->regs->desptr);
+
+                       /* clear NAK by writing CNAK */
+                       if (ep->naking) {
+                               tmp = readl(&ep->regs->ctl);
+                               tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                               writel(tmp, &ep->regs->ctl);
+                               ep->naking = 0;
+                               UDC_QUEUE_CNAK(ep, ep->num);
+                       }
+
+                       if (ep->in) {
+                               /* enable ep irq */
+                               tmp = readl(&dev->regs->ep_irqmsk);
+                               tmp &= AMD_UNMASK_BIT(ep->num);
+                               writel(tmp, &dev->regs->ep_irqmsk);
+                       }
+               }
+
+       } else if (ep->dma) {
+
+               /*
+                * prep_dma not used for OUT ep's, this is not possible
+                * for PPB modes, because of chain creation reasons
+                */
+               if (ep->in) {
+                       retval = prep_dma(ep, req, gfp);
+                       if (retval != 0)
+                               goto finished;
+               }
+       }
+       VDBG(dev, "list_add\n");
+       /* add request to ep queue */
+       if (req) {
+
+               list_add_tail(&req->queue, &ep->queue);
+
+               /* open rxfifo if out data queued */
+               if (open_rxfifo) {
+                       /* enable DMA */
+                       req->dma_going = 1;
+                       udc_set_rde(dev);
+                       if (ep->num != UDC_EP0OUT_IX)
+                               dev->data_ep_queued = 1;
+               }
+               /* stop OUT naking */
+               if (!ep->in) {
+                       if (!use_dma && udc_rxfifo_pending) {
+                               DBG(dev, "udc_queue(): pending bytes in"
+                                       "rxfifo after nyet\n");
+                               /*
+                                * read pending bytes afer nyet:
+                                * referring to isr
+                                */
+                               if (udc_rxfifo_read(ep, req)) {
+                                       /* finish */
+                                       complete_req(ep, req, 0);
+                               }
+                               udc_rxfifo_pending = 0;
+
+                       }
+               }
+       }
+
+finished:
+       spin_unlock_irqrestore(&dev->lock, iflags);
+       return retval;
+}
+
+/* Empty request queue of an endpoint; caller holds spinlock */
+static void empty_req_queue(struct udc_ep *ep)
+{
+       struct udc_request      *req;
+
+       ep->halted = 1;
+       while (!list_empty(&ep->queue)) {
+               req = list_entry(ep->queue.next,
+                       struct udc_request,
+                       queue);
+               complete_req(ep, req, -ESHUTDOWN);
+       }
+}
+
+/* Dequeues a request packet, called by gadget driver */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+       struct udc_ep           *ep;
+       struct udc_request      *req;
+       unsigned                halted;
+       unsigned long           iflags;
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+                               && ep->num != UDC_EP0OUT_IX)))
+               return -EINVAL;
+
+       req = container_of(usbreq, struct udc_request, req);
+
+       spin_lock_irqsave(&ep->dev->lock, iflags);
+       halted = ep->halted;
+       ep->halted = 1;
+       /* request in processing or next one */
+       if (ep->queue.next == &req->queue) {
+               if (ep->dma && req->dma_going) {
+                       if (ep->in)
+                               ep->cancel_transfer = 1;
+                       else {
+                               u32 tmp;
+                               u32 dma_sts;
+                               /* stop potential receive DMA */
+                               tmp = readl(&udc->regs->ctl);
+                               writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
+                                                       &udc->regs->ctl);
+                               /*
+                                * Cancel transfer later in ISR
+                                * if descriptor was touched.
+                                */
+                               dma_sts = AMD_GETBITS(req->td_data->status,
+                                                       UDC_DMA_OUT_STS_BS);
+                               if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
+                                       ep->cancel_transfer = 1;
+                               else {
+                                       udc_init_bna_dummy(ep->req);
+                                       writel(ep->bna_dummy_req->td_phys,
+                                               &ep->regs->desptr);
+                               }
+                               writel(tmp, &udc->regs->ctl);
+                       }
+               }
+       }
+       complete_req(ep, req, -ECONNRESET);
+       ep->halted = halted;
+
+       spin_unlock_irqrestore(&ep->dev->lock, iflags);
+       return 0;
+}
+
+/* Halt or clear halt of endpoint */
+static int
+udc_set_halt(struct usb_ep *usbep, int halt)
+{
+       struct udc_ep   *ep;
+       u32 tmp;
+       unsigned long iflags;
+       int retval = 0;
+
+       if (!usbep)
+               return -EINVAL;
+
+       pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
+
+       ep = container_of(usbep, struct udc_ep, ep);
+       if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+               return -EINVAL;
+       if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+               return -ESHUTDOWN;
+
+       spin_lock_irqsave(&udc_stall_spinlock, iflags);
+       /* halt or clear halt */
+       if (halt) {
+               if (ep->num == 0)
+                       ep->dev->stall_ep0in = 1;
+               else {
+                       /*
+                        * set STALL
+                        * rxfifo empty not taken into acount
+                        */
+                       tmp = readl(&ep->regs->ctl);
+                       tmp |= AMD_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);
+                       ep->halted = 1;
+
+                       /* setup poll timer */
+                       if (!timer_pending(&udc_pollstall_timer)) {
+                               udc_pollstall_timer.expires = jiffies +
+                                       HZ * UDC_POLLSTALL_TIMER_USECONDS
+                                       / (1000 * 1000);
+                               if (!stop_pollstall_timer) {
+                                       DBG(ep->dev, "start polltimer\n");
+                                       add_timer(&udc_pollstall_timer);
+                               }
+                       }
+               }
+       } else {
+               /* ep is halted by set_halt() before */
+               if (ep->halted) {
+                       tmp = readl(&ep->regs->ctl);
+                       /* clear stall bit */
+                       tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+                       /* clear NAK by writing CNAK */
+                       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(tmp, &ep->regs->ctl);
+                       ep->halted = 0;
+                       UDC_QUEUE_CNAK(ep, ep->num);
+               }
+       }
+       spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+       return retval;
+}
+
+/* gadget interface */
+static const struct usb_ep_ops udc_ep_ops = {
+       .enable         = udc_ep_enable,
+       .disable        = udc_ep_disable,
+
+       .alloc_request  = udc_alloc_request,
+       .free_request   = udc_free_request,
+
+       .queue          = udc_queue,
+       .dequeue        = udc_dequeue,
+
+       .set_halt       = udc_set_halt,
+       /* fifo ops not implemented */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Get frame counter (not implemented) */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+       return -EOPNOTSUPP;
+}
+
+/* Remote wakeup gadget interface */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+       struct udc              *dev;
+
+       if (!gadget)
+               return -EINVAL;
+       dev = container_of(gadget, struct udc, gadget);
+       udc_remote_wakeup(dev);
+
+       return 0;
+}
+
+/* gadget operations */
+static const struct usb_gadget_ops udc_ops = {
+       .wakeup         = udc_wakeup,
+       .get_frame      = udc_get_frame,
+};
+
+/* Setups endpoint parameters, adds endpoints to linked list */
+static void make_ep_lists(struct udc *dev)
+{
+       /* make gadget ep lists */
+       INIT_LIST_HEAD(&dev->gadget.ep_list);
+       list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+                                               &dev->gadget.ep_list);
+       list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
+                                               &dev->gadget.ep_list);
+       list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+                                               &dev->gadget.ep_list);
+
+       /* fifo config */
+       dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+       dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/* init registers at driver load time */
+static int startup_registers(struct udc *dev)
+{
+       u32 tmp;
+
+       /* init controller by soft reset */
+       udc_soft_reset(dev);
+
+       /* mask not needed interrupts */
+       udc_mask_unused_interrupts(dev);
+
+       /* put into initial config */
+       udc_basic_init(dev);
+       /* link up all endpoints */
+       udc_setup_endpoints(dev);
+
+       /* program speed */
+       tmp = readl(&dev->regs->cfg);
+       if (use_fullspeed) {
+               tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+       } else {
+               tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+       }
+       writel(tmp, &dev->regs->cfg);
+
+       return 0;
+}
+
+/* Inits UDC context */
+static void udc_basic_init(struct udc *dev)
+{
+       u32     tmp;
+
+       DBG(dev, "udc_basic_init()\n");
+
+       dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+       /* stop RDE timer */
+       if (timer_pending(&udc_timer)) {
+               set_rde = 0;
+               mod_timer(&udc_timer, jiffies - 1);
+       }
+       /* stop poll stall timer */
+       if (timer_pending(&udc_pollstall_timer)) {
+               mod_timer(&udc_pollstall_timer, jiffies - 1);
+       }
+       /* disable DMA */
+       tmp = readl(&dev->regs->ctl);
+       tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+       tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+       writel(tmp, &dev->regs->ctl);
+
+       /* enable dynamic CSR programming */
+       tmp = readl(&dev->regs->cfg);
+       tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+       /* set self powered */
+       tmp |= AMD_BIT(UDC_DEVCFG_SP);
+       /* set remote wakeupable */
+       tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+       writel(tmp, &dev->regs->cfg);
+
+       make_ep_lists(dev);
+
+       dev->data_ep_enabled = 0;
+       dev->data_ep_queued = 0;
+}
+
+/* Sets initial endpoint parameters */
+static void udc_setup_endpoints(struct udc *dev)
+{
+       struct udc_ep   *ep;
+       u32     tmp;
+       u32     reg;
+
+       DBG(dev, "udc_setup_endpoints()\n");
+
+       /* read enum speed */
+       tmp = readl(&dev->regs->sts);
+       tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+       if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+               dev->gadget.speed = USB_SPEED_HIGH;
+       } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+               dev->gadget.speed = USB_SPEED_FULL;
+       }
+
+       /* set basic ep parameters */
+       for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+               ep = &dev->ep[tmp];
+               ep->dev = dev;
+               ep->ep.name = ep_string[tmp];
+               ep->num = tmp;
+               /* txfifo size is calculated at enable time */
+               ep->txfifo = dev->txfifo;
+
+               /* fifo size */
+               if (tmp < UDC_EPIN_NUM) {
+                       ep->fifo_depth = UDC_TXFIFO_SIZE;
+                       ep->in = 1;
+               } else {
+                       ep->fifo_depth = UDC_RXFIFO_SIZE;
+                       ep->in = 0;
+
+               }
+               ep->regs = &dev->ep_regs[tmp];
+               /*
+                * ep will be reset only if ep was not enabled before to avoid
+                * disabling ep interrupts when ENUM interrupt occurs but ep is
+                * not enabled by gadget driver
+                */
+               if (!ep->desc) {
+                       ep_init(dev->regs, ep);
+               }
+
+               if (use_dma) {
+                       /*
+                        * ep->dma is not really used, just to indicate that
+                        * DMA is active: remove this
+                        * dma regs = dev control regs
+                        */
+                       ep->dma = &dev->regs->ctl;
+
+                       /* nak OUT endpoints until enable - not for ep0 */
+                       if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
+                                               && tmp > UDC_EPIN_NUM) {
+                               /* set NAK */
+                               reg = readl(&dev->ep[tmp].regs->ctl);
+                               reg |= AMD_BIT(UDC_EPCTL_SNAK);
+                               writel(reg, &dev->ep[tmp].regs->ctl);
+                               dev->ep[tmp].naking = 1;
+
+                       }
+               }
+       }
+       /* EP0 max packet */
+       if (dev->gadget.speed == USB_SPEED_FULL) {
+               dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+               dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
+                                               UDC_FS_EP0OUT_MAX_PKT_SIZE;
+       } else if (dev->gadget.speed == USB_SPEED_HIGH) {
+               dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+               dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+       }
+
+       /*
+        * with suspend bug workaround, ep0 params for gadget driver
+        * are set at gadget driver bind() call
+        */
+       dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+       dev->ep[UDC_EP0IN_IX].halted = 0;
+       INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+       /* init cfg/alt/int */
+       dev->cur_config = 0;
+       dev->cur_intf = 0;
+       dev->cur_alt = 0;
+}
+
+/* Bringup after Connect event, initial bringup to be ready for ep0 events */
+static void usb_connect(struct udc *dev)
+{
+
+       dev_info(&dev->pdev->dev, "USB Connect\n");
+
+       dev->connected = 1;
+
+       /* put into initial config */
+       udc_basic_init(dev);
+
+       /* enable device setup interrupts */
+       udc_enable_dev_setup_interrupts(dev);
+}
+
+/*
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+
+       dev_info(&dev->pdev->dev, "USB Disconnect\n");
+
+       dev->connected = 0;
+
+       /* mask interrupts */
+       udc_mask_unused_interrupts(dev);
+
+       /* REVISIT there doesn't seem to be a point to having this
+        * talk to a tasklet ... do it directly, we already hold
+        * the spinlock needed to process the disconnect.
+        */
+
+       tasklet_schedule(&disconnect_tasklet);
+}
+
+/* Tasklet for disconnect to be outside of interrupt context */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+       struct udc *dev = (struct udc *)(*((struct udc **) par));
+       u32 tmp;
+
+       DBG(dev, "Tasklet disconnect\n");
+       spin_lock_irq(&dev->lock);
+
+       if (dev->driver) {
+               spin_unlock(&dev->lock);
+               dev->driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+
+               /* empty queues */
+               for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+                       empty_req_queue(&dev->ep[tmp]);
+               }
+
+       }
+
+       /* disable ep0 */
+       ep_init(dev->regs,
+                       &dev->ep[UDC_EP0IN_IX]);
+
+
+       if (!soft_reset_occured) {
+               /* init controller by soft reset */
+               udc_soft_reset(dev);
+               soft_reset_occured++;
+       }
+
+       /* re-enable dev interrupts */
+       udc_enable_dev_setup_interrupts(dev);
+       /* back to full speed ? */
+       if (use_fullspeed) {
+               tmp = readl(&dev->regs->cfg);
+               tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+               writel(tmp, &dev->regs->cfg);
+       }
+
+       spin_unlock_irq(&dev->lock);
+}
+
+/* Reset the UDC core */
+static void udc_soft_reset(struct udc *dev)
+{
+       unsigned long   flags;
+
+       DBG(dev, "Soft reset\n");
+       /*
+        * reset possible waiting interrupts, because int.
+        * status is lost after soft reset,
+        * ep int. status reset
+        */
+       writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+       /* device int. status reset */
+       writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+       spin_lock_irqsave(&udc_irq_spinlock, flags);
+       writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+       readl(&dev->regs->cfg);
+       spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+
+}
+
+/* RDE timer callback to set RDE bit */
+static void udc_timer_function(unsigned long v)
+{
+       u32 tmp;
+
+       spin_lock_irq(&udc_irq_spinlock);
+
+       if (set_rde > 0) {
+               /*
+                * open the fifo if fifo was filled on last timer call
+                * conditionally
+                */
+               if (set_rde > 1) {
+                       /* set RDE to receive setup data */
+                       tmp = readl(&udc->regs->ctl);
+                       tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+                       writel(tmp, &udc->regs->ctl);
+                       set_rde = -1;
+               } else if (readl(&udc->regs->sts)
+                               & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+                       /*
+                        * if fifo empty setup polling, do not just
+                        * open the fifo
+                        */
+                       udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+                       if (!stop_timer) {
+                               add_timer(&udc_timer);
+                       }
+               } else {
+                       /*
+                        * fifo contains data now, setup timer for opening
+                        * the fifo when timer expires to be able to receive
+                        * setup packets, when data packets gets queued by
+                        * gadget layer then timer will forced to expire with
+                        * set_rde=0 (RDE is set in udc_queue())
+                        */
+                       set_rde++;
+                       /* debug: lhadmot_timer_start = 221070 */
+                       udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+                       if (!stop_timer) {
+                               add_timer(&udc_timer);
+                       }
+               }
+
+       } else
+               set_rde = -1; /* RDE was set by udc_queue() */
+       spin_unlock_irq(&udc_irq_spinlock);
+       if (stop_timer)
+               complete(&on_exit);
+
+}
+
+/* Handle halt state, used in stall poll timer */
+static void udc_handle_halt_state(struct udc_ep *ep)
+{
+       u32 tmp;
+       /* set stall as long not halted */
+       if (ep->halted == 1) {
+               tmp = readl(&ep->regs->ctl);
+               /* STALL cleared ? */
+               if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+                       /*
+                        * FIXME: MSC spec requires that stall remains
+                        * even on receivng of CLEAR_FEATURE HALT. So
+                        * we would set STALL again here to be compliant.
+                        * But with current mass storage drivers this does
+                        * not work (would produce endless host retries).
+                        * So we clear halt on CLEAR_FEATURE.
+                        *
+                       DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
+                       tmp |= AMD_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);*/
+
+                       /* clear NAK by writing CNAK */
+                       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(tmp, &ep->regs->ctl);
+                       ep->halted = 0;
+                       UDC_QUEUE_CNAK(ep, ep->num);
+               }
+       }
+}
+
+/* Stall timer callback to poll S bit and set it again after */
+static void udc_pollstall_timer_function(unsigned long v)
+{
+       struct udc_ep *ep;
+       int halted = 0;
+
+       spin_lock_irq(&udc_stall_spinlock);
+       /*
+        * only one IN and OUT endpoints are handled
+        * IN poll stall
+        */
+       ep = &udc->ep[UDC_EPIN_IX];
+       udc_handle_halt_state(ep);
+       if (ep->halted)
+               halted = 1;
+       /* OUT poll stall */
+       ep = &udc->ep[UDC_EPOUT_IX];
+       udc_handle_halt_state(ep);
+       if (ep->halted)
+               halted = 1;
+
+       /* setup timer again when still halted */
+       if (!stop_pollstall_timer && halted) {
+               udc_pollstall_timer.expires = jiffies +
+                                       HZ * UDC_POLLSTALL_TIMER_USECONDS
+                                       / (1000 * 1000);
+               add_timer(&udc_pollstall_timer);
+       }
+       spin_unlock_irq(&udc_stall_spinlock);
+
+       if (stop_pollstall_timer)
+               complete(&on_pollstall_exit);
+}
+
+/* Inits endpoint 0 so that SETUP packets are processed */
+static void activate_control_endpoints(struct udc *dev)
+{
+       u32 tmp;
+
+       DBG(dev, "activate_control_endpoints\n");
+
+       /* flush fifo */
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+       tmp |= AMD_BIT(UDC_EPCTL_F);
+       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+       /* set ep0 directions */
+       dev->ep[UDC_EP0IN_IX].in = 1;
+       dev->ep[UDC_EP0OUT_IX].in = 0;
+
+       /* set buffer size (tx fifo entries) of EP0_IN */
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+                                       UDC_EPIN_BUFF_SIZE);
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
+                                       UDC_EPIN_BUFF_SIZE);
+       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+       /* set max packet size of EP0_IN */
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+                                       UDC_EP_MAX_PKT_SIZE);
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+                               UDC_EP_MAX_PKT_SIZE);
+       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+       /* set max packet size of EP0_OUT */
+       tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+                                       UDC_EP_MAX_PKT_SIZE);
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+                                       UDC_EP_MAX_PKT_SIZE);
+       writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+       /* set max packet size of EP0 in UDC CSR */
+       tmp = readl(&dev->csr->ne[0]);
+       if (dev->gadget.speed == USB_SPEED_FULL)
+               tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+                                       UDC_CSR_NE_MAX_PKT);
+       else if (dev->gadget.speed == USB_SPEED_HIGH)
+               tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+                                       UDC_CSR_NE_MAX_PKT);
+       writel(tmp, &dev->csr->ne[0]);
+
+       if (use_dma) {
+               dev->ep[UDC_EP0OUT_IX].td->status |=
+                       AMD_BIT(UDC_DMA_OUT_STS_L);
+               /* write dma desc address */
+               writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+                       &dev->ep[UDC_EP0OUT_IX].regs->subptr);
+               writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+                       &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+               /* stop RDE timer */
+               if (timer_pending(&udc_timer)) {
+                       set_rde = 0;
+                       mod_timer(&udc_timer, jiffies - 1);
+               }
+               /* stop pollstall timer */
+               if (timer_pending(&udc_pollstall_timer)) {
+                       mod_timer(&udc_pollstall_timer, jiffies - 1);
+               }
+               /* enable DMA */
+               tmp = readl(&dev->regs->ctl);
+               tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+                               | AMD_BIT(UDC_DEVCTL_RDE)
+                               | AMD_BIT(UDC_DEVCTL_TDE);
+               if (use_dma_bufferfill_mode) {
+                       tmp |= AMD_BIT(UDC_DEVCTL_BF);
+               } else if (use_dma_ppb_du) {
+                       tmp |= AMD_BIT(UDC_DEVCTL_DU);
+               }
+               writel(tmp, &dev->regs->ctl);
+       }
+
+       /* clear NAK by writing CNAK for EP0IN */
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+       dev->ep[UDC_EP0IN_IX].naking = 0;
+       UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+       /* clear NAK by writing CNAK for EP0OUT */
+       tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+       writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+       dev->ep[UDC_EP0OUT_IX].naking = 0;
+       UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/* Make endpoint 0 ready for control traffic */
+static int setup_ep0(struct udc *dev)
+{
+       activate_control_endpoints(dev);
+       /* enable ep0 interrupts */
+       udc_enable_ep0_interrupts(dev);
+       /* enable device setup interrupts */
+       udc_enable_dev_setup_interrupts(dev);
+
+       return 0;
+}
+
+/* Called by gadget driver to register itself */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       struct udc              *dev = udc;
+       int                     retval;
+       u32 tmp;
+
+       if (!driver || !driver->bind || !driver->setup
+                       || driver->speed != USB_SPEED_HIGH)
+               return -EINVAL;
+       if (!dev)
+               return -ENODEV;
+       if (dev->driver)
+               return -EBUSY;
+
+       driver->driver.bus = NULL;
+       dev->driver = driver;
+       dev->gadget.dev.driver = &driver->driver;
+
+       retval = driver->bind(&dev->gadget);
+
+       /* Some gadget drivers use both ep0 directions.
+        * NOTE: to gadget driver, ep0 is just one endpoint...
+        */
+       dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+               dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+       if (retval) {
+               DBG(dev, "binding to %s returning %d\n",
+                               driver->driver.name, retval);
+               dev->driver = NULL;
+               dev->gadget.dev.driver = NULL;
+               return retval;
+       }
+
+       /* get ready for ep0 traffic */
+       setup_ep0(dev);
+
+       /* clear SD */
+       tmp = readl(&dev->regs->ctl);
+       tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+       writel(tmp, &dev->regs->ctl);
+
+       usb_connect(dev);
+
+       return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/* shutdown requests and disconnect from gadget */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+       int tmp;
+
+       /* empty queues and init hardware */
+       udc_basic_init(dev);
+       for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+               empty_req_queue(&dev->ep[tmp]);
+       }
+
+       if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+               spin_unlock(&dev->lock);
+               driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+       }
+       /* init */
+       udc_setup_endpoints(dev);
+}
+
+/* Called by gadget driver to unregister itself */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       struct udc      *dev = udc;
+       unsigned long   flags;
+       u32 tmp;
+
+       if (!dev)
+               return -ENODEV;
+       if (!driver || driver != dev->driver || !driver->unbind)
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       udc_mask_unused_interrupts(dev);
+       shutdown(dev, driver);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       driver->unbind(&dev->gadget);
+       dev->driver = NULL;
+
+       /* set SD */
+       tmp = readl(&dev->regs->ctl);
+       tmp |= AMD_BIT(UDC_DEVCTL_SD);
+       writel(tmp, &dev->regs->ctl);
+
+
+       DBG(dev, "%s: unregistered\n", driver->driver.name);
+
+       return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/* Clear pending NAK bits */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+       u32 tmp;
+       u32 reg;
+
+       /* check epin's */
+       DBG(dev, "CNAK pending queue processing\n");
+       for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+               if (cnak_pending & (1 << tmp)) {
+                       DBG(dev, "CNAK pending for ep%d\n", tmp);
+                       /* clear NAK by writing CNAK */
+                       reg = readl(&dev->ep[tmp].regs->ctl);
+                       reg |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(reg, &dev->ep[tmp].regs->ctl);
+                       dev->ep[tmp].naking = 0;
+                       UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+               }
+       }
+       /* ...  and ep0out */
+       if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+               DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+               /* clear NAK by writing CNAK */
+               reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+               reg |= AMD_BIT(UDC_EPCTL_CNAK);
+               writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+               dev->ep[UDC_EP0OUT_IX].naking = 0;
+               UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+                               dev->ep[UDC_EP0OUT_IX].num);
+       }
+}
+
+/* Enabling RX DMA after setup packet */
+static void udc_ep0_set_rde(struct udc *dev)
+{
+       if (use_dma) {
+               /*
+                * only enable RXDMA when no data endpoint enabled
+                * or data is queued
+                */
+               if (!dev->data_ep_enabled || dev->data_ep_queued) {
+                       udc_set_rde(dev);
+               } else {
+                       /*
+                        * setup timer for enabling RDE (to not enable
+                        * RXFIFO DMA for data endpoints to early)
+                        */
+                       if (set_rde != 0 && !timer_pending(&udc_timer)) {
+                               udc_timer.expires =
+                                       jiffies + HZ/UDC_RDE_TIMER_DIV;
+                               set_rde = 1;
+                               if (!stop_timer) {
+                                       add_timer(&udc_timer);
+                               }
+                       }
+               }
+       }
+}
+
+
+/* Interrupt handler for data OUT traffic */
+static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+       irqreturn_t             ret_val = IRQ_NONE;
+       u32                     tmp;
+       struct udc_ep           *ep;
+       struct udc_request      *req;
+       unsigned int            count;
+       struct udc_data_dma     *td = NULL;
+       unsigned                dma_done;
+
+       VDBG(dev, "ep%d irq\n", ep_ix);
+       ep = &dev->ep[ep_ix];
+
+       tmp = readl(&ep->regs->sts);
+       if (use_dma) {
+               /* BNA event ? */
+               if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+                       DBG(dev, "BNA ep%dout occured - DESPTR = %x \n",
+                                       ep->num, readl(&ep->regs->desptr));
+                       /* clear BNA */
+                       writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+                       if (!ep->cancel_transfer)
+                               ep->bna_occurred = 1;
+                       else
+                               ep->cancel_transfer = 0;
+                       ret_val = IRQ_HANDLED;
+                       goto finished;
+               }
+       }
+       /* HE event ? */
+       if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+               dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num);
+
+               /* clear HE */
+               writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+               ret_val = IRQ_HANDLED;
+               goto finished;
+       }
+
+       if (!list_empty(&ep->queue)) {
+
+               /* next request */
+               req = list_entry(ep->queue.next,
+                       struct udc_request, queue);
+       } else {
+               req = NULL;
+               udc_rxfifo_pending = 1;
+       }
+       VDBG(dev, "req = %p\n", req);
+       /* fifo mode */
+       if (!use_dma) {
+
+               /* read fifo */
+               if (req && udc_rxfifo_read(ep, req)) {
+                       ret_val = IRQ_HANDLED;
+
+                       /* finish */
+                       complete_req(ep, req, 0);
+                       /* next request */
+                       if (!list_empty(&ep->queue) && !ep->halted) {
+                               req = list_entry(ep->queue.next,
+                                       struct udc_request, queue);
+                       } else
+                               req = NULL;
+               }
+
+       /* DMA */
+       } else if (!ep->cancel_transfer && req != NULL) {
+               ret_val = IRQ_HANDLED;
+
+               /* check for DMA done */
+               if (!use_dma_ppb) {
+                       dma_done = AMD_GETBITS(req->td_data->status,
+                                               UDC_DMA_OUT_STS_BS);
+               /* packet per buffer mode - rx bytes */
+               } else {
+                       /*
+                        * if BNA occurred then recover desc. from
+                        * BNA dummy desc.
+                        */
+                       if (ep->bna_occurred) {
+                               VDBG(dev, "Recover desc. from BNA dummy\n");
+                               memcpy(req->td_data, ep->bna_dummy_req->td_data,
+                                               sizeof(struct udc_data_dma));
+                               ep->bna_occurred = 0;
+                               udc_init_bna_dummy(ep->req);
+                       }
+                       td = udc_get_last_dma_desc(req);
+                       dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+               }
+               if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+                       /* buffer fill mode - rx bytes */
+                       if (!use_dma_ppb) {
+                               /* received number bytes */
+                               count = AMD_GETBITS(req->td_data->status,
+                                               UDC_DMA_OUT_STS_RXBYTES);
+                               VDBG(dev, "rx bytes=%u\n", count);
+                       /* packet per buffer mode - rx bytes */
+                       } else {
+                               VDBG(dev, "req->td_data=%p\n", req->td_data);
+                               VDBG(dev, "last desc = %p\n", td);
+                               /* received number bytes */
+                               if (use_dma_ppb_du) {
+                                       /* every desc. counts bytes */
+                                       count = udc_get_ppbdu_rxbytes(req);
+                               } else {
+                                       /* last desc. counts bytes */
+                                       count = AMD_GETBITS(td->status,
+                                               UDC_DMA_OUT_STS_RXBYTES);
+                                       if (!count && req->req.length
+                                               == UDC_DMA_MAXPACKET) {
+                                               /*
+                                                * on 64k packets the RXBYTES
+                                                * field is zero
+                                                */
+                                               count = UDC_DMA_MAXPACKET;
+                                       }
+                               }
+                               VDBG(dev, "last desc rx bytes=%u\n", count);
+                       }
+
+                       tmp = req->req.length - req->req.actual;
+                       if (count > tmp) {
+                               if ((tmp % ep->ep.maxpacket) != 0) {
+                                       DBG(dev, "%s: rx %db, space=%db\n",
+                                               ep->ep.name, count, tmp);
+                                       req->req.status = -EOVERFLOW;
+                               }
+                               count = tmp;
+                       }
+                       req->req.actual += count;
+                       req->dma_going = 0;
+                       /* complete request */
+                       complete_req(ep, req, 0);
+
+                       /* next request */
+                       if (!list_empty(&ep->queue) && !ep->halted) {
+                               req = list_entry(ep->queue.next,
+                                       struct udc_request,
+                                       queue);
+                               /*
+                                * DMA may be already started by udc_queue()
+                                * called by gadget drivers completion
+                                * routine. This happens when queue
+                                * holds one request only.
+                                */
+                               if (req->dma_going == 0) {
+                                       /* next dma */
+                                       if (prep_dma(ep, req, GFP_ATOMIC) != 0)
+                                               goto finished;
+                                       /* write desc pointer */
+                                       writel(req->td_phys,
+                                               &ep->regs->desptr);
+                                       req->dma_going = 1;
+                                       /* enable DMA */
+                                       udc_set_rde(dev);
+                               }
+                       } else {
+                               /*
+                                * implant BNA dummy descriptor to allow
+                                * RXFIFO opening by RDE
+                                */
+                               if (ep->bna_dummy_req) {
+                                       /* write desc pointer */
+                                       writel(ep->bna_dummy_req->td_phys,
+                                               &ep->regs->desptr);
+                                       ep->bna_occurred = 0;
+                               }
+
+                               /*
+                                * schedule timer for setting RDE if queue
+                                * remains empty to allow ep0 packets pass
+                                * through
+                                */
+                               if (set_rde != 0
+                                               && !timer_pending(&udc_timer)) {
+                                       udc_timer.expires =
+                                               jiffies
+                                               + HZ*UDC_RDE_TIMER_SECONDS;
+                                       set_rde = 1;
+                                       if (!stop_timer) {
+                                               add_timer(&udc_timer);
+                                       }
+                               }
+                               if (ep->num != UDC_EP0OUT_IX)
+                                       dev->data_ep_queued = 0;
+                       }
+
+               } else {
+                       /*
+                       * RX DMA must be reenabled for each desc in PPBDU mode
+                       * and must be enabled for PPBNDU mode in case of BNA
+                       */
+                       udc_set_rde(dev);
+               }
+
+       } else if (ep->cancel_transfer) {
+               ret_val = IRQ_HANDLED;
+               ep->cancel_transfer = 0;
+       }
+
+       /* check pending CNAKS */
+       if (cnak_pending) {
+               /* CNAk processing when rxfifo empty only */
+               if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+                       udc_process_cnak_queue(dev);
+               }
+       }
+
+       /* clear OUT bits in ep status */
+       writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
+finished:
+       return ret_val;
+}
+
+/* Interrupt handler for data IN traffic */
+static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+       irqreturn_t ret_val = IRQ_NONE;
+       u32 tmp;
+       u32 epsts;
+       struct udc_ep *ep;
+       struct udc_request *req;
+       struct udc_data_dma *td;
+       unsigned dma_done;
+       unsigned len;
+
+       ep = &dev->ep[ep_ix];
+
+       epsts = readl(&ep->regs->sts);
+       if (use_dma) {
+               /* BNA ? */
+               if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
+                       dev_err(&dev->pdev->dev,
+                               "BNA ep%din occured - DESPTR = %08lx \n",
+                               ep->num,
+                               (unsigned long) readl(&ep->regs->desptr));
+
+                       /* clear BNA */
+                       writel(epsts, &ep->regs->sts);
+                       ret_val = IRQ_HANDLED;
+                       goto finished;
+               }
+       }
+       /* HE event ? */
+       if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
+               dev_err(&dev->pdev->dev,
+                       "HE ep%dn occured - DESPTR = %08lx \n",
+                       ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+               /* clear HE */
+               writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+               ret_val = IRQ_HANDLED;
+               goto finished;
+       }
+
+       /* DMA completion */
+       if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
+               VDBG(dev, "TDC set- completion\n");
+               ret_val = IRQ_HANDLED;
+               if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
+                       req = list_entry(ep->queue.next,
+                                       struct udc_request, queue);
+                       if (req) {
+                               /*
+                                * length bytes transfered
+                                * check dma done of last desc. in PPBDU mode
+                                */
+                               if (use_dma_ppb_du) {
+                                       td = udc_get_last_dma_desc(req);
+                                       if (td) {
+                                               dma_done =
+                                                       AMD_GETBITS(td->status,
+                                                       UDC_DMA_IN_STS_BS);
+                                               /* don't care DMA done */
+                                               req->req.actual =
+                                                       req->req.length;
+                                       }
+                               } else {
+                                       /* assume all bytes transferred */
+                                       req->req.actual = req->req.length;
+                               }
+
+                               if (req->req.actual == req->req.length) {
+                                       /* complete req */
+                                       complete_req(ep, req, 0);
+                                       req->dma_going = 0;
+                                       /* further request available ? */
+                                       if (list_empty(&ep->queue)) {
+                                               /* disable interrupt */
+                                               tmp = readl(
+                                                       &dev->regs->ep_irqmsk);
+                                               tmp |= AMD_BIT(ep->num);
+                                               writel(tmp,
+                                                       &dev->regs->ep_irqmsk);
+                                       }
+
+                               }
+                       }
+               }
+               ep->cancel_transfer = 0;
+
+       }
+       /*
+        * status reg has IN bit set and TDC not set (if TDC was handled,
+        * IN must not be handled (UDC defect) ?
+        */
+       if ((epsts & AMD_BIT(UDC_EPSTS_IN))
+                       && !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
+               ret_val = IRQ_HANDLED;
+               if (!list_empty(&ep->queue)) {
+                       /* next request */
+                       req = list_entry(ep->queue.next,
+                                       struct udc_request, queue);
+                       /* FIFO mode */
+                       if (!use_dma) {
+                               /* write fifo */
+                               udc_txfifo_write(ep, &req->req);
+                               len = req->req.length - req->req.actual;
+                                               if (len > ep->ep.maxpacket)
+                                                       len = ep->ep.maxpacket;
+                                               req->req.actual += len;
+                               if (req->req.actual == req->req.length
+                                       || (len != ep->ep.maxpacket)) {
+                                       /* complete req */
+                                       complete_req(ep, req, 0);
+                               }
+                       /* DMA */
+                       } else if (req && !req->dma_going) {
+                               VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
+                                       req, req->td_data);
+                               if (req->td_data) {
+
+                                       req->dma_going = 1;
+
+                                       /*
+                                        * unset L bit of first desc.
+                                        * for chain
+                                        */
+                                       if (use_dma_ppb && req->req.length >
+                                                       ep->ep.maxpacket) {
+                                               req->td_data->status &=
+                                                       AMD_CLEAR_BIT(
+                                                       UDC_DMA_IN_STS_L);
+                                       }
+
+                                       /* write desc pointer */
+                                       writel(req->td_phys, &ep->regs->desptr);
+
+                                       /* set HOST READY */
+                                       req->td_data->status =
+                                               AMD_ADDBITS(
+                                               req->td_data->status,
+                                               UDC_DMA_IN_STS_BS_HOST_READY,
+                                               UDC_DMA_IN_STS_BS);
+
+                                       /* set poll demand bit */
+                                       tmp = readl(&ep->regs->ctl);
+                                       tmp |= AMD_BIT(UDC_EPCTL_P);
+                                       writel(tmp, &ep->regs->ctl);
+                               }
+                       }
+
+               }
+       }
+       /* clear status bits */
+       writel(epsts, &ep->regs->sts);
+
+finished:
+       return ret_val;
+
+}
+
+/* Interrupt handler for Control OUT traffic */
+static irqreturn_t udc_control_out_isr(struct udc *dev)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+       irqreturn_t ret_val = IRQ_NONE;
+       u32 tmp;
+       int setup_supported;
+       u32 count;
+       int set = 0;
+       struct udc_ep   *ep;
+       struct udc_ep   *ep_tmp;
+
+       ep = &dev->ep[UDC_EP0OUT_IX];
+
+       /* clear irq */
+       writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+       tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+       /* check BNA and clear if set */
+       if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+               VDBG(dev, "ep0: BNA set\n");
+               writel(AMD_BIT(UDC_EPSTS_BNA),
+                       &dev->ep[UDC_EP0OUT_IX].regs->sts);
+               ep->bna_occurred = 1;
+               ret_val = IRQ_HANDLED;
+               goto finished;
+       }
+
+       /* type of data: SETUP or DATA 0 bytes */
+       tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+       VDBG(dev, "data_typ = %x\n", tmp);
+
+       /* setup data */
+       if (tmp == UDC_EPSTS_OUT_SETUP) {
+               ret_val = IRQ_HANDLED;
+
+               ep->dev->stall_ep0in = 0;
+               dev->waiting_zlp_ack_ep0in = 0;
+
+               /* set NAK for EP0_IN */
+               tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+               tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+               writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+               dev->ep[UDC_EP0IN_IX].naking = 1;
+               /* get setup data */
+               if (use_dma) {
+
+                       /* clear OUT bits in ep status */
+                       writel(UDC_EPSTS_OUT_CLEAR,
+                               &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+                       setup_data.data[0] =
+                               dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+                       setup_data.data[1] =
+                               dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+                       /* set HOST READY */
+                       dev->ep[UDC_EP0OUT_IX].td_stp->status =
+                                       UDC_DMA_STP_STS_BS_HOST_READY;
+               } else {
+                       /* read fifo */
+                       udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+               }
+
+               /* determine direction of control data */
+               if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+                       dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+                       /* enable RDE */
+                       udc_ep0_set_rde(dev);
+                       set = 0;
+               } else {
+                       dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+                       /*
+                        * implant BNA dummy descriptor to allow RXFIFO opening
+                        * by RDE
+                        */
+                       if (ep->bna_dummy_req) {
+                               /* write desc pointer */
+                               writel(ep->bna_dummy_req->td_phys,
+                                       &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+                               ep->bna_occurred = 0;
+                       }
+
+                       set = 1;
+                       dev->ep[UDC_EP0OUT_IX].naking = 1;
+                       /*
+                        * setup timer for enabling RDE (to not enable
+                        * RXFIFO DMA for data to early)
+                        */
+                       set_rde = 1;
+                       if (!timer_pending(&udc_timer)) {
+                               udc_timer.expires = jiffies +
+                                                       HZ/UDC_RDE_TIMER_DIV;
+                               if (!stop_timer) {
+                                       add_timer(&udc_timer);
+                               }
+                       }
+               }
+
+               /*
+                * mass storage reset must be processed here because
+                * next packet may be a CLEAR_FEATURE HALT which would not
+                * clear the stall bit when no STALL handshake was received
+                * before (autostall can cause this)
+                */
+               if (setup_data.data[0] == UDC_MSCRES_DWORD0
+                               && setup_data.data[1] == UDC_MSCRES_DWORD1) {
+                       DBG(dev, "MSC Reset\n");
+                       /*
+                        * clear stall bits
+                        * only one IN and OUT endpoints are handled
+                        */
+                       ep_tmp = &udc->ep[UDC_EPIN_IX];
+                       udc_set_halt(&ep_tmp->ep, 0);
+                       ep_tmp = &udc->ep[UDC_EPOUT_IX];
+                       udc_set_halt(&ep_tmp->ep, 0);
+               }
+
+               /* call gadget with setup data received */
+               spin_unlock(&dev->lock);
+               setup_supported = dev->driver->setup(&dev->gadget,
+                                               &setup_data.request);
+               spin_lock(&dev->lock);
+
+               tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+               /* ep0 in returns data (not zlp) on IN phase */
+               if (setup_supported >= 0 && setup_supported <
+                               UDC_EP0IN_MAXPACKET) {
+                       /* clear NAK by writing CNAK in EP0_IN */
+                       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+                       dev->ep[UDC_EP0IN_IX].naking = 0;
+                       UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+               /* if unsupported request then stall */
+               } else if (setup_supported < 0) {
+                       tmp |= AMD_BIT(UDC_EPCTL_S);
+                       writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+               } else
+                       dev->waiting_zlp_ack_ep0in = 1;
+
+
+               /* clear NAK by writing CNAK in EP0_OUT */
+               if (!set) {
+                       tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+                       tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+                       writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+                       dev->ep[UDC_EP0OUT_IX].naking = 0;
+                       UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+               }
+
+               if (!use_dma) {
+                       /* clear OUT bits in ep status */
+                       writel(UDC_EPSTS_OUT_CLEAR,
+                               &dev->ep[UDC_EP0OUT_IX].regs->sts);
+               }
+
+       /* data packet 0 bytes */
+       } else if (tmp == UDC_EPSTS_OUT_DATA) {
+               /* clear OUT bits in ep status */
+               writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+               /* get setup data: only 0 packet */
+               if (use_dma) {
+                       /* no req if 0 packet, just reactivate */
+                       if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+                               VDBG(dev, "ZLP\n");
+
+                               /* set HOST READY */
+                               dev->ep[UDC_EP0OUT_IX].td->status =
+                                       AMD_ADDBITS(
+                                       dev->ep[UDC_EP0OUT_IX].td->status,
+                                       UDC_DMA_OUT_STS_BS_HOST_READY,
+                                       UDC_DMA_OUT_STS_BS);
+                               /* enable RDE */
+                               udc_ep0_set_rde(dev);
+                               ret_val = IRQ_HANDLED;
+
+                       } else {
+                               /* control write */
+                               ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+                               /* re-program desc. pointer for possible ZLPs */
+                               writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+                                       &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+                               /* enable RDE */
+                               udc_ep0_set_rde(dev);
+                       }
+               } else {
+
+                       /* received number bytes */
+                       count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+                       count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+                       /* out data for fifo mode not working */
+                       count = 0;
+
+                       /* 0 packet or real data ? */
+                       if (count != 0) {
+                               ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+                       } else {
+                               /* dummy read confirm */
+                               readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+                               ret_val = IRQ_HANDLED;
+                       }
+               }
+       }
+
+       /* check pending CNAKS */
+       if (cnak_pending) {
+               /* CNAk processing when rxfifo empty only */
+               if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+                       udc_process_cnak_queue(dev);
+               }
+       }
+
+finished:
+       return ret_val;
+}
+
+/* Interrupt handler for Control IN traffic */
+static irqreturn_t udc_control_in_isr(struct udc *dev)
+{
+       irqreturn_t ret_val = IRQ_NONE;
+       u32 tmp;
+       struct udc_ep *ep;
+       struct udc_request *req;
+       unsigned len;
+
+       ep = &dev->ep[UDC_EP0IN_IX];
+
+       /* clear irq */
+       writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+       tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+       /* DMA completion */
+       if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+               VDBG(dev, "isr: TDC clear \n");
+               ret_val = IRQ_HANDLED;
+
+               /* clear TDC bit */
+               writel(AMD_BIT(UDC_EPSTS_TDC),
+                               &dev->ep[UDC_EP0IN_IX].regs->sts);
+
+       /* status reg has IN bit set ? */
+       } else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+               ret_val = IRQ_HANDLED;
+
+               if (ep->dma) {
+                       /* clear IN bit */
+                       writel(AMD_BIT(UDC_EPSTS_IN),
+                               &dev->ep[UDC_EP0IN_IX].regs->sts);
+               }
+               if (dev->stall_ep0in) {
+                       DBG(dev, "stall ep0in\n");
+                       /* halt ep0in */
+                       tmp = readl(&ep->regs->ctl);
+                       tmp |= AMD_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);
+               } else {
+                       if (!list_empty(&ep->queue)) {
+                               /* next request */
+                               req = list_entry(ep->queue.next,
+                                               struct udc_request, queue);
+
+                               if (ep->dma) {
+                                       /* write desc pointer */
+                                       writel(req->td_phys, &ep->regs->desptr);
+                                       /* set HOST READY */
+                                       req->td_data->status =
+                                               AMD_ADDBITS(
+                                               req->td_data->status,
+                                               UDC_DMA_STP_STS_BS_HOST_READY,
+                                               UDC_DMA_STP_STS_BS);
+
+                                       /* set poll demand bit */
+                                       tmp =
+                                       readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+                                       tmp |= AMD_BIT(UDC_EPCTL_P);
+                                       writel(tmp,
+                                       &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+                                       /* all bytes will be transferred */
+                                       req->req.actual = req->req.length;
+
+                                       /* complete req */
+                                       complete_req(ep, req, 0);
+
+                               } else {
+                                       /* write fifo */
+                                       udc_txfifo_write(ep, &req->req);
+
+                                       /* lengh bytes transfered */
+                                       len = req->req.length - req->req.actual;
+                                       if (len > ep->ep.maxpacket)
+                                               len = ep->ep.maxpacket;
+
+                                       req->req.actual += len;
+                                       if (req->req.actual == req->req.length
+                                               || (len != ep->ep.maxpacket)) {
+                                               /* complete req */
+                                               complete_req(ep, req, 0);
+                                       }
+                               }
+
+                       }
+               }
+               ep->halted = 0;
+               dev->stall_ep0in = 0;
+               if (!ep->dma) {
+                       /* clear IN bit */
+                       writel(AMD_BIT(UDC_EPSTS_IN),
+                               &dev->ep[UDC_EP0IN_IX].regs->sts);
+               }
+       }
+
+       return ret_val;
+}
+
+
+/* Interrupt handler for global device events */
+static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+       irqreturn_t ret_val = IRQ_NONE;
+       u32 tmp;
+       u32 cfg;
+       struct udc_ep *ep;
+       u16 i;
+       u8 udc_csr_epix;
+
+       /* SET_CONFIG irq ? */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+               ret_val = IRQ_HANDLED;
+
+               /* read config value */
+               tmp = readl(&dev->regs->sts);
+               cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+               DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
+               dev->cur_config = cfg;
+               dev->set_cfg_not_acked = 1;
+
+               /* make usb request for gadget driver */
+               memset(&setup_data, 0 , sizeof(union udc_setup_data));
+               setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+               setup_data.request.wValue = dev->cur_config;
+
+               /* programm the NE registers */
+               for (i = 0; i < UDC_EP_NUM; i++) {
+                       ep = &dev->ep[i];
+                       if (ep->in) {
+
+                               /* ep ix in UDC CSR register space */
+                               udc_csr_epix = ep->num;
+
+
+                       /* OUT ep */
+                       } else {
+                               /* ep ix in UDC CSR register space */
+                               udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+                       }
+
+                       tmp = readl(&dev->csr->ne[udc_csr_epix]);
+                       /* ep cfg */
+                       tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
+                                               UDC_CSR_NE_CFG);
+                       /* write reg */
+                       writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+                       /* clear stall bits */
+                       ep->halted = 0;
+                       tmp = readl(&ep->regs->ctl);
+                       tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);
+               }
+               /* call gadget zero with setup data received */
+               spin_unlock(&dev->lock);
+               tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+               spin_lock(&dev->lock);
+
+       } /* SET_INTERFACE ? */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+               ret_val = IRQ_HANDLED;
+
+               dev->set_cfg_not_acked = 1;
+               /* read interface and alt setting values */
+               tmp = readl(&dev->regs->sts);
+               dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+               dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+               /* make usb request for gadget driver */
+               memset(&setup_data, 0 , sizeof(union udc_setup_data));
+               setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+               setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+               setup_data.request.wValue = dev->cur_alt;
+               setup_data.request.wIndex = dev->cur_intf;
+
+               DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
+                               dev->cur_alt, dev->cur_intf);
+
+               /* programm the NE registers */
+               for (i = 0; i < UDC_EP_NUM; i++) {
+                       ep = &dev->ep[i];
+                       if (ep->in) {
+
+                               /* ep ix in UDC CSR register space */
+                               udc_csr_epix = ep->num;
+
+
+                       /* OUT ep */
+                       } else {
+                               /* ep ix in UDC CSR register space */
+                               udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+                       }
+
+                       /* UDC CSR reg */
+                       /* set ep values */
+                       tmp = readl(&dev->csr->ne[udc_csr_epix]);
+                       /* ep interface */
+                       tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
+                                               UDC_CSR_NE_INTF);
+                       /* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
+                       /* ep alt */
+                       tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
+                                               UDC_CSR_NE_ALT);
+                       /* write reg */
+                       writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+                       /* clear stall bits */
+                       ep->halted = 0;
+                       tmp = readl(&ep->regs->ctl);
+                       tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+                       writel(tmp, &ep->regs->ctl);
+               }
+
+               /* call gadget zero with setup data received */
+               spin_unlock(&dev->lock);
+               tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+               spin_lock(&dev->lock);
+
+       } /* USB reset */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+               DBG(dev, "USB Reset interrupt\n");
+               ret_val = IRQ_HANDLED;
+
+               /* allow soft reset when suspend occurs */
+               soft_reset_occured = 0;
+
+               dev->waiting_zlp_ack_ep0in = 0;
+               dev->set_cfg_not_acked = 0;
+
+               /* mask not needed interrupts */
+               udc_mask_unused_interrupts(dev);
+
+               /* call gadget to resume and reset configs etc. */
+               spin_unlock(&dev->lock);
+               if (dev->sys_suspended && dev->driver->resume) {
+                       dev->driver->resume(&dev->gadget);
+                       dev->sys_suspended = 0;
+               }
+               dev->driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+
+               /* disable ep0 to empty req queue */
+               empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+               ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+               /* soft reset when rxfifo not empty */
+               tmp = readl(&dev->regs->sts);
+               if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+                               && !soft_reset_after_usbreset_occured) {
+                       udc_soft_reset(dev);
+                       soft_reset_after_usbreset_occured++;
+               }
+
+               /*
+                * DMA reset to kill potential old DMA hw hang,
+                * POLL bit is already reset by ep_init() through
+                * disconnect()
+                */
+               DBG(dev, "DMA machine reset\n");
+               tmp = readl(&dev->regs->cfg);
+               writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
+               writel(tmp, &dev->regs->cfg);
+
+               /* put into initial config */
+               udc_basic_init(dev);
+
+               /* enable device setup interrupts */
+               udc_enable_dev_setup_interrupts(dev);
+
+               /* enable suspend interrupt */
+               tmp = readl(&dev->regs->irqmsk);
+               tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
+               writel(tmp, &dev->regs->irqmsk);
+
+       } /* USB suspend */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+               DBG(dev, "USB Suspend interrupt\n");
+               ret_val = IRQ_HANDLED;
+               if (dev->driver->suspend) {
+                       spin_unlock(&dev->lock);
+                       dev->sys_suspended = 1;
+                       dev->driver->suspend(&dev->gadget);
+                       spin_lock(&dev->lock);
+               }
+       } /* new speed ? */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+               DBG(dev, "ENUM interrupt\n");
+               ret_val = IRQ_HANDLED;
+               soft_reset_after_usbreset_occured = 0;
+
+               /* disable ep0 to empty req queue */
+               empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+               ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+               /* link up all endpoints */
+               udc_setup_endpoints(dev);
+               if (dev->gadget.speed == USB_SPEED_HIGH) {
+                       dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+                               "high");
+               } else if (dev->gadget.speed == USB_SPEED_FULL) {
+                       dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+                               "full");
+               }
+
+               /* init ep 0 */
+               activate_control_endpoints(dev);
+
+               /* enable ep0 interrupts */
+               udc_enable_ep0_interrupts(dev);
+       }
+       /* session valid change interrupt */
+       if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+               DBG(dev, "USB SVC interrupt\n");
+               ret_val = IRQ_HANDLED;
+
+               /* check that session is not valid to detect disconnect */
+               tmp = readl(&dev->regs->sts);
+               if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+                       /* disable suspend interrupt */
+                       tmp = readl(&dev->regs->irqmsk);
+                       tmp |= AMD_BIT(UDC_DEVINT_US);
+                       writel(tmp, &dev->regs->irqmsk);
+                       DBG(dev, "USB Disconnect (session valid low)\n");
+                       /* cleanup on disconnect */
+                       usb_disconnect(udc);
+               }
+
+       }
+
+       return ret_val;
+}
+
+/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+       struct udc *dev = pdev;
+       u32 reg;
+       u16 i;
+       u32 ep_irq;
+       irqreturn_t ret_val = IRQ_NONE;
+
+       spin_lock(&dev->lock);
+
+       /* check for ep irq */
+       reg = readl(&dev->regs->ep_irqsts);
+       if (reg) {
+               if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+                       ret_val |= udc_control_out_isr(dev);
+               if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
+                       ret_val |= udc_control_in_isr(dev);
+
+               /*
+                * data endpoint
+                * iterate ep's
+                */
+               for (i = 1; i < UDC_EP_NUM; i++) {
+                       ep_irq = 1 << i;
+                       if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
+                               continue;
+
+                       /* clear irq status */
+                       writel(ep_irq, &dev->regs->ep_irqsts);
+
+                       /* irq for out ep ? */
+                       if (i > UDC_EPIN_NUM)
+                               ret_val |= udc_data_out_isr(dev, i);
+                       else
+                               ret_val |= udc_data_in_isr(dev, i);
+               }
+
+       }
+
+
+       /* check for dev irq */
+       reg = readl(&dev->regs->irqsts);
+       if (reg) {
+               /* clear irq */
+               writel(reg, &dev->regs->irqsts);
+               ret_val |= udc_dev_isr(dev, reg);
+       }
+
+
+       spin_unlock(&dev->lock);
+       return ret_val;
+}
+
+/* Tears down device */
+static void gadget_release(struct device *pdev)
+{
+       struct amd5536udc *dev = dev_get_drvdata(pdev);
+       kfree(dev);
+}
+
+/* Cleanup on device remove */
+static void udc_remove(struct udc *dev)
+{
+       /* remove timer */
+       stop_timer++;
+       if (timer_pending(&udc_timer))
+               wait_for_completion(&on_exit);
+       if (udc_timer.data)
+               del_timer_sync(&udc_timer);
+       /* remove pollstall timer */
+       stop_pollstall_timer++;
+       if (timer_pending(&udc_pollstall_timer))
+               wait_for_completion(&on_pollstall_exit);
+       if (udc_pollstall_timer.data)
+               del_timer_sync(&udc_pollstall_timer);
+       udc = NULL;
+}
+
+/* Reset all pci context */
+static void udc_pci_remove(struct pci_dev *pdev)
+{
+       struct udc              *dev;
+
+       dev = pci_get_drvdata(pdev);
+
+       /* gadget driver must not be registered */
+       BUG_ON(dev->driver != NULL);
+
+       /* dma pool cleanup */
+       if (dev->data_requests)
+               pci_pool_destroy(dev->data_requests);
+
+       if (dev->stp_requests) {
+               /* cleanup DMA desc's for ep0in */
+               pci_pool_free(dev->stp_requests,
+                       dev->ep[UDC_EP0OUT_IX].td_stp,
+                       dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+               pci_pool_free(dev->stp_requests,
+                       dev->ep[UDC_EP0OUT_IX].td,
+                       dev->ep[UDC_EP0OUT_IX].td_phys);
+
+               pci_pool_destroy(dev->stp_requests);
+       }
+
+       /* reset controller */
+       writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+       if (dev->irq_registered)
+               free_irq(pdev->irq, dev);
+       if (dev->regs)
+               iounmap(dev->regs);
+       if (dev->mem_region)
+               release_mem_region(pci_resource_start(pdev, 0),
+                               pci_resource_len(pdev, 0));
+       if (dev->active)
+               pci_disable_device(pdev);
+
+       device_unregister(&dev->gadget.dev);
+       pci_set_drvdata(pdev, NULL);
+
+       udc_remove(dev);
+}
+
+/* create dma pools on init */
+static int init_dma_pools(struct udc *dev)
+{
+       struct udc_stp_dma      *td_stp;
+       struct udc_data_dma     *td_data;
+       int retval;
+
+       /* consistent DMA mode setting ? */
+       if (use_dma_ppb) {
+               use_dma_bufferfill_mode = 0;
+       } else {
+               use_dma_ppb_du = 0;
+               use_dma_bufferfill_mode = 1;
+       }
+
+       /* DMA setup */
+       dev->data_requests = dma_pool_create("data_requests", NULL,
+               sizeof(struct udc_data_dma), 0, 0);
+       if (!dev->data_requests) {
+               DBG(dev, "can't get request data pool\n");
+               retval = -ENOMEM;
+               goto finished;
+       }
+
+       /* EP0 in dma regs = dev control regs */
+       dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+       /* dma desc for setup data */
+       dev->stp_requests = dma_pool_create("setup requests", NULL,
+               sizeof(struct udc_stp_dma), 0, 0);
+       if (!dev->stp_requests) {
+               DBG(dev, "can't get stp request pool\n");
+               retval = -ENOMEM;
+               goto finished;
+       }
+       /* setup */
+       td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+                               &dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+       if (td_stp == NULL) {
+               retval = -ENOMEM;
+               goto finished;
+       }
+       dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+
+       /* data: 0 packets !? */
+       td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+                               &dev->ep[UDC_EP0OUT_IX].td_phys);
+       if (td_data == NULL) {
+               retval = -ENOMEM;
+               goto finished;
+       }
+       dev->ep[UDC_EP0OUT_IX].td = td_data;
+       return 0;
+
+finished:
+       return retval;
+}
+
+/* Called by pci bus driver to init pci context */
+static int udc_pci_probe(
+       struct pci_dev *pdev,
+       const struct pci_device_id *id
+)
+{
+       struct udc              *dev;
+       unsigned long           resource;
+       unsigned long           len;
+       int                     retval = 0;
+
+       /* one udc only */
+       if (udc) {
+               dev_dbg(&pdev->dev, "already probed\n");
+               return -EBUSY;
+       }
+
+       /* init */
+       dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
+       if (!dev) {
+               retval = -ENOMEM;
+               goto finished;
+       }
+       memset(dev, 0, sizeof(struct udc));
+
+       /* pci setup */
+       if (pci_enable_device(pdev) < 0) {
+               retval = -ENODEV;
+               goto finished;
+       }
+       dev->active = 1;
+
+       /* PCI resource allocation */
+       resource = pci_resource_start(pdev, 0);
+       len = pci_resource_len(pdev, 0);
+
+       if (!request_mem_region(resource, len, name)) {
+               dev_dbg(&pdev->dev, "pci device used already\n");
+               retval = -EBUSY;
+               goto finished;
+       }
+       dev->mem_region = 1;
+
+       dev->virt_addr = ioremap_nocache(resource, len);
+       if (dev->virt_addr == NULL) {
+               dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+               retval = -EFAULT;
+               goto finished;
+       }
+
+       if (!pdev->irq) {
+               dev_err(&dev->pdev->dev, "irq not set\n");
+               retval = -ENODEV;
+               goto finished;
+       }
+
+       if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+               dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+               retval = -EBUSY;
+               goto finished;
+       }
+       dev->irq_registered = 1;
+
+       pci_set_drvdata(pdev, dev);
+
+       /* chip revision */
+       dev->chiprev = 0;
+
+       pci_set_master(pdev);
+       pci_set_mwi(pdev);
+
+       /* chip rev for Hs AMD5536 */
+       pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
+       /* init dma pools */
+       if (use_dma) {
+               retval = init_dma_pools(dev);
+               if (retval != 0)
+                       goto finished;
+       }
+
+       dev->phys_addr = resource;
+       dev->irq = pdev->irq;
+       dev->pdev = pdev;
+       dev->gadget.dev.parent = &pdev->dev;
+       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+       /* general probing */
+       if (udc_probe(dev) == 0)
+               return 0;
+
+finished:
+       if (dev)
+               udc_pci_remove(pdev);
+       return retval;
+}
+
+/* general probe */
+static int udc_probe(struct udc *dev)
+{
+       char            tmp[128];
+       u32             reg;
+       int             retval;
+
+       /* mark timer as not initialized */
+       udc_timer.data = 0;
+       udc_pollstall_timer.data = 0;
+
+       /* device struct setup */
+       spin_lock_init(&dev->lock);
+       dev->gadget.ops = &udc_ops;
+
+       strcpy(dev->gadget.dev.bus_id, "gadget");
+       dev->gadget.dev.release = gadget_release;
+       dev->gadget.name = name;
+       dev->gadget.name = name;
+       dev->gadget.is_dualspeed = 1;
+
+       /* udc csr registers base */
+       dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+       /* dev registers base */
+       dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+       /* ep registers base */
+       dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+       /* fifo's base */
+       dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+       dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
+       /* init registers, interrupts, ... */
+       startup_registers(dev);
+
+       dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+
+       snprintf(tmp, sizeof tmp, "%d", dev->irq);
+       dev_info(&dev->pdev->dev,
+               "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+               tmp, dev->phys_addr, dev->chiprev,
+               (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+       strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+       if (dev->chiprev == UDC_HSA0_REV) {
+               dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+               retval = -ENODEV;
+               goto finished;
+       }
+       dev_info(&dev->pdev->dev,
+               "driver version: %s(for Geode5536 B1)\n", tmp);
+       udc = dev;
+
+       retval = device_register(&dev->gadget.dev);
+       if (retval)
+               goto finished;
+
+       /* timer init */
+       init_timer(&udc_timer);
+       udc_timer.function = udc_timer_function;
+       udc_timer.data = 1;
+       /* timer pollstall init */
+       init_timer(&udc_pollstall_timer);
+       udc_pollstall_timer.function = udc_pollstall_timer_function;
+       udc_pollstall_timer.data = 1;
+
+       /* set SD */
+       reg = readl(&dev->regs->ctl);
+       reg |= AMD_BIT(UDC_DEVCTL_SD);
+       writel(reg, &dev->regs->ctl);
+
+       /* print dev register info */
+       print_regs(dev);
+
+       return 0;
+
+finished:
+       return retval;
+}
+
+/* Initiates a remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+       unsigned long flags;
+       u32 tmp;
+
+       DBG(dev, "UDC initiates remote wakeup\n");
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       tmp = readl(&dev->regs->ctl);
+       tmp |= AMD_BIT(UDC_DEVCTL_RES);
+       writel(tmp, &dev->regs->ctl);
+       tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+       writel(tmp, &dev->regs->ctl);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return 0;
+}
+
+/* PCI device parameters */
+static const struct pci_device_id pci_id[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
+               .class =        (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+               .class_mask =   0xffffffff,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(pci, pci_id);
+
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+       .name =         (char *) name,
+       .id_table =     pci_id,
+       .probe =        udc_pci_probe,
+       .remove =       udc_pci_remove,
+};
+
+/* Inits driver */
+static int __init init(void)
+{
+       return pci_register_driver(&udc_pci_driver);
+}
+module_init(init);
+
+/* Cleans driver */
+static void __exit cleanup(void)
+{
+       pci_unregister_driver(&udc_pci_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
new file mode 100644 (file)
index 0000000..4bbabbb
--- /dev/null
@@ -0,0 +1,626 @@
+/*
+ * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 AMD5536UDC_H
+#define AMD5536UDC_H
+
+/* various constants */
+#define UDC_RDE_TIMER_SECONDS          1
+#define UDC_RDE_TIMER_DIV              10
+#define UDC_POLLSTALL_TIMER_USECONDS   500
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/*
+ * SETUP usb commands
+ * needed, because some SETUP's are handled in hw, but must be passed to
+ * gadget driver above
+ * SET_CONFIG
+ */
+#define UDC_SETCONFIG_DWORD0                   0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK                0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS         16
+
+#define UDC_SETCONFIG_DWORD1                   0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0                     0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK            0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS             16
+
+#define UDC_SETINTF_DWORD1                     0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK           0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS            0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0                      0x0000ff21
+#define UDC_MSCRES_DWORD1                      0x00000000
+
+/* Global CSR's -------------------------------------------------------------*/
+#define UDC_CSR_ADDR                           0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK                    0x0000000f
+#define UDC_CSR_NE_NUM_OFS                     0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK                    0x00000010
+#define UDC_CSR_NE_DIR_OFS                     4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK                   0x00000060
+#define UDC_CSR_NE_TYPE_OFS                    5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK                    0x00000780
+#define UDC_CSR_NE_CFG_OFS                     7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK                   0x00007800
+#define UDC_CSR_NE_INTF_OFS                    11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK                    0x00078000
+#define UDC_CSR_NE_ALT_OFS                     15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK                        0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS                 19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR                                0x400
+
+#define UDC_DEVCFG_SOFTRESET                   31
+#define UDC_DEVCFG_HNPSFEN                     30
+#define UDC_DEVCFG_DMARST                      29
+#define UDC_DEVCFG_SET_DESC                    18
+#define UDC_DEVCFG_CSR_PRG                     17
+#define UDC_DEVCFG_STATUS                      7
+#define UDC_DEVCFG_DIR                         6
+#define UDC_DEVCFG_PI                          5
+#define UDC_DEVCFG_SS                          4
+#define UDC_DEVCFG_SP                          3
+#define UDC_DEVCFG_RWKP                                2
+
+#define UDC_DEVCFG_SPD_MASK                    0x3
+#define UDC_DEVCFG_SPD_OFS                     0
+#define UDC_DEVCFG_SPD_HS                      0x0
+#define UDC_DEVCFG_SPD_FS                      0x1
+#define UDC_DEVCFG_SPD_LS                      0x2
+/*#define UDC_DEVCFG_SPD_FS                    0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR                                0x404
+
+#define UDC_DEVCTL_THLEN_MASK                  0xff000000
+#define UDC_DEVCTL_THLEN_OFS                   24
+
+#define UDC_DEVCTL_BRLEN_MASK                  0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS                   16
+
+#define UDC_DEVCTL_CSR_DONE                    13
+#define UDC_DEVCTL_DEVNAK                      12
+#define UDC_DEVCTL_SD                          10
+#define UDC_DEVCTL_MODE                                9
+#define UDC_DEVCTL_BREN                                8
+#define UDC_DEVCTL_THE                         7
+#define UDC_DEVCTL_BF                          6
+#define UDC_DEVCTL_BE                          5
+#define UDC_DEVCTL_DU                          4
+#define UDC_DEVCTL_TDE                         3
+#define UDC_DEVCTL_RDE                         2
+#define UDC_DEVCTL_RES                         0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR                                0x408
+
+#define UDC_DEVSTS_TS_MASK                     0xfffc0000
+#define UDC_DEVSTS_TS_OFS                      18
+
+#define UDC_DEVSTS_SESSVLD                     17
+#define UDC_DEVSTS_PHY_ERROR                   16
+#define UDC_DEVSTS_RXFIFO_EMPTY                        15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK             0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS              13
+#define UDC_DEVSTS_ENUM_SPEED_FULL             1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH             0
+
+#define UDC_DEVSTS_SUSP                                12
+
+#define UDC_DEVSTS_ALT_MASK                    0x00000f00
+#define UDC_DEVSTS_ALT_OFS                     8
+
+#define UDC_DEVSTS_INTF_MASK                   0x000000f0
+#define UDC_DEVSTS_INTF_OFS                    4
+
+#define UDC_DEVSTS_CFG_MASK                    0x0000000f
+#define UDC_DEVSTS_CFG_OFS                     0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR                                0x40c
+
+#define UDC_DEVINT_SVC                         7
+#define UDC_DEVINT_ENUM                                6
+#define UDC_DEVINT_SOF                         5
+#define UDC_DEVINT_US                          4
+#define UDC_DEVINT_UR                          3
+#define UDC_DEVINT_ES                          2
+#define UDC_DEVINT_SI                          1
+#define UDC_DEVINT_SC                          0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR                    0x410
+
+#define UDC_DEVINT_MSK                         0x7f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR                         0x414
+
+#define UDC_EPINT_OUT_MASK                     0xffff0000
+#define UDC_EPINT_OUT_OFS                      16
+#define UDC_EPINT_IN_MASK                      0x0000ffff
+#define UDC_EPINT_IN_OFS                       0
+
+#define UDC_EPINT_IN_EP0                       0
+#define UDC_EPINT_IN_EP1                       1
+#define UDC_EPINT_IN_EP2                       2
+#define UDC_EPINT_IN_EP3                       3
+#define UDC_EPINT_OUT_EP0                      16
+#define UDC_EPINT_OUT_EP1                      17
+#define UDC_EPINT_OUT_EP2                      18
+#define UDC_EPINT_OUT_EP3                      19
+
+#define UDC_EPINT_EP0_ENABLE_MSK               0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR                     0x418
+
+#define UDC_EPINT_OUT_MSK_MASK                 0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS                  16
+#define UDC_EPINT_IN_MSK_MASK                  0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS                   0
+
+#define UDC_EPINT_MSK_DISABLE_ALL              0xffffffff
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE              0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE                    0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+#define UDC_EPREGS_ADDR                                0x0
+#define UDC_EPIN_REGS_ADDR                     0x0
+#define UDC_EPOUT_REGS_ADDR                    0x200
+
+#define UDC_EPCTL_ADDR                         0x0
+
+#define UDC_EPCTL_RRDY                         9
+#define UDC_EPCTL_CNAK                         8
+#define UDC_EPCTL_SNAK                         7
+#define UDC_EPCTL_NAK                          6
+
+#define UDC_EPCTL_ET_MASK                      0x00000030
+#define UDC_EPCTL_ET_OFS                       4
+#define UDC_EPCTL_ET_CONTROL                   0
+#define UDC_EPCTL_ET_ISO                       1
+#define UDC_EPCTL_ET_BULK                      2
+#define UDC_EPCTL_ET_INTERRUPT                 3
+
+#define UDC_EPCTL_P                            3
+#define UDC_EPCTL_SN                           2
+#define UDC_EPCTL_F                            1
+#define UDC_EPCTL_S                            0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR                         0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK             0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS              11
+
+#define UDC_EPSTS_TDC                          10
+#define UDC_EPSTS_HE                           9
+#define UDC_EPSTS_BNA                          7
+#define UDC_EPSTS_IN                           6
+
+#define UDC_EPSTS_OUT_MASK                     0x00000030
+#define UDC_EPSTS_OUT_OFS                      4
+#define UDC_EPSTS_OUT_DATA                     1
+#define UDC_EPSTS_OUT_DATA_CLEAR               0x10
+#define UDC_EPSTS_OUT_SETUP                    2
+#define UDC_EPSTS_OUT_SETUP_CLEAR              0x20
+#define UDC_EPSTS_OUT_CLEAR                    0x30
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR                        0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR            0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK                        0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS                 0
+/* EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE                    32
+/* EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE                 32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT                        2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE                     256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE            32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE                  32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK            0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS             0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR               0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR               0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK               0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS                        16
+#define UDC_EP_MAX_PKT_SIZE_MASK               0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS                        0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE                 64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE                        64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE              64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE             64
+
+/*
+ * Endpoint dma descriptors ------------------------------------------------
+ *
+ * Setup data, Status dword
+ */
+#define UDC_DMA_STP_STS_CFG_MASK               0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS                        16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK           0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS            16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK          0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS           20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK           0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS            24
+#define UDC_DMA_STP_STS_RX_MASK                        0x30000000
+#define UDC_DMA_STP_STS_RX_OFS                 28
+#define UDC_DMA_STP_STS_BS_MASK                        0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS                 30
+#define UDC_DMA_STP_STS_BS_HOST_READY          0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY            1
+#define UDC_DMA_STP_STS_BS_DMA_DONE            2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY           3
+/* IN data, Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK            0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS             0
+#define        UDC_DMA_IN_STS_FRAMENUM_MASK            0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS            0
+#define UDC_DMA_IN_STS_L                       27
+#define UDC_DMA_IN_STS_TX_MASK                 0x30000000
+#define UDC_DMA_IN_STS_TX_OFS                  28
+#define UDC_DMA_IN_STS_BS_MASK                 0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS                  30
+#define UDC_DMA_IN_STS_BS_HOST_READY           0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY             1
+#define UDC_DMA_IN_STS_BS_DMA_DONE             2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY            3
+/* OUT data, Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK           0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS            0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK          0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS           0
+#define UDC_DMA_OUT_STS_L                      27
+#define UDC_DMA_OUT_STS_RX_MASK                        0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS                 28
+#define UDC_DMA_OUT_STS_BS_MASK                        0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS                 30
+#define UDC_DMA_OUT_STS_BS_HOST_READY          0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY            1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE            2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY           3
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET                    1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET                      65536
+
+/* un-usable DMA address */
+#define DMA_DONT_USE                           (~(dma_addr_t) 0 )
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR                     0x10
+#define UDC_EP_DESPTR_ADDR                     0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR              0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM                             32
+#define UDC_EPIN_NUM                           16
+#define UDC_EPIN_NUM_USED                      5
+#define UDC_EPOUT_NUM                          16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM                                9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS                  12
+
+#define UDC_EP0OUT_IX                          16
+#define UDC_EP0IN_IX                           0
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR                                0x800
+#define UDC_RXFIFO_SIZE                                0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR                                0xc00
+#define UDC_TXFIFO_SIZE                                0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX                     1
+#define UDC_EPIN_IX                            2
+#define UDC_EPOUT_IX                           18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES                                4
+#define UDC_BITS_PER_BYTE_SHIFT                        3
+#define UDC_BYTE_MASK                          0xff
+#define UDC_BITS_PER_BYTE                      8
+
+/*---------------------------------------------------------------------------*/
+/* UDC CSR's */
+struct udc_csrs {
+
+       /* sca - setup command address */
+       u32 sca;
+
+       /* ep ne's */
+       u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+       /* device configuration */
+       u32 cfg;
+
+       /* device control */
+       u32 ctl;
+
+       /* device status */
+       u32 sts;
+
+       /* device interrupt */
+       u32 irqsts;
+
+       /* device interrupt mask */
+       u32 irqmsk;
+
+       /* endpoint interrupt */
+       u32 ep_irqsts;
+
+       /* endpoint interrupt mask */
+       u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+       /* endpoint control */
+       u32 ctl;
+
+       /* endpoint status */
+       u32 sts;
+
+       /* endpoint buffer size in/ receive packet frame number out */
+       u32 bufin_framenum;
+
+       /* endpoint buffer size out/max packet size */
+       u32 bufout_maxpkt;
+
+       /* endpoint setup buffer pointer */
+       u32 subptr;
+
+       /* endpoint data descriptor pointer */
+       u32 desptr;
+
+       /* reserverd */
+       u32 reserved;
+
+       /* write/read confirmation */
+       u32 confirm;
+
+} __attribute__ ((packed));
+
+/* control data DMA desc */
+struct udc_stp_dma {
+       /* status quadlet */
+       u32     status;
+       /* reserved */
+       u32     _reserved;
+       /* first setup word */
+       u32     data12;
+       /* second setup word */
+       u32     data34;
+} __attribute__ ((aligned (16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+       /* status quadlet */
+       u32     status;
+       /* reserved */
+       u32     _reserved;
+       /* buffer pointer */
+       u32     bufptr;
+       /* next descriptor pointer */
+       u32     next;
+} __attribute__ ((aligned (16)));
+
+/* request packet */
+struct udc_request {
+       /* embedded gadget ep */
+       struct usb_request              req;
+
+       /* flags */
+       unsigned                        dma_going : 1,
+                                       dma_mapping : 1,
+                                       dma_done : 1;
+       /* phys. address */
+       dma_addr_t                      td_phys;
+       /* first dma desc. of chain */
+       struct udc_data_dma             *td_data;
+       /* last dma desc. of chain */
+       struct udc_data_dma             *td_data_last;
+       struct list_head                queue;
+
+       /* chain length */
+       unsigned                        chain_len;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+       struct usb_ep                   ep;
+       struct udc_ep_regs __iomem      *regs;
+       u32 __iomem                     *txfifo;
+       u32 __iomem                     *dma;
+       dma_addr_t                      td_phys;
+       dma_addr_t                      td_stp_dma;
+       struct udc_stp_dma              *td_stp;
+       struct udc_data_dma             *td;
+       /* temp request */
+       struct udc_request              *req;
+       unsigned                        req_used;
+       unsigned                        req_completed;
+       /* dummy DMA desc for BNA dummy */
+       struct udc_request              *bna_dummy_req;
+       unsigned                        bna_occurred;
+
+       /* NAK state */
+       unsigned                        naking;
+
+       struct udc                      *dev;
+
+       /* queue for requests */
+       struct list_head                queue;
+       const struct usb_endpoint_descriptor    *desc;
+       unsigned                        halted;
+       unsigned                        cancel_transfer;
+       unsigned                        num : 5,
+                                       fifo_depth : 14,
+                                       in : 1;
+};
+
+/* device struct */
+struct udc {
+       struct usb_gadget               gadget;
+       spinlock_t                      lock;   /* protects all state */
+       /* all endpoints */
+       struct udc_ep                   ep[UDC_EP_NUM];
+       struct usb_gadget_driver        *driver;
+       /* operational flags */
+       unsigned                        active : 1,
+                                       stall_ep0in : 1,
+                                       waiting_zlp_ack_ep0in : 1,
+                                       set_cfg_not_acked : 1,
+                                       irq_registered : 1,
+                                       data_ep_enabled : 1,
+                                       data_ep_queued : 1,
+                                       mem_region : 1,
+                                       sys_suspended : 1,
+                                       connected;
+
+       u16                             chiprev;
+
+       /* registers */
+       struct pci_dev                  *pdev;
+       struct udc_csrs __iomem         *csr;
+       struct udc_regs __iomem         *regs;
+       struct udc_ep_regs __iomem      *ep_regs;
+       u32 __iomem                     *rxfifo;
+       u32 __iomem                     *txfifo;
+
+       /* DMA desc pools */
+       struct pci_pool                 *data_requests;
+       struct pci_pool                 *stp_requests;
+
+       /* device data */
+       unsigned long                   phys_addr;
+       void __iomem                    *virt_addr;
+       unsigned                        irq;
+
+       /* states */
+       u16                             cur_config;
+       u16                             cur_intf;
+       u16                             cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+       u32                     data[2];
+       struct usb_ctrlrequest  request;
+};
+
+/*
+ *---------------------------------------------------------------------------
+ * SET and GET bitfields in u32 values
+ * via constants for mask/offset:
+ * <bit_field_stub_name> is the text between
+ * UDC_ and _MASK|_OFS of appropiate
+ * constant
+ *
+ * set bitfield value in u32 u32Val
+ */
+#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name)          \
+       (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK))))      \
+       | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS))         \
+               & ((u32) bitfield_stub_name##_MASK)))
+
+/*
+ * set bitfield value in zero-initialized u32 u32Val
+ * => bitfield bits in u32Val are all zero
+ */
+#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name)     \
+       ((u32Val)                                                       \
+       | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS))         \
+               & ((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define AMD_GETBITS(u32Val, bitfield_stub_name)                                \
+       ((u32Val & ((u32) bitfield_stub_name##_MASK))                   \
+               >> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* debug macros ------------------------------------------------------------*/
+
+#define DBG(udc , args...)     dev_dbg(&(udc)->pdev->dev, args)
+
+#ifdef UDC_VERBOSE
+#define VDBG                   DBG
+#else
+#define VDBG(udc , args...)    do {} while (0)
+#endif
+
+#endif /* #ifdef AMD5536UDC_H */
index dbaf867436dffbc69e3172810fd4b24a89d7c10f..a3376739a81b0cb839ea01f292ca34535ce68197 100644 (file)
@@ -305,6 +305,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define        DEV_CONFIG_CDC
+#endif
+
 
 /*-------------------------------------------------------------------------*/
 
index 53e9139ba3886137ac2f642eb72587183251a777..f7f159c1002b76e8e2f2dafd163913f08e009f77 100644 (file)
 #define        gadget_is_net2280(g)    0
 #endif
 
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define        gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
+#else
+#define        gadget_is_amd5536udc(g) 0
+#endif
+
 #ifdef CONFIG_USB_GADGET_DUMMY_HCD
 #define        gadget_is_dummy(g)      !strcmp("dummy_udc", (g)->name)
 #else
@@ -202,7 +208,9 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x18;
        else if (gadget_is_fsl_usb2(gadget))
                return 0x19;
-       else if (gadget_is_m66592(gadget))
+       else if (gadget_is_amd5536udc(gadget))
                return 0x20;
+       else if (gadget_is_m66592(gadget))
+               return 0x21;
        return -ENOENT;
 }
index 0174a322e007b036646d0eba9d7589b0950e4b7e..700dda8a91579666cf04af70416e2dae6fb01912 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/list.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
+
 #include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
 #include "m66592-udc.h"
 
-MODULE_DESCRIPTION("M66592 USB gadget driiver");
+
+MODULE_DESCRIPTION("M66592 USB gadget driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yoshihiro Shimoda");
 
@@ -49,16 +41,21 @@ MODULE_AUTHOR("Yoshihiro Shimoda");
 /* module parameters */
 static unsigned short clock = M66592_XTAL24;
 module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=16384)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+               "(default=16384)");
+
 static unsigned short vif = M66592_LDRV;
 module_param(vif, ushort, 0644);
-MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)");
+
+static unsigned short endian;
 module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
 static unsigned short irq_sense = M66592_INTL;
 module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0(default=2)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
+               "(default=2)");
 
 static const char udc_name[] = "m66592_udc";
 static const char *m66592_ep_name[] = {
@@ -72,8 +69,8 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
                        gfp_t gfp_flags);
 
 static void transfer_complete(struct m66592_ep *ep,
-                             struct m66592_request *req,
-                             int status);
+               struct m66592_request *req, int status);
+
 /*-------------------------------------------------------------------------*/
 static inline u16 get_usb_speed(struct m66592 *m66592)
 {
@@ -81,25 +78,25 @@ static inline u16 get_usb_speed(struct m66592 *m66592)
 }
 
 static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum,
-                           unsigned long reg)
+               unsigned long reg)
 {
        u16 tmp;
 
        tmp = m66592_read(m66592, M66592_INTENB0);
        m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
-                   M66592_INTENB0);
+                       M66592_INTENB0);
        m66592_bset(m66592, (1 << pipenum), reg);
        m66592_write(m66592, tmp, M66592_INTENB0);
 }
 
 static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum,
-                            unsigned long reg)
+               unsigned long reg)
 {
        u16 tmp;
 
        tmp = m66592_read(m66592, M66592_INTENB0);
        m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
-                   M66592_INTENB0);
+                       M66592_INTENB0);
        m66592_bclr(m66592, (1 << pipenum), reg);
        m66592_write(m66592, tmp, M66592_INTENB0);
 }
@@ -108,17 +105,19 @@ static void m66592_usb_connect(struct m66592 *m66592)
 {
        m66592_bset(m66592, M66592_CTRE, M66592_INTENB0);
        m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
-                   M66592_INTENB0);
+                       M66592_INTENB0);
        m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
 
        m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
 }
 
 static void m66592_usb_disconnect(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
        m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0);
        m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
-                   M66592_INTENB0);
+                       M66592_INTENB0);
        m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
        m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
 
@@ -148,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum)
 }
 
 static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
-                                      u16 pid)
+               u16 pid)
 {
        unsigned long offset;
 
@@ -250,7 +249,7 @@ static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
 }
 
 static int pipe_buffer_setting(struct m66592 *m66592,
-                              struct m66592_pipe_info *info)
+               struct m66592_pipe_info *info)
 {
        u16 bufnum = 0, buf_bsize = 0;
        u16 pipecfg = 0;
@@ -287,7 +286,7 @@ static int pipe_buffer_setting(struct m66592 *m66592,
        }
        if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
                printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
-                      m66592->bi_bufnum);
+                               m66592->bi_bufnum);
                return -ENOMEM;
        }
 
@@ -328,7 +327,7 @@ static void pipe_buffer_release(struct m66592 *m66592,
                        m66592->bulk--;
        } else
                printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
-                      info->pipe);
+                               info->pipe);
 }
 
 static void pipe_initialize(struct m66592_ep *ep)
@@ -350,8 +349,8 @@ static void pipe_initialize(struct m66592_ep *ep)
 }
 
 static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
-                             const struct usb_endpoint_descriptor *desc,
-                             u16 pipenum, int dma)
+               const struct usb_endpoint_descriptor *desc,
+               u16 pipenum, int dma)
 {
        if ((pipenum != 0) && dma) {
                if (m66592->num_dma == 0) {
@@ -385,7 +384,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
 
        ep->pipectr = get_pipectr_addr(pipenum);
        ep->pipenum = pipenum;
-       ep->ep.maxpacket = desc->wMaxPacketSize;
+       ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
        m66592->pipenum2ep[pipenum] = ep;
        m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
        INIT_LIST_HEAD(&ep->queue);
@@ -407,7 +406,7 @@ static void m66592_ep_release(struct m66592_ep *ep)
 }
 
 static int alloc_pipe_config(struct m66592_ep *ep,
-                            const struct usb_endpoint_descriptor *desc)
+               const struct usb_endpoint_descriptor *desc)
 {
        struct m66592 *m66592 = ep->m66592;
        struct m66592_pipe_info info;
@@ -419,15 +418,15 @@ static int alloc_pipe_config(struct m66592_ep *ep,
 
        BUG_ON(ep->pipenum);
 
-       switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
        case USB_ENDPOINT_XFER_BULK:
                if (m66592->bulk >= M66592_MAX_NUM_BULK) {
                        if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
                                printk(KERN_ERR "bulk pipe is insufficient\n");
                                return -ENODEV;
                        } else {
-                               info.pipe = M66592_BASE_PIPENUM_ISOC +
-                                           m66592->isochronous;
+                               info.pipe = M66592_BASE_PIPENUM_ISOC
+                                               + m66592->isochronous;
                                counter = &m66592->isochronous;
                        }
                } else {
@@ -462,7 +461,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
        ep->type = info.type;
 
        info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       info.maxpacket = desc->wMaxPacketSize;
+       info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
        info.interval = desc->bInterval;
        if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
                info.dir_in = 1;
@@ -525,8 +524,8 @@ static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
 
        pipe_change(m66592, ep->pipenum);
        m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0,
-                   (M66592_ISEL | M66592_CURPIPE),
-                   M66592_CFIFOSEL);
+                       (M66592_ISEL | M66592_CURPIPE),
+                       M66592_CFIFOSEL);
        m66592_write(m66592, M66592_BCLR, ep->fifoctr);
        if (req->req.length == 0) {
                m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
@@ -561,8 +560,8 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
 
        if (ep->pipenum == 0) {
                m66592_mdfy(m66592, M66592_PIPE0,
-                           (M66592_ISEL | M66592_CURPIPE),
-                           M66592_CFIFOSEL);
+                               (M66592_ISEL | M66592_CURPIPE),
+                               M66592_CFIFOSEL);
                m66592_write(m66592, M66592_BCLR, ep->fifoctr);
                pipe_start(m66592, pipenum);
                pipe_irq_enable(m66592, pipenum);
@@ -572,8 +571,9 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
                        pipe_change(m66592, pipenum);
                        m66592_bset(m66592, M66592_TRENB, ep->fifosel);
                        m66592_write(m66592,
-                                    (req->req.length + ep->ep.maxpacket - 1) /
-                                    ep->ep.maxpacket, ep->fifotrn);
+                               (req->req.length + ep->ep.maxpacket - 1)
+                                       / ep->ep.maxpacket,
+                               ep->fifotrn);
                }
                pipe_start(m66592, pipenum);    /* trigger once */
                pipe_irq_enable(m66592, pipenum);
@@ -614,7 +614,7 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
 static void init_controller(struct m66592 *m66592)
 {
        m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
-                   M66592_PINCFG);
+                       M66592_PINCFG);
        m66592_bset(m66592, M66592_HSE, M66592_SYSCFG);         /* High spd */
        m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
 
@@ -634,7 +634,7 @@ static void init_controller(struct m66592 *m66592)
 
        m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
        m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
-                    M66592_DMA0CFG);
+                       M66592_DMA0CFG);
 }
 
 static void disable_controller(struct m66592 *m66592)
@@ -659,8 +659,9 @@ static void m66592_start_xclock(struct m66592 *m66592)
 
 /*-------------------------------------------------------------------------*/
 static void transfer_complete(struct m66592_ep *ep,
-                             struct m66592_request *req,
-                             int status)
+               struct m66592_request *req, int status)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
        int restart = 0;
 
@@ -680,8 +681,9 @@ static void transfer_complete(struct m66592_ep *ep,
        if (!list_empty(&ep->queue))
                restart = 1;
 
-       if (likely(req->req.complete))
-               req->req.complete(&ep->ep, &req->req);
+       spin_unlock(&ep->m66592->lock);
+       req->req.complete(&ep->ep, &req->req);
+       spin_lock(&ep->m66592->lock);
 
        if (restart) {
                req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -693,7 +695,7 @@ static void transfer_complete(struct m66592_ep *ep,
 static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
 {
        int i;
-       volatile u16 tmp;
+       u16 tmp;
        unsigned bufsize;
        size_t size;
        void *buf;
@@ -731,8 +733,9 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
        req->req.actual += size;
 
        /* check transfer finish */
-       if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-           (size % ep->ep.maxpacket) || (size == 0)) {
+       if ((!req->req.zero && (req->req.actual == req->req.length))
+                       || (size % ep->ep.maxpacket)
+                       || (size == 0)) {
                disable_irq_ready(m66592, pipenum);
                disable_irq_empty(m66592, pipenum);
        } else {
@@ -768,16 +771,19 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
        /* write fifo */
        if (req->req.buf) {
                m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
-               if ((size == 0) || ((size % ep->ep.maxpacket) != 0) ||
-                   ((bufsize != ep->ep.maxpacket) && (bufsize > size)))
+               if ((size == 0)
+                               || ((size % ep->ep.maxpacket) != 0)
+                               || ((bufsize != ep->ep.maxpacket)
+                                       && (bufsize > size)))
                        m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
        }
 
        /* update parameters */
        req->req.actual += size;
        /* check transfer finish */
-       if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-           (size % ep->ep.maxpacket) || (size == 0)) {
+       if ((!req->req.zero && (req->req.actual == req->req.length))
+                       || (size % ep->ep.maxpacket)
+                       || (size == 0)) {
                disable_irq_ready(m66592, pipenum);
                enable_irq_empty(m66592, pipenum);
        } else {
@@ -821,8 +827,9 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req)
        req->req.actual += size;
 
        /* check transfer finish */
-       if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-           (size % ep->ep.maxpacket) || (size == 0)) {
+       if ((!req->req.zero && (req->req.actual == req->req.length))
+                       || (size % ep->ep.maxpacket)
+                       || (size == 0)) {
                pipe_stop(m66592, pipenum);
                pipe_irq_disable(m66592, pipenum);
                finish = 1;
@@ -850,7 +857,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb)
        if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) {
                m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS);
                m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE,
-                           M66592_CFIFOSEL);
+                               M66592_CFIFOSEL);
 
                ep = &m66592->ep[0];
                req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -909,23 +916,26 @@ static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb)
 }
 
 static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
        struct m66592_ep *ep;
        u16 pid;
        u16 status = 0;
+       u16 w_index = le16_to_cpu(ctrl->wIndex);
 
        switch (ctrl->bRequestType & USB_RECIP_MASK) {
        case USB_RECIP_DEVICE:
-               status = 1;     /* selfpower */
+               status = 1 << USB_DEVICE_SELF_POWERED;
                break;
        case USB_RECIP_INTERFACE:
                status = 0;
                break;
        case USB_RECIP_ENDPOINT:
-               ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+               ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
                pid = control_reg_get_pid(m66592, ep->pipenum);
                if (pid == M66592_PID_STALL)
-                       status = 1;
+                       status = 1 << USB_ENDPOINT_HALT;
                else
                        status = 0;
                break;
@@ -934,11 +944,13 @@ static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
                return;         /* exit */
        }
 
-       *m66592->ep0_buf = status;
-       m66592->ep0_req->buf = m66592->ep0_buf;
+       m66592->ep0_data = cpu_to_le16(status);
+       m66592->ep0_req->buf = &m66592->ep0_data;
        m66592->ep0_req->length = 2;
        /* AV: what happens if we get called again before that gets through? */
+       spin_unlock(&m66592->lock);
        m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
+       spin_lock(&m66592->lock);
 }
 
 static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
@@ -953,8 +965,9 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
        case USB_RECIP_ENDPOINT: {
                struct m66592_ep *ep;
                struct m66592_request *req;
+               u16 w_index = le16_to_cpu(ctrl->wIndex);
 
-               ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+               ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
                pipe_stop(m66592, ep->pipenum);
                control_reg_sqclr(m66592, ep->pipenum);
 
@@ -989,8 +1002,9 @@ static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
                break;
        case USB_RECIP_ENDPOINT: {
                struct m66592_ep *ep;
+               u16 w_index = le16_to_cpu(ctrl->wIndex);
 
-               ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+               ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
                pipe_stall(m66592, ep->pipenum);
 
                control_end(m66592, 1);
@@ -1066,14 +1080,16 @@ static void irq_device_state(struct m66592 *m66592)
        }
        if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
                m66592_update_usb_speed(m66592);
-       if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) &&
-           m66592->gadget.speed == USB_SPEED_UNKNOWN)
+       if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS)
+                       && m66592->gadget.speed == USB_SPEED_UNKNOWN)
                m66592_update_usb_speed(m66592);
 
        m66592->old_dvsq = dvsq;
 }
 
 static void irq_control_stage(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
        struct usb_ctrlrequest ctrl;
        u16 ctsq;
@@ -1095,8 +1111,10 @@ static void irq_control_stage(struct m66592 *m66592)
        case M66592_CS_WRDS:
        case M66592_CS_WRND:
                if (setup_packet(m66592, &ctrl)) {
+                       spin_unlock(&m66592->lock);
                        if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0)
                                pipe_stall(m66592, 0);
+                       spin_lock(&m66592->lock);
                }
                break;
        case M66592_CS_RDSS:
@@ -1119,6 +1137,8 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
        u16 savepipe;
        u16 mask0;
 
+       spin_lock(&m66592->lock);
+
        intsts0 = m66592_read(m66592, M66592_INTSTS0);
        intenb0 = m66592_read(m66592, M66592_INTENB0);
 
@@ -1134,27 +1154,27 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
                bempenb = m66592_read(m66592, M66592_BEMPENB);
 
                if (mask0 & M66592_VBINT) {
-                       m66592_write(m66592, (u16)~M66592_VBINT,
-                                    M66592_INTSTS0);
+                       m66592_write(m66592,  0xffff & ~M66592_VBINT,
+                                       M66592_INTSTS0);
                        m66592_start_xclock(m66592);
 
                        /* start vbus sampling */
                        m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0)
-                                          & M66592_VBSTS;
+                                       & M66592_VBSTS;
                        m66592->scount = M66592_MAX_SAMPLING;
 
                        mod_timer(&m66592->timer,
-                                 jiffies + msecs_to_jiffies(50));
+                                       jiffies + msecs_to_jiffies(50));
                }
                if (intsts0 & M66592_DVSQ)
                        irq_device_state(m66592);
 
-               if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) &&
-                   (brdysts & brdyenb)) {
+               if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE)
+                               && (brdysts & brdyenb)) {
                        irq_pipe_ready(m66592, brdysts, brdyenb);
                }
-               if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) &&
-                   (bempsts & bempenb)) {
+               if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE)
+                               && (bempsts & bempenb)) {
                        irq_pipe_empty(m66592, bempsts, bempenb);
                }
 
@@ -1164,6 +1184,7 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
 
        m66592_write(m66592, savepipe, M66592_CFIFOSEL);
 
+       spin_unlock(&m66592->lock);
        return IRQ_HANDLED;
 }
 
@@ -1191,13 +1212,13 @@ static void m66592_timer(unsigned long _m66592)
                                        m66592_usb_disconnect(m66592);
                        } else {
                                mod_timer(&m66592->timer,
-                                         jiffies + msecs_to_jiffies(50));
+                                       jiffies + msecs_to_jiffies(50));
                        }
                } else {
                        m66592->scount = M66592_MAX_SAMPLING;
                        m66592->old_vbus = tmp;
                        mod_timer(&m66592->timer,
-                                 jiffies + msecs_to_jiffies(50));
+                                       jiffies + msecs_to_jiffies(50));
                }
        }
        spin_unlock_irqrestore(&m66592->lock, flags);
@@ -1335,11 +1356,6 @@ out:
        return ret;
 }
 
-static int m66592_fifo_status(struct usb_ep *_ep)
-{
-       return -EOPNOTSUPP;
-}
-
 static void m66592_fifo_flush(struct usb_ep *_ep)
 {
        struct m66592_ep *ep;
@@ -1365,7 +1381,6 @@ static struct usb_ep_ops m66592_ep_ops = {
        .dequeue        = m66592_dequeue,
 
        .set_halt       = m66592_set_halt,
-       .fifo_status    = m66592_fifo_status,
        .fifo_flush     = m66592_fifo_flush,
 };
 
@@ -1377,11 +1392,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
        struct m66592 *m66592 = the_controller;
        int retval;
 
-       if (!driver ||
-           driver->speed != USB_SPEED_HIGH ||
-           !driver->bind ||
-           !driver->unbind ||
-           !driver->setup)
+       if (!driver
+                       || driver->speed != USB_SPEED_HIGH
+                       || !driver->bind
+                       || !driver->setup)
                return -EINVAL;
        if (!m66592)
                return -ENODEV;
@@ -1413,8 +1427,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
                m66592->old_vbus = m66592_read(m66592,
                                         M66592_INTSTS0) & M66592_VBSTS;
                m66592->scount = M66592_MAX_SAMPLING;
-               mod_timer(&m66592->timer,
-                         jiffies + msecs_to_jiffies(50));
+               mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50));
        }
 
        return 0;
@@ -1432,6 +1445,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
        struct m66592 *m66592 = the_controller;
        unsigned long flags;
 
+       if (driver != m66592->driver || !driver->unbind)
+               return -EINVAL;
+
        spin_lock_irqsave(&m66592->lock, flags);
        if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
                m66592_usb_disconnect(m66592);
@@ -1461,46 +1477,35 @@ static struct usb_gadget_ops m66592_gadget_ops = {
        .get_frame              = m66592_get_frame,
 };
 
-#if defined(CONFIG_PM)
-static int m66592_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       pdev->dev.power.power_state = state;
-       return 0;
-}
-
-static int m66592_resume(struct platform_device *pdev)
-{
-       pdev->dev.power.power_state = PMSG_ON;
-       return 0;
-}
-#else  /* if defined(CONFIG_PM) */
-#define m66592_suspend         NULL
-#define m66592_resume          NULL
-#endif
-
-static int __init_or_module m66592_remove(struct platform_device *pdev)
+static int __exit m66592_remove(struct platform_device *pdev)
 {
        struct m66592           *m66592 = dev_get_drvdata(&pdev->dev);
 
        del_timer_sync(&m66592->timer);
        iounmap(m66592->reg);
        free_irq(platform_get_irq(pdev, 0), m66592);
+       m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
        kfree(m66592);
        return 0;
 }
 
+static void nop_completion(struct usb_ep *ep, struct usb_request *r)
+{
+}
+
 #define resource_len(r) (((r)->end - (r)->start) + 1)
+
 static int __init m66592_probe(struct platform_device *pdev)
 {
-       struct resource *res = NULL;
-       int irq = -1;
+       struct resource *res;
+       int irq;
        void __iomem *reg = NULL;
        struct m66592 *m66592 = NULL;
        int ret = 0;
        int i;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-                                          (char *)udc_name);
+                       (char *)udc_name);
        if (!res) {
                ret = -ENODEV;
                printk(KERN_ERR "platform_get_resource_byname error.\n");
@@ -1548,7 +1553,7 @@ static int __init m66592_probe(struct platform_device *pdev)
        m66592->bi_bufnum = M66592_BASE_BUFNUM;
 
        ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
-                         udc_name, m66592);
+                       udc_name, m66592);
        if (ret < 0) {
                printk(KERN_ERR "request_irq error (%d)\n", ret);
                goto clean_up;
@@ -1563,7 +1568,7 @@ static int __init m66592_probe(struct platform_device *pdev)
                if (i != 0) {
                        INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list);
                        list_add_tail(&m66592->ep[i].ep.ep_list,
-                                     &m66592->gadget.ep_list);
+                                       &m66592->gadget.ep_list);
                }
                ep->m66592 = m66592;
                INIT_LIST_HEAD(&ep->queue);
@@ -1583,20 +1588,18 @@ static int __init m66592_probe(struct platform_device *pdev)
 
        the_controller = m66592;
 
-       /* AV: leaks */
        m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
        if (m66592->ep0_req == NULL)
-               goto clean_up;
-       /* AV: leaks, and do we really need it separately allocated? */
-       m66592->ep0_buf = kzalloc(2, GFP_KERNEL);
-       if (m66592->ep0_buf == NULL)
-               goto clean_up;
+               goto clean_up2;
+       m66592->ep0_req->complete = nop_completion;
 
        init_controller(m66592);
 
-       printk("driver %s, %s\n", udc_name, DRIVER_VERSION);
+       dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
        return 0;
 
+clean_up2:
+       free_irq(irq, m66592);
 clean_up:
        if (m66592) {
                if (m66592->ep0_req)
@@ -1611,10 +1614,7 @@ clean_up:
 
 /*-------------------------------------------------------------------------*/
 static struct platform_driver m66592_driver = {
-       .probe =        m66592_probe,
-       .remove =       m66592_remove,
-       .suspend =      m66592_suspend,
-       .resume =       m66592_resume,
+       .remove =       __exit_p(m66592_remove),
        .driver         = {
                .name = (char *) udc_name,
        },
@@ -1622,7 +1622,7 @@ static struct platform_driver m66592_driver = {
 
 static int __init m66592_udc_init(void)
 {
-       return platform_driver_register(&m66592_driver);
+       return platform_driver_probe(&m66592_driver, m66592_probe);
 }
 module_init(m66592_udc_init);
 
@@ -1631,4 +1631,3 @@ static void __exit m66592_udc_cleanup(void)
        platform_driver_unregister(&m66592_driver);
 }
 module_exit(m66592_udc_cleanup);
-
index 26b54f8b894580227eaac2b5ee6c35291737cf67..bfa0c645f229b97752c5362c8503cf1e8f8e46f3 100644 (file)
 #define __M66592_UDC_H__
 
 #define M66592_SYSCFG          0x00
-#define        M66592_XTAL             0xC000  /* b15-14: Crystal selection */
-#define          M66592_XTAL48          0x8000           /* 48MHz */
-#define   M66592_XTAL24                 0x4000           /* 24MHz */
-#define          M66592_XTAL12          0x0000           /* 12MHz */
-#define        M66592_XCKE             0x2000  /* b13: External clock enable */
-#define        M66592_RCKE             0x1000  /* b12: Register clock enable */
-#define        M66592_PLLC             0x0800  /* b11: PLL control */
-#define        M66592_SCKE             0x0400  /* b10: USB clock enable */
-#define        M66592_ATCKM            0x0100  /* b8: Automatic supply functional enable */
-#define        M66592_HSE              0x0080  /* b7: Hi-speed enable */
-#define        M66592_DCFM             0x0040  /* b6: Controller function select  */
-#define        M66592_DMRPD            0x0020  /* b5: D- pull down control */
-#define        M66592_DPRPU            0x0010  /* b4: D+ pull up control */
-#define        M66592_FSRPC            0x0004  /* b2: Full-speed receiver enable */
-#define        M66592_PCUT             0x0002  /* b1: Low power sleep enable */
-#define        M66592_USBE             0x0001  /* b0: USB module operation enable */
+#define M66592_XTAL            0xC000  /* b15-14: Crystal selection */
+#define   M66592_XTAL48                 0x8000         /* 48MHz */
+#define   M66592_XTAL24                 0x4000         /* 24MHz */
+#define   M66592_XTAL12                 0x0000         /* 12MHz */
+#define M66592_XCKE            0x2000  /* b13: External clock enable */
+#define M66592_RCKE            0x1000  /* b12: Register clock enable */
+#define M66592_PLLC            0x0800  /* b11: PLL control */
+#define M66592_SCKE            0x0400  /* b10: USB clock enable */
+#define M66592_ATCKM           0x0100  /* b8: Automatic clock supply */
+#define M66592_HSE             0x0080  /* b7: Hi-speed enable */
+#define M66592_DCFM            0x0040  /* b6: Controller function select  */
+#define M66592_DMRPD           0x0020  /* b5: D- pull down control */
+#define M66592_DPRPU           0x0010  /* b4: D+ pull up control */
+#define M66592_FSRPC           0x0004  /* b2: Full-speed receiver enable */
+#define M66592_PCUT            0x0002  /* b1: Low power sleep enable */
+#define M66592_USBE            0x0001  /* b0: USB module operation enable */
 
 #define M66592_SYSSTS          0x02
-#define        M66592_LNST             0x0003  /* b1-0: D+, D- line status */
-#define          M66592_SE1             0x0003           /* SE1 */
-#define          M66592_KSTS            0x0002           /* K State */
-#define          M66592_JSTS            0x0001           /* J State */
-#define          M66592_SE0             0x0000           /* SE0 */
+#define M66592_LNST            0x0003  /* b1-0: D+, D- line status */
+#define   M66592_SE1            0x0003         /* SE1 */
+#define   M66592_KSTS           0x0002         /* K State */
+#define   M66592_JSTS           0x0001         /* J State */
+#define   M66592_SE0            0x0000         /* SE0 */
 
 #define M66592_DVSTCTR         0x04
-#define        M66592_WKUP             0x0100  /* b8: Remote wakeup */
-#define        M66592_RWUPE            0x0080  /* b7: Remote wakeup sense */
-#define        M66592_USBRST           0x0040  /* b6: USB reset enable */
-#define        M66592_RESUME           0x0020  /* b5: Resume enable */
-#define        M66592_UACT             0x0010  /* b4: USB bus enable */
-#define        M66592_RHST             0x0003  /* b1-0: Reset handshake status */
-#define          M66592_HSMODE          0x0003           /* Hi-Speed mode */
-#define          M66592_FSMODE          0x0002           /* Full-Speed mode */
-#define          M66592_HSPROC          0x0001           /* HS handshake is processing */
+#define M66592_WKUP            0x0100  /* b8: Remote wakeup */
+#define M66592_RWUPE           0x0080  /* b7: Remote wakeup sense */
+#define M66592_USBRST          0x0040  /* b6: USB reset enable */
+#define M66592_RESUME          0x0020  /* b5: Resume enable */
+#define M66592_UACT            0x0010  /* b4: USB bus enable */
+#define M66592_RHST            0x0003  /* b1-0: Reset handshake status */
+#define   M66592_HSMODE                 0x0003         /* Hi-Speed mode */
+#define   M66592_FSMODE                 0x0002         /* Full-Speed mode */
+#define   M66592_HSPROC                 0x0001         /* HS handshake is processing */
 
 #define M66592_TESTMODE                0x06
-#define        M66592_UTST             0x000F  /* b4-0: Test select */
-#define          M66592_H_TST_PACKET    0x000C           /* HOST TEST Packet */
-#define          M66592_H_TST_SE0_NAK   0x000B           /* HOST TEST SE0 NAK */
-#define          M66592_H_TST_K         0x000A           /* HOST TEST K */
-#define          M66592_H_TST_J         0x0009           /* HOST TEST J */
-#define          M66592_H_TST_NORMAL    0x0000           /* HOST Normal Mode */
-#define          M66592_P_TST_PACKET    0x0004           /* PERI TEST Packet */
-#define          M66592_P_TST_SE0_NAK   0x0003           /* PERI TEST SE0 NAK */
-#define          M66592_P_TST_K         0x0002           /* PERI TEST K */
-#define          M66592_P_TST_J         0x0001           /* PERI TEST J */
-#define          M66592_P_TST_NORMAL    0x0000           /* PERI Normal Mode */
+#define M66592_UTST            0x000F  /* b4-0: Test select */
+#define   M66592_H_TST_PACKET   0x000C         /* HOST TEST Packet */
+#define   M66592_H_TST_SE0_NAK  0x000B         /* HOST TEST SE0 NAK */
+#define   M66592_H_TST_K        0x000A         /* HOST TEST K */
+#define   M66592_H_TST_J        0x0009         /* HOST TEST J */
+#define   M66592_H_TST_NORMAL   0x0000         /* HOST Normal Mode */
+#define   M66592_P_TST_PACKET   0x0004         /* PERI TEST Packet */
+#define   M66592_P_TST_SE0_NAK  0x0003         /* PERI TEST SE0 NAK */
+#define   M66592_P_TST_K        0x0002         /* PERI TEST K */
+#define   M66592_P_TST_J        0x0001         /* PERI TEST J */
+#define   M66592_P_TST_NORMAL   0x0000         /* PERI Normal Mode */
 
 #define M66592_PINCFG          0x0A
-#define        M66592_LDRV             0x8000  /* b15: Drive Current Adjust */
-#define        M66592_BIGEND           0x0100  /* b8: Big endian mode */
+#define M66592_LDRV            0x8000  /* b15: Drive Current Adjust */
+#define M66592_BIGEND          0x0100  /* b8: Big endian mode */
 
 #define M66592_DMA0CFG         0x0C
 #define M66592_DMA1CFG         0x0E
-#define        M66592_DREQA            0x4000  /* b14: Dreq active select */
-#define        M66592_BURST            0x2000  /* b13: Burst mode */
-#define        M66592_DACKA            0x0400  /* b10: Dack active select */
-#define        M66592_DFORM            0x0380  /* b9-7: DMA mode select */
-#define          M66592_CPU_ADR_RD_WR   0x0000           /* Address + RD/WR mode (CPU bus) */
-#define          M66592_CPU_DACK_RD_WR  0x0100           /* DACK + RD/WR mode (CPU bus) */
-#define          M66592_CPU_DACK_ONLY   0x0180           /* DACK only mode (CPU bus) */
-#define          M66592_SPLIT_DACK_ONLY         0x0200           /* DACK only mode (SPLIT bus) */
-#define          M66592_SPLIT_DACK_DSTB         0x0300           /* DACK + DSTB0 mode (SPLIT bus) */
-#define        M66592_DENDA            0x0040  /* b6: Dend active select */
-#define        M66592_PKTM             0x0020  /* b5: Packet mode */
-#define        M66592_DENDE            0x0010  /* b4: Dend enable */
-#define        M66592_OBUS             0x0004  /* b2: OUTbus mode */
+#define M66592_DREQA           0x4000  /* b14: Dreq active select */
+#define M66592_BURST           0x2000  /* b13: Burst mode */
+#define M66592_DACKA           0x0400  /* b10: Dack active select */
+#define M66592_DFORM           0x0380  /* b9-7: DMA mode select */
+#define   M66592_CPU_ADR_RD_WR  0x0000   /* Address + RD/WR mode (CPU bus) */
+#define   M66592_CPU_DACK_RD_WR         0x0100   /* DACK + RD/WR mode (CPU bus) */
+#define   M66592_CPU_DACK_ONLY  0x0180   /* DACK only mode (CPU bus) */
+#define   M66592_SPLIT_DACK_ONLY 0x0200   /* DACK only mode (SPLIT bus) */
+#define   M66592_SPLIT_DACK_DSTB 0x0300   /* DACK + DSTB0 mode (SPLIT bus) */
+#define M66592_DENDA           0x0040  /* b6: Dend active select */
+#define M66592_PKTM            0x0020  /* b5: Packet mode */
+#define M66592_DENDE           0x0010  /* b4: Dend enable */
+#define M66592_OBUS            0x0004  /* b2: OUTbus mode */
 
 #define M66592_CFIFO           0x10
 #define M66592_D0FIFO          0x14
 #define M66592_CFIFOSEL                0x1E
 #define M66592_D0FIFOSEL       0x24
 #define M66592_D1FIFOSEL       0x2A
-#define        M66592_RCNT             0x8000  /* b15: Read count mode */
-#define        M66592_REW              0x4000  /* b14: Buffer rewind */
-#define        M66592_DCLRM            0x2000  /* b13: DMA buffer clear mode */
-#define        M66592_DREQE            0x1000  /* b12: DREQ output enable */
-#define        M66592_MBW              0x0400  /* b10: Maximum bit width for FIFO access */
-#define          M66592_MBW_8           0x0000   /*  8bit */
-#define          M66592_MBW_16          0x0400           /* 16bit */
-#define        M66592_TRENB            0x0200  /* b9: Transaction counter enable */
-#define        M66592_TRCLR            0x0100  /* b8: Transaction counter clear */
-#define        M66592_DEZPM            0x0080  /* b7: Zero-length packet additional mode */
-#define        M66592_ISEL             0x0020  /* b5: DCP FIFO port direction select */
-#define        M66592_CURPIPE          0x0007  /* b2-0: PIPE select */
+#define M66592_RCNT            0x8000  /* b15: Read count mode */
+#define M66592_REW             0x4000  /* b14: Buffer rewind */
+#define M66592_DCLRM           0x2000  /* b13: DMA buffer clear mode */
+#define M66592_DREQE           0x1000  /* b12: DREQ output enable */
+#define M66592_MBW             0x0400  /* b10: Maximum bit width for FIFO */
+#define   M66592_MBW_8          0x0000   /*  8bit */
+#define   M66592_MBW_16                 0x0400   /* 16bit */
+#define M66592_TRENB           0x0200  /* b9: Transaction counter enable */
+#define M66592_TRCLR           0x0100  /* b8: Transaction counter clear */
+#define M66592_DEZPM           0x0080  /* b7: Zero-length packet mode */
+#define M66592_ISEL            0x0020  /* b5: DCP FIFO port direction select */
+#define M66592_CURPIPE         0x0007  /* b2-0: PIPE select */
 
 #define M66592_CFIFOCTR                0x20
 #define M66592_D0FIFOCTR       0x26
 #define M66592_D1FIFOCTR       0x2c
-#define        M66592_BVAL             0x8000  /* b15: Buffer valid flag */
-#define        M66592_BCLR             0x4000  /* b14: Buffer clear */
-#define        M66592_FRDY             0x2000  /* b13: FIFO ready */
-#define        M66592_DTLN             0x0FFF  /* b11-0: FIFO received data length */
+#define M66592_BVAL            0x8000  /* b15: Buffer valid flag */
+#define M66592_BCLR            0x4000  /* b14: Buffer clear */
+#define M66592_FRDY            0x2000  /* b13: FIFO ready */
+#define M66592_DTLN            0x0FFF  /* b11-0: FIFO received data length */
 
 #define M66592_CFIFOSIE                0x22
-#define        M66592_TGL              0x8000  /* b15: Buffer toggle */
-#define        M66592_SCLR             0x4000  /* b14: Buffer clear */
-#define        M66592_SBUSY            0x2000  /* b13: SIE_FIFO busy */
+#define M66592_TGL             0x8000  /* b15: Buffer toggle */
+#define M66592_SCLR            0x4000  /* b14: Buffer clear */
+#define M66592_SBUSY           0x2000  /* b13: SIE_FIFO busy */
 
 #define M66592_D0FIFOTRN       0x28
 #define M66592_D1FIFOTRN       0x2E
-#define        M66592_TRNCNT           0xFFFF  /* b15-0: Transaction counter */
+#define M66592_TRNCNT          0xFFFF  /* b15-0: Transaction counter */
 
 #define M66592_INTENB0 0x30
-#define        M66592_VBSE     0x8000  /* b15: VBUS interrupt */
-#define        M66592_RSME     0x4000  /* b14: Resume interrupt */
-#define        M66592_SOFE     0x2000  /* b13: Frame update interrupt */
-#define        M66592_DVSE     0x1000  /* b12: Device state transition interrupt */
-#define        M66592_CTRE     0x0800  /* b11: Control transfer stage transition interrupt */
-#define        M66592_BEMPE    0x0400  /* b10: Buffer empty interrupt */
-#define        M66592_NRDYE    0x0200  /* b9: Buffer not ready interrupt */
-#define        M66592_BRDYE    0x0100  /* b8: Buffer ready interrupt */
-#define        M66592_URST     0x0080  /* b7: USB reset detected interrupt */
-#define        M66592_SADR     0x0040  /* b6: Set address executed interrupt */
-#define        M66592_SCFG     0x0020  /* b5: Set configuration executed interrupt */
-#define        M66592_SUSP     0x0010  /* b4: Suspend detected interrupt */
-#define        M66592_WDST     0x0008  /* b3: Control write data stage completed interrupt */
-#define        M66592_RDST     0x0004  /* b2: Control read data stage completed interrupt */
-#define        M66592_CMPL     0x0002  /* b1: Control transfer complete interrupt */
-#define        M66592_SERR     0x0001  /* b0: Sequence error interrupt */
+#define M66592_VBSE    0x8000  /* b15: VBUS interrupt */
+#define M66592_RSME    0x4000  /* b14: Resume interrupt */
+#define M66592_SOFE    0x2000  /* b13: Frame update interrupt */
+#define M66592_DVSE    0x1000  /* b12: Device state transition interrupt */
+#define M66592_CTRE    0x0800  /* b11: Control transfer stage transition irq */
+#define M66592_BEMPE   0x0400  /* b10: Buffer empty interrupt */
+#define M66592_NRDYE   0x0200  /* b9: Buffer not ready interrupt */
+#define M66592_BRDYE   0x0100  /* b8: Buffer ready interrupt */
+#define M66592_URST    0x0080  /* b7: USB reset detected interrupt */
+#define M66592_SADR    0x0040  /* b6: Set address executed interrupt */
+#define M66592_SCFG    0x0020  /* b5: Set configuration executed interrupt */
+#define M66592_SUSP    0x0010  /* b4: Suspend detected interrupt */
+#define M66592_WDST    0x0008  /* b3: Control write data stage completed irq */
+#define M66592_RDST    0x0004  /* b2: Control read data stage completed irq */
+#define M66592_CMPL    0x0002  /* b1: Control transfer complete interrupt */
+#define M66592_SERR    0x0001  /* b0: Sequence error interrupt */
 
 #define M66592_INTENB1 0x32
-#define        M66592_BCHGE    0x4000  /* b14: USB us chenge interrupt */
-#define        M66592_DTCHE    0x1000  /* b12: Detach sense interrupt */
-#define        M66592_SIGNE    0x0020  /* b5: SETUP IGNORE interrupt */
-#define        M66592_SACKE    0x0010  /* b4: SETUP ACK interrupt */
-#define        M66592_BRDYM    0x0004  /* b2: BRDY clear timing */
-#define        M66592_INTL     0x0002  /* b1: Interrupt sense select */
-#define        M66592_PCSE     0x0001  /* b0: PCUT enable by CS assert */
+#define M66592_BCHGE   0x4000  /* b14: USB us chenge interrupt */
+#define M66592_DTCHE   0x1000  /* b12: Detach sense interrupt */
+#define M66592_SIGNE   0x0020  /* b5: SETUP IGNORE interrupt */
+#define M66592_SACKE   0x0010  /* b4: SETUP ACK interrupt */
+#define M66592_BRDYM   0x0004  /* b2: BRDY clear timing */
+#define M66592_INTL    0x0002  /* b1: Interrupt sense select */
+#define M66592_PCSE    0x0001  /* b0: PCUT enable by CS assert */
 
 #define M66592_BRDYENB         0x36
 #define M66592_BRDYSTS         0x46
-#define        M66592_BRDY7            0x0080  /* b7: PIPE7 */
-#define        M66592_BRDY6            0x0040  /* b6: PIPE6 */
-#define        M66592_BRDY5            0x0020  /* b5: PIPE5 */
-#define        M66592_BRDY4            0x0010  /* b4: PIPE4 */
-#define        M66592_BRDY3            0x0008  /* b3: PIPE3 */
-#define        M66592_BRDY2            0x0004  /* b2: PIPE2 */
-#define        M66592_BRDY1            0x0002  /* b1: PIPE1 */
-#define        M66592_BRDY0            0x0001  /* b1: PIPE0 */
+#define M66592_BRDY7           0x0080  /* b7: PIPE7 */
+#define M66592_BRDY6           0x0040  /* b6: PIPE6 */
+#define M66592_BRDY5           0x0020  /* b5: PIPE5 */
+#define M66592_BRDY4           0x0010  /* b4: PIPE4 */
+#define M66592_BRDY3           0x0008  /* b3: PIPE3 */
+#define M66592_BRDY2           0x0004  /* b2: PIPE2 */
+#define M66592_BRDY1           0x0002  /* b1: PIPE1 */
+#define M66592_BRDY0           0x0001  /* b1: PIPE0 */
 
 #define M66592_NRDYENB         0x38
 #define M66592_NRDYSTS         0x48
-#define        M66592_NRDY7            0x0080  /* b7: PIPE7 */
-#define        M66592_NRDY6            0x0040  /* b6: PIPE6 */
-#define        M66592_NRDY5            0x0020  /* b5: PIPE5 */
-#define        M66592_NRDY4            0x0010  /* b4: PIPE4 */
-#define        M66592_NRDY3            0x0008  /* b3: PIPE3 */
-#define        M66592_NRDY2            0x0004  /* b2: PIPE2 */
-#define        M66592_NRDY1            0x0002  /* b1: PIPE1 */
-#define        M66592_NRDY0            0x0001  /* b1: PIPE0 */
+#define M66592_NRDY7           0x0080  /* b7: PIPE7 */
+#define M66592_NRDY6           0x0040  /* b6: PIPE6 */
+#define M66592_NRDY5           0x0020  /* b5: PIPE5 */
+#define M66592_NRDY4           0x0010  /* b4: PIPE4 */
+#define M66592_NRDY3           0x0008  /* b3: PIPE3 */
+#define M66592_NRDY2           0x0004  /* b2: PIPE2 */
+#define M66592_NRDY1           0x0002  /* b1: PIPE1 */
+#define M66592_NRDY0           0x0001  /* b1: PIPE0 */
 
 #define M66592_BEMPENB         0x3A
 #define M66592_BEMPSTS         0x4A
-#define        M66592_BEMP7            0x0080  /* b7: PIPE7 */
-#define        M66592_BEMP6            0x0040  /* b6: PIPE6 */
-#define        M66592_BEMP5            0x0020  /* b5: PIPE5 */
-#define        M66592_BEMP4            0x0010  /* b4: PIPE4 */
-#define        M66592_BEMP3            0x0008  /* b3: PIPE3 */
-#define        M66592_BEMP2            0x0004  /* b2: PIPE2 */
-#define        M66592_BEMP1            0x0002  /* b1: PIPE1 */
-#define        M66592_BEMP0            0x0001  /* b0: PIPE0 */
+#define M66592_BEMP7           0x0080  /* b7: PIPE7 */
+#define M66592_BEMP6           0x0040  /* b6: PIPE6 */
+#define M66592_BEMP5           0x0020  /* b5: PIPE5 */
+#define M66592_BEMP4           0x0010  /* b4: PIPE4 */
+#define M66592_BEMP3           0x0008  /* b3: PIPE3 */
+#define M66592_BEMP2           0x0004  /* b2: PIPE2 */
+#define M66592_BEMP1           0x0002  /* b1: PIPE1 */
+#define M66592_BEMP0           0x0001  /* b0: PIPE0 */
 
 #define M66592_SOFCFG          0x3C
-#define        M66592_SOFM             0x000C  /* b3-2: SOF palse mode */
-#define          M66592_SOF_125US       0x0008           /* SOF OUT 125us uFrame Signal */
-#define          M66592_SOF_1MS         0x0004           /* SOF OUT 1ms Frame Signal */
-#define          M66592_SOF_DISABLE     0x0000           /* SOF OUT Disable */
+#define M66592_SOFM            0x000C  /* b3-2: SOF palse mode */
+#define   M66592_SOF_125US      0x0008   /* SOF OUT 125us uFrame Signal */
+#define   M66592_SOF_1MS        0x0004   /* SOF OUT 1ms Frame Signal */
+#define   M66592_SOF_DISABLE    0x0000   /* SOF OUT Disable */
 
 #define M66592_INTSTS0         0x40
-#define        M66592_VBINT            0x8000  /* b15: VBUS interrupt */
-#define        M66592_RESM             0x4000  /* b14: Resume interrupt */
-#define        M66592_SOFR             0x2000  /* b13: SOF frame update interrupt */
-#define        M66592_DVST             0x1000  /* b12: Device state transition interrupt */
-#define        M66592_CTRT             0x0800  /* b11: Control transfer stage transition interrupt */
-#define        M66592_BEMP             0x0400  /* b10: Buffer empty interrupt */
-#define        M66592_NRDY             0x0200  /* b9: Buffer not ready interrupt */
-#define        M66592_BRDY             0x0100  /* b8: Buffer ready interrupt */
-#define        M66592_VBSTS            0x0080  /* b7: VBUS input port */
-#define        M66592_DVSQ             0x0070  /* b6-4: Device state */
-#define          M66592_DS_SPD_CNFG     0x0070           /* Suspend Configured */
-#define          M66592_DS_SPD_ADDR     0x0060           /* Suspend Address */
-#define          M66592_DS_SPD_DFLT     0x0050           /* Suspend Default */
-#define          M66592_DS_SPD_POWR     0x0040           /* Suspend Powered */
-#define          M66592_DS_SUSP         0x0040           /* Suspend */
-#define          M66592_DS_CNFG         0x0030           /* Configured */
-#define          M66592_DS_ADDS         0x0020           /* Address */
-#define          M66592_DS_DFLT         0x0010           /* Default */
-#define          M66592_DS_POWR         0x0000           /* Powered */
-#define        M66592_DVSQS            0x0030  /* b5-4: Device state */
-#define        M66592_VALID            0x0008  /* b3: Setup packet detected flag */
-#define        M66592_CTSQ             0x0007  /* b2-0: Control transfer stage */
-#define          M66592_CS_SQER         0x0006           /* Sequence error */
-#define          M66592_CS_WRND         0x0005           /* Control write nodata status stage */
-#define          M66592_CS_WRSS         0x0004           /* Control write status stage */
-#define          M66592_CS_WRDS         0x0003           /* Control write data stage */
-#define          M66592_CS_RDSS         0x0002           /* Control read status stage */
-#define          M66592_CS_RDDS         0x0001           /* Control read data stage */
-#define          M66592_CS_IDST         0x0000           /* Idle or setup stage */
+#define M66592_VBINT           0x8000  /* b15: VBUS interrupt */
+#define M66592_RESM            0x4000  /* b14: Resume interrupt */
+#define M66592_SOFR            0x2000  /* b13: SOF frame update interrupt */
+#define M66592_DVST            0x1000  /* b12: Device state transition */
+#define M66592_CTRT            0x0800  /* b11: Control stage transition */
+#define M66592_BEMP            0x0400  /* b10: Buffer empty interrupt */
+#define M66592_NRDY            0x0200  /* b9: Buffer not ready interrupt */
+#define M66592_BRDY            0x0100  /* b8: Buffer ready interrupt */
+#define M66592_VBSTS           0x0080  /* b7: VBUS input port */
+#define M66592_DVSQ            0x0070  /* b6-4: Device state */
+#define   M66592_DS_SPD_CNFG    0x0070    /* Suspend Configured */
+#define   M66592_DS_SPD_ADDR    0x0060    /* Suspend Address */
+#define   M66592_DS_SPD_DFLT    0x0050    /* Suspend Default */
+#define   M66592_DS_SPD_POWR    0x0040    /* Suspend Powered */
+#define   M66592_DS_SUSP        0x0040    /* Suspend */
+#define   M66592_DS_CNFG        0x0030    /* Configured */
+#define   M66592_DS_ADDS        0x0020    /* Address */
+#define   M66592_DS_DFLT        0x0010    /* Default */
+#define   M66592_DS_POWR        0x0000    /* Powered */
+#define M66592_DVSQS           0x0030  /* b5-4: Device state */
+#define M66592_VALID           0x0008  /* b3: Setup packet detected flag */
+#define M66592_CTSQ            0x0007  /* b2-0: Control transfer stage */
+#define   M66592_CS_SQER        0x0006   /* Sequence error */
+#define   M66592_CS_WRND        0x0005   /* Control write nodata status */
+#define   M66592_CS_WRSS        0x0004   /* Control write status stage */
+#define   M66592_CS_WRDS        0x0003   /* Control write data stage */
+#define   M66592_CS_RDSS        0x0002   /* Control read status stage */
+#define   M66592_CS_RDDS        0x0001   /* Control read data stage */
+#define   M66592_CS_IDST        0x0000   /* Idle or setup stage */
 
 #define M66592_INTSTS1         0x42
-#define        M66592_BCHG             0x4000  /* b14: USB bus chenge interrupt */
-#define        M66592_DTCH             0x1000  /* b12: Detach sense interrupt */
-#define        M66592_SIGN             0x0020  /* b5: SETUP IGNORE interrupt */
-#define        M66592_SACK             0x0010  /* b4: SETUP ACK interrupt */
+#define M66592_BCHG            0x4000  /* b14: USB bus chenge interrupt */
+#define M66592_DTCH            0x1000  /* b12: Detach sense interrupt */
+#define M66592_SIGN            0x0020  /* b5: SETUP IGNORE interrupt */
+#define M66592_SACK            0x0010  /* b4: SETUP ACK interrupt */
 
 #define M66592_FRMNUM          0x4C
-#define        M66592_OVRN             0x8000  /* b15: Overrun error */
-#define        M66592_CRCE             0x4000  /* b14: Received data error */
-#define        M66592_SOFRM            0x0800  /* b11: SOF output mode */
-#define        M66592_FRNM             0x07FF  /* b10-0: Frame number */
+#define M66592_OVRN            0x8000  /* b15: Overrun error */
+#define M66592_CRCE            0x4000  /* b14: Received data error */
+#define M66592_SOFRM           0x0800  /* b11: SOF output mode */
+#define M66592_FRNM            0x07FF  /* b10-0: Frame number */
 
 #define M66592_UFRMNUM         0x4E
-#define        M66592_UFRNM            0x0007  /* b2-0: Micro frame number */
+#define M66592_UFRNM           0x0007  /* b2-0: Micro frame number */
 
 #define M66592_RECOVER         0x50
-#define        M66592_STSRECOV         0x0700  /* Status recovery */
-#define          M66592_STSR_HI         0x0400           /* FULL(0) or HI(1) Speed */
-#define          M66592_STSR_DEFAULT    0x0100           /* Default state */
-#define          M66592_STSR_ADDRESS    0x0200           /* Address state */
-#define          M66592_STSR_CONFIG     0x0300           /* Configured state */
-#define        M66592_USBADDR          0x007F  /* b6-0: USB address */
+#define M66592_STSRECOV                0x0700  /* Status recovery */
+#define   M66592_STSR_HI        0x0400           /* FULL(0) or HI(1) Speed */
+#define   M66592_STSR_DEFAULT   0x0100           /* Default state */
+#define   M66592_STSR_ADDRESS   0x0200           /* Address state */
+#define   M66592_STSR_CONFIG    0x0300           /* Configured state */
+#define M66592_USBADDR         0x007F  /* b6-0: USB address */
 
 #define M66592_USBREQ                  0x54
-#define        M66592_bRequest                 0xFF00  /* b15-8: bRequest */
-#define          M66592_GET_STATUS              0x0000
-#define          M66592_CLEAR_FEATURE           0x0100
-#define          M66592_ReqRESERVED             0x0200
-#define          M66592_SET_FEATURE             0x0300
-#define          M66592_ReqRESERVED1            0x0400
-#define          M66592_SET_ADDRESS             0x0500
-#define          M66592_GET_DESCRIPTOR          0x0600
-#define          M66592_SET_DESCRIPTOR          0x0700
-#define          M66592_GET_CONFIGURATION       0x0800
-#define          M66592_SET_CONFIGURATION       0x0900
-#define          M66592_GET_INTERFACE           0x0A00
-#define          M66592_SET_INTERFACE           0x0B00
-#define          M66592_SYNCH_FRAME             0x0C00
-#define        M66592_bmRequestType            0x00FF  /* b7-0: bmRequestType */
-#define        M66592_bmRequestTypeDir         0x0080  /* b7  : Data transfer direction */
-#define          M66592_HOST_TO_DEVICE          0x0000
-#define          M66592_DEVICE_TO_HOST          0x0080
-#define        M66592_bmRequestTypeType        0x0060  /* b6-5: Type */
-#define          M66592_STANDARD                0x0000
-#define          M66592_CLASS                   0x0020
-#define          M66592_VENDOR                  0x0040
-#define        M66592_bmRequestTypeRecip       0x001F  /* b4-0: Recipient */
-#define          M66592_DEVICE                  0x0000
-#define          M66592_INTERFACE               0x0001
-#define          M66592_ENDPOINT                0x0002
+#define M66592_bRequest                        0xFF00  /* b15-8: bRequest */
+#define   M66592_GET_STATUS             0x0000
+#define   M66592_CLEAR_FEATURE          0x0100
+#define   M66592_ReqRESERVED            0x0200
+#define   M66592_SET_FEATURE            0x0300
+#define   M66592_ReqRESERVED1           0x0400
+#define   M66592_SET_ADDRESS            0x0500
+#define   M66592_GET_DESCRIPTOR                 0x0600
+#define   M66592_SET_DESCRIPTOR                 0x0700
+#define   M66592_GET_CONFIGURATION      0x0800
+#define   M66592_SET_CONFIGURATION      0x0900
+#define   M66592_GET_INTERFACE          0x0A00
+#define   M66592_SET_INTERFACE          0x0B00
+#define   M66592_SYNCH_FRAME            0x0C00
+#define M66592_bmRequestType           0x00FF  /* b7-0: bmRequestType */
+#define M66592_bmRequestTypeDir                0x0080  /* b7  : Data direction */
+#define   M66592_HOST_TO_DEVICE                 0x0000
+#define   M66592_DEVICE_TO_HOST                 0x0080
+#define M66592_bmRequestTypeType       0x0060  /* b6-5: Type */
+#define   M66592_STANDARD               0x0000
+#define   M66592_CLASS                  0x0020
+#define   M66592_VENDOR                         0x0040
+#define M66592_bmRequestTypeRecip      0x001F  /* b4-0: Recipient */
+#define   M66592_DEVICE                         0x0000
+#define   M66592_INTERFACE              0x0001
+#define   M66592_ENDPOINT               0x0002
 
 #define M66592_USBVAL                          0x56
-#define        M66592_wValue                           0xFFFF  /* b15-0: wValue */
+#define M66592_wValue                          0xFFFF  /* b15-0: wValue */
 /* Standard Feature Selector */
-#define          M66592_ENDPOINT_HALT                  0x0000
-#define          M66592_DEVICE_REMOTE_WAKEUP           0x0001
-#define          M66592_TEST_MODE                      0x0002
+#define   M66592_ENDPOINT_HALT                 0x0000
+#define   M66592_DEVICE_REMOTE_WAKEUP          0x0001
+#define   M66592_TEST_MODE                     0x0002
 /* Descriptor Types */
-#define        M66592_DT_TYPE                          0xFF00
-#define        M66592_GET_DT_TYPE(v)                   (((v) & DT_TYPE) >> 8)
-#define          M66592_DT_DEVICE                      0x01
-#define          M66592_DT_CONFIGURATION               0x02
-#define          M66592_DT_STRING                      0x03
-#define          M66592_DT_INTERFACE                   0x04
-#define          M66592_DT_ENDPOINT                    0x05
-#define          M66592_DT_DEVICE_QUALIFIER            0x06
-#define          M66592_DT_OTHER_SPEED_CONFIGURATION   0x07
-#define          M66592_DT_INTERFACE_POWER             0x08
-#define        M66592_DT_INDEX                         0x00FF
-#define        M66592_CONF_NUM                         0x00FF
-#define        M66592_ALT_SET                          0x00FF
+#define M66592_DT_TYPE                         0xFF00
+#define M66592_GET_DT_TYPE(v)                  (((v) & DT_TYPE) >> 8)
+#define   M66592_DT_DEVICE                     0x01
+#define   M66592_DT_CONFIGURATION              0x02
+#define   M66592_DT_STRING                     0x03
+#define   M66592_DT_INTERFACE                  0x04
+#define   M66592_DT_ENDPOINT                   0x05
+#define   M66592_DT_DEVICE_QUALIFIER           0x06
+#define   M66592_DT_OTHER_SPEED_CONFIGURATION  0x07
+#define   M66592_DT_INTERFACE_POWER            0x08
+#define M66592_DT_INDEX                                0x00FF
+#define M66592_CONF_NUM                                0x00FF
+#define M66592_ALT_SET                         0x00FF
 
 #define M66592_USBINDEX                        0x58
-#define        M66592_wIndex                   0xFFFF  /* b15-0: wIndex */
-#define        M66592_TEST_SELECT              0xFF00  /* b15-b8: Test Mode Selectors */
-#define          M66592_TEST_J                  0x0100           /* Test_J */
-#define          M66592_TEST_K                  0x0200           /* Test_K */
-#define          M66592_TEST_SE0_NAK            0x0300           /* Test_SE0_NAK */
-#define          M66592_TEST_PACKET             0x0400           /* Test_Packet */
-#define          M66592_TEST_FORCE_ENABLE       0x0500           /* Test_Force_Enable */
-#define          M66592_TEST_STSelectors        0x0600           /* Standard test selectors */
-#define          M66592_TEST_Reserved           0x4000           /* Reserved */
-#define          M66592_TEST_VSTModes           0xC000           /* Vendor-specific test modes */
-#define        M66592_EP_DIR                   0x0080  /* b7: Endpoint Direction */
-#define          M66592_EP_DIR_IN               0x0080
-#define          M66592_EP_DIR_OUT              0x0000
+#define M66592_wIndex                  0xFFFF  /* b15-0: wIndex */
+#define M66592_TEST_SELECT             0xFF00  /* b15-b8: Test Mode */
+#define   M66592_TEST_J                         0x0100   /* Test_J */
+#define   M66592_TEST_K                         0x0200   /* Test_K */
+#define   M66592_TEST_SE0_NAK           0x0300   /* Test_SE0_NAK */
+#define   M66592_TEST_PACKET            0x0400   /* Test_Packet */
+#define   M66592_TEST_FORCE_ENABLE      0x0500   /* Test_Force_Enable */
+#define   M66592_TEST_STSelectors       0x0600   /* Standard test selectors */
+#define   M66592_TEST_Reserved          0x4000   /* Reserved */
+#define   M66592_TEST_VSTModes          0xC000   /* Vendor-specific tests */
+#define M66592_EP_DIR                  0x0080  /* b7: Endpoint Direction */
+#define   M66592_EP_DIR_IN              0x0080
+#define   M66592_EP_DIR_OUT             0x0000
 
 #define M66592_USBLENG         0x5A
-#define        M66592_wLength          0xFFFF  /* b15-0: wLength */
+#define M66592_wLength         0xFFFF  /* b15-0: wLength */
 
 #define M66592_DCPCFG          0x5C
-#define        M66592_CNTMD            0x0100  /* b8: Continuous transfer mode select */
-#define        M66592_DIR              0x0010  /* b4: Control transfer DIR select */
+#define M66592_CNTMD           0x0100  /* b8: Continuous transfer mode */
+#define M66592_DIR             0x0010  /* b4: Control transfer DIR select */
 
 #define M66592_DCPMAXP         0x5E
-#define        M66592_DEVSEL           0xC000  /* b15-14: Device address select */
-#define          M66592_DEVICE_0        0x0000           /* Device address 0 */
-#define          M66592_DEVICE_1        0x4000           /* Device address 1 */
-#define          M66592_DEVICE_2        0x8000           /* Device address 2 */
-#define          M66592_DEVICE_3        0xC000           /* Device address 3 */
-#define        M66592_MAXP             0x007F  /* b6-0: Maxpacket size of default control pipe */
+#define M66592_DEVSEL          0xC000  /* b15-14: Device address select */
+#define   M66592_DEVICE_0       0x0000           /* Device address 0 */
+#define   M66592_DEVICE_1       0x4000           /* Device address 1 */
+#define   M66592_DEVICE_2       0x8000           /* Device address 2 */
+#define   M66592_DEVICE_3       0xC000           /* Device address 3 */
+#define M66592_MAXP            0x007F  /* b6-0: Maxpacket size of ep0 */
 
 #define M66592_DCPCTR          0x60
-#define        M66592_BSTS             0x8000  /* b15: Buffer status */
-#define        M66592_SUREQ            0x4000  /* b14: Send USB request  */
-#define        M66592_SQCLR            0x0100  /* b8: Sequence toggle bit clear */
-#define        M66592_SQSET            0x0080  /* b7: Sequence toggle bit set */
-#define        M66592_SQMON            0x0040  /* b6: Sequence toggle bit monitor */
-#define        M66592_CCPL             0x0004  /* b2: Enable control transfer complete */
-#define        M66592_PID              0x0003  /* b1-0: Response PID */
-#define          M66592_PID_STALL       0x0002           /* STALL */
-#define          M66592_PID_BUF         0x0001           /* BUF */
-#define          M66592_PID_NAK         0x0000           /* NAK */
+#define M66592_BSTS            0x8000  /* b15: Buffer status */
+#define M66592_SUREQ           0x4000  /* b14: Send USB request  */
+#define M66592_SQCLR           0x0100  /* b8: Sequence toggle bit clear */
+#define M66592_SQSET           0x0080  /* b7: Sequence toggle bit set */
+#define M66592_SQMON           0x0040  /* b6: Sequence toggle bit monitor */
+#define M66592_CCPL            0x0004  /* b2: control transfer complete */
+#define M66592_PID             0x0003  /* b1-0: Response PID */
+#define   M66592_PID_STALL      0x0002           /* STALL */
+#define   M66592_PID_BUF        0x0001           /* BUF */
+#define   M66592_PID_NAK        0x0000           /* NAK */
 
 #define M66592_PIPESEL         0x64
-#define        M66592_PIPENM           0x0007  /* b2-0: Pipe select */
-#define          M66592_PIPE0           0x0000           /* PIPE 0 */
-#define          M66592_PIPE1           0x0001           /* PIPE 1 */
-#define          M66592_PIPE2           0x0002           /* PIPE 2 */
-#define          M66592_PIPE3           0x0003           /* PIPE 3 */
-#define          M66592_PIPE4           0x0004           /* PIPE 4 */
-#define          M66592_PIPE5           0x0005           /* PIPE 5 */
-#define          M66592_PIPE6           0x0006           /* PIPE 6 */
-#define          M66592_PIPE7           0x0007           /* PIPE 7 */
+#define M66592_PIPENM          0x0007  /* b2-0: Pipe select */
+#define   M66592_PIPE0          0x0000           /* PIPE 0 */
+#define   M66592_PIPE1          0x0001           /* PIPE 1 */
+#define   M66592_PIPE2          0x0002           /* PIPE 2 */
+#define   M66592_PIPE3          0x0003           /* PIPE 3 */
+#define   M66592_PIPE4          0x0004           /* PIPE 4 */
+#define   M66592_PIPE5          0x0005           /* PIPE 5 */
+#define   M66592_PIPE6          0x0006           /* PIPE 6 */
+#define   M66592_PIPE7          0x0007           /* PIPE 7 */
 
 #define M66592_PIPECFG         0x66
-#define        M66592_TYP              0xC000  /* b15-14: Transfer type */
-#define          M66592_ISO             0xC000           /* Isochronous */
-#define          M66592_INT             0x8000           /* Interrupt */
-#define          M66592_BULK            0x4000           /* Bulk */
-#define        M66592_BFRE             0x0400  /* b10: Buffer ready interrupt mode select */
-#define        M66592_DBLB             0x0200  /* b9: Double buffer mode select */
-#define        M66592_CNTMD            0x0100  /* b8: Continuous transfer mode select */
-#define        M66592_SHTNAK           0x0080  /* b7: Transfer end NAK */
-#define        M66592_DIR              0x0010  /* b4: Transfer direction select */
-#define          M66592_DIR_H_OUT       0x0010           /* HOST OUT */
-#define          M66592_DIR_P_IN        0x0010           /* PERI IN */
-#define          M66592_DIR_H_IN        0x0000           /* HOST IN */
-#define          M66592_DIR_P_OUT       0x0000           /* PERI OUT */
-#define        M66592_EPNUM            0x000F  /* b3-0: Eendpoint number select */
-#define          M66592_EP1             0x0001
-#define          M66592_EP2             0x0002
-#define          M66592_EP3             0x0003
-#define          M66592_EP4             0x0004
-#define          M66592_EP5             0x0005
-#define          M66592_EP6             0x0006
-#define          M66592_EP7             0x0007
-#define          M66592_EP8             0x0008
-#define          M66592_EP9             0x0009
-#define          M66592_EP10            0x000A
-#define          M66592_EP11            0x000B
-#define          M66592_EP12            0x000C
-#define          M66592_EP13            0x000D
-#define          M66592_EP14            0x000E
-#define          M66592_EP15            0x000F
+#define M66592_TYP             0xC000  /* b15-14: Transfer type */
+#define   M66592_ISO            0xC000           /* Isochronous */
+#define   M66592_INT            0x8000           /* Interrupt */
+#define   M66592_BULK           0x4000           /* Bulk */
+#define M66592_BFRE            0x0400  /* b10: Buffer ready interrupt mode */
+#define M66592_DBLB            0x0200  /* b9: Double buffer mode select */
+#define M66592_CNTMD           0x0100  /* b8: Continuous transfer mode */
+#define M66592_SHTNAK          0x0080  /* b7: Transfer end NAK */
+#define M66592_DIR             0x0010  /* b4: Transfer direction select */
+#define   M66592_DIR_H_OUT      0x0010           /* HOST OUT */
+#define   M66592_DIR_P_IN       0x0010           /* PERI IN */
+#define   M66592_DIR_H_IN       0x0000           /* HOST IN */
+#define   M66592_DIR_P_OUT      0x0000           /* PERI OUT */
+#define M66592_EPNUM           0x000F  /* b3-0: Eendpoint number select */
+#define   M66592_EP1            0x0001
+#define   M66592_EP2            0x0002
+#define   M66592_EP3            0x0003
+#define   M66592_EP4            0x0004
+#define   M66592_EP5            0x0005
+#define   M66592_EP6            0x0006
+#define   M66592_EP7            0x0007
+#define   M66592_EP8            0x0008
+#define   M66592_EP9            0x0009
+#define   M66592_EP10           0x000A
+#define   M66592_EP11           0x000B
+#define   M66592_EP12           0x000C
+#define   M66592_EP13           0x000D
+#define   M66592_EP14           0x000E
+#define   M66592_EP15           0x000F
 
 #define M66592_PIPEBUF         0x68
-#define        M66592_BUFSIZE          0x7C00  /* b14-10: Pipe buffer size */
-#define        M66592_BUF_SIZE(x)      ((((x) / 64) - 1) << 10)
-#define        M66592_BUFNMB           0x00FF  /* b7-0: Pipe buffer number */
+#define M66592_BUFSIZE         0x7C00  /* b14-10: Pipe buffer size */
+#define M66592_BUF_SIZE(x)     ((((x) / 64) - 1) << 10)
+#define M66592_BUFNMB          0x00FF  /* b7-0: Pipe buffer number */
 
 #define M66592_PIPEMAXP                0x6A
-#define        M66592_MXPS             0x07FF  /* b10-0: Maxpacket size */
+#define M66592_MXPS            0x07FF  /* b10-0: Maxpacket size */
 
 #define M66592_PIPEPERI                0x6C
-#define        M66592_IFIS             0x1000  /* b12: Isochronous in-buffer flush mode select */
-#define        M66592_IITV             0x0007  /* b2-0: Isochronous interval */
+#define M66592_IFIS            0x1000  /* b12: ISO in-buffer flush mode */
+#define M66592_IITV            0x0007  /* b2-0: ISO interval */
 
 #define M66592_PIPE1CTR                0x70
 #define M66592_PIPE2CTR                0x72
 #define M66592_PIPE5CTR                0x78
 #define M66592_PIPE6CTR                0x7A
 #define M66592_PIPE7CTR                0x7C
-#define        M66592_BSTS             0x8000  /* b15: Buffer status */
-#define        M66592_INBUFM           0x4000  /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define        M66592_ACLRM            0x0200  /* b9: Out buffer auto clear mode */
-#define        M66592_SQCLR            0x0100  /* b8: Sequence toggle bit clear */
-#define        M66592_SQSET            0x0080  /* b7: Sequence toggle bit set */
-#define        M66592_SQMON            0x0040  /* b6: Sequence toggle bit monitor */
-#define        M66592_PID              0x0003  /* b1-0: Response PID */
+#define M66592_BSTS            0x8000  /* b15: Buffer status */
+#define M66592_INBUFM          0x4000  /* b14: IN buffer monitor (PIPE 1-5) */
+#define M66592_ACLRM           0x0200  /* b9: Out buffer auto clear mode */
+#define M66592_SQCLR           0x0100  /* b8: Sequence toggle bit clear */
+#define M66592_SQSET           0x0080  /* b7: Sequence toggle bit set */
+#define M66592_SQMON           0x0040  /* b6: Sequence toggle bit monitor */
+#define M66592_PID             0x0003  /* b1-0: Response PID */
 
 #define M66592_INVALID_REG     0x7E
 
 
-#define __iomem
-
 #define get_pipectr_addr(pipenum)      (M66592_PIPE1CTR + (pipenum - 1) * 2)
 
 #define M66592_MAX_SAMPLING    10
@@ -449,7 +447,7 @@ struct m66592_ep {
        struct m66592           *m66592;
 
        struct list_head        queue;
-       unsigned                busy:1;
+       unsigned                busy:1;
        unsigned                internal_ccpl:1;        /* use only control */
 
        /* this member can able to after m66592_enable */
@@ -477,7 +475,7 @@ struct m66592 {
        struct m66592_ep        *epaddr2ep[16];
 
        struct usb_request      *ep0_req;       /* for internal request */
-       u16                     *ep0_buf;       /* for internal request */
+       u16                     ep0_data;       /* for internal request */
 
        struct timer_list       timer;
 
@@ -527,8 +525,8 @@ static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset)
 }
 
 static inline void m66592_read_fifo(struct m66592 *m66592,
-                                   unsigned long offset,
-                                   void *buf, unsigned long len)
+               unsigned long offset,
+               void *buf, unsigned long len)
 {
        unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
 
@@ -543,8 +541,8 @@ static inline void m66592_write(struct m66592 *m66592, u16 val,
 }
 
 static inline void m66592_write_fifo(struct m66592 *m66592,
-                                    unsigned long offset,
-                                    void *buf, unsigned long len)
+               unsigned long offset,
+               void *buf, unsigned long len)
 {
        unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
        unsigned long odd = len & 0x0001;
@@ -558,7 +556,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
 }
 
 static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
-                              unsigned long offset)
+               unsigned long offset)
 {
        u16 tmp;
        tmp = m66592_read(m66592, offset);
index 38138bb9ddb08835039534ba0b006c40972d353b..9cd98e73dc1d7e5e73876a874b393305e31dcebf 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
+#include <linux/mutex.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -258,7 +259,7 @@ static const char *EP_IN_NAME;
 static const char *EP_OUT_NAME;
 static const char *EP_NOTIFY_NAME;
 
-static struct semaphore        gs_open_close_sem[GS_NUM_PORTS];
+static struct mutex gs_open_close_lock[GS_NUM_PORTS];
 
 static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
 static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
@@ -595,7 +596,7 @@ static int __init gs_module_init(void)
        tty_set_operations(gs_tty_driver, &gs_tty_ops);
 
        for (i=0; i < GS_NUM_PORTS; i++)
-               sema_init(&gs_open_close_sem[i], 1);
+               mutex_init(&gs_open_close_lock[i]);
 
        retval = tty_register_driver(gs_tty_driver);
        if (retval) {
@@ -635,7 +636,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
        struct gs_port *port;
        struct gs_dev *dev;
        struct gs_buf *buf;
-       struct semaphore *sem;
+       struct mutex *mtx;
        int ret;
 
        port_num = tty->index;
@@ -656,10 +657,10 @@ static int gs_open(struct tty_struct *tty, struct file *file)
                return -ENODEV;
        }
 
-       sem = &gs_open_close_sem[port_num];
-       if (down_interruptible(sem)) {
+       mtx = &gs_open_close_lock[port_num];
+       if (mutex_lock_interruptible(mtx)) {
                printk(KERN_ERR
-               "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
+               "gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
                        port_num, tty, file);
                return -ERESTARTSYS;
        }
@@ -754,12 +755,12 @@ static int gs_open(struct tty_struct *tty, struct file *file)
 
 exit_unlock_port:
        spin_unlock_irqrestore(&port->port_lock, flags);
-       up(sem);
+       mutex_unlock(mtx);
        return ret;
 
 exit_unlock_dev:
        spin_unlock_irqrestore(&dev->dev_lock, flags);
-       up(sem);
+       mutex_unlock(mtx);
        return ret;
 
 }
@@ -781,7 +782,7 @@ exit_unlock_dev:
 static void gs_close(struct tty_struct *tty, struct file *file)
 {
        struct gs_port *port = tty->driver_data;
-       struct semaphore *sem;
+       struct mutex *mtx;
 
        if (port == NULL) {
                printk(KERN_ERR "gs_close: NULL port pointer\n");
@@ -790,8 +791,8 @@ static void gs_close(struct tty_struct *tty, struct file *file)
 
        gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
 
-       sem = &gs_open_close_sem[port->port_num];
-       down(sem);
+       mtx = &gs_open_close_lock[port->port_num];
+       mutex_lock(mtx);
 
        spin_lock_irq(&port->port_lock);
 
@@ -846,7 +847,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
 
 exit:
        spin_unlock_irq(&port->port_lock);
-       up(sem);
+       mutex_unlock(mtx);
 }
 
 /*
index 46873f2534b5d152d3b277e424a5c046ae402b3f..5c851a36de722e36d67fb65128219213d95d0235 100644 (file)
@@ -228,7 +228,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
                                   struct urb, urb_list);
                ptd = &ep->ptd;
                len = ep->length;
-               spin_lock(&urb->lock);
                ep->data = (unsigned char *)urb->transfer_buffer
                    + urb->actual_length;
 
@@ -264,7 +263,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
                    | PTD_EP(ep->epnum);
                ptd->len = PTD_LEN(len) | PTD_DIR(dir);
                ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
-               spin_unlock(&urb->lock);
                if (!ep->active) {
                        ptd->mps |= PTD_LAST_MSK;
                        isp116x->atl_last_dir = dir;
@@ -274,6 +272,61 @@ static void preproc_atl_queue(struct isp116x *isp116x)
        }
 }
 
+/*
+  Take done or failed requests out of schedule. Give back
+  processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+                          struct urb *urb)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+       unsigned i;
+
+       urb->hcpriv = NULL;
+       ep->error_count = 0;
+
+       if (usb_pipecontrol(urb->pipe))
+               ep->nextpid = USB_PID_SETUP;
+
+       urb_dbg(urb, "Finish");
+
+       spin_unlock(&isp116x->lock);
+       usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+       spin_lock(&isp116x->lock);
+
+       /* take idle endpoints out of the schedule */
+       if (!list_empty(&ep->hep->urb_list))
+               return;
+
+       /* async deschedule */
+       if (!list_empty(&ep->schedule)) {
+               list_del_init(&ep->schedule);
+               return;
+       }
+
+       /* periodic deschedule */
+       DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+       for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+               struct isp116x_ep *temp;
+               struct isp116x_ep **prev = &isp116x->periodic[i];
+
+               while (*prev && ((temp = *prev) != ep))
+                       prev = &temp->next;
+               if (*prev)
+                       *prev = ep->next;
+               isp116x->load[i] -= ep->load;
+       }
+       ep->branch = PERIODIC_SIZE;
+       isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+           ep->load / ep->period;
+
+       /* switch irq type? */
+       if (!--isp116x->periodic_count) {
+               isp116x->irqenb &= ~HCuPINT_SOF;
+               isp116x->irqenb |= HCuPINT_ATL;
+       }
+}
+
 /*
   Analyze transfer results, handle partial transfers and errors
 */
@@ -284,6 +337,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
        struct usb_device *udev;
        struct ptd *ptd;
        int short_not_ok;
+       int status;
        u8 cc;
 
        for (ep = isp116x->atl_active; ep; ep = ep->active) {
@@ -294,7 +348,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                ptd = &ep->ptd;
                cc = PTD_GET_CC(ptd);
                short_not_ok = 1;
-               spin_lock(&urb->lock);
+               status = -EINPROGRESS;
 
                /* Data underrun is special. For allowed underrun
                   we clear the error and continue as normal. For
@@ -302,47 +356,36 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                   immediately while for control transfer,
                   we do a STATUS stage. */
                if (cc == TD_DATAUNDERRUN) {
-                       if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
-                               DBG("Allowed data underrun\n");
+                       if (!(urb->transfer_flags & URB_SHORT_NOT_OK) ||
+                                       usb_pipecontrol(urb->pipe)) {
+                               DBG("Allowed or control data underrun\n");
                                cc = TD_CC_NOERROR;
                                short_not_ok = 0;
                        } else {
                                ep->error_count = 1;
-                               if (usb_pipecontrol(urb->pipe))
-                                       ep->nextpid = USB_PID_ACK;
-                               else
-                                       usb_settoggle(udev, ep->epnum,
-                                                     ep->nextpid ==
-                                                     USB_PID_OUT,
-                                                     PTD_GET_TOGGLE(ptd));
+                               usb_settoggle(udev, ep->epnum,
+                                             ep->nextpid == USB_PID_OUT,
+                                             PTD_GET_TOGGLE(ptd));
                                urb->actual_length += PTD_GET_COUNT(ptd);
-                               urb->status = cc_to_error[TD_DATAUNDERRUN];
-                               spin_unlock(&urb->lock);
-                               continue;
+                               status = cc_to_error[TD_DATAUNDERRUN];
+                               goto done;
                        }
                }
-               /* Keep underrun error through the STATUS stage */
-               if (urb->status == cc_to_error[TD_DATAUNDERRUN])
-                       cc = TD_DATAUNDERRUN;
 
                if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
                    && (++ep->error_count >= 3 || cc == TD_CC_STALL
                        || cc == TD_DATAOVERRUN)) {
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = cc_to_error[cc];
+                       status = cc_to_error[cc];
                        if (ep->nextpid == USB_PID_ACK)
                                ep->nextpid = 0;
-                       spin_unlock(&urb->lock);
-                       continue;
+                       goto done;
                }
                /* According to usb spec, zero-length Int transfer signals
                   finishing of the urb. Hey, does this apply only
                   for IN endpoints? */
                if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = 0;
-                       spin_unlock(&urb->lock);
-                       continue;
+                       status = 0;
+                       goto done;
                }
 
                /* Relax after previously failed, but later succeeded
@@ -381,8 +424,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                        /* All data for this URB is transferred, let's finish */
                        if (usb_pipecontrol(urb->pipe))
                                ep->nextpid = USB_PID_ACK;
-                       else if (urb->status == -EINPROGRESS)
-                               urb->status = 0;
+                       else
+                               status = 0;
                        break;
                case USB_PID_SETUP:
                        if (PTD_GET_ACTIVE(ptd)
@@ -402,69 +445,27 @@ static void postproc_atl_queue(struct isp116x *isp116x)
                        if (PTD_GET_ACTIVE(ptd)
                            || (cc != TD_CC_NOERROR && cc < 0x0E))
                                break;
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = 0;
+                       if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+                                       urb->actual_length <
+                                               urb->transfer_buffer_length)
+                               status = -EREMOTEIO;
+                       else
+                               status = 0;
                        ep->nextpid = 0;
                        break;
                default:
                        BUG();
                }
-               spin_unlock(&urb->lock);
-       }
-}
-
-/*
-  Take done or failed requests out of schedule. Give back
-  processed urbs.
-*/
-static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
-                          struct urb *urb)
-__releases(isp116x->lock) __acquires(isp116x->lock)
-{
-       unsigned i;
-
-       urb->hcpriv = NULL;
-       ep->error_count = 0;
-
-       if (usb_pipecontrol(urb->pipe))
-               ep->nextpid = USB_PID_SETUP;
-
-       urb_dbg(urb, "Finish");
-
-       spin_unlock(&isp116x->lock);
-       usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
-       spin_lock(&isp116x->lock);
-
-       /* take idle endpoints out of the schedule */
-       if (!list_empty(&ep->hep->urb_list))
-               return;
-
-       /* async deschedule */
-       if (!list_empty(&ep->schedule)) {
-               list_del_init(&ep->schedule);
-               return;
-       }
 
-       /* periodic deschedule */
-       DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
-       for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
-               struct isp116x_ep *temp;
-               struct isp116x_ep **prev = &isp116x->periodic[i];
-
-               while (*prev && ((temp = *prev) != ep))
-                       prev = &temp->next;
-               if (*prev)
-                       *prev = ep->next;
-               isp116x->load[i] -= ep->load;
-       }
-       ep->branch = PERIODIC_SIZE;
-       isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
-           ep->load / ep->period;
-
-       /* switch irq type? */
-       if (!--isp116x->periodic_count) {
-               isp116x->irqenb &= ~HCuPINT_SOF;
-               isp116x->irqenb |= HCuPINT_ATL;
+ done:
+               if (status != -EINPROGRESS) {
+                       spin_lock(&urb->lock);
+                       if (urb->status == -EINPROGRESS)
+                               urb->status = status;
+                       spin_unlock(&urb->lock);
+               }
+               if (urb->status != -EINPROGRESS)
+                       finish_request(isp116x, ep, urb);
        }
 }
 
@@ -570,9 +571,6 @@ static void start_atl_transfers(struct isp116x *isp116x)
 */
 static void finish_atl_transfers(struct isp116x *isp116x)
 {
-       struct isp116x_ep *ep;
-       struct urb *urb;
-
        if (!isp116x->atl_active)
                return;
        /* Fifo not ready? */
@@ -582,16 +580,6 @@ static void finish_atl_transfers(struct isp116x *isp116x)
        atomic_inc(&isp116x->atl_finishing);
        unpack_fifo(isp116x);
        postproc_atl_queue(isp116x);
-       for (ep = isp116x->atl_active; ep; ep = ep->active) {
-               urb =
-                   container_of(ep->hep->urb_list.next, struct urb, urb_list);
-               /* USB_PID_ACK check here avoids finishing of
-                  control transfers, for which TD_DATAUNDERRUN
-                  occured, while URB_SHORT_NOT_OK was set */
-               if (urb && urb->status != -EINPROGRESS
-                   && ep->nextpid != USB_PID_ACK)
-                       finish_request(isp116x, ep, urb);
-       }
        atomic_dec(&isp116x->atl_finishing);
 }
 
@@ -821,15 +809,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
        }
 
        /* in case of unlink-during-submit */
-       spin_lock(&urb->lock);
        if (urb->status != -EINPROGRESS) {
-               spin_unlock(&urb->lock);
                finish_request(isp116x, ep, urb);
                ret = 0;
                goto fail;
        }
        urb->hcpriv = hep;
-       spin_unlock(&urb->lock);
        start_atl_transfers(isp116x);
 
       fail:
index a7a7070c6e2ac9d9d8c10d815a0c38e3169775ca..d60f1985320cfc630e107e81bd3c406a4229a083 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
 
 #include "../core/hcd.h"
 #include "r8a66597.h"
@@ -54,16 +52,21 @@ static const char hcd_name[] = "r8a66597_hcd";
 /* module parameters */
 static unsigned short clock = XTAL12;
 module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=0)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+               "(default=0)");
+
 static unsigned short vif = LDRV;
 module_param(vif, ushort, 0644);
 MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+
+static unsigned short endian;
 module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
 static unsigned short irq_sense = INTL;
 module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0(default=32)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
+               "(default=32)");
 
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
 static int r8a66597_get_frame(struct usb_hcd *hcd);
@@ -308,7 +311,7 @@ static int make_r8a66597_device(struct r8a66597 *r8a66597,
        struct r8a66597_device *dev;
        int usb_address = urb->setup_packet[2]; /* urb->pipe is address 0 */
 
-       dev = kzalloc(sizeof(struct r8a66597_device), GFP_KERNEL);
+       dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC);
        if (dev == NULL)
                return -ENOMEM;
 
@@ -611,33 +614,33 @@ static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
        u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;
 
        memset(array, 0, sizeof(array));
-        switch(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-        case USB_ENDPOINT_XFER_BULK:
+       switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       case USB_ENDPOINT_XFER_BULK:
                if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
                        array[i++] = 4;
                else {
                        array[i++] = 3;
                        array[i++] = 5;
                }
-                break;
-        case USB_ENDPOINT_XFER_INT:
+               break;
+       case USB_ENDPOINT_XFER_INT:
                if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
                        array[i++] = 6;
                        array[i++] = 7;
                        array[i++] = 8;
                } else
                        array[i++] = 9;
-                break;
-        case USB_ENDPOINT_XFER_ISOC:
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
                if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
                        array[i++] = 2;
                else
                        array[i++] = 1;
-                break;
-        default:
-                err("Illegal type");
-                return 0;
-        }
+               break;
+       default:
+               err("Illegal type");
+               return 0;
+       }
 
        i = 1;
        min = array[0];
@@ -654,7 +657,7 @@ static u16 get_r8a66597_type(__u8 type)
 {
        u16 r8a66597_type;
 
-       switch(type) {
+       switch (type) {
        case USB_ENDPOINT_XFER_BULK:
                r8a66597_type = R8A66597_BULK;
                break;
@@ -874,7 +877,7 @@ static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port)
 {
        r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
                                         | (1 << USB_PORT_FEAT_C_CONNECTION);
-       r8a66597_write(r8a66597, (u16)~DTCH, get_intsts_reg(port));
+       r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
        r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
 }
 
@@ -917,7 +920,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
 
        r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
                       DCPMAXP);
-       r8a66597_write(r8a66597, (u16)~(SIGN | SACK), INTSTS1);
+       r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 
        for (i = 0; i < 4; i++) {
                r8a66597_write(r8a66597, p[i], setup_addr);
@@ -948,19 +951,18 @@ static void prepare_packet_read(struct r8a66597 *r8a66597,
                        pipe_irq_disable(r8a66597, td->pipenum);
                        pipe_setting(r8a66597, td);
                        pipe_stop(r8a66597, td->pipe);
-                       r8a66597_write(r8a66597, (u16)~(1 << td->pipenum),
-                                      BRDYSTS);
+                       r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
 
                        if (td->pipe->pipetre) {
                                r8a66597_write(r8a66597, TRCLR,
-                                               td->pipe->pipetre);
+                                               td->pipe->pipetre);
                                r8a66597_write(r8a66597,
-                                              (urb->transfer_buffer_length
-                                              + td->maxpacket - 1)
-                                              / td->maxpacket,
-                                              td->pipe->pipetrn);
+                                               (urb->transfer_buffer_length
+                                               + td->maxpacket - 1)
+                                               / td->maxpacket,
+                                               td->pipe->pipetrn);
                                r8a66597_bset(r8a66597, TRENB,
-                                             td->pipe->pipetre);
+                                               td->pipe->pipetre);
                        }
 
                        pipe_start(r8a66597, td->pipe);
@@ -991,7 +993,7 @@ static void prepare_packet_write(struct r8a66597 *r8a66597,
                if (td->pipe->pipetre)
                        r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);
        }
-       r8a66597_write(r8a66597, (u16)~(1 << td->pipenum), BRDYSTS);
+       r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
 
        fifo_change_from_pipe(r8a66597, td->pipe);
        tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
@@ -1009,21 +1011,21 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
        struct urb *urb = td->urb;
 
        r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+       pipe_stop(r8a66597, td->pipe);
 
        if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {
                r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
                r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
                r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
-               r8a66597_write(r8a66597, BVAL | BCLR, CFIFOCTR);
-               r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
+               r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+               r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+               r8a66597_write(r8a66597, BVAL, CFIFOCTR);
                enable_irq_empty(r8a66597, 0);
        } else {
                r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
                r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
                r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
                r8a66597_write(r8a66597, BCLR, CFIFOCTR);
-               r8a66597_write(r8a66597, (u16)~BRDY0, BRDYSTS);
-               r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
                enable_irq_ready(r8a66597, 0);
        }
        enable_irq_nrdy(r8a66597, 0);
@@ -1269,7 +1271,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
 
        /* write fifo */
        if (pipenum > 0)
-               r8a66597_write(r8a66597, (u16)~(1 << pipenum), BEMPSTS);
+               r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
        if (urb->transfer_buffer) {
                r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
                if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
@@ -1362,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
 
        mask = r8a66597_read(r8a66597, BRDYSTS)
               & r8a66597_read(r8a66597, BRDYENB);
-       r8a66597_write(r8a66597, (u16)~mask, BRDYSTS);
+       r8a66597_write(r8a66597, ~mask, BRDYSTS);
        if (mask & BRDY0) {
                td = r8a66597_get_td(r8a66597, 0);
                if (td && td->type == USB_PID_IN)
@@ -1397,7 +1399,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
 
        mask = r8a66597_read(r8a66597, BEMPSTS)
               & r8a66597_read(r8a66597, BEMPENB);
-       r8a66597_write(r8a66597, (u16)~mask, BEMPSTS);
+       r8a66597_write(r8a66597, ~mask, BEMPSTS);
        if (mask & BEMP0) {
                cfifo_change(r8a66597, 0);
                td = r8a66597_get_td(r8a66597, 0);
@@ -1434,7 +1436,7 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
 
        mask = r8a66597_read(r8a66597, NRDYSTS)
               & r8a66597_read(r8a66597, NRDYENB);
-       r8a66597_write(r8a66597, (u16)~mask, NRDYSTS);
+       r8a66597_write(r8a66597, ~mask, NRDYSTS);
        if (mask & NRDY0) {
                cfifo_change(r8a66597, 0);
                set_urb_error(r8a66597, 0);
@@ -1488,14 +1490,14 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
        mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY);
        if (mask2) {
                if (mask2 & ATTCH) {
-                       r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS2);
+                       r8a66597_write(r8a66597, ~ATTCH, INTSTS2);
                        r8a66597_bclr(r8a66597, ATTCHE, INTENB2);
 
                        /* start usb bus sampling */
                        start_root_hub_sampling(r8a66597, 1);
                }
                if (mask2 & DTCH) {
-                       r8a66597_write(r8a66597, (u16)~DTCH, INTSTS2);
+                       r8a66597_write(r8a66597, ~DTCH, INTSTS2);
                        r8a66597_bclr(r8a66597, DTCHE, INTENB2);
                        r8a66597_usb_disconnect(r8a66597, 1);
                }
@@ -1503,24 +1505,24 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
 
        if (mask1) {
                if (mask1 & ATTCH) {
-                       r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS1);
+                       r8a66597_write(r8a66597, ~ATTCH, INTSTS1);
                        r8a66597_bclr(r8a66597, ATTCHE, INTENB1);
 
                        /* start usb bus sampling */
                        start_root_hub_sampling(r8a66597, 0);
                }
                if (mask1 & DTCH) {
-                       r8a66597_write(r8a66597, (u16)~DTCH, INTSTS1);
+                       r8a66597_write(r8a66597, ~DTCH, INTSTS1);
                        r8a66597_bclr(r8a66597, DTCHE, INTENB1);
                        r8a66597_usb_disconnect(r8a66597, 0);
                }
                if (mask1 & SIGN) {
-                       r8a66597_write(r8a66597, (u16)~SIGN, INTSTS1);
+                       r8a66597_write(r8a66597, ~SIGN, INTSTS1);
                        set_urb_error(r8a66597, 0);
                        check_next_phase(r8a66597);
                }
                if (mask1 & SACK) {
-                       r8a66597_write(r8a66597, (u16)~SACK, INTSTS1);
+                       r8a66597_write(r8a66597, ~SACK, INTSTS1);
                        check_next_phase(r8a66597);
                }
        }
@@ -1663,13 +1665,9 @@ static int check_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
 static int r8a66597_start(struct usb_hcd *hcd)
 {
        struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
-       int ret;
 
        hcd->state = HC_STATE_RUNNING;
-       if ((ret = enable_controller(r8a66597)) < 0)
-               return ret;
-
-       return 0;
+       return enable_controller(r8a66597);
 }
 
 static void r8a66597_stop(struct usb_hcd *hcd)
@@ -1696,13 +1694,12 @@ static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
 
 static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
                                            struct urb *urb,
-                                           struct usb_host_endpoint *hep,
-                                           gfp_t mem_flags)
+                                           struct usb_host_endpoint *hep)
 {
        struct r8a66597_td *td;
        u16 pipenum;
 
-       td = kzalloc(sizeof(struct r8a66597_td), mem_flags);
+       td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC);
        if (td == NULL)
                return NULL;
 
@@ -1741,7 +1738,8 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
        }
 
        if (!hep->hcpriv) {
-               hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), mem_flags);
+               hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
+                               GFP_ATOMIC);
                if (!hep->hcpriv) {
                        ret = -ENOMEM;
                        goto error;
@@ -1755,7 +1753,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
                init_pipe_config(r8a66597, urb);
 
        set_address_zero(r8a66597, urb);
-       td = r8a66597_make_td(r8a66597, urb, hep, mem_flags);
+       td = r8a66597_make_td(r8a66597, urb, hep);
        if (td == NULL) {
                ret = -ENOMEM;
                goto error;
index 97c2a71ac7a125dd38a4ce245ed2606d8200dfd4..fe9ceb077d9bbddaf38f7dd6998ca73d1bea7b1a 100644 (file)
 #define        DTLN            0x0FFF  /* b11-0: FIFO received data length */
 
 /* Interrupt Enable Register 0 */
-#define        VBSE            0x8000  /* b15: VBUS interrupt */
-#define        RSME            0x4000  /* b14: Resume interrupt */
-#define        SOFE            0x2000  /* b13: Frame update interrupt */
-#define        DVSE            0x1000  /* b12: Device state transition interrupt */
-#define        CTRE            0x0800  /* b11: Control transfer stage transition interrupt */
-#define        BEMPE           0x0400  /* b10: Buffer empty interrupt */
-#define        NRDYE           0x0200  /* b9: Buffer not ready interrupt */
-#define        BRDYE           0x0100  /* b8: Buffer ready interrupt */
+#define        VBSE    0x8000  /* b15: VBUS interrupt */
+#define        RSME    0x4000  /* b14: Resume interrupt */
+#define        SOFE    0x2000  /* b13: Frame update interrupt */
+#define        DVSE    0x1000  /* b12: Device state transition interrupt */
+#define        CTRE    0x0800  /* b11: Control transfer stage transition interrupt */
+#define        BEMPE   0x0400  /* b10: Buffer empty interrupt */
+#define        NRDYE   0x0200  /* b9: Buffer not ready interrupt */
+#define        BRDYE   0x0100  /* b8: Buffer ready interrupt */
 
 /* Interrupt Enable Register 1 */
 #define        OVRCRE          0x8000  /* b15: Over-current interrupt */
 #define          SOF_DISABLE    0x0000   /* SOF OUT Disable */
 
 /* Interrupt Status Register 0 */
-#define        VBINT           0x8000  /* b15: VBUS interrupt */
-#define        RESM            0x4000  /* b14: Resume interrupt */
-#define        SOFR            0x2000  /* b13: SOF frame update interrupt */
-#define        DVST            0x1000  /* b12: Device state transition interrupt */
-#define        CTRT            0x0800  /* b11: Control transfer stage transition interrupt */
-#define        BEMP            0x0400  /* b10: Buffer empty interrupt */
-#define        NRDY            0x0200  /* b9: Buffer not ready interrupt */
-#define        BRDY            0x0100  /* b8: Buffer ready interrupt */
-#define        VBSTS           0x0080  /* b7: VBUS input port */
-#define        DVSQ            0x0070  /* b6-4: Device state */
+#define        VBINT   0x8000  /* b15: VBUS interrupt */
+#define        RESM    0x4000  /* b14: Resume interrupt */
+#define        SOFR    0x2000  /* b13: SOF frame update interrupt */
+#define        DVST    0x1000  /* b12: Device state transition interrupt */
+#define        CTRT    0x0800  /* b11: Control transfer stage transition interrupt */
+#define        BEMP    0x0400  /* b10: Buffer empty interrupt */
+#define        NRDY    0x0200  /* b9: Buffer not ready interrupt */
+#define        BRDY    0x0100  /* b8: Buffer ready interrupt */
+#define        VBSTS   0x0080  /* b7: VBUS input port */
+#define        DVSQ    0x0070  /* b6-4: Device state */
 #define          DS_SPD_CNFG    0x0070   /* Suspend Configured */
 #define          DS_SPD_ADDR    0x0060   /* Suspend Address */
 #define          DS_SPD_DFLT    0x0050   /* Suspend Default */
 /* Micro Frame Number Register */
 #define        UFRNM           0x0007  /* b2-0: Micro frame number */
 
-/* USB Address / Low Power Status Recovery Register */
-//#define      USBADDR         0x007F  /* b6-0: USB address */
-
 /* Default Control Pipe Maxpacket Size Register */
 /* Pipe Maxpacket Size Register */
-#define        DEVSEL          0xF000  /* b15-14: Device address select */
-#define        MAXP            0x007F  /* b6-0: Maxpacket size of default control pipe */
+#define        DEVSEL  0xF000  /* b15-14: Device address select */
+#define        MAXP    0x007F  /* b6-0: Maxpacket size of default control pipe */
 
 /* Default Control Pipe Control Register */
 #define        BSTS            0x8000  /* b15: Buffer status */
 #define        MXPS            0x07FF  /* b10-0: Maxpacket size */
 
 /* Pipe Cycle Configuration Register */
-#define        IFIS            0x1000  /* b12: Isochronous in-buffer flush mode select */
-#define        IITV            0x0007  /* b2-0: Isochronous interval */
+#define        IFIS    0x1000  /* b12: Isochronous in-buffer flush mode select */
+#define        IITV    0x0007  /* b2-0: Isochronous interval */
 
 /* Pipex Control Register */
-#define        BSTS            0x8000  /* b15: Buffer status */
-#define        INBUFM          0x4000  /* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define        CSCLR           0x2000  /* b13: complete-split status clear */
-#define        CSSTS           0x1000  /* b12: complete-split status */
-#define        ATREPM          0x0400  /* b10: Auto repeat mode */
-#define        ACLRM           0x0200  /* b9: Out buffer auto clear mode */
-#define        SQCLR           0x0100  /* b8: Sequence toggle bit clear */
-#define        SQSET           0x0080  /* b7: Sequence toggle bit set */
-#define        SQMON           0x0040  /* b6: Sequence toggle bit monitor */
-#define        PBUSY           0x0020  /* b5: pipe busy */
-#define        PID             0x0003  /* b1-0: Response PID */
+#define        BSTS    0x8000  /* b15: Buffer status */
+#define        INBUFM  0x4000  /* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define        CSCLR   0x2000  /* b13: complete-split status clear */
+#define        CSSTS   0x1000  /* b12: complete-split status */
+#define        ATREPM  0x0400  /* b10: Auto repeat mode */
+#define        ACLRM   0x0200  /* b9: Out buffer auto clear mode */
+#define        SQCLR   0x0100  /* b8: Sequence toggle bit clear */
+#define        SQSET   0x0080  /* b7: Sequence toggle bit set */
+#define        SQMON   0x0040  /* b6: Sequence toggle bit monitor */
+#define        PBUSY   0x0020  /* b5: pipe busy */
+#define        PID     0x0003  /* b1-0: Response PID */
 
 /* PIPExTRE */
 #define        TRENB           0x0200  /* b9: Transaction counter enable */
 #define make_devsel(addr)              (addr << 12)
 
 struct r8a66597_pipe_info {
-        u16 pipenum;
-        u16 address;   /* R8A66597 HCD usb addres */
-        u16 epnum;
-        u16 maxpacket;
-        u16 type;
-        u16 bufnum;
-        u16 buf_bsize;
-        u16 interval;
-        u16 dir_in;
+       u16 pipenum;
+       u16 address;    /* R8A66597 HCD usb addres */
+       u16 epnum;
+       u16 maxpacket;
+       u16 type;
+       u16 bufnum;
+       u16 buf_bsize;
+       u16 interval;
+       u16 dir_in;
 };
 
 struct r8a66597_pipe {
index e98df2ee990131643d6e162c67b82145bab018bf..7f765ec038cd4eb3846276c3c1f88879851260c0 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 #include <linux/pci_ids.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -83,7 +84,7 @@ static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
 * u132_module_lock exists to protect access to global variables
 *
 */
-static struct semaphore u132_module_lock;
+static struct mutex u132_module_lock;
 static int u132_exiting = 0;
 static int u132_instances = 0;
 static struct list_head u132_static_list;
@@ -258,10 +259,10 @@ static void u132_hcd_delete(struct kref *kref)
         struct platform_device *pdev = u132->platform_dev;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         u132->going += 1;
-        down(&u132_module_lock);
+        mutex_lock(&u132_module_lock);
         list_del_init(&u132->u132_list);
         u132_instances -= 1;
-        up(&u132_module_lock);
+        mutex_unlock(&u132_module_lock);
         dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
                 "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
         usb_put_hcd(hcd);
@@ -3111,10 +3112,10 @@ static int __devinit u132_probe(struct platform_device *pdev)
                 int retval = 0;
                 struct u132 *u132 = hcd_to_u132(hcd);
                 hcd->rsrc_start = 0;
-                down(&u132_module_lock);
+                mutex_lock(&u132_module_lock);
                 list_add_tail(&u132->u132_list, &u132_static_list);
                 u132->sequence_num = ++u132_instances;
-                up(&u132_module_lock);
+                mutex_unlock(&u132_module_lock);
                 u132_u132_init_kref(u132);
                 u132_initialise(u132, pdev);
                 hcd->product_desc = "ELAN U132 Host Controller";
@@ -3216,7 +3217,7 @@ static int __init u132_hcd_init(void)
         INIT_LIST_HEAD(&u132_static_list);
         u132_instances = 0;
         u132_exiting = 0;
-        init_MUTEX(&u132_module_lock);
+        mutex_init(&u132_module_lock);
         if (usb_disabled())
                 return -ENODEV;
         printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
@@ -3232,9 +3233,9 @@ static void __exit u132_hcd_exit(void)
 {
         struct u132 *u132;
         struct u132 *temp;
-        down(&u132_module_lock);
+        mutex_lock(&u132_module_lock);
         u132_exiting += 1;
-        up(&u132_module_lock);
+        mutex_unlock(&u132_module_lock);
         list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
                 platform_device_unregister(u132->platform_dev);
         } platform_driver_unregister(&u132_platform_driver);
index 4aed305982ec3f8b1c9e90cce2b7b1e0885fe5c4..3bb908ca38e9c91ffd59df6e148608d23ab2d8f9 100644 (file)
@@ -827,8 +827,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
         * If direction is "send", change the packet ID from SETUP (0x2D)
         * to OUT (0xE1).  Else change it from SETUP to IN (0x69) and
         * set Short Packet Detect (SPD) for all data packets.
+        *
+        * 0-length transfers always get treated as "send".
         */
-       if (usb_pipeout(urb->pipe))
+       if (usb_pipeout(urb->pipe) || len == 0)
                destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
        else {
                destination ^= (USB_PID_SETUP ^ USB_PID_IN);
@@ -839,7 +841,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
         * Build the DATA TDs
         */
        while (len > 0) {
-               int pktsze = min(len, maxsze);
+               int pktsze = maxsze;
+
+               if (len <= pktsze) {            /* The last data packet */
+                       pktsze = len;
+                       status &= ~TD_CTRL_SPD;
+               }
 
                td = uhci_alloc_td(uhci);
                if (!td)
@@ -866,20 +873,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
                goto nomem;
        *plink = LINK_TO_TD(td);
 
-       /*
-        * It's IN if the pipe is an output pipe or we're not expecting
-        * data back.
-        */
-       destination &= ~TD_TOKEN_PID_MASK;
-       if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
-               destination |= USB_PID_IN;
-       else
-               destination |= USB_PID_OUT;
-
+       /* Change direction for the status transaction */
+       destination ^= (USB_PID_IN ^ USB_PID_OUT);
        destination |= TD_TOKEN_TOGGLE;         /* End in Data1 */
 
-       status &= ~TD_CTRL_SPD;
-
        uhci_add_td_to_urbp(td, urbp);
        uhci_fill_td(td, status | TD_CTRL_IOC,
                        destination | uhci_explen(0), 0);
@@ -1185,10 +1182,18 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
                                }
                        }
 
+               /* Did we receive a short packet? */
                } else if (len < uhci_expected_length(td_token(td))) {
 
-                       /* We received a short packet */
-                       if (urb->transfer_flags & URB_SHORT_NOT_OK)
+                       /* For control transfers, go to the status TD if
+                        * this isn't already the last data TD */
+                       if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+                               if (td->list.next != urbp->td_list.prev)
+                                       ret = 1;
+                       }
+
+                       /* For bulk and interrupt, this may be an error */
+                       else if (urb->transfer_flags & URB_SHORT_NOT_OK)
                                ret = -EREMOTEIO;
 
                        /* Fixup needed only if this isn't the URB's last TD */
@@ -1208,10 +1213,6 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
 
 err:
        if (ret < 0) {
-               /* In case a control transfer gets an error
-                * during the setup stage */
-               urb->actual_length = max(urb->actual_length, 0);
-
                /* Note that the queue has stopped and save
                 * the next toggle value */
                qh->element = UHCI_PTR_TERM;
@@ -1489,9 +1490,25 @@ __acquires(uhci->lock)
 {
        struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
+       if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+
+               /* urb->actual_length < 0 means the setup transaction didn't
+                * complete successfully.  Either it failed or the URB was
+                * unlinked first.  Regardless, don't confuse people with a
+                * negative length. */
+               urb->actual_length = max(urb->actual_length, 0);
+
+               /* Report erroneous short transfers */
+               if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+                               urb->actual_length <
+                                       urb->transfer_buffer_length &&
+                               urb->status == 0))
+                       urb->status = -EREMOTEIO;
+       }
+
        /* When giving back the first URB in an Isochronous queue,
         * reinitialize the QH's iso-related members for the next URB. */
-       if (qh->type == USB_ENDPOINT_XFER_ISOC &&
+       else if (qh->type == USB_ENDPOINT_XFER_ISOC &&
                        urbp->node.prev == &qh->queue &&
                        urbp->node.next != &qh->queue) {
                struct urb *nurb = list_entry(urbp->node.next,
index 36502a06f73af9f3fff9d0bcdb453f4d3c4ced1a..d1131a87a5b13ad72e40e4f573a6a7ace8979445 100644 (file)
@@ -284,9 +284,9 @@ static void mdc800_usb_irq (struct urb *urb)
        int data_received=0, wake_up;
        unsigned char* b=urb->transfer_buffer;
        struct mdc800_data* mdc800=urb->context;
+       int status = urb->status;
 
-       if (urb->status >= 0)
-       {
+       if (status >= 0) {
 
                //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
 
@@ -324,7 +324,7 @@ static void mdc800_usb_irq (struct urb *urb)
                ||
                        ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
                ||
-                       (urb->status < 0)
+                       (status < 0)
                );
 
        if (wake_up)
@@ -376,15 +376,12 @@ static int mdc800_usb_waitForIRQ (int mode, int msec)
 static void mdc800_usb_write_notify (struct urb *urb)
 {
        struct mdc800_data* mdc800=urb->context;
+       int status = urb->status;
 
-       if (urb->status != 0)
-       {
-               err ("writing command fails (status=%i)", urb->status);
-       }
+       if (status != 0)
+               err ("writing command fails (status=%i)", status);
        else
-       {       
                mdc800->state=READY;
-       }
        mdc800->written = 1;
        wake_up (&mdc800->write_wait);
 }
@@ -396,9 +393,9 @@ static void mdc800_usb_write_notify (struct urb *urb)
 static void mdc800_usb_download_notify (struct urb *urb)
 {
        struct mdc800_data* mdc800=urb->context;
+       int status = urb->status;
 
-       if (urb->status == 0)
-       {
+       if (status == 0) {
                /* Fill output buffer with these data */
                memcpy (mdc800->out,  urb->transfer_buffer, 64);
                mdc800->out_count=64;
@@ -408,10 +405,8 @@ static void mdc800_usb_download_notify (struct urb *urb)
                {
                        mdc800->state=READY;
                }
-       }
-       else
-       {
-               err ("request bytes fails (status:%i)", urb->status);
+       } else {
+               err ("request bytes fails (status:%i)", status);
        }
        mdc800->downloaded = 1;
        wake_up (&mdc800->download_wait);
@@ -649,9 +644,9 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
 
        retval=0;
        mdc800->irq_urb->dev = mdc800->dev;
-       if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
-       {
-               err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+       retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL);
+       if (retval) {
+               err ("request USB irq fails (submit_retval=%i).", retval);
                errn = -EIO;
                goto error_out;
        }
@@ -698,6 +693,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 {
        size_t left=len, sts=len; /* single transfer size */
        char __user *ptr = buf;
+       int retval;
 
        mutex_lock(&mdc800->io_lock);
        if (mdc800->state == NOT_CONNECTED)
@@ -737,9 +733,9 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 
                                /* Download -> Request new bytes */
                                mdc800->download_urb->dev = mdc800->dev;
-                               if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
-                               {
-                                       err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+                               retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL);
+                               if (retval) {
+                                       err ("Can't submit download urb (retval=%i)",retval);
                                        mutex_unlock(&mdc800->io_lock);
                                        return len-left;
                                }
@@ -788,6 +784,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
 static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos)
 {
        size_t i=0;
+       int retval;
 
        mutex_lock(&mdc800->io_lock);
        if (mdc800->state != READY)
@@ -854,9 +851,9 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
                        mdc800->state=WORKING;
                        memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
                        mdc800->write_urb->dev = mdc800->dev;
-                       if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
-                       {
-                               err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+                       retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL);
+                       if (retval) {
+                               err ("submitting write urb fails (retval=%i)", retval);
                                mutex_unlock(&mdc800->io_lock);
                                return -EIO;
                        }
index 51bd80d2b8ccb4379756b83d6185e175b2bbd4b8..768b2c11a2311d6efa8237e7868c4c642d8998dc 100644 (file)
@@ -189,7 +189,7 @@ static struct usb_driver mts_usb_driver = {
 #define MTS_DEBUG_INT() \
        do { MTS_DEBUG_GOT_HERE(); \
             MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
-            MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+            MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
              mts_debug_dump(context->instance);\
           } while(0)
 #else
@@ -393,8 +393,6 @@ void mts_int_submit_urb (struct urb* transfer,
                      context
                );
 
-       transfer->status = 0;
-
        res = usb_submit_urb( transfer, GFP_ATOMIC );
        if ( unlikely(res) ) {
                MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
@@ -444,12 +442,13 @@ static void mts_get_status( struct urb *transfer )
 static void mts_data_done( struct urb* transfer )
 /* Interrupt context! */
 {
+       int status = transfer->status;
        MTS_INT_INIT();
 
        if ( context->data_length != transfer->actual_length ) {
                context->srb->resid = context->data_length - transfer->actual_length;
-       } else if ( unlikely(transfer->status) ) {
-               context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+       } else if ( unlikely(status) ) {
+               context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
        }
 
        mts_get_status(transfer);
@@ -461,10 +460,11 @@ static void mts_data_done( struct urb* transfer )
 static void mts_command_done( struct urb *transfer )
 /* Interrupt context! */
 {
+       int status = transfer->status;
        MTS_INT_INIT();
 
-       if ( unlikely(transfer->status) ) {
-               if (transfer->status == -ENOENT) {
+       if ( unlikely(status) ) {
+               if (status == -ENOENT) {
                        /* We are being killed */
                        MTS_DEBUG_GOT_HERE();
                        context->srb->result = DID_ABORT<<16;
@@ -502,12 +502,13 @@ static void mts_command_done( struct urb *transfer )
 static void mts_do_sg (struct urb* transfer)
 {
        struct scatterlist * sg;
+       int status = transfer->status;
        MTS_INT_INIT();
 
        MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
 
-       if (unlikely(transfer->status)) {
-                context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+       if (unlikely(status)) {
+                context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
                mts_transfer_cleanup(transfer);
         }
 
index d72c42e5f22d0a8f1434b9d36c864d177bd0c34a..e9fdbc8997b32c2be588a3b52030448c4a689307 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_USB_DEBUG
@@ -80,7 +81,7 @@ MODULE_DEVICE_TABLE(usb, device_table);
 
 /* Structure to hold all of our device specific stuff */
 struct adu_device {
-       struct semaphore        sem; /* locks this structure */
+       struct mutex            mtx; /* locks this structure */
        struct usb_device*      udev; /* save off the usb device pointer */
        struct usb_interface*   interface;
        unsigned char           minor; /* the starting minor number for this device */
@@ -178,17 +179,18 @@ static void adu_delete(struct adu_device *dev)
 static void adu_interrupt_in_callback(struct urb *urb)
 {
        struct adu_device *dev = urb->context;
+       int status = urb->status;
 
-       dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+       dbg(4," %s : enter, status %d", __FUNCTION__, status);
        adu_debug_data(5, __FUNCTION__, urb->actual_length,
                       urb->transfer_buffer);
 
        spin_lock(&dev->buflock);
 
-       if (urb->status != 0) {
-               if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+       if (status != 0) {
+               if ((status != -ENOENT) && (status != -ECONNRESET)) {
                        dbg(1," %s : nonzero status received: %d",
-                           __FUNCTION__, urb->status);
+                           __FUNCTION__, status);
                }
                goto exit;
        }
@@ -216,21 +218,22 @@ exit:
        wake_up_interruptible(&dev->read_wait);
        adu_debug_data(5, __FUNCTION__, urb->actual_length,
                       urb->transfer_buffer);
-       dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+       dbg(4," %s : leave, status %d", __FUNCTION__, status);
 }
 
 static void adu_interrupt_out_callback(struct urb *urb)
 {
        struct adu_device *dev = urb->context;
+       int status = urb->status;
 
-       dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+       dbg(4," %s : enter, status %d", __FUNCTION__, status);
        adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-       if (urb->status != 0) {
-               if ((urb->status != -ENOENT) &&
-                   (urb->status != -ECONNRESET)) {
+       if (status != 0) {
+               if ((status != -ENOENT) &&
+                   (status != -ECONNRESET)) {
                        dbg(1, " %s :nonzero status received: %d",
-                           __FUNCTION__, urb->status);
+                           __FUNCTION__, status);
                }
                goto exit;
        }
@@ -240,7 +243,7 @@ exit:
 
        adu_debug_data(5, __FUNCTION__, urb->actual_length,
                       urb->transfer_buffer);
-       dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+       dbg(4," %s : leave, status %d", __FUNCTION__, status);
 }
 
 static int adu_open(struct inode *inode, struct file *file)
@@ -269,8 +272,8 @@ static int adu_open(struct inode *inode, struct file *file)
        }
 
        /* lock this device */
-       if ((retval = down_interruptible(&dev->sem))) {
-               dbg(2, "%s : sem down failed", __FUNCTION__);
+       if ((retval = mutex_lock_interruptible(&dev->mtx))) {
+               dbg(2, "%s : mutex lock failed", __FUNCTION__);
                goto exit_no_device;
        }
 
@@ -299,7 +302,7 @@ static int adu_open(struct inode *inode, struct file *file)
                if (retval)
                        --dev->open_count;
        }
-       up(&dev->sem);
+       mutex_unlock(&dev->mtx);
 
 exit_no_device:
        dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
@@ -347,7 +350,7 @@ static int adu_release(struct inode *inode, struct file *file)
        }
 
        /* lock our device */
-       down(&dev->sem); /* not interruptible */
+       mutex_lock(&dev->mtx); /* not interruptible */
 
        if (dev->open_count <= 0) {
                dbg(1," %s : device not opened", __FUNCTION__);
@@ -357,7 +360,7 @@ static int adu_release(struct inode *inode, struct file *file)
 
        if (dev->udev == NULL) {
                /* the device was unplugged before the file was released */
-               up(&dev->sem);
+               mutex_unlock(&dev->mtx);
                adu_delete(dev);
                dev = NULL;
        } else {
@@ -367,7 +370,7 @@ static int adu_release(struct inode *inode, struct file *file)
 
 exit:
        if (dev)
-               up(&dev->sem);
+               mutex_unlock(&dev->mtx);
        dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
        return retval;
 }
@@ -390,7 +393,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
        dev = file->private_data;
        dbg(2," %s : dev=%p", __FUNCTION__, dev);
        /* lock this object */
-       if (down_interruptible(&dev->sem))
+       if (mutex_lock_interruptible(&dev->mtx))
                return -ERESTARTSYS;
 
        /* verify that the device wasn't unplugged */
@@ -522,7 +525,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
 
 exit:
        /* unlock the device */
-       up(&dev->sem);
+       mutex_unlock(&dev->mtx);
 
        dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
        return retval;
@@ -543,7 +546,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
        dev = file->private_data;
 
        /* lock this object */
-       retval = down_interruptible(&dev->sem);
+       retval = mutex_lock_interruptible(&dev->mtx);
        if (retval)
                goto exit_nolock;
 
@@ -571,9 +574,9 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
                                retval = -EINTR;
                                goto exit;
                        }
-                       up(&dev->sem);
+                       mutex_unlock(&dev->mtx);
                        timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
-                       retval = down_interruptible(&dev->sem);
+                       retval = mutex_lock_interruptible(&dev->mtx);
                        if (retval) {
                                retval = bytes_written ? bytes_written : retval;
                                goto exit_nolock;
@@ -638,7 +641,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
 
 exit:
        /* unlock the device */
-       up(&dev->sem);
+       mutex_unlock(&dev->mtx);
 exit_nolock:
 
        dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
@@ -698,7 +701,7 @@ static int adu_probe(struct usb_interface *interface,
                goto exit;
        }
 
-       init_MUTEX(&dev->sem);
+       mutex_init(&dev->mtx);
        spin_lock_init(&dev->buflock);
        dev->udev = udev;
        init_waitqueue_head(&dev->read_wait);
@@ -835,16 +838,16 @@ static void adu_disconnect(struct usb_interface *interface)
        usb_deregister_dev(interface, &adu_class);
        dev->minor = 0;
 
-       down(&dev->sem); /* not interruptible */
+       mutex_lock(&dev->mtx); /* not interruptible */
 
        /* if the device is not opened, then we clean up right now */
        dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
        if (!dev->open_count) {
-               up(&dev->sem);
+               mutex_unlock(&dev->mtx);
                adu_delete(dev);
        } else {
                dev->udev = NULL;
-               up(&dev->sem);
+               mutex_unlock(&dev->mtx);
        }
 
        dev_info(&interface->dev, "ADU device adutux%d now disconnected",
index cf70c16f0e3f6981af7cd1b7946d9d91a712678e..b09c83568c1a8b455520feb3cd58df8250fe3aef 100644 (file)
@@ -88,9 +88,10 @@ static void appledisplay_complete(struct urb *urb)
 {
        struct appledisplay *pdata = urb->context;
        unsigned long flags;
+       int status = urb->status;
        int retval;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                /* success */
                break;
@@ -102,12 +103,12 @@ static void appledisplay_complete(struct urb *urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* This urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d",
-                       __FUNCTION__, urb->status);
+               dbg("%s - urb shuttingdown with status: %d",
+                       __FUNCTION__, status);
                return;
        default:
                dbg("%s - nonzero urb status received: %d",
-                       __FUNCTION__, urb->status);
+                       __FUNCTION__, status);
                goto exit;
        }
 
index 42d4e6454a77f3bfec9562bc41b44a85ab42afb8..df7e1ecc810a18acf4f41d8e6d11746fc88873b5 100644 (file)
@@ -862,14 +862,16 @@ static void auerswald_ctrlread_wretcomplete (struct urb * urb)
         pauerbuf_t bp = (pauerbuf_t) urb->context;
         pauerswald_t cp;
        int ret;
+       int status = urb->status;
+
         dbg ("auerswald_ctrlread_wretcomplete called");
-        dbg ("complete with status: %d", urb->status);
+        dbg ("complete with status: %d", status);
        cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
 
        /* check if it is possible to advance */
-       if (!auerswald_status_retry (urb->status) || !cp->usbdev) {
+       if (!auerswald_status_retry(status) || !cp->usbdev) {
                /* reuse the buffer */
-               err ("control dummy: transmission error %d, can not retry", urb->status);
+               err ("control dummy: transmission error %d, can not retry", status);
                auerbuf_releasebuf (bp);
                /* Wake up all processes waiting for a buffer */
                wake_up (&cp->bufferwait);
@@ -902,21 +904,23 @@ static void auerswald_ctrlread_complete (struct urb * urb)
         pauerswald_t  cp;
         pauerscon_t   scp;
         pauerbuf_t    bp  = (pauerbuf_t) urb->context;
+       int status = urb->status;
        int ret;
+
         dbg ("auerswald_ctrlread_complete called");
 
        cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
 
        /* check if there is valid data in this urb */
-        if (urb->status) {
-               dbg ("complete with non-zero status: %d", urb->status);
+        if (status) {
+               dbg ("complete with non-zero status: %d", status);
                /* should we do a retry? */
-               if (!auerswald_status_retry (urb->status)
+               if (!auerswald_status_retry(status)
                 || !cp->usbdev
                 || (cp->version < AUV_RETRY)
                  || (bp->retries >= AU_RETRIES)) {
                        /* reuse the buffer */
-                       err ("control read: transmission error %d, can not retry", urb->status);
+                       err ("control read: transmission error %d, can not retry", status);
                        auerbuf_releasebuf (bp);
                        /* Wake up all processes waiting for a buffer */
                        wake_up (&cp->bufferwait);
@@ -974,12 +978,13 @@ static void auerswald_int_complete (struct urb * urb)
         unsigned  int channelid;
         unsigned  int bytecount;
         int ret;
+       int status = urb->status;
         pauerbuf_t   bp = NULL;
         pauerswald_t cp = (pauerswald_t) urb->context;
 
         dbg ("%s called", __FUNCTION__);
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                /* success */
                break;
@@ -987,10 +992,10 @@ static void auerswald_int_complete (struct urb * urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
                return;
        default:
-               dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+               dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
                goto exit;
        }
 
index e0f122e131d720e0580382f88845c2bf47cde5a7..538b535e955ba0be89303c18a54076bfdc0f2743 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/kref.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/workqueue.h>
@@ -64,7 +65,7 @@ static struct workqueue_struct *respond_queue;
 * ftdi_module_lock exists to protect access to global variables
 *
 */
-static struct semaphore ftdi_module_lock;
+static struct mutex ftdi_module_lock;
 static int ftdi_instances = 0;
 static struct list_head ftdi_static_list;
 /*
@@ -199,10 +200,10 @@ static void ftdi_elan_delete(struct kref *kref)
         dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
         usb_put_dev(ftdi->udev);
         ftdi->disconnected += 1;
-        down(&ftdi_module_lock);
+        mutex_lock(&ftdi_module_lock);
         list_del_init(&ftdi->ftdi_list);
         ftdi_instances -= 1;
-        up(&ftdi_module_lock);
+        mutex_unlock(&ftdi_module_lock);
         kfree(ftdi->bulk_in_buffer);
         ftdi->bulk_in_buffer = NULL;
 }
@@ -746,10 +747,12 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
 static void ftdi_elan_write_bulk_callback(struct urb *urb)
 {
         struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
-        if (urb->status && !(urb->status == -ENOENT || urb->status ==
-                -ECONNRESET || urb->status == -ESHUTDOWN)) {
+       int status = urb->status;
+
+       if (status && !(status == -ENOENT || status == -ECONNRESET ||
+           status == -ESHUTDOWN)) {
                 dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
-                        "d\n", urb, urb->status);
+                        "d\n", urb, status);
         }
         usb_buffer_free(urb->dev, urb->transfer_buffer_length,
                 urb->transfer_buffer, urb->transfer_dma);
@@ -2780,10 +2783,10 @@ static int ftdi_elan_probe(struct usb_interface *interface,
                 return -ENOMEM;
         }
         memset(ftdi, 0x00, sizeof(struct usb_ftdi));
-        down(&ftdi_module_lock);
+        mutex_lock(&ftdi_module_lock);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         ftdi->sequence_num = ++ftdi_instances;
-        up(&ftdi_module_lock);
+        mutex_unlock(&ftdi_module_lock);
         ftdi_elan_init_kref(ftdi);
         init_MUTEX(&ftdi->sw_lock);
         ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -2909,7 +2912,7 @@ static int __init ftdi_elan_init(void)
         int result;
         printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
               __TIME__, __DATE__);
-        init_MUTEX(&ftdi_module_lock);
+        mutex_init(&ftdi_module_lock);
         INIT_LIST_HEAD(&ftdi_static_list);
         status_queue = create_singlethread_workqueue("ftdi-status-control");
        if (!status_queue)
index 28548d186712ab24872eb15be6d69c86452b8db9..46d9f27ec17380122d0f3db1ef198b04d3fa2696 100644 (file)
@@ -158,9 +158,10 @@ static void iowarrior_callback(struct urb *urb)
        int read_idx;
        int aux_idx;
        int offset;
-       int status;
+       int status = urb->status;
+       int retval;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                /* success */
                break;
@@ -213,10 +214,10 @@ static void iowarrior_callback(struct urb *urb)
        wake_up_interruptible(&dev->read_wait);
 
 exit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
                dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
-                       __FUNCTION__, status);
+                       __FUNCTION__, retval);
 
 }
 
@@ -226,13 +227,15 @@ exit:
 static void iowarrior_write_callback(struct urb *urb)
 {
        struct iowarrior *dev;
+       int status = urb->status;
+
        dev = (struct iowarrior *)urb->context;
        /* sync/async unlink faults aren't errors */
-       if (urb->status &&
-           !(urb->status == -ENOENT ||
-             urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+       if (status &&
+           !(status == -ENOENT ||
+             status == -ECONNRESET || status == -ESHUTDOWN)) {
                dbg("%s - nonzero write bulk status received: %d",
-                   __func__, urb->status);
+                   __func__, status);
        }
        /* free up our allocated buffer */
        usb_buffer_free(urb->dev, urb->transfer_buffer_length,
index 5e950b90c5414900fb1f7f8fe91a750660dda56d..8208496dfc638410ade09db081d0c7c729571d32 100644 (file)
@@ -219,16 +219,17 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
        struct ld_usb *dev = urb->context;
        size_t *actual_buffer;
        unsigned int next_ring_head;
+       int status = urb->status;
        int retval;
 
-       if (urb->status) {
-               if (urb->status == -ENOENT ||
-                   urb->status == -ECONNRESET ||
-                   urb->status == -ESHUTDOWN) {
+       if (status) {
+               if (status == -ENOENT ||
+                   status == -ECONNRESET ||
+                   status == -ESHUTDOWN) {
                        goto exit;
                } else {
                        dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
-                                __FUNCTION__, urb->status);
+                                __FUNCTION__, status);
                        spin_lock(&dev->rbsl);
                        goto resubmit; /* maybe we can recover */
                }
@@ -275,14 +276,15 @@ exit:
 static void ld_usb_interrupt_out_callback(struct urb *urb)
 {
        struct ld_usb *dev = urb->context;
+       int status = urb->status;
 
        /* sync/async unlink faults aren't errors */
-       if (urb->status && !(urb->status == -ENOENT ||
-                            urb->status == -ECONNRESET ||
-                            urb->status == -ESHUTDOWN))
+       if (status && !(status == -ENOENT ||
+                       status == -ECONNRESET ||
+                       status == -ESHUTDOWN))
                dbg_info(&dev->intf->dev,
                         "%s - nonzero write interrupt status received: %d\n",
-                        __FUNCTION__, urb->status);
+                        __FUNCTION__, status);
 
        dev->interrupt_out_busy = 0;
        wake_up_interruptible(&dev->write_wait);
index 2ed0daea894c8c93e5c7313d8dd6558634171095..561970b889a50cefb76626a6227001eb970df774 100644 (file)
@@ -742,19 +742,20 @@ exit:
 static void tower_interrupt_in_callback (struct urb *urb)
 {
        struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+       int status = urb->status;
        int retval;
 
-       dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: enter, status %d", __FUNCTION__, status);
 
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-       if (urb->status) {
-               if (urb->status == -ENOENT ||
-                   urb->status == -ECONNRESET ||
-                   urb->status == -ESHUTDOWN) {
+       if (status) {
+               if (status == -ENOENT ||
+                   status == -ECONNRESET ||
+                   status == -ESHUTDOWN) {
                        goto exit;
                } else {
-                       dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);
+                       dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status);
                        goto resubmit; /* maybe we can recover */
                }
        }
@@ -788,7 +789,7 @@ exit:
        wake_up_interruptible (&dev->read_wait);
 
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-       dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
@@ -798,23 +799,24 @@ exit:
 static void tower_interrupt_out_callback (struct urb *urb)
 {
        struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+       int status = urb->status;
 
-       dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: enter, status %d", __FUNCTION__, status);
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
        /* sync/async unlink faults aren't errors */
-       if (urb->status && !(urb->status == -ENOENT ||
-                            urb->status == -ECONNRESET ||
-                            urb->status == -ESHUTDOWN)) {
+       if (status && !(status == -ENOENT ||
+                       status == -ECONNRESET ||
+                       status == -ESHUTDOWN)) {
                dbg(1, "%s - nonzero write bulk status received: %d",
-                   __FUNCTION__, urb->status);
+                   __FUNCTION__, status);
        }
 
        dev->interrupt_out_busy = 0;
        wake_up_interruptible(&dev->write_wait);
 
        lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-       dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+       dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
index 371bf2b1197db8761ff01e20fe25ea97ce5fbb65..aa9bcceabe744fa213c073456f9cf5d5a6381f3a 100644 (file)
@@ -305,9 +305,10 @@ static void interfacekit_irq(struct urb *urb)
        struct interfacekit *kit = urb->context;
        unsigned char *buffer = kit->data;
        int i, level, sensor;
-       int status;
+       int retval;
+       int status = urb->status;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                 /* success */
                break;
        case -ECONNRESET:       /* unlink */
@@ -377,11 +378,11 @@ static void interfacekit_irq(struct urb *urb)
                schedule_delayed_work(&kit->do_notify, 0);
 
 resubmit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
-               err("can't resubmit intr, %s-%s/interfacekit0, status %d",
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
+               err("can't resubmit intr, %s-%s/interfacekit0, retval %d",
                        kit->udev->bus->bus_name,
-                       kit->udev->devpath, status);
+                       kit->udev->devpath, retval);
 }
 
 static void do_notify(struct work_struct *work)
index 5727e1ea2f91db1cd454545d16190ad32535779b..df0ebcdb9d6a6fbef91cffd476a0f5151945b324 100644 (file)
@@ -95,9 +95,10 @@ static void motorcontrol_irq(struct urb *urb)
        struct motorcontrol *mc = urb->context;
        unsigned char *buffer = mc->data;
        int i, level;
-       int status;
+       int retval;
+       int status = urb->status;;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                 /* success */
                break;
        case -ECONNRESET:       /* unlink */
@@ -151,12 +152,12 @@ static void motorcontrol_irq(struct urb *urb)
                schedule_delayed_work(&mc->do_notify, 0);
 
 resubmit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval)
                dev_err(&mc->intf->dev,
-                       "can't resubmit intr, %s-%s/motorcontrol0, status %d",
+                       "can't resubmit intr, %s-%s/motorcontrol0, retval %d",
                        mc->udev->bus->bus_name,
-                       mc->udev->devpath, status);
+                       mc->udev->devpath, retval);
 }
 
 static void do_notify(struct work_struct *work)
index 504f7221b0d095e8847b902cc6e8955c6517172f..719842032712b68c0e42c22b16c58d57332a65a7 100644 (file)
@@ -176,16 +176,17 @@ static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
 static void lcd_write_bulk_callback(struct urb *urb)
 {
        struct usb_lcd *dev;
+       int status = urb->status;
 
        dev = (struct usb_lcd *)urb->context;
 
        /* sync/async unlink faults aren't errors */
-       if (urb->status &&
-           !(urb->status == -ENOENT ||
-             urb->status == -ECONNRESET ||
-              urb->status == -ESHUTDOWN)) {
+       if (status &&
+           !(status == -ENOENT ||
+             status == -ECONNRESET ||
+              status == -ESHUTDOWN)) {
                dbg("USBLCD: %s - nonzero write bulk status received: %d",
-                   __FUNCTION__, urb->status);
+                   __FUNCTION__, status);
        }
 
        /* free up our allocated buffer */
index fb321864a92da4b85e551b9534582c31eecbac0b..e901d31e051b3d579e3dcebdf1e66f161e2a31ba 100644 (file)
@@ -768,8 +768,8 @@ static void ctrl_complete (struct urb *urb)
 
                /* some faults are allowed, not required */
                if (subcase->expected > 0 && (
-                         ((urb->status == -subcase->expected   /* happened */
-                          || urb->status == 0))))              /* didn't */
+                         ((status == -subcase->expected        /* happened */
+                          || status == 0))))                   /* didn't */
                        status = 0;
                /* sometimes more than one fault is allowed */
                else if (subcase->number == 12 && status == -EPIPE)
index 1a60f9c473ada6d7b2506ba015a62c35800c63af..2734fe2b9c43b0443f7ef70b62d886ebe3c785bf 100644 (file)
@@ -111,12 +111,13 @@ static void async_complete(struct urb *urb)
        struct uss720_async_request *rq;
        struct parport *pp;
        struct parport_uss720_private *priv;
+       int status = urb->status;
 
        rq = urb->context;
        priv = rq->priv;
        pp = priv->pp;
-       if (urb->status) {
-               err("async_complete: urb error %d", urb->status);
+       if (status) {
+               err("async_complete: urb error %d", status);
        } else if (rq->dr.bRequest == 3) {
                memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
index 0d3903691e8c4a03a048c0c65e8c064e2ed52a49..b8670905bc3ac858d4e30aa91c2191e4c883c88e 100644 (file)
@@ -2794,16 +2794,14 @@ static void edge_shutdown (struct usb_serial *serial)
 
        dbg ("%s", __FUNCTION__);
 
-       for (i=0; i < serial->num_ports; ++i) {
+       for (i = 0; i < serial->num_ports; ++i) {
                edge_port = usb_get_serial_port_data(serial->port[i]);
                edge_remove_sysfs_attrs(edge_port->port);
-               if (edge_port) {
-                       edge_buf_free(edge_port->ep_out_buf);
-                       kfree(edge_port);
-               }
+               edge_buf_free(edge_port->ep_out_buf);
+               kfree(edge_port);
                usb_set_serial_port_data(serial->port[i], NULL);
        }
-       kfree (usb_get_serial_data(serial));
+       kfree(usb_get_serial_data(serial));
        usb_set_serial_data(serial, NULL);
 }
 
index 231b584f6d0f22b5a5e7c27a91289f2d5619e7d6..01e811becec4659055bc27f02ec2693ac66011d2 100644 (file)
@@ -110,11 +110,6 @@ static void mos7720_interrupt_callback(struct urb *urb)
 
        dbg("%s"," : Entering\n");
 
-       if (!urb) {
-               dbg("%s","Invalid Pointer !!!!:\n");
-               return;
-       }
-
        switch (status) {
        case 0:
                /* success */
index 37f41f576d3d9db9d2fee3ec412c69a0ad4441a4..f76480f1455dfddcf8fb53b5fa851b262bbac247 100644 (file)
@@ -436,11 +436,6 @@ static void mos7840_control_callback(struct urb *urb)
        int result = 0;
        int status = urb->status;
 
-       if (!urb) {
-               dbg("%s", "Invalid Pointer !!!!:\n");
-               return;
-       }
-
        mos7840_port = (struct moschip_port *)urb->context;
 
        switch (status) {
@@ -525,10 +520,6 @@ static void mos7840_interrupt_callback(struct urb *urb)
        int status = urb->status;
 
        dbg("%s", " : Entering\n");
-       if (!urb) {
-               dbg("%s", "Invalid Pointer !!!!:\n");
-               return;
-       }
 
        switch (status) {
        case 0:
@@ -676,11 +667,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)
        struct tty_struct *tty;
        int status = urb->status;
 
-       if (!urb) {
-               dbg("%s", "Invalid Pointer !!!!:\n");
-               return;
-       }
-
        if (status) {
                dbg("nonzero read bulk status received: %d", status);
                return;
@@ -753,11 +739,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
        int status = urb->status;
        int i;
 
-       if (!urb) {
-               dbg("%s", "Invalid Pointer !!!!:\n");
-               return;
-       }
-
        mos7840_port = (struct moschip_port *)urb->context;
        spin_lock(&mos7840_port->pool_lock);
        for (i = 0; i < NUM_URBS; i++) {
index e7db20343d1a156a898fe51e27754d8929a8f890..0794ccdebfd402a94fd4b71c8f661901dc873e56 100644 (file)
@@ -1,7 +1,7 @@
 /*
   USB Driver for Sierra Wireless
 
-  Copyright (C) 2006  Kevin Lloyd <linux@sierrawireless.com>
+  Copyright (C) 2006, 2007  Kevin Lloyd <linux@sierrawireless.com>
 
   IMPORTANT DISCLAIMER: This driver is not commercially supported by
   Sierra Wireless. Use at your own risk.
 
   Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
-
 */
 
-#define DRIVER_VERSION "v.1.0.6"
+#define DRIVER_VERSION "v.1.2.5b"
 #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
+#define SWIMS_USB_REQUEST_SetMode      0x0B
+#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40
+#define SWIMS_USB_INDEX_SetMode                0x0000
+#define SWIMS_SET_MODE_Modem           0x0001
+
+/* per port private data */
+#define N_IN_URB       4
+#define N_OUT_URB      4
+#define IN_BUFLEN      4096
+
+static int debug;
+
+enum devicetype {
+       DEVICE_3_PORT =         0,
+       DEVICE_1_PORT =         1,
+       DEVICE_INSTALLER =      2,
+};
+
+int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
+{
+       int result;
+       dev_dbg(&udev->dev, "%s", "SET POWER STATE");
+       result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       0x00,                   /* __u8 request      */
+                       0x40,                   /* __u8 request type */
+                       swiState,               /* __u16 value       */
+                       0,                      /* __u16 index       */
+                       NULL,                   /* void *data        */
+                       0,                      /* __u16 size        */
+                       USB_CTRL_SET_TIMEOUT);  /* int timeout       */
+       return result;
+}
+
+int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+{
+       int result;
+       dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH");
+       result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       SWIMS_USB_REQUEST_SetMode,      /* __u8 request      */
+                       SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */
+                       eSocMode,                       /* __u16 value       */
+                       SWIMS_USB_INDEX_SetMode,        /* __u16 index       */
+                       NULL,                           /* void *data        */
+                       0,                              /* __u16 size        */
+                       USB_CTRL_SET_TIMEOUT);          /* int timeout       */
+       return result;
+}
+
+int sierra_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+       int result;
+       struct usb_device *udev;
+
+       udev = usb_get_dev(interface_to_usbdev(iface));
+
+       /* Check if in installer mode */
+       if (id->driver_info == DEVICE_INSTALLER) {
+               dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
+               result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+               /*We do not want to bind to the device when in installer mode*/
+               return -EIO;
+       }
+
+       return usb_serial_probe(iface, id);
+}
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
-       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
        { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+       { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+       { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+       { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+       { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+       { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
+       { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
 
-       { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
-       { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+       { USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
+       { USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+
+       { USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
        { }
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -58,35 +132,36 @@ static struct usb_device_id id_table_1port [] = {
 static struct usb_device_id id_table_3port [] = {
        { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
-       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
        { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+       { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/
+
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+       { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+       { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+       { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+       { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+       { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+       { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */
+       { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */
        { }
 };
 
 static struct usb_driver sierra_driver = {
        .name       = "sierra",
-       .probe      = usb_serial_probe,
+       .probe      = sierra_probe,
        .disconnect = usb_serial_disconnect,
        .id_table   = id_table,
        .no_dynamic_id =        1,
 };
 
 
-static int debug;
-
-/* per port private data */
-#define N_IN_URB       4
-#define N_OUT_URB      4
-#define IN_BUFLEN      4096
-
 struct sierra_port_private {
        spinlock_t lock;        /* lock the structure */
        int outstanding_urbs;   /* number of out urbs in flight */
@@ -421,7 +496,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
        int i;
        struct urb *urb;
        int result;
-       __u16 set_mode_dzero = 0x0000;
 
        portdata = usb_get_serial_port_data(port);
 
@@ -457,12 +531,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
 
        port->tty->low_latency = 1;
 
-       /* set mode to D0 */
-       result = usb_control_msg(serial->dev,
-                                usb_rcvctrlpipe(serial->dev, 0),
-                                0x00, 0x40, set_mode_dzero, 0, NULL,
-                                0, USB_CTRL_SET_TIMEOUT);
-
        sierra_send_setup(port);
 
        /* start up the interrupt endpoint if we have one */
@@ -510,6 +578,9 @@ static int sierra_startup(struct usb_serial *serial)
 
        dbg("%s", __FUNCTION__);
 
+       /*Set Device mode to D0 */
+       sierra_set_power_state(serial->dev, 0x0000);
+
        /* Now setup per port private data */
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
index 1628cb258562845e6ad85daa09eb04c5491aa7aa..9a410b5a6e5b06e946cbf3865faa9961b37cd3a6 100644 (file)
  */
 int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-  int ret;
+       int ret;
 
-  if(srb == NULL)
-    return USB_STOR_TRANSPORT_ERROR;
+       if (srb == NULL)
+               return USB_STOR_TRANSPORT_ERROR;
 
-  US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+       US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
 
-  switch(srb->device->lun) {
-  case 0:
+       switch (srb->device->lun) {
+               case 0:
 
-    /*
-     * LUN 0 corresponds to the CompactFlash card reader.
-     */
-    ret = usb_stor_CB_transport(srb, us);
-    break;
+                       /*
+                        * LUN 0 corresponds to the CompactFlash card reader.
+                        */
+                       ret = usb_stor_CB_transport(srb, us);
+                       break;
 
 #ifdef CONFIG_USB_STORAGE_SDDR09
-  case 1:
+               case 1:
 
-    /*
-     * LUN 1 corresponds to the SmartMedia card reader.
-     */
+                       /*
+                        * LUN 1 corresponds to the SmartMedia card reader.
+                        */
 
-    /*
-     * Set the LUN to 0 (just in case).
-     */
-    srb->device->lun = 0; us->srb->device->lun = 0;
-    ret = sddr09_transport(srb, us);
-    srb->device->lun = 1; us->srb->device->lun = 1;
-    break;
+                       /*
+                        * Set the LUN to 0 (just in case).
+                        */
+                       srb->device->lun = 0; us->srb->device->lun = 0;
+                       ret = sddr09_transport(srb, us);
+                       srb->device->lun = 1; us->srb->device->lun = 1;
+                       break;
 
 #endif
 
-  default:
-    US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
-    ret = USB_STOR_TRANSPORT_ERROR;
-    break;
-  }
-  return ret;
+               default:
+                       US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
+                       ret = USB_STOR_TRANSPORT_ERROR;
+                       break;
+       }
+       return ret;
 }
index d35369392feda4b8939e5a47f91da758b95f2743..dfd42fe9e5f0567d27e009f5514ab5a70d742b97 100644 (file)
@@ -57,9 +57,10 @@ static void usb_onetouch_irq(struct urb *urb)
        struct usb_onetouch *onetouch = urb->context;
        signed char *data = onetouch->data;
        struct input_dev *dev = onetouch->dev;
-       int status;
+       int status = urb->status;
+       int retval;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:                 /* success */
                break;
        case -ECONNRESET:       /* unlink */
@@ -75,11 +76,11 @@ static void usb_onetouch_irq(struct urb *urb)
        input_sync(dev);
 
 resubmit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
-       if (status)
-               err ("can't resubmit intr, %s-%s/input0, status %d",
+       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       if (retval)
+               err ("can't resubmit intr, %s-%s/input0, retval %d",
                        onetouch->udev->bus->bus_name,
-                       onetouch->udev->devpath, status);
+                       onetouch->udev->devpath, retval);
 }
 
 static int usb_onetouch_open(struct input_dev *dev)
index b6bf31a97b60d46bff07725cc7eec98b1a5e7c65..a624e72f81dc39a41bf79236d0f24707251b7c41 100644 (file)
@@ -313,6 +313,13 @@ UNUSUAL_DEV(  0x04b0, 0x0301, 0x0010, 0x0010,
                US_SC_DEVICE, US_PR_DEVICE,NULL,
                US_FL_NOT_LOCKABLE ),
 
+/* Reported by Stefan de Konink <skinkie@xs4all.nl> */
+UNUSUAL_DEV(  0x04b0, 0x0401, 0x0200, 0x0200,
+               "NIKON",
+               "NIKON DSC D100",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_FIX_CAPACITY),
+
 /* Reported by Andreas Bockhold <andreas@bockionline.de> */
 UNUSUAL_DEV(  0x04b0, 0x0405, 0x0100, 0x0100,
                "NIKON",
@@ -1384,6 +1391,17 @@ UNUSUAL_DEV(  0x1019, 0x0c55, 0x0000, 0x0110,
                US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
                0 ),
 
+/* Reported by Kevin Lloyd <linux@sierrawireless.com>
+ * Entry is needed for the initializer function override,
+ * which instructs the device to load as a modem
+ * device.
+ */
+UNUSUAL_DEV(  0x1199, 0x0fff, 0x0000, 0x9999,
+               "Sierra Wireless",
+               "USB MMC Storage",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               US_FL_IGNORE_DEVICE),
+
 /* Reported by Jaco Kroon <jaco@kroon.co.za>
  * The usb-storage module found on the Digitech GNX4 (and supposedly other
  * devices) misbehaves and causes a bunch of invalid I/O errors.
index 0c7bf75732ea8d8a3e29c087288593baeb2318f9..13990697b5c12a76e41cd31fdc37873bebcbc2d5 100644 (file)
@@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
        int node, len, i, j, ret;
        u32 mem, chip_id;
 
-       /* Do not attach when we have a serial console. */
-       if (!con_is_present())
-               return -ENXIO;
-
        /*
         * Map memory-mapped registers.
         */
index e9bbc3455c94d5ff8c02b7f05cdbd24df46f22be..1b3f6586bc9f433295ccee5bf5c32d5868e6d461 100644 (file)
@@ -174,7 +174,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
        struct cr_panel *crp;
        u8 dev_en;
 
-       crp = kzalloc(sizeof(crp), GFP_KERNEL);
+       crp = kzalloc(sizeof(*crp), GFP_KERNEL);
        if (crp == NULL)
                return -ENOMEM;
 
index eb1a4812ad1d27b471dd61bcfbaac5ba54b2630d..b87ea21d3d78480faeca4bdc5f06d71aea4fe2b6 100644 (file)
@@ -379,10 +379,6 @@ int __init igafb_init(void)
        if (fb_get_options("igafb", NULL))
                return -ENODEV;
 
-        /* Do not attach when we have a serial console. */
-        if (!con_is_present())
-                return -ENXIO;
-
         pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
                                PCI_DEVICE_ID_INTERG_1682, 0);
        if (pdev == NULL) {
index 1b36f45076ade8a365661120baf7741c2e3cef2b..8ccee9ee1d9d0dbfb66f851ed0f50ae811c3f354 100644 (file)
@@ -792,6 +792,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
 {
        struct msghdr msg;
        struct iovec iov[1];
+       int n;
 
        _enter("");
 
@@ -806,22 +807,20 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
        msg.msg_flags           = 0;
 
        call->state = AFS_CALL_AWAIT_ACK;
-       switch (rxrpc_kernel_send_data(call->rxcall, &msg, len)) {
-       case 0:
+       n = rxrpc_kernel_send_data(call->rxcall, &msg, len);
+       if (n >= 0) {
                _leave(" [replied]");
                return;
-
-       case -ENOMEM:
+       }
+       if (n == -ENOMEM) {
                _debug("oom");
                rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT);
-       default:
-               rxrpc_kernel_end_call(call->rxcall);
-               call->rxcall = NULL;
-               call->type->destructor(call);
-               afs_free_call(call);
-               _leave(" [error]");
-               return;
        }
+       rxrpc_kernel_end_call(call->rxcall);
+       call->rxcall = NULL;
+       call->type->destructor(call);
+       afs_free_call(call);
+       _leave(" [error]");
 }
 
 /*
index 02ebb1f1d3b0e2fa70298d21dbb1b88d4471a65d..0e5ec371ce727e8fcccd79d33108b9aca1f051ca 100644 (file)
@@ -2221,7 +2221,7 @@ block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
        lock_page(page);
        size = i_size_read(inode);
        if ((page->mapping != inode->i_mapping) ||
-           ((page->index << PAGE_CACHE_SHIFT) > size)) {
+           (page_offset(page) > size)) {
                /* page got truncated out from underneath us */
                goto out_unlock;
        }
index 7d5a43cb0d5c81ee470ee8ec9f7a7cabc329b7e7..e4ab7bc14efede18f657dc477d1c92137bc37e27 100644 (file)
@@ -409,8 +409,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
        if (!PageUptodate(page))
                rc = ecryptfs_do_readpage(file, page, page->index);
        if (page->index != 0) {
-               loff_t end_of_prev_pg_pos =
-                       (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1);
+               loff_t end_of_prev_pg_pos = page_offset(page) - 1;
 
                if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) {
                        rc = ecryptfs_truncate(file->f_path.dentry,
@@ -736,7 +735,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
                goto out;
        }
        inode->i_blocks = lower_inode->i_blocks;
-       pos = (page->index << PAGE_CACHE_SHIFT) + to;
+       pos = page_offset(page) + to;
        if (pos > i_size_read(inode)) {
                i_size_write(inode, pos);
                ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
index ee64749e2eebd55bb1c8ea95d19cfb30a447e0ea..98756156d29878b8df182497214b9640d45ac79d 100644 (file)
@@ -89,7 +89,7 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
 {
        int ret;
        struct address_space *mapping = inode->i_mapping;
-       loff_t pos = page->index << PAGE_CACHE_SHIFT;
+       loff_t pos = page_offset(page);
        unsigned int len = PAGE_CACHE_SIZE;
        pgoff_t last_index;
        struct page *locked_page = NULL;
index 22496d2a73fa1ab5efe6f663cfc1a92a9a316543..0a09732180847ce6cb7d67f91477c2314296003a 100644 (file)
@@ -594,7 +594,7 @@ find_page:
                ret = add_to_page_cache_lru(page, mapping, index,
                                            GFP_KERNEL);
                if (unlikely(ret))
-                       goto out;
+                       goto out_release;
        }
 
        ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len);
@@ -650,8 +650,9 @@ find_page:
         */
        mark_page_accessed(page);
 out:
-       page_cache_release(page);
        unlock_page(page);
+out_release:
+       page_cache_release(page);
 out_ret:
        return ret;
 }
index c054d7a9aaa771cfb5743052c76fdca953b4aa69..efa1b8f7251d9f12eeab86432eae8aac919b6646 100644 (file)
@@ -90,13 +90,27 @@ enum {
 extern __u8 isa_irq_to_vector_map[16];
 #define isa_irq_to_vector(x)   isa_irq_to_vector_map[(x)]
 
+struct irq_cfg {
+       ia64_vector vector;
+       cpumask_t domain;
+};
+extern spinlock_t vector_lock;
+extern struct irq_cfg irq_cfg[NR_IRQS];
+#define irq_to_domain(x)       irq_cfg[(x)].domain
+DECLARE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq);
+
 extern struct hw_interrupt_type irq_type_ia64_lsapic;  /* CPU-internal interrupt controller */
 
+extern int bind_irq_vector(int irq, int vector, cpumask_t domain);
 extern int assign_irq_vector (int irq);        /* allocate a free vector */
 extern void free_irq_vector (int vector);
 extern int reserve_irq_vector (int vector);
+extern void __setup_vector_irq(int cpu);
+extern int reassign_irq_vector(int irq, int cpu);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
 extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
+extern int check_irq_used (int irq);
+extern void destroy_and_reserve_irq (unsigned int irq);
 
 static inline void ia64_resend_irq(unsigned int vector)
 {
@@ -113,7 +127,7 @@ extern irq_desc_t irq_desc[NR_IRQS];
 static inline unsigned int
 __ia64_local_vector_to_irq (ia64_vector vec)
 {
-       return (unsigned int) vec;
+       return __get_cpu_var(vector_irq)[vec];
 }
 #endif
 
@@ -131,7 +145,7 @@ __ia64_local_vector_to_irq (ia64_vector vec)
 static inline ia64_vector
 irq_to_vector (int irq)
 {
-       return (ia64_vector) irq;
+       return irq_cfg[irq].vector;
 }
 
 /*
index 421cb6b62a7c1455c1cd0de701bdfcc289e7fc90..b8f712859140504c7c3cff48f518a0f7fd7d8014 100644 (file)
 #define        IOSAPIC_MASK_SHIFT              16
 #define        IOSAPIC_MASK                    (1<<IOSAPIC_MASK_SHIFT)
 
+#define IOSAPIC_VECTOR_MASK            0xffffff00
+
 #ifndef __ASSEMBLY__
 
 #ifdef CONFIG_IOSAPIC
 
 #define NR_IOSAPICS                    256
 
-static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
+static inline unsigned int __iosapic_read(char __iomem *iosapic, unsigned int reg)
 {
        writel(reg, iosapic + IOSAPIC_REG_SELECT);
        return readl(iosapic + IOSAPIC_WINDOW);
 }
 
-static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
+static inline void __iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
 {
        writel(reg, iosapic + IOSAPIC_REG_SELECT);
        writel(val, iosapic + IOSAPIC_WINDOW);
index 67221615e3173537ac8df7b4ba6de436dd97db3c..35b360b82e43f9958d0f967347fcb2052a618578 100644 (file)
 #include <linux/types.h>
 #include <linux/cpumask.h>
 
-#define NR_IRQS                256
-#define NR_IRQ_VECTORS NR_IRQS
+#define NR_VECTORS     256
+
+#if (NR_VECTORS + 32 * NR_CPUS) < 1024
+#define NR_IRQS (NR_VECTORS + 32 * NR_CPUS)
+#else
+#define NR_IRQS 1024
+#endif
 
 static __inline__ int
 irq_canonicalize (int irq)
index 2d1640cc240a72adae31ec3033bbbdce37f96eb8..8aba06a7b0389cca8401c20a04029b3ec4ad454b 100644 (file)
 #ifndef _ASM_IA64_RWSEM_H
 #define _ASM_IA64_RWSEM_H
 
+#ifndef _LINUX_RWSEM_H
+#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
+#endif
+
 #include <linux/list.h>
 #include <linux/spinlock.h>
 
index 441c9e0017762b0133c8a2e017e62596b2b8e11a..315f8de950a23a48cbc765b660d610d9ebd8725f 100644 (file)
 #define __NR_sync_file_range           1300
 #define __NR_tee                       1301
 #define __NR_vmsplice                  1302
-/* 1303 reserved for move_pages */
+#define __NR_fallocate                 1303
 #define __NR_getcpu                    1304
 #define __NR_epoll_pwait               1305
 #define __NR_utimensat                 1306
index 5e0fcf41804d634a02b9d0d2d53122680b6ecef0..47bb9cf107b7aa4cf1b8935d3a451eb2f5d20313 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/raw_io.h>
 #include <asm/virtconvert.h>
 
+#include <asm-generic/iomap.h>
 
 #ifdef CONFIG_ATARI
 #include <asm/atarihw.h>
@@ -152,6 +153,16 @@ static inline u16 __iomem *isa_itw(unsigned long addr)
     default: return NULL; /* avoid warnings, just in case */
     }
 }
+static inline u32 __iomem *isa_itl(unsigned long addr)
+{
+  switch(ISA_TYPE)
+    {
+#ifdef CONFIG_AMIGA_PCMCIA
+    case AG_ISA: return (u32 __iomem *)AG_ISA_IO_W(addr);
+#endif
+    default: return 0; /* avoid warnings, just in case */
+    }
+}
 static inline u8 __iomem *isa_mtb(unsigned long addr)
 {
   switch(ISA_TYPE)
@@ -188,8 +199,10 @@ static inline u16 __iomem *isa_mtw(unsigned long addr)
 
 #define isa_inb(port)      in_8(isa_itb(port))
 #define isa_inw(port)      (ISA_SEX ? in_be16(isa_itw(port)) : in_le16(isa_itw(port)))
+#define isa_inl(port)      (ISA_SEX ? in_be32(isa_itl(port)) : in_le32(isa_itl(port)))
 #define isa_outb(val,port) out_8(isa_itb(port),(val))
 #define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val)))
+#define isa_outl(val,port) (ISA_SEX ? out_be32(isa_itl(port),(val)) : out_le32(isa_itl(port),(val)))
 
 #define isa_readb(p)       in_8(isa_mtb((unsigned long)(p)))
 #define isa_readw(p)       \
@@ -234,6 +247,15 @@ static inline void isa_delay(void)
 #define isa_outsw(port, buf, nr)    \
        (ISA_SEX ? raw_outsw(isa_itw(port), (u16 *)(buf), (nr)) :  \
                   raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
+
+#define isa_insl(port, buf, nr)     \
+       (ISA_SEX ? raw_insl(isa_itl(port), (u32 *)(buf), (nr)) :    \
+                  raw_insw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
+
+#define isa_outsl(port, buf, nr)    \
+       (ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) :  \
+                  raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
+
 #endif  /* CONFIG_ISA */
 
 
@@ -246,14 +268,16 @@ static inline void isa_delay(void)
 #define inw_p   isa_inw_p
 #define outw    isa_outw
 #define outw_p  isa_outw_p
-#define inl     isa_inw
-#define inl_p   isa_inw_p
-#define outl    isa_outw
-#define outl_p  isa_outw_p
+#define inl     isa_inl
+#define inl_p   isa_inl_p
+#define outl    isa_outl
+#define outl_p  isa_outl_p
 #define insb    isa_insb
 #define insw    isa_insw
+#define insl    isa_insl
 #define outsb   isa_outsb
 #define outsw   isa_outsw
+#define outsl   isa_outsl
 #define readb   isa_readb
 #define readw   isa_readw
 #define writeb  isa_writeb
@@ -262,8 +286,6 @@ static inline void isa_delay(void)
 
 #if defined(CONFIG_PCI)
 
-#define inl(port)        in_le32(port)
-#define outl(val,port)   out_le32((port),(val))
 #define readl(addr)      in_le32(addr)
 #define writel(val,addr) out_le32((addr),(val))
 
@@ -282,6 +304,8 @@ static inline void isa_delay(void)
 #define outb(val,port) out_8((port),(val))
 #define inw(port)      in_le16(port)
 #define outw(val,port) out_le16((port),(val))
+#define inl(port)      in_le32(port)
+#define outl(val,port) out_le32((port),(val))
 
 #else
 /*
@@ -306,20 +330,35 @@ static inline void isa_delay(void)
 #endif
 #endif /* CONFIG_PCI */
 
-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && defined(CONFIG_HP300)
+#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI)
 /*
- * We need to define dummy functions otherwise drivers/serial/8250.c doesn't link
+ * We need to define dummy functions for GENERIC_IOMAP support.
  */
-#define inb(port)        0xff
-#define inb_p(port)      0xff
-#define outb(val,port)   do { } while (0)
-#define outb_p(val,port) do { } while (0)
+#define inb(port)          0xff
+#define inb_p(port)        0xff
+#define outb(val,port)     ((void)0)
+#define outb_p(val,port)   ((void)0)
+#define inw(port)          0xffff
+#define outw(val,port)     ((void)0)
+#define inl(port)          0xffffffffUL
+#define outl(val,port)     ((void)0)
+
+#define insb(port,buf,nr)  ((void)0)
+#define outsb(port,buf,nr) ((void)0)
+#define insw(port,buf,nr)  ((void)0)
+#define outsw(port,buf,nr) ((void)0)
+#define insl(port,buf,nr)  ((void)0)
+#define outsl(port,buf,nr) ((void)0)
 
 /*
  * These should be valid on any ioremap()ed region
  */
 #define readb(addr)      in_8(addr)
 #define writeb(val,addr) out_8((addr),(val))
+#define readw(addr)      in_le16(addr)
+#define writew(val,addr) out_le16((addr),(val))
+#endif
+#if !defined(CONFIG_PCI)
 #define readl(addr)      in_le32(addr)
 #define writel(val,addr) out_le32((addr),(val))
 #endif
@@ -351,6 +390,18 @@ extern void dma_cache_wback_inv(unsigned long start, unsigned long size);
 extern void dma_cache_wback(unsigned long start, unsigned long size);
 extern void dma_cache_inv(unsigned long start, unsigned long size);
 
+static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count)
+{
+       __builtin_memset((void __force *) addr, val, count);
+}
+static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
+{
+       __builtin_memcpy(dst, (void __force *) src, count);
+}
+static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int count)
+{
+       __builtin_memcpy((void __force *) dst, src, count);
+}
 
 #ifndef CONFIG_SUN3
 #define IO_SPACE_LIMIT 0xffff
index 811ccd25d4a6dc9f9a6b7c5890f658f349ed46d4..91c623f0994c958f5fdef6f646314640df10029e 100644 (file)
@@ -49,10 +49,16 @@ extern void __iounmap(void *addr, unsigned long size);
 #define raw_inb in_8
 #define raw_inw in_be16
 #define raw_inl in_be32
+#define __raw_readb in_8
+#define __raw_readw in_be16
+#define __raw_readl in_be32
 
 #define raw_outb(val,port) out_8((port),(val))
 #define raw_outw(val,port) out_be16((port),(val))
 #define raw_outl(val,port) out_be32((port),(val))
+#define __raw_writeb(val,addr) out_8((addr),(val))
+#define __raw_writew(val,addr) out_be16((addr),(val))
+#define __raw_writel(val,addr) out_be32((addr),(val))
 
 static inline void raw_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len)
 {
@@ -336,8 +342,6 @@ static inline void raw_outsw_swapw(volatile u16 __iomem *port, const u16 *buf,
                : "d0", "a0", "a1", "d6");
 }
 
-#define __raw_writel raw_outl
-
 #endif /* __KERNEL__ */
 
 #endif /* _RAW_IO_H */
index 1b60624dab7e4aacca7518818aeaf2c6214baa33..7d8003769a44d28a5d4b8f330d70068ecd69210d 100644 (file)
@@ -138,7 +138,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -181,7 +181,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -190,7 +190,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -233,7 +233,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -250,7 +250,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -302,7 +302,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -519,7 +519,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -562,7 +562,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -571,7 +571,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -614,7 +614,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -631,7 +631,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
 {
        unsigned long result;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (cpu_has_llsc && R10000_LLSC_WAR) {
                unsigned long temp;
@@ -683,7 +683,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return result;
 }
@@ -791,10 +791,11 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
  * atomic*_return operations are serializing but not the non-*_return
  * versions.
  */
-#define smp_mb__before_atomic_dec()    smp_mb()
-#define smp_mb__after_atomic_dec()     smp_mb()
-#define smp_mb__before_atomic_inc()    smp_mb()
-#define smp_mb__after_atomic_inc()     smp_mb()
+#define smp_mb__before_atomic_dec()    smp_llsc_mb()
+#define smp_mb__after_atomic_dec()     smp_llsc_mb()
+#define smp_mb__before_atomic_inc()    smp_llsc_mb()
+#define smp_mb__after_atomic_inc()     smp_llsc_mb()
 
 #include <asm-generic/atomic.h>
+
 #endif /* _ASM_ATOMIC_H */
index ed82631b0017256747e798e5b69350269576f05b..9d8cfbb5e7967c97d2f03bc79ac430335260d962 100644 (file)
 #else
 #define __WEAK_ORDERING_MB     "               \n"
 #endif
+#if defined(CONFIG_WEAK_REORDERING_BEYOND_LLSC) && defined(CONFIG_SMP)
+#define __WEAK_LLSC_MB         "       sync    \n"
+#else
+#define __WEAK_LLSC_MB         "               \n"
+#endif
 
 #define smp_mb()       __asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
 #define smp_rmb()      __asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
 #define set_mb(var, value) \
        do { var = value; smp_mb(); } while (0)
 
+#define smp_llsc_mb()  __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+#define smp_llsc_rmb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+#define smp_llsc_wmb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+
 #endif /* __ASM_BARRIER_H */
index d9e81af53f78b3f1528cd3ed27b165fca5cf0e61..148bc79557f12b94f22b4669d7a3a6d344f24b12 100644 (file)
@@ -38,8 +38,8 @@
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
-#define smp_mb__before_clear_bit()     smp_mb()
-#define smp_mb__after_clear_bit()      smp_mb()
+#define smp_mb__before_clear_bit()     smp_llsc_mb()
+#define smp_mb__after_clear_bit()      smp_llsc_mb()
 
 /*
  * set_bit - Atomically set a bit in memory
@@ -289,7 +289,7 @@ static inline int test_and_set_bit(unsigned long nr,
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return res != 0;
 }
@@ -377,7 +377,7 @@ static inline int test_and_clear_bit(unsigned long nr,
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return res != 0;
 }
@@ -445,7 +445,7 @@ static inline int test_and_change_bit(unsigned long nr,
                raw_local_irq_restore(flags);
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return res != 0;
 }
diff --git a/include/asm-mips/ds1216.h b/include/asm-mips/ds1216.h
deleted file mode 100644 (file)
index 1ff8b73..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _DS1216_H
-#define _DS1216_H
-
-extern volatile unsigned char *ds1216_base;
-unsigned long ds1216_get_cmos_time(void);
-int ds1216_set_rtc_mmss(unsigned long nowtime);
-
-#define DS1216_SEC_BYTE                1
-#define DS1216_MIN_BYTE                2
-#define DS1216_HOUR_BYTE       3
-#define DS1216_HOUR_MASK       (0x1f)
-#define DS1216_AMPM_MASK       (1<<5)
-#define DS1216_1224_MASK       (1<<7)
-#define DS1216_DAY_BYTE                4
-#define DS1216_DAY_MASK                (0x7)
-#define DS1216_DATE_BYTE       5
-#define DS1216_DATE_MASK       (0x3f)
-#define DS1216_MONTH_BYTE      6
-#define DS1216_MONTH_MASK      (0x1f)
-#define DS1216_YEAR_BYTE       7
-
-#define DS1216_SEC(buf)                (buf[DS1216_SEC_BYTE])
-#define DS1216_MIN(buf)                (buf[DS1216_MIN_BYTE])
-#define DS1216_HOUR(buf)       (buf[DS1216_HOUR_BYTE] & DS1216_HOUR_MASK)
-#define DS1216_AMPM(buf)       (buf[DS1216_HOUR_BYTE] & DS1216_AMPM_MASK)
-#define DS1216_1224(buf)       (buf[DS1216_HOUR_BYTE] & DS1216_1224_MASK)
-#define DS1216_DATE(buf)       (buf[DS1216_DATE_BYTE] & DS1216_DATE_MASK)
-#define DS1216_MONTH(buf)      (buf[DS1216_MONTH_BYTE] & DS1216_MONTH_MASK)
-#define DS1216_YEAR(buf)       (buf[DS1216_YEAR_BYTE])
-
-#endif
index 47e5679c235303f5812eb1d4cd39a2140af89016..b623882bce192287e76d8cf7a59d42f710d8deef 100644 (file)
@@ -29,7 +29,7 @@
                "       .set    mips3                           \n"     \
                "2:     sc      $1, %2                          \n"     \
                "       beqzl   $1, 1b                          \n"     \
-               __WEAK_ORDERING_MB                                      \
+               __WEAK_LLSC_MB                                          \
                "3:                                             \n"     \
                "       .set    pop                             \n"     \
                "       .set    mips0                           \n"     \
@@ -55,7 +55,7 @@
                "       .set    mips3                           \n"     \
                "2:     sc      $1, %2                          \n"     \
                "       beqz    $1, 1b                          \n"     \
-               __WEAK_ORDERING_MB                                      \
+               __WEAK_LLSC_MB                                          \
                "3:                                             \n"     \
                "       .set    pop                             \n"     \
                "       .set    mips0                           \n"     \
@@ -152,7 +152,7 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
                "       .set    mips3                                   \n"
                "2:     sc      $1, %1                                  \n"
                "       beqzl   $1, 1b                                  \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "3:                                                     \n"
                "       .set    pop                                     \n"
                "       .section .fixup,\"ax\"                          \n"
@@ -179,7 +179,7 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
                "       .set    mips3                                   \n"
                "2:     sc      $1, %1                                  \n"
                "       beqz    $1, 1b                                  \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "3:                                                     \n"
                "       .set    pop                                     \n"
                "       .section .fixup,\"ax\"                          \n"
diff --git a/include/asm-mips/gfx.h b/include/asm-mips/gfx.h
deleted file mode 100644 (file)
index 37235e4..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.
- *
- * This is the user-visible SGI GFX interface.
- *
- * This must be used verbatim into the GNU libc.  It does not include
- * any kernel-only bits on it.
- *
- * miguel@nuclecu.unam.mx
- */
-#ifndef _ASM_GFX_H
-#define _ASM_GFX_H
-
-/* The iocls, yes, they do not make sense, but such is life */
-#define GFX_BASE             100
-#define GFX_GETNUM_BOARDS    (GFX_BASE + 1)
-#define GFX_GETBOARD_INFO    (GFX_BASE + 2)
-#define GFX_ATTACH_BOARD     (GFX_BASE + 3)
-#define GFX_DETACH_BOARD     (GFX_BASE + 4)
-#define GFX_IS_MANAGED       (GFX_BASE + 5)
-
-#define GFX_MAPALL           (GFX_BASE + 10)
-#define GFX_LABEL            (GFX_BASE + 11)
-
-#define GFX_INFO_NAME_SIZE  16
-#define GFX_INFO_LABEL_SIZE 16
-
-struct gfx_info {
-       char name  [GFX_INFO_NAME_SIZE];  /* board name */
-       char label [GFX_INFO_LABEL_SIZE]; /* label name */
-       unsigned short int xpmax, ypmax;  /* screen resolution */
-       unsigned int lenght;              /* size of a complete gfx_info for this board */
-};
-
-struct gfx_getboardinfo_args {
-       unsigned int board;     /* board number.  starting from zero */
-       void *buf;              /* pointer to gfx_info */
-       unsigned int len;       /* buffer size of buf */
-};
-
-struct gfx_attach_board_args {
-       unsigned int board;     /* board number, starting from zero */
-       void        *vaddr;     /* address where the board registers should be mapped */
-};
-
-#ifdef __KERNEL__
-/* umap.c */
-extern void remove_mapping (struct vm_area_struct *vma, struct task_struct *, unsigned long, unsigned long);
-extern void *vmalloc_uncached (unsigned long size);
-extern int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr);
-#endif
-
-#endif /* _ASM_GFX_H */
index c6dfa59d1986d95da18d3b9a88c3c3716f4ffb27..d38f069d9e9544fbaa61825e8e457a1734b736a0 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2006, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_COBALT_CPU_FEATURE_OVERRIDES_H
 #define __ASM_COBALT_CPU_FEATURE_OVERRIDES_H
@@ -46,6 +46,8 @@
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_icache_snoops_remote_store 0
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_mips32r1       0
 #define cpu_has_mips32r2       0
index 0d31854222f90a96af8c860c7a74d38c340848bc..07f4322c235d5b2147f2c606ccbbb115d05b5df5 100644 (file)
@@ -4,6 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2004 Thomas Koeller <thomas.koeller@baslerweb.com>
+ * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H
@@ -27,6 +28,8 @@
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
 #define cpu_icache_snoops_remote_store 0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
index f7c5dc8a5336663c3b2fe1f3443e3ace396a5f40..9c8735158da1b011875df9af9a02f9e5e9648b4d 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
  */
 #ifndef __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
@@ -30,6 +30,8 @@
 #define cpu_has_ic_fills_f_dc  0
 
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
index a071974b67bb7e8f69f3492a8f881462151a4e7d..fe076380c1891175549b62b180dea3dba1aaf122 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
  */
 #ifndef __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
@@ -27,6 +27,8 @@
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
 #define cpu_icache_snoops_remote_store 1
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
index 2a3de092bf130af48835c4a14f21a2b71f068159..6782fccebe8da2f473f2e3176f46ec61497771d8 100644 (file)
@@ -4,7 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2005 Ilya A. Volynets-Evenbakh
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2005, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
@@ -38,6 +38,8 @@
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
 #define cpu_has_4k_cache       1
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 
 #define cpu_has_mips32r1       0
index 529445dacedb7283f44b3430ebdfb27602a76da2..d2daaed235d57dbb3f262f70309d470f3cbfd2de 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
  */
 #ifndef __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
@@ -24,6 +24,7 @@
 #define cpu_has_ic_fills_f_dc  0
 
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
 
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         0
index 7e07283140a3e04f70e7b583f2bb938ab5d6ea5e..ccf5433635376aa1197be4b769516c940736e083 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
  *
  * SNI RM200 C apparently was only shipped with R4600 V2.0 and R5000 processors.
  */
@@ -32,6 +32,8 @@
 #define cpu_has_dsp            0
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 
 #define cpu_has_mips32r1       0
 #define cpu_has_mips32r2       0
index a25968f277a2ff0b82dff1b1198baf280aa47428..63d5bf649af1c6aeefa0b5ba9df5cce064629a04 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
@@ -26,6 +26,8 @@
 #define cpu_has_dc_aliases     0
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 #define cpu_icache_snoops_remote_store 0
 
 #define cpu_has_nofpuex                0
index 42cebb7ce7a630d9c18f725a3b7692f237c87b53..470e5e9e10d659b830ea934f52941bee527d63b2 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
  */
 #ifndef __ASM_MACH_YOSEMITE_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_YOSEMITE_CPU_FEATURE_OVERRIDES_H
@@ -26,6 +26,8 @@
 #define cpu_has_dc_aliases     0
 #define cpu_has_ic_fills_f_dc  0
 #define cpu_has_dsp            0
+#define cpu_has_mipsmt         0
+#define cpu_has_userlocal      0
 #define cpu_icache_snoops_remote_store 0
 
 #define cpu_has_nofpuex                0
index 35e431cd796bf499bccfc2d6ef4bd76ad578009e..bb897016c491a24e8369d461a50a59a892457154 100644 (file)
@@ -67,7 +67,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
                : "memory");
        }
 
-       smp_mb();
+       smp_llsc_mb();
 }
 
 static inline void __raw_spin_unlock(raw_spinlock_t *lock)
@@ -118,7 +118,7 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
                : "memory");
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return res == 0;
 }
@@ -183,7 +183,7 @@ static inline void __raw_read_lock(raw_rwlock_t *rw)
                : "memory");
        }
 
-       smp_mb();
+       smp_llsc_mb();
 }
 
 /* Note the use of sub, not subu which will make the kernel die with an
@@ -193,7 +193,7 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw)
 {
        unsigned int tmp;
 
-       smp_mb();
+       smp_llsc_mb();
 
        if (R10000_LLSC_WAR) {
                __asm__ __volatile__(
@@ -262,7 +262,7 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
                : "memory");
        }
 
-       smp_mb();
+       smp_llsc_mb();
 }
 
 static inline void __raw_write_unlock(raw_rwlock_t *rw)
@@ -293,7 +293,7 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
                "       .set    reorder                                 \n"
                "       beqzl   %1, 1b                                  \n"
                "        nop                                            \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "       li      %2, 1                                   \n"
                "2:                                                     \n"
                : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
@@ -310,7 +310,7 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
                "       beqz    %1, 1b                                  \n"
                "        nop                                            \n"
                "       .set    reorder                                 \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "       li      %2, 1                                   \n"
                "2:                                                     \n"
                : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
@@ -336,7 +336,7 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
                "       sc      %1, %0                                  \n"
                "       beqzl   %1, 1b                                  \n"
                "        nop                                            \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "       li      %2, 1                                   \n"
                "       .set    reorder                                 \n"
                "2:                                                     \n"
@@ -354,7 +354,7 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
                "       beqz    %1, 3f                                  \n"
                "        li     %2, 1                                   \n"
                "2:                                                     \n"
-               __WEAK_ORDERING_MB
+               __WEAK_LLSC_MB
                "       .subsection 2                                   \n"
                "3:     b       1b                                      \n"
                "        li     %2, 0                                   \n"
index 76339165bc20e90e84089f8da7fb795f9b9b00c2..8d0b1cd4a45e837989ced15e273b1aef9efb9db9 100644 (file)
@@ -117,7 +117,7 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
                raw_local_irq_restore(flags);   /* implies memory barrier  */
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return retval;
 }
@@ -165,7 +165,7 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
                raw_local_irq_restore(flags);   /* implies memory barrier  */
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return retval;
 }
@@ -246,7 +246,7 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
                raw_local_irq_restore(flags);   /* implies memory barrier  */
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return retval;
 }
@@ -352,7 +352,7 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
                raw_local_irq_restore(flags);   /* implies memory barrier  */
        }
 
-       smp_mb();
+       smp_llsc_mb();
 
        return retval;
 }
@@ -470,6 +470,6 @@ extern int stop_a_enabled;
  */
 #define __ARCH_WANT_UNLOCKED_CTXSW
 
-#define arch_align_stack(x) (x)
+extern unsigned long arch_align_stack(unsigned long sp);
 
 #endif /* _ASM_SYSTEM_H */
index e9af49eb1aa85060bc63f5773bf9a5bd8bde32db..ec2a8a2c737c81d09b0d9c7fd3f34623669e0169 100644 (file)
@@ -3,14 +3,12 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
-#include <linux/mod_devicetable.h>
-#include <asm/prom.h>
-
+#include <linux/of.h>
 
 /*
  * The of_device is a kind of "base class" that is a superset of
  * struct device for use by devices attached to an OF node and
- * probed using OF properties
+ * probed using OF properties.
  */
 struct of_device
 {
@@ -18,24 +16,14 @@ struct of_device
        u64                     dma_mask;       /* DMA mask */
        struct device           dev;            /* Generic device interface */
 };
-#define        to_of_device(d) container_of(d, struct of_device, dev)
-
-extern const struct of_device_id *of_match_node(
-       const struct of_device_id *matches, const struct device_node *node);
-extern const struct of_device_id *of_match_device(
-       const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern void of_release_dev(struct device *dev);
 
 extern ssize_t of_device_get_modalias(struct of_device *ofdev,
                                        char *str, ssize_t len);
 extern int of_device_uevent(struct device *dev,
        char **envp, int num_envp, char *buffer, int buffer_size);
 
+/* This is just here during the transition */
+#include <linux/of_device.h>
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_OF_DEVICE_H */
index 217eafb167e900a0c2b43210e97a87d767c64fda..80e6fad28b4fdb7762d93cef14296c59b875a149 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef _ASM_POWERPC_OF_PLATFORM_H
+#define _ASM_POWERPC_OF_PLATFORM_H
 /*
  *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
  *                      <benh@kernel.crashing.org>
@@ -9,37 +11,8 @@
  *
  */
 
-#include <asm/of_device.h>
-
-/*
- * The of_platform_bus_type is a bus type used by drivers that do not
- * attach to a macio or similar bus but still use OF probing
- * mechanism
- */
-extern struct bus_type of_platform_bus_type;
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the "platform bus" (of_platform_bus_type)
- */
-struct of_platform_driver
-{
-       char                    *name;
-       struct of_device_id     *match_table;
-       struct module           *owner;
-
-       int     (*probe)(struct of_device* dev,
-                        const struct of_device_id *match);
-       int     (*remove)(struct of_device* dev);
-
-       int     (*suspend)(struct of_device* dev, pm_message_t state);
-       int     (*resume)(struct of_device* dev);
-       int     (*shutdown)(struct of_device* dev);
-
-       struct device_driver    driver;
-};
-#define        to_of_platform_driver(drv) \
-       container_of(drv,struct of_platform_driver, driver)
+/* This is just here during the transition */
+#include <linux/of_platform.h>
 
 /* Platform drivers register/unregister */
 extern int of_register_platform_driver(struct of_platform_driver *drv);
@@ -56,5 +29,6 @@ extern int of_platform_bus_probe(struct device_node *root,
                                 struct of_device_id *matches,
                                 struct device *parent);
 
-extern struct of_device *of_find_device_by_node(struct device_node *np);
 extern struct of_device *of_find_device_by_phandle(phandle ph);
+
+#endif /* _ASM_POWERPC_OF_PLATFORM_H */
index 8d6b47f7b3007f014dafbc3a3c8278513c52db23..938fefb4c4bca07d6873829d6fceda73f9742496 100644 (file)
@@ -39,14 +39,16 @@ struct op_system_config {
 
 /* Per-arch configuration */
 struct op_powerpc_model {
-       void (*reg_setup) (struct op_counter_config *,
+       int (*reg_setup) (struct op_counter_config *,
                           struct op_system_config *,
                           int num_counters);
-       void (*cpu_setup) (struct op_counter_config *);
-       void (*start) (struct op_counter_config *);
-        void (*global_start) (struct op_counter_config *);
+       int  (*cpu_setup) (struct op_counter_config *);
+       int  (*start) (struct op_counter_config *);
+       int  (*global_start) (struct op_counter_config *);
        void (*stop) (void);
        void (*global_stop) (void);
+       int (*sync_start)(void);
+       int (*sync_stop)(void);
        void (*handle_interrupt) (struct pt_regs *,
                                  struct op_counter_config *);
        int num_counters;
index cb0f8aa43088590ef27d8f1ec2c6726544c0fb44..2259d4ce3846f3b1badc3b52977d1658c9aed3e5 100644 (file)
@@ -55,13 +55,13 @@ typedef struct {
 struct pmi_handler {
        struct list_head node;
        u8 type;
-       void (*handle_pmi_message) (struct of_device *, pmi_message_t);
+       void (*handle_pmi_message) (pmi_message_t);
 };
 
-void pmi_register_handler(struct of_device *, struct pmi_handler *);
-void pmi_unregister_handler(struct of_device *, struct pmi_handler *);
+int pmi_register_handler(struct pmi_handler *);
+void pmi_unregister_handler(struct pmi_handler *);
 
-void pmi_send_message(struct of_device *, pmi_message_t);
+int pmi_send_message(pmi_message_t);
 
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PMI_H */
index 1632baa17dc6964f0ae9bd7234b3bb350726bcec..6e391c9894ce7e513f7e75e1a62c263d5f7a6eb1 100644 (file)
 #include <asm/irq.h>
 #include <asm/atomic.h>
 
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        1
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT        1
+
+#define of_compat_cmp(s1, s2, l)       strncasecmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)            strcmp((s1), (s2))
+#define of_node_cmp(s1, s2)            strcasecmp((s1), (s2))
+
 /* Definitions used by the flattened device tree */
 #define OF_DT_HEADER           0xd00dfeed      /* marker */
 #define OF_DT_BEGIN_NODE       0x1             /* Start of node, full name */
@@ -97,10 +104,6 @@ struct device_node {
 
 extern struct device_node *of_chosen;
 
-/* flag descriptions */
-#define OF_DYNAMIC     1 /* node and properties were allocated via kmalloc */
-#define OF_DETACHED    2 /* node has been detached from the device tree */
-
 static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
 {
        return test_bit(flag, &n->_flags);
@@ -120,31 +123,7 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e
 }
 
 
-/* New style node lookup */
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name);
-#define for_each_node_by_name(dn, name) \
-       for (dn = of_find_node_by_name(NULL, name); dn; \
-            dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type);
-#define for_each_node_by_type(dn, type) \
-       for (dn = of_find_node_by_type(NULL, type); dn; \
-            dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compat);
-#define for_each_compatible_node(dn, type, compatible) \
-       for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
-            dn = of_find_compatible_node(dn, type, compatible))
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_find_all_nodes(struct device_node *prev);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
-                                            struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
-                                        const char *name,
-                                        int *lenp);
 extern struct device_node *of_node_get(struct device_node *node);
 extern void of_node_put(struct device_node *node);
 
@@ -166,17 +145,9 @@ extern void of_detach_node(const struct device_node *);
 extern void finish_device_tree(void);
 extern void unflatten_device_tree(void);
 extern void early_init_devtree(void *);
-extern int of_device_is_compatible(const struct device_node *device,
-                               const char *);
 #define device_is_compatible(d, c)     of_device_is_compatible((d), (c))
 extern int machine_is_compatible(const char *compat);
-extern const void *of_get_property(const struct device_node *node,
-                               const char *name,
-                               int *lenp);
-#define get_property(a, b, c)  of_get_property((a), (b), (c))
 extern void print_properties(struct device_node *node);
-extern int of_n_addr_cells(struct device_node* np);
-extern int of_n_size_cells(struct device_node* np);
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
 extern int prom_add_property(struct device_node* np, struct property* prop);
@@ -230,7 +201,6 @@ static inline unsigned long of_read_ulong(const u32 *cell, int size)
 
 /* Translate an OF address block into a CPU physical address
  */
-#define OF_BAD_ADDR    ((u64)-1)
 extern u64 of_translate_address(struct device_node *np, const u32 *addr);
 
 /* Extract an address from a device, returns the region size and
@@ -357,5 +327,11 @@ extern int of_irq_to_resource(struct device_node *dev, int index,
  */
 extern void __iomem *of_iomap(struct device_node *device, int index);
 
+/*
+ * NB:  This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_PROM_H */
index eedc828cef2dc31a9fcbec613a99590017e1da9c..8836c0f1f2f74c2d266cebbdcc2136250a0a5186 100644 (file)
@@ -107,10 +107,10 @@ struct spu_runqueue;
 struct device_node;
 
 enum spu_utilization_state {
-       SPU_UTIL_SYSTEM,
        SPU_UTIL_USER,
+       SPU_UTIL_SYSTEM,
        SPU_UTIL_IOWAIT,
-       SPU_UTIL_IDLE,
+       SPU_UTIL_IDLE_LOADED,
        SPU_UTIL_MAX
 };
 
@@ -121,9 +121,9 @@ struct spu {
        unsigned long problem_phys;
        struct spu_problem __iomem *problem;
        struct spu_priv2 __iomem *priv2;
-       struct list_head list;
-       struct list_head sched_list;
+       struct list_head cbe_list;
        struct list_head full_list;
+       enum { SPU_FREE, SPU_USED } alloc_state;
        int number;
        unsigned int irqs[3];
        u32 node;
@@ -137,6 +137,7 @@ struct spu {
        struct spu_runqueue *rq;
        unsigned long long timestamp;
        pid_t pid;
+       pid_t tgid;
        int class_0_pending;
        spinlock_t register_lock;
 
@@ -165,11 +166,14 @@ struct spu {
 
        struct sys_device sysdev;
 
+       int has_mem_affinity;
+       struct list_head aff_list;
+
        struct {
                /* protected by interrupt reentrancy */
-               enum spu_utilization_state utilization_state;
-               unsigned long tstamp;           /* time of last ctx switch */
-               unsigned long times[SPU_UTIL_MAX];
+               enum spu_utilization_state util_state;
+               unsigned long long tstamp;
+               unsigned long long times[SPU_UTIL_MAX];
                unsigned long long vol_ctx_switch;
                unsigned long long invol_ctx_switch;
                unsigned long long min_flt;
@@ -181,13 +185,29 @@ struct spu {
        } stats;
 };
 
-struct spu *spu_alloc(void);
-struct spu *spu_alloc_node(int node);
-void spu_free(struct spu *spu);
+struct cbe_spu_info {
+       struct mutex list_mutex;
+       struct list_head spus;
+       int n_spus;
+       int nr_active;
+       atomic_t reserved_spus;
+};
+
+extern struct cbe_spu_info cbe_spu_info[];
+
+void spu_init_channels(struct spu *spu);
 int spu_irq_class_0_bottom(struct spu *spu);
 int spu_irq_class_1_bottom(struct spu *spu);
 void spu_irq_setaffinity(struct spu *spu, int cpu);
 
+#ifdef CONFIG_KEXEC
+void crash_register_spus(struct list_head *list);
+#else
+static inline void crash_register_spus(struct list_head *list)
+{
+}
+#endif
+
 extern void spu_invalidate_slbs(struct spu *spu);
 extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm);
 
@@ -195,6 +215,20 @@ extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm);
 struct mm_struct;
 extern void spu_flush_all_slbs(struct mm_struct *mm);
 
+/* This interface allows a profiler (e.g., OProfile) to store a ref
+ * to spu context information that it creates. This caching technique
+ * avoids the need to recreate this information after a save/restore operation.
+ *
+ * Assumes the caller has already incremented the ref count to
+ * profile_info; then spu_context_destroy must call kref_put
+ * on prof_info_kref.
+ */
+void spu_set_profile_private_kref(struct spu_context *ctx,
+                                 struct kref *prof_info_kref,
+                                 void ( * prof_info_release) (struct kref *kref));
+
+void *spu_get_profile_private_kref(struct spu_context *ctx);
+
 /* system callbacks from the SPU */
 struct spu_syscall_block {
        u64 nr_ret;
@@ -206,7 +240,8 @@ extern long spu_sys_callback(struct spu_syscall_block *s);
 struct file;
 extern struct spufs_calls {
        asmlinkage long (*create_thread)(const char __user *name,
-                                       unsigned int flags, mode_t mode);
+                                       unsigned int flags, mode_t mode,
+                                       struct file *neighbor);
        asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
                                                __u32 __user *ustatus);
        struct module *owner;
@@ -233,8 +268,10 @@ struct spu_coredump_calls {
 #define SPU_CREATE_GANG                        0x0002
 #define SPU_CREATE_NOSCHED             0x0004
 #define SPU_CREATE_ISOLATE             0x0008
+#define SPU_CREATE_AFFINITY_SPU                0x0010
+#define SPU_CREATE_AFFINITY_MEM                0x0020
 
-#define SPU_CREATE_FLAG_ALL            0x000f /* mask of all valid flags */
+#define SPU_CREATE_FLAG_ALL            0x003f /* mask of all valid flags */
 
 
 #ifdef CONFIG_SPU_FS_MODULE
@@ -403,6 +440,7 @@ struct spu_priv2 {
 #define MFC_CNTL_RESUME_DMA_QUEUE              (0ull << 0)
 #define MFC_CNTL_SUSPEND_DMA_QUEUE             (1ull << 0)
 #define MFC_CNTL_SUSPEND_DMA_QUEUE_MASK                (1ull << 0)
+#define MFC_CNTL_SUSPEND_MASK                  (1ull << 4)
 #define MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION    (0ull << 8)
 #define MFC_CNTL_SUSPEND_IN_PROGRESS           (1ull << 8)
 #define MFC_CNTL_SUSPEND_COMPLETE              (3ull << 8)
index c48ae185c8744ecc3a6e57a3c93bb852a039c5f4..e87794d5d4eadc75513bcd9a5e0708e3cefb439c 100644 (file)
 #define SPU_STOPPED_STATUS_P_I  8
 #define SPU_STOPPED_STATUS_R    9
 
+/*
+ * Definitions for software decrementer status flag.
+ */
+#define SPU_DECR_STATUS_RUNNING 0x1
+#define SPU_DECR_STATUS_WRAPPED 0x2
+
 #ifndef  __ASSEMBLY__
 /**
  * spu_reg128 - generic 128-bit register definition.
@@ -63,7 +69,7 @@ struct spu_reg128 {
  * @gprs: Array of saved registers.
  * @fpcr: Saved floating point status control register.
  * @decr: Saved decrementer value.
- * @decr_status: Indicates decrementer run status.
+ * @decr_status: Indicates software decrementer status flags.
  * @ppu_mb: Saved PPU mailbox data.
  * @ppuint_mb: Saved PPU interrupting mailbox data.
  * @tag_mask: Saved tag group mask.
index 386d797d86b79f47b4fa2dfa82fc72b0a0a44b05..b550a27a7042c85bc856a39b0eec86dcba0ca9a8 100644 (file)
@@ -14,6 +14,7 @@ struct clk_ops {
        void (*disable)(struct clk *clk);
        void (*recalc)(struct clk *clk);
        int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
+       long (*round_rate)(struct clk *clk, unsigned long rate);
 };
 
 struct clk {
index 4ca3f765bacc11ecf3070a3b8b0770408dd9284c..20d42959f52ad25d3da5a7c5824b03a96cbffb73 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __ASM_SH_HW_IRQ_H
 #define __ASM_SH_HW_IRQ_H
 
+#include <linux/init.h>
 #include <asm/atomic.h>
 
 extern atomic_t irq_err_count;
@@ -22,7 +23,6 @@ struct intc2_desc {
 };
 
 void register_intc2_controller(struct intc2_desc *);
-void init_IRQ_intc2(void);
 
 struct ipr_data {
        unsigned char irq;
@@ -40,11 +40,82 @@ struct ipr_desc {
 };
 
 void register_ipr_controller(struct ipr_desc *);
-void init_IRQ_ipr(void);
 
 /*
  * Enable individual interrupt mode for external IPR IRQs.
  */
-void ipr_irq_enable_irlm(void);
+void __init ipr_irq_enable_irlm(void);
+
+typedef unsigned char intc_enum;
+
+struct intc_vect {
+       intc_enum enum_id;
+       unsigned short vect;
+};
+
+#define INTC_VECT(enum_id, vect) { enum_id, vect }
+
+struct intc_prio {
+       intc_enum enum_id;
+       unsigned char priority;
+};
+
+#define INTC_PRIO(enum_id, prio) { enum_id, prio }
+
+struct intc_group {
+       intc_enum enum_id;
+       intc_enum *enum_ids;
+};
+
+#define INTC_GROUP(enum_id, ids...) { enum_id, (intc_enum []) { ids, 0 } }
+
+struct intc_mask_reg {
+       unsigned long set_reg, clr_reg, reg_width;
+       intc_enum enum_ids[32];
+};
+
+struct intc_prio_reg {
+       unsigned long reg, reg_width, field_width;
+       intc_enum enum_ids[16];
+};
+
+struct intc_sense_reg {
+       unsigned long reg, reg_width, field_width;
+       intc_enum enum_ids[16];
+};
+
+struct intc_desc {
+       struct intc_vect *vectors;
+       unsigned int nr_vectors;
+       struct intc_group *groups;
+       unsigned int nr_groups;
+       struct intc_prio *priorities;
+       unsigned int nr_priorities;
+       struct intc_mask_reg *mask_regs;
+       unsigned int nr_mask_regs;
+       struct intc_prio_reg *prio_regs;
+       unsigned int nr_prio_regs;
+       struct intc_sense_reg *sense_regs;
+       unsigned int nr_sense_regs;
+       struct irq_chip chip;
+};
+
+#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
+#define DECLARE_INTC_DESC(symbol, chipname, vectors, groups,           \
+       priorities, mask_regs, prio_regs, sense_regs)                   \
+struct intc_desc symbol = {                                            \
+       _INTC_ARRAY(vectors), _INTC_ARRAY(groups),                      \
+       _INTC_ARRAY(priorities),                                        \
+       _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs),                 \
+       _INTC_ARRAY(sense_regs),                                        \
+       .chip.name = chipname,                                          \
+}
+
+void __init register_intc_controller(struct intc_desc *desc);
+
+void __init plat_irq_setup(void);
+
+enum { IRQ_MODE_IRQ, IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 };
+void __init plat_irq_setup_pins(int mode);
 
 #endif /* __ASM_SH_HW_IRQ_H */
index b3b31e4725c66aa998da3d67c7d87ce6d4466261..e0e89fcb8388846ea3b228485bba339e622b051d 100644 (file)
 /* IRQ */
 #define IRQ0_IRQ        32
 #define IRQ1_IRQ        33
-#define INTC_ICR0       0xA4140000UL
-#define INTC_ICR1       0xA414001CUL
-
-#define INTMSK0         0xa4140044
-#define INTMSKCLR0      0xa4140064
-#define INTC_INTPRI0    0xa4140010
 
 #define IRQ01_MODE      0xb1800000
 #define IRQ01_STS       0xb1800004
 #define IRQ01_MASK      0xb1800008
-#define EXT_BIT                (0x3fc0)        /* SH IRQ1 */
-#define MRSHPC_BIT0    (0x0004)        /* SH IRQ1 */
-#define MRSHPC_BIT1    (0x0008)        /* SH IRQ1 */
-#define MRSHPC_BIT2    (0x0010)        /* SH IRQ1 */
-#define MRSHPC_BIT3    (0x0020)        /* SH IRQ1 */
-#define SMC_BIT                (0x0002)        /* SH IRQ0 */
-#define USB_BIT                (0x0001)        /* SH IRQ0 */
-
-#define MRSHPC_IRQ3            11
-#define MRSHPC_IRQ2            12
-#define MRSHPC_IRQ1            13
-#define MRSHPC_IRQ0            14
-#define SMC_IRQ                10
-#define EXT_IRQ                5
-#define USB_IRQ                6
 
+/* Bits in IRQ01_* registers */
+
+#define SE7722_FPGA_IRQ_USB    0 /* IRQ0 */
+#define SE7722_FPGA_IRQ_SMC    1 /* IRQ0 */
+#define SE7722_FPGA_IRQ_MRSHPC0        2 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC1        3 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC2        4 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC3        5 /* IRQ1 */
+
+#define SE7722_FPGA_IRQ_NR     6
+#define SE7722_FPGA_IRQ_BASE   110
+
+#define MRSHPC_IRQ3            (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC3)
+#define MRSHPC_IRQ2            (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC2)
+#define MRSHPC_IRQ1            (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC1)
+#define MRSHPC_IRQ0            (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC0)
+#define SMC_IRQ                (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_SMC)
+#define USB_IRQ                (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_USB)
 
 /* arch/sh/boards/se/7722/irq.c */
 void init_se7722_IRQ(void);
-int se7722_irq_demux(int);
 
 #define __IO_PREFIX            se7722
 #include <asm/io_generic.h>
index 77bcb09d6ac8be2125494d2011951b1a96112949..b182b1cb05fd24369aa0d1381f553c3135c7e57f 100644 (file)
 #define __NR_signalfd          321
 #define __NR_timerfd           322
 #define __NR_eventfd           323
+#define __NR_fallocate         324
 
-#define NR_syscalls 324
+#define NR_syscalls 325
 
 #ifdef __KERNEL__
 
index ea3adc600b41987eff9e7b3223a0d35599c3a549..1a5197f369b20b0535510bab47fe22aa2f6faf71 100644 (file)
 #define __NR_signalfd          349
 #define __NR_timerfd           350
 #define __NR_eventfd           351
+#define __NR_fallocate         352
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 352
+#define NR_syscalls 353
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index d8f9872b0e2dc3587a9e658adc957f093b7906fb..4a56d84d69c427d461ff8ba097d21ba75dc4365b 100644 (file)
@@ -3,5 +3,17 @@
  *
  * This file is released under the GPLv2
  */
-#include <asm-generic/device.h>
+#ifndef _ASM_SPARC_DEVICE_H
+#define _ASM_SPARC_DEVICE_H
+
+struct device_node;
+struct of_device;
+
+struct dev_archdata {
+       struct device_node      *prom_node;
+       struct of_device        *op;
+};
+
+#endif /* _ASM_SPARC_DEVICE_H */
+
 
index c7df3803099200c9e3a9a6721138d0fe8b26ae92..c73ca081e1f56721c6f3912dd60730b1de6ecc2b 100644 (file)
@@ -1,11 +1,20 @@
 #ifndef _ASM_FB_H_
 #define _ASM_FB_H_
 #include <linux/fb.h>
+#include <asm/prom.h>
 
 #define fb_pgprotect(...) do {} while (0)
 
 static inline int fb_is_primary_device(struct fb_info *info)
 {
+       struct device *dev = info->device;
+       struct device_node *node;
+
+       node = dev->archdata.prom_node;
+       if (node &&
+           node == of_console_device)
+               return 1;
+
        return 0;
 }
 
index 7cb00c1b09c686b8a095935ac32d2a32c64f0515..e5f5aedc2293e6b857ef0f5753050aa5c733bb91 100644 (file)
@@ -3,13 +3,9 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/mod_devicetable.h>
 #include <asm/openprom.h>
-#include <asm/prom.h>
-
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-extern struct bus_type of_bus_type;
 
 /*
  * The of_device is a kind of "base class" that is a superset of
@@ -30,50 +26,13 @@ struct of_device
        int                             portid;
        int                             clock_freq;
 };
-#define        to_of_device(d) container_of(d, struct of_device, dev)
 
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
-extern struct of_device *of_find_device_by_node(struct device_node *);
-
-extern const struct of_device_id *of_match_device(
-       const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the ISA, EBUS, and SBUS busses on sparc64.
- */
-struct of_platform_driver
-{
-       char                    *name;
-       struct of_device_id     *match_table;
-       struct module           *owner;
-
-       int     (*probe)(struct of_device* dev, const struct of_device_id *match);
-       int     (*remove)(struct of_device* dev);
-
-       int     (*suspend)(struct of_device* dev, pm_message_t state);
-       int     (*resume)(struct of_device* dev);
-       int     (*shutdown)(struct of_device* dev);
-
-       struct device_driver    driver;
-};
-#define        to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv,
-                             struct bus_type *bus);
-extern void of_unregister_driver(struct of_platform_driver *drv);
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
-                                                  const char *bus_id,
-                                                  struct device *parent,
-                                                  struct bus_type *bus);
-extern void of_release_dev(struct device *dev);
+/* These are just here during the transition */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_SPARC_OF_DEVICE_H */
diff --git a/include/asm-sparc/of_platform.h b/include/asm-sparc/of_platform.h
new file mode 100644 (file)
index 0000000..64a2300
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _ASM_SPARC_OF_PLATFORM_H
+#define _ASM_SPARC_OF_PLATFORM_H
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *                      <benh@kernel.crashing.org>
+ *    Modified for Sparc by merging parts of asm-sparc/of_device.h
+ *             by Stephen Rothwell
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the 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 is just here during the transition */
+#include <linux/of_platform.h>
+
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+extern struct bus_type of_platform_bus_type;
+#define of_bus_type    of_platform_bus_type    /* for compatibility */
+
+extern int of_register_driver(struct of_platform_driver *drv,
+                             struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+                                                  const char *bus_id,
+                                                  struct device *parent,
+                                                  struct bus_type *bus);
+
+#endif /* _ASM_SPARC_OF_PLATFORM_H */
index 91691e52c058340047fef1eb08f4cb43b49376ee..17ba82ee220a791c40b13d4079ab607c11f4c2a4 100644 (file)
@@ -158,32 +158,6 @@ extern void prom_putchar(char character);
 extern void prom_printf(char *fmt, ...);
 extern void prom_write(const char *buf, unsigned int len);
 
-/* Query for input device type */
-
-enum prom_input_device {
-       PROMDEV_IKBD,                   /* input from keyboard */
-       PROMDEV_ITTYA,                  /* input from ttya */
-       PROMDEV_ITTYB,                  /* input from ttyb */
-       PROMDEV_IRSC,                   /* input from rsc */
-       PROMDEV_IVCONS,                 /* input from virtual-console */
-       PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
-       PROMDEV_OSCREEN,                /* to screen */
-       PROMDEV_OTTYA,                  /* to ttya */
-       PROMDEV_OTTYB,                  /* to ttyb */
-       PROMDEV_ORSC,                   /* to rsc */
-       PROMDEV_OVCONS,                 /* to virtual-console */
-       PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
 /* Multiprocessor operations... */
 
 /* Start the CPU with the given device tree node, context table, and context
index 9ea105ebe2ffa1fdfefc2d65f86d38d587f5e77c..350676c589f9d05c6bb659334441b2335f391908 100644 (file)
@@ -2,7 +2,6 @@
 #define _SPARC_PROM_H
 #ifdef __KERNEL__
 
-
 /*
  * Definitions for talking to the Open Firmware PROM on
  * Power Macintosh computers.
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <asm/atomic.h>
 
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        2
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT        1
+
+#define of_compat_cmp(s1, s2, l)       strncmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)            strcasecmp((s1), (s2))
+#define of_node_cmp(s1, s2)            strcmp((s1), (s2))
+
 typedef u32 phandle;
 typedef u32 ihandle;
 
@@ -55,53 +60,34 @@ struct device_node {
        unsigned int unique_id;
 };
 
-/* flag descriptions */
-#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
-
 #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
 #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
 
-#define OF_BAD_ADDR    ((u64)-1)
-
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
-       dn->pde = de;
-}
-
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name);
-#define for_each_node_by_name(dn, name) \
-       for (dn = of_find_node_by_name(NULL, name); dn; \
-            dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type);
-#define for_each_node_by_type(dn, type) \
-       for (dn = of_find_node_by_type(NULL, type); dn; \
-            dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compat);
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
-                                            struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
-                                        const char *name,
-                                        int *lenp);
-extern int of_device_is_compatible(const struct device_node *device,
-                                  const char *);
-extern const void *of_get_property(const struct device_node *node,
-                                  const char *name,
-                                  int *lenp);
-#define get_property(node,name,lenp) of_get_property(node,name,lenp)
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern int of_getintprop_default(struct device_node *np,
                                 const char *name,
                                 int def);
-extern int of_n_addr_cells(struct device_node *np);
-extern int of_n_size_cells(struct device_node *np);
 
 extern void prom_build_devicetree(void);
 
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+       return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+/*
+ * NB:  This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
 #endif /* __KERNEL__ */
 #endif /* _SPARC_PROM_H */
index 64471bcd96f9caf5d817573a23bb99acff777725..029b3e0d5e4ca3ea71c286da6ab1291311fb866b 100644 (file)
@@ -1,4 +1,3 @@
-/* $Id: unistd.h,v 1.74 2002/02/08 03:57:18 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -9,7 +8,7 @@
  * think of right now to force the arguments into fixed registers
  * before the trap into the system call with gcc 'asm' statements.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
  *
  * SunOS compatibility based upon preliminary work which is:
  *
 #define __NR_signalfd          311
 #define __NR_timerfd           312
 #define __NR_eventfd           313
+#define __NR_fallocate         314
 
-#define NR_SYSCALLS            314
+#define NR_SYSCALLS            315
 
 #ifdef __KERNEL__
 #define __ARCH_WANT_IPC_PARSE_VERSION
index d6cd3a175fc34b8fbcec6f034905b4c7f588621a..389012e5fbad874bcb2432f41472ad9d948ecd51 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/fb.h>
 #include <linux/fs.h>
 #include <asm/page.h>
+#include <asm/prom.h>
 
 static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
                                unsigned long off)
@@ -12,6 +13,14 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
 
 static inline int fb_is_primary_device(struct fb_info *info)
 {
+       struct device *dev = info->device;
+       struct device_node *node;
+
+       node = dev->archdata.prom_node;
+       if (node &&
+           node == of_console_device)
+               return 1;
+
        return 0;
 }
 
index 60e9173c9acb910554e5b155b5e104aefbabf8b5..46d69b3223c587cb64fd10729488dda8b44a553f 100644 (file)
@@ -3,14 +3,9 @@
 #ifdef __KERNEL__
 
 #include <linux/device.h>
+#include <linux/of.h>
 #include <linux/mod_devicetable.h>
 #include <asm/openprom.h>
-#include <asm/prom.h>
-
-extern struct bus_type isa_bus_type;
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-extern struct bus_type of_bus_type;
 
 /*
  * The of_device is a kind of "base class" that is a superset of
@@ -31,50 +26,13 @@ struct of_device
        int                             portid;
        int                             clock_freq;
 };
-#define        to_of_device(d) container_of(d, struct of_device, dev)
 
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
-extern struct of_device *of_find_device_by_node(struct device_node *);
-
-extern const struct of_device_id *of_match_device(
-       const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the ISA, EBUS, and SBUS busses on sparc64.
- */
-struct of_platform_driver
-{
-       char                    *name;
-       struct of_device_id     *match_table;
-       struct module           *owner;
-
-       int     (*probe)(struct of_device* dev, const struct of_device_id *match);
-       int     (*remove)(struct of_device* dev);
-
-       int     (*suspend)(struct of_device* dev, pm_message_t state);
-       int     (*resume)(struct of_device* dev);
-       int     (*shutdown)(struct of_device* dev);
-
-       struct device_driver    driver;
-};
-#define        to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv,
-                             struct bus_type *bus);
-extern void of_unregister_driver(struct of_platform_driver *drv);
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
-                                                  const char *bus_id,
-                                                  struct device *parent,
-                                                  struct bus_type *bus);
-extern void of_release_dev(struct device *dev);
+/* These are just here during the transition */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_SPARC64_OF_DEVICE_H */
diff --git a/include/asm-sparc64/of_platform.h b/include/asm-sparc64/of_platform.h
new file mode 100644 (file)
index 0000000..f7c1f17
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _ASM_SPARC64_OF_PLATFORM_H
+#define _ASM_SPARC64_OF_PLATFORM_H
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *                      <benh@kernel.crashing.org>
+ *    Modified for Sparc by merging parts of asm-sparc/of_device.h
+ *             by Stephen Rothwell
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the 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 is just here during the transition */
+#include <linux/of_platform.h>
+
+extern struct bus_type isa_bus_type;
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+extern struct bus_type of_platform_bus_type;
+#define of_bus_type    of_platform_bus_type    /* for compatibility */
+
+extern int of_register_driver(struct of_platform_driver *drv,
+                             struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+                                                  const char *bus_id,
+                                                  struct device *parent,
+                                                  struct bus_type *bus);
+
+#endif /* _ASM_SPARC64_OF_PLATFORM_H */
index 992f9f7a476cef4e79fa7dee9403d1e835ddf0c9..3f23c5dc5f2140040db7c13bc66774c0954ce08d 100644 (file)
@@ -140,32 +140,6 @@ extern void prom_putchar(char character);
 extern void prom_printf(const char *fmt, ...);
 extern void prom_write(const char *buf, unsigned int len);
 
-/* Query for input device type */
-
-enum prom_input_device {
-       PROMDEV_IKBD,                   /* input from keyboard */
-       PROMDEV_ITTYA,                  /* input from ttya */
-       PROMDEV_ITTYB,                  /* input from ttyb */
-       PROMDEV_IRSC,                   /* input from rsc */
-       PROMDEV_IVCONS,                 /* input from virtual-console */
-       PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
-       PROMDEV_OSCREEN,                /* to screen */
-       PROMDEV_OTTYA,                  /* to ttya */
-       PROMDEV_OTTYB,                  /* to ttyb */
-       PROMDEV_ORSC,                   /* to rsc */
-       PROMDEV_OVCONS,                 /* to virtual-console */
-       PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
 /* Multiprocessor operations... */
 #ifdef CONFIG_SMP
 /* Start the CPU with the given device tree node at the passed program
@@ -319,6 +293,8 @@ extern int prom_inst2pkg(int);
 extern int prom_service_exists(const char *service_name);
 extern void prom_sun4v_guest_soft_state(void);
 
+extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
+
 /* Client interface level routines. */
 extern void prom_set_trap_table(unsigned long tba);
 extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
index 23cc63f049a896769f4ed62e8d6ef8044f57d817..600afe5ae2e3b21955a24ff081f949b6b12e2ded 100644 (file)
@@ -8,8 +8,9 @@
 #define _ASM_SPARC64_PARPORT_H 1
 
 #include <asm/ebus.h>
-#include <asm/isa.h>
 #include <asm/ns87303.h>
+#include <asm/of_device.h>
+#include <asm/prom.h>
 
 #define PARPORT_PC_MAX_PORTS   PARPORT_MAX
 
@@ -35,8 +36,12 @@ static struct sparc_ebus_info {
        unsigned int addr;
        unsigned int count;
        int lock;
+
+       struct parport *port;
 } sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
 
+static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS);
+
 static __inline__ int request_dma(unsigned int dmanr, const char *device_id)
 {
        if (dmanr >= PARPORT_PC_MAX_PORTS)
@@ -98,117 +103,145 @@ static __inline__ unsigned int get_dma_residue(unsigned int dmanr)
        return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
 }
 
-static int ebus_ecpp_p(struct linux_ebus_device *edev)
+static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match)
 {
-       if (!strcmp(edev->prom_node->name, "ecpp"))
-               return 1;
-       if (!strcmp(edev->prom_node->name, "parallel")) {
-               const char *compat;
-
-               compat = of_get_property(edev->prom_node,
-                                        "compatible", NULL);
-               if (compat &&
-                   (!strcmp(compat, "ecpp") ||
-                    !strcmp(compat, "ns87317-ecpp") ||
-                    !strcmp(compat + 13, "ecpp")))
-                       return 1;
+       unsigned long base = op->resource[0].start;
+       unsigned long config = op->resource[1].start;
+       unsigned long d_base = op->resource[2].start;
+       unsigned long d_len;
+       struct device_node *parent;
+       struct parport *p;
+       int slot, err;
+
+       parent = op->node->parent;
+       if (!strcmp(parent->name, "dma")) {
+               p = parport_pc_probe_port(base, base + 0x400,
+                                         op->irqs[0], PARPORT_DMA_NOFIFO,
+                                         op->dev.parent);
+               if (!p)
+                       return -ENOMEM;
+               dev_set_drvdata(&op->dev, p);
+               return 0;
        }
+
+       for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) {
+               if (!test_and_set_bit(slot, dma_slot_map))
+                       break;
+       }
+       err = -ENODEV;
+       if (slot >= PARPORT_PC_MAX_PORTS)
+               goto out_err;
+
+       spin_lock_init(&sparc_ebus_dmas[slot].info.lock);
+
+       d_len = (op->resource[2].end - d_base) + 1UL;
+       sparc_ebus_dmas[slot].info.regs =
+               of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA");
+
+       if (!sparc_ebus_dmas[slot].info.regs)
+               goto out_clear_map;
+
+       sparc_ebus_dmas[slot].info.flags = 0;
+       sparc_ebus_dmas[slot].info.callback = NULL;
+       sparc_ebus_dmas[slot].info.client_cookie = NULL;
+       sparc_ebus_dmas[slot].info.irq = 0xdeadbeef;
+       strcpy(sparc_ebus_dmas[slot].info.name, "parport");
+       if (ebus_dma_register(&sparc_ebus_dmas[slot].info))
+               goto out_unmap_regs;
+
+       ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1);
+
+       /* Configure IRQ to Push Pull, Level Low */
+       /* Enable ECP, set bit 2 of the CTR first */
+       outb(0x04, base + 0x02);
+       ns87303_modify(config, PCR,
+                      PCR_EPP_ENABLE |
+                      PCR_IRQ_ODRAIN,
+                      PCR_ECP_ENABLE |
+                      PCR_ECP_CLK_ENA |
+                      PCR_IRQ_POLAR);
+
+       /* CTR bit 5 controls direction of port */
+       ns87303_modify(config, PTR,
+                      0, PTR_LPT_REG_DIR);
+
+       p = parport_pc_probe_port(base, base + 0x400,
+                                 op->irqs[0],
+                                 slot,
+                                 op->dev.parent);
+       err = -ENOMEM;
+       if (!p)
+               goto out_disable_irq;
+
+       dev_set_drvdata(&op->dev, p);
+
        return 0;
+
+out_disable_irq:
+       ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+       ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+
+out_unmap_regs:
+       of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len);
+
+out_clear_map:
+       clear_bit(slot, dma_slot_map);
+
+out_err:
+       return err;
 }
 
-static int parport_isa_probe(int count)
+static int __devexit ecpp_remove(struct of_device *op)
 {
-       struct sparc_isa_bridge *isa_br;
-       struct sparc_isa_device *isa_dev;
-
-       for_each_isa(isa_br) {
-               for_each_isadev(isa_dev, isa_br) {
-                       struct sparc_isa_device *child;
-                       unsigned long base;
-
-                       if (strcmp(isa_dev->prom_node->name, "dma"))
-                               continue;
-
-                       child = isa_dev->child;
-                       while (child) {
-                               if (!strcmp(child->prom_node->name, "parallel"))
-                                       break;
-                               child = child->next;
-                       }
-                       if (!child)
-                               continue;
-
-                       base = child->resource.start;
-
-                       /* No DMA, see commentary in
-                        * asm-sparc64/floppy.h:isa_floppy_init()
-                        */
-                       if (parport_pc_probe_port(base, base + 0x400,
-                                                 child->irq, PARPORT_DMA_NOFIFO,
-                                                 &child->bus->self->dev))
-                               count++;
-               }
+       struct parport *p = dev_get_drvdata(&op->dev);
+       int slot = p->dma;
+
+       parport_pc_unregister_port(p);
+
+       if (slot != PARPORT_DMA_NOFIFO) {
+               unsigned long d_base = op->resource[2].start;
+               unsigned long d_len;
+
+               d_len = (op->resource[2].end - d_base) + 1UL;
+
+               ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+               ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+               of_iounmap(&op->resource[2],
+                          sparc_ebus_dmas[slot].info.regs,
+                          d_len);
+               clear_bit(slot, dma_slot_map);
        }
 
-       return count;
+       return 0;
 }
 
-static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
+static struct of_device_id ecpp_match[] = {
+       {
+               .name = "ecpp",
+       },
+       {
+               .name = "parallel",
+               .compatible = "ecpp",
+       },
+       {
+               .name = "parallel",
+               .compatible = "ns87317-ecpp",
+       },
+       {},
+};
+
+static struct of_platform_driver ecpp_driver = {
+       .name                   = "ecpp",
+       .match_table            = ecpp_match,
+       .probe                  = ecpp_probe,
+       .remove                 = __devexit_p(ecpp_remove),
+};
+
+static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
 {
-       struct linux_ebus *ebus;
-       struct linux_ebus_device *edev;
-       int count = 0;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (ebus_ecpp_p(edev)) {
-                               unsigned long base = edev->resource[0].start;
-                               unsigned long config = edev->resource[1].start;
-                               unsigned long d_base = edev->resource[2].start;
-                               unsigned long d_len;
-
-                               spin_lock_init(&sparc_ebus_dmas[count].info.lock);
-                               d_len = (edev->resource[2].end -
-                                        d_base) + 1;
-                               sparc_ebus_dmas[count].info.regs =
-                                       ioremap(d_base, d_len);
-                               if (!sparc_ebus_dmas[count].info.regs)
-                                       continue;
-                               sparc_ebus_dmas[count].info.flags = 0;
-                               sparc_ebus_dmas[count].info.callback = NULL;
-                               sparc_ebus_dmas[count].info.client_cookie = NULL;
-                               sparc_ebus_dmas[count].info.irq = 0xdeadbeef;
-                               strcpy(sparc_ebus_dmas[count].info.name, "parport");
-                               if (ebus_dma_register(&sparc_ebus_dmas[count].info))
-                                       continue;
-                               ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1);
-
-                               /* Configure IRQ to Push Pull, Level Low */
-                               /* Enable ECP, set bit 2 of the CTR first */
-                               outb(0x04, base + 0x02);
-                               ns87303_modify(config, PCR,
-                                              PCR_EPP_ENABLE |
-                                              PCR_IRQ_ODRAIN,
-                                              PCR_ECP_ENABLE |
-                                              PCR_ECP_CLK_ENA |
-                                              PCR_IRQ_POLAR);
-
-                               /* CTR bit 5 controls direction of port */
-                               ns87303_modify(config, PTR,
-                                              0, PTR_LPT_REG_DIR);
-
-                               if (parport_pc_probe_port(base, base + 0x400,
-                                                         edev->irqs[0],
-                                                         count,
-                                                         &ebus->self->dev))
-                                       count++;
-                       }
-               }
-       }
+       of_register_driver(&ecpp_driver, &of_bus_type);
 
-       count = parport_isa_probe(count);
-
-       return count;
+       return 0;
 }
 
 #endif /* !(_ASM_SPARC64_PARPORT_H */
diff --git a/include/asm-sparc64/power.h b/include/asm-sparc64/power.h
deleted file mode 100644 (file)
index 94495c1..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _SPARC64_POWER_H
-#define _SPARC64_POWER_H
-
-extern void wake_up_powerd(void);
-extern int start_powerd(void);
-
-#endif /* !(_SPARC64_POWER_H) */
index b4df3042add06fa5dbde80de1d43b8add4dd800b..31dcb92fbae0cc27039c33c189c3f73d2730a09a 100644 (file)
@@ -2,7 +2,6 @@
 #define _SPARC64_PROM_H
 #ifdef __KERNEL__
 
-
 /*
  * Definitions for talking to the Open Firmware PROM on
  * Power Macintosh computers.
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-
 #include <linux/types.h>
 #include <linux/proc_fs.h>
 #include <asm/atomic.h>
 
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        2
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT        1
+
+#define of_compat_cmp(s1, s2, l)       strncmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)            strcasecmp((s1), (s2))
+#define of_node_cmp(s1, s2)            strcmp((s1), (s2))
+
 typedef u32 phandle;
 typedef u32 ihandle;
 
@@ -63,54 +68,35 @@ struct of_irq_controller {
        void            *data;
 };
 
-/* flag descriptions */
-#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
-
 #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
 #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
 
-#define OF_BAD_ADDR    ((u64)-1)
-
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
-       dn->pde = de;
-}
-
-extern struct device_node *of_find_node_by_name(struct device_node *from,
-       const char *name);
-#define for_each_node_by_name(dn, name) \
-       for (dn = of_find_node_by_name(NULL, name); dn; \
-            dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
-       const char *type);
-#define for_each_node_by_type(dn, type) \
-       for (dn = of_find_node_by_type(NULL, type); dn; \
-            dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
-       const char *type, const char *compat);
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_find_node_by_cpuid(int cpuid);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
-                                            struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
-                                        const char *name,
-                                        int *lenp);
-extern int of_device_is_compatible(const struct device_node *device,
-                                  const char *);
-extern const void *of_get_property(const struct device_node *node,
-                            const char *name,
-                            int *lenp);
-#define get_property(node,name,lenp) of_get_property(node,name,lenp)
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
 extern int of_getintprop_default(struct device_node *np,
                                 const char *name,
                                 int def);
-extern int of_n_addr_cells(struct device_node *np);
-extern int of_n_size_cells(struct device_node *np);
 
 extern void prom_build_devicetree(void);
 
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+       return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+/*
+ * NB:  This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
 #endif /* __KERNEL__ */
 #endif /* _SPARC64_PROM_H */
index 409067408eec07504db76532dd75b213c51d5177..64891cb10f05c572c6ec1e9a86f0eef14271a4b9 100644 (file)
@@ -115,14 +115,8 @@ do {       __asm__ __volatile__("ba,pt     %%xcc, 1f\n\t" \
 #ifndef __ASSEMBLY__
 
 extern void sun_do_break(void);
-extern int serial_console;
 extern int stop_a_enabled;
 
-static __inline__ int con_is_present(void)
-{
-       return serial_console ? 0 : 1;
-}
-
 extern void synchronize_user_stack(void);
 
 extern void __flushw_user(void);
index 53e96ed9c0243a49224374ec3dde78a88b91b264..cb751b4d0f564aab760af0f6faff8faeb34748e1 100644 (file)
@@ -1,4 +1,3 @@
-/* $Id: unistd.h,v 1.50 2002/02/08 03:57:18 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -9,7 +8,7 @@
  * think of right now to force the arguments into fixed registers
  * before the trap into the system call with gcc 'asm' statements.
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
  *
  * SunOS compatibility based upon preliminary work which is:
  *
 #define __NR_signalfd          311
 #define __NR_timerfd           312
 #define __NR_eventfd           313
+#define __NR_fallocate         314
 
-#define NR_SYSCALLS            314
+#define NR_SYSCALLS            315
 
 #ifdef __KERNEL__
 /* sysconf options, for SunOS compatibility */
index c0a8d4ed5bcb33669d808b4f1105c1913fe1dfac..f7417e91b1706bb79c438446b8b941e5ddb7c9ef 100644 (file)
@@ -275,6 +275,8 @@ struct vio_dev {
        char                    compat[VIO_MAX_COMPAT_LEN];
        int                     compat_len;
 
+       u64                     dev_no;
+
        unsigned long           channel_id;
 
        unsigned int            tx_irq;
index ff1255079fa196a9d7cdfbe9cfa45fa42f9146a1..bdca3f1b3213ffb4871ed3cc028ae5a1f9257220 100644 (file)
@@ -51,10 +51,6 @@ struct dma_chan_ref {
  * @ASYNC_TX_ACK: immediately ack the descriptor, precludes setting up a
  * dependency chain
  * @ASYNC_TX_DEP_ACK: ack the dependency descriptor.  Useful for chaining.
- * @ASYNC_TX_KMAP_SRC: if the transaction is to be performed synchronously
- * take an atomic mapping (KM_USER0) on the source page(s)
- * @ASYNC_TX_KMAP_DST: if the transaction is to be performed synchronously
- * take an atomic mapping (KM_USER0) on the dest page(s)
  */
 enum async_tx_flags {
        ASYNC_TX_XOR_ZERO_DST    = (1 << 0),
@@ -62,8 +58,6 @@ enum async_tx_flags {
        ASYNC_TX_ASSUME_COHERENT = (1 << 2),
        ASYNC_TX_ACK             = (1 << 3),
        ASYNC_TX_DEP_ACK         = (1 << 4),
-       ASYNC_TX_KMAP_SRC        = (1 << 5),
-       ASYNC_TX_KMAP_DST        = (1 << 6),
 };
 
 #ifdef CONFIG_DMA_ENGINE
index bf297b03a4e4650cd4c02a9dbe4e55307674411d..16ea3374dddf7a543501fca71718c5d72b885e07 100644 (file)
@@ -67,6 +67,12 @@ struct clocksource {
        unsigned long flags;
        cycle_t (*vread)(void);
        void (*resume)(void);
+#ifdef CONFIG_IA64
+       void *fsys_mmio;        /* used by fsyscall asm code */
+#define CLKSRC_FSYS_MMIO_SET(mmio, addr)      ((mmio) = (addr))
+#else
+#define CLKSRC_FSYS_MMIO_SET(mmio, addr)      do { } while (0)
+#endif
 
        /* timekeeping specific data, ignore */
        cycle_t cycle_interval;
index 0fe7cdf326f735c0722ffc08443cbcf993991fca..98c69ab80c849a65ce70eecac68dda81bd6eef82 100644 (file)
@@ -12,6 +12,7 @@
 
 #ifdef CONFIG_PROFILING
  
+#include <linux/dcache.h>
 #include <linux/types.h>
  
 struct dcookie_user;
index 0311bad838b112cf7aedc2fa9a7c7b9749156ceb..5834e843a946af4bf2a1e9597c73ec050b904baa 100644 (file)
@@ -20,7 +20,8 @@
 #define EM_PARISC      15      /* HPPA */
 #define EM_SPARC32PLUS 18      /* Sun's "v8plus" */
 #define EM_PPC         20      /* PowerPC */
-#define EM_PPC64       21       /* PowerPC64 */
+#define EM_PPC64       21       /* PowerPC64 */
+#define EM_SPU         23      /* Cell BE SPU */
 #define EM_SH          42      /* SuperH */
 #define EM_SPARCV9     43      /* SPARC v9 64-bit */
 #define EM_IA_64       50      /* HP/Intel IA-64 */
index aa83d41630965400af10535b4a29b2ce724a40bc..b690148657140aac33bf11c2e1e288a9398e6ac6 100644 (file)
 #define I2C_DRIVERID_KS0127    86      /* Samsung ks0127 video decoder */
 #define I2C_DRIVERID_TLV320AIC23B 87   /* TI TLV320AIC23B audio codec  */
 #define I2C_DRIVERID_ISL1208   88      /* Intersil ISL1208 RTC         */
-#define I2C_DRIVERID_WM8731            89      /* Wolfson WM8731 audio codec */
-#define I2C_DRIVERID_WM8750            90      /* Wolfson WM8750 audio codec */
-#define I2C_DRIVERID_WM8753            91      /* Wolfson WM8753 audio codec */
+#define I2C_DRIVERID_WM8731    89      /* Wolfson WM8731 audio codec */
+#define I2C_DRIVERID_WM8750    90      /* Wolfson WM8750 audio codec */
+#define I2C_DRIVERID_WM8753    91      /* Wolfson WM8753 audio codec */
+#define I2C_DRIVERID_LM4857    92      /* LM4857 Audio Amplifier */
 
 #define I2C_DRIVERID_I2CDEV    900
 #define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
index 18c98b54303099eec767b2b9b9d7cf4a185f3c76..e02c6a66b2ba74fecdb015b202933541dc3f5257 100644 (file)
@@ -344,7 +344,8 @@ struct input_absinfo {
 #define KEY_BRIGHTNESSUP       225
 #define KEY_MEDIA              226
 
-#define KEY_SWITCHVIDEOMODE    227
+#define KEY_SWITCHVIDEOMODE    227     /* Cycle between available video
+                                          outputs (Monitor/LCD/TV-out/etc) */
 #define KEY_KBDILLUMTOGGLE     228
 #define KEY_KBDILLUMDOWN       229
 #define KEY_KBDILLUMUP         230
index 2eaa142cd06171bae79f35a7e72442648cb86f46..baf29387cab4201a991ff4a8663fbba5e05fa149 100644 (file)
@@ -53,6 +53,14 @@ static inline int task_ioprio(struct task_struct *task)
        return IOPRIO_NORM;
 }
 
+static inline int task_ioprio_class(struct task_struct *task)
+{
+       if (ioprio_valid(task->ioprio))
+               return IOPRIO_PRIO_CLASS(task->ioprio);
+
+       return IOPRIO_CLASS_BE;
+}
+
 static inline int task_nice_ioprio(struct task_struct *task)
 {
        return (task_nice(task) + 20) / 5;
index 47cd2a1c554487b7ae6a028a085b1107c7090712..be5a43928c848fc885625c2e1313b080084cb4d4 100644 (file)
@@ -323,6 +323,7 @@ enum ata_completion_errors {
        AC_ERR_INVALID          = (1 << 7), /* invalid argument */
        AC_ERR_OTHER            = (1 << 8), /* unknown */
        AC_ERR_NODEV_HINT       = (1 << 9), /* polling device detection hint */
+       AC_ERR_NCQ              = (1 << 10), /* marker for offending NCQ qc */
 };
 
 /* forward declarations */
@@ -530,6 +531,7 @@ struct ata_port {
        unsigned int            cbl;    /* cable type; ATA_CBL_xxx */
        unsigned int            hw_sata_spd_limit;
        unsigned int            sata_spd_limit; /* SATA PHY speed limit */
+       unsigned int            sata_spd;       /* current SATA PHY speed */
 
        /* record runtime error info, protected by host lock */
        struct ata_eh_info      eh_info;
@@ -563,6 +565,9 @@ struct ata_port {
        pm_message_t            pm_mesg;
        int                     *pm_result;
 
+       struct timer_list       fastdrain_timer;
+       unsigned long           fastdrain_cnt;
+
        void                    *private_data;
 
 #ifdef CONFIG_ATA_ACPI
@@ -619,9 +624,8 @@ struct ata_port_operations {
        u8 (*irq_on) (struct ata_port *);
        u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq);
 
-       u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
-       void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
-                          u32 val);
+       int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+       int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
        int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
        int (*port_resume) (struct ata_port *ap);
@@ -764,7 +768,8 @@ extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *);
  */
 extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
 extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp);
+extern void ata_tf_to_fis(const struct ata_taskfile *tf,
+                         u8 pmp, int is_cmd, u8 *fis);
 extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
 extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
 extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
@@ -909,27 +914,21 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
 /*
  * ata_eh_info helpers
  */
-#define ata_ehi_push_desc(ehi, fmt, args...) do { \
-       (ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \
-                                    ATA_EH_DESC_LEN - (ehi)->desc_len, \
-                                    fmt , ##args); \
-} while (0)
-
-#define ata_ehi_clear_desc(ehi) do { \
-       (ehi)->desc[0] = '\0'; \
-       (ehi)->desc_len = 0; \
-} while (0)
-
-static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
+extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void ata_ehi_clear_desc(struct ata_eh_info *ehi);
+
+static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi)
 {
-       ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
+       ehi->flags |= ATA_EHI_RESUME_LINK;
        ehi->action |= ATA_EH_SOFTRESET;
        ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
 }
 
 static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
 {
-       __ata_ehi_hotplugged(ehi);
+       ata_ehi_schedule_probe(ehi);
+       ehi->flags |= ATA_EHI_HOTPLUGGED;
        ehi->err_mask |= AC_ERR_ATA_BUS;
 }
 
diff --git a/include/linux/of.h b/include/linux/of.h
new file mode 100644 (file)
index 0000000..47734ff
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _LINUX_OF_H
+#define _LINUX_OF_H
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh and other computers.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
+ * Updates for SPARC64 by David S. Miller
+ * Derived from PowerPC and Sparc prom.h files by Stephen Rothwell, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/types.h>
+
+#include <asm/bitops.h>
+#include <asm/prom.h>
+
+/* flag descriptions */
+#define OF_DYNAMIC     1 /* node and properties were allocated via kmalloc */
+#define OF_DETACHED    2 /* node has been detached from the device tree */
+
+#define OF_BAD_ADDR    ((u64)-1)
+
+extern struct device_node *of_find_node_by_name(struct device_node *from,
+       const char *name);
+#define for_each_node_by_name(dn, name) \
+       for (dn = of_find_node_by_name(NULL, name); dn; \
+            dn = of_find_node_by_name(dn, name))
+extern struct device_node *of_find_node_by_type(struct device_node *from,
+       const char *type);
+#define for_each_node_by_type(dn, type) \
+       for (dn = of_find_node_by_type(NULL, type); dn; \
+            dn = of_find_node_by_type(dn, type))
+extern struct device_node *of_find_compatible_node(struct device_node *from,
+       const char *type, const char *compat);
+#define for_each_compatible_node(dn, type, compatible) \
+       for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
+            dn = of_find_compatible_node(dn, type, compatible))
+extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_by_phandle(phandle handle);
+extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_child(const struct device_node *node,
+                                            struct device_node *prev);
+extern struct property *of_find_property(const struct device_node *np,
+                                        const char *name,
+                                        int *lenp);
+extern int of_device_is_compatible(const struct device_node *device,
+                                  const char *);
+extern const void *of_get_property(const struct device_node *node,
+                               const char *name,
+                               int *lenp);
+#define get_property(a, b, c)  of_get_property((a), (b), (c))
+extern int of_n_addr_cells(struct device_node *np);
+extern int of_n_size_cells(struct device_node *np);
+
+#endif /* _LINUX_OF_H */
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
new file mode 100644 (file)
index 0000000..91bf84b
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _LINUX_OF_DEVICE_H
+#define _LINUX_OF_DEVICE_H
+#ifdef __KERNEL__
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/mod_devicetable.h>
+
+#include <asm/of_device.h>
+
+#define        to_of_device(d) container_of(d, struct of_device, dev)
+
+extern const struct of_device_id *of_match_node(
+       const struct of_device_id *matches, const struct device_node *node);
+extern const struct of_device_id *of_match_device(
+       const struct of_device_id *matches, const struct of_device *dev);
+
+extern struct of_device *of_dev_get(struct of_device *dev);
+extern void of_dev_put(struct of_device *dev);
+
+extern int of_device_register(struct of_device *ofdev);
+extern void of_device_unregister(struct of_device *ofdev);
+extern void of_release_dev(struct device *dev);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
new file mode 100644 (file)
index 0000000..5fd44e6
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef _LINUX_OF_PLATFORM_H
+#define _LINUX_OF_PLATFORM_H
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *                      <benh@kernel.crashing.org>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+#include <linux/of_device.h>
+
+/*
+ * The of_platform_bus_type is a bus type used by drivers that do not
+ * attach to a macio or similar bus but still use OF probing
+ * mechanism
+ */
+extern struct bus_type of_platform_bus_type;
+
+/*
+ * An of_platform_driver driver is attached to a basic of_device on
+ * the "platform bus" (of_platform_bus_type) (or ISA, EBUS and SBUS
+ * busses on sparc).
+ */
+struct of_platform_driver
+{
+       char                    *name;
+       struct of_device_id     *match_table;
+       struct module           *owner;
+
+       int     (*probe)(struct of_device* dev,
+                        const struct of_device_id *match);
+       int     (*remove)(struct of_device* dev);
+
+       int     (*suspend)(struct of_device* dev, pm_message_t state);
+       int     (*resume)(struct of_device* dev);
+       int     (*shutdown)(struct of_device* dev);
+
+       struct device_driver    driver;
+};
+#define        to_of_platform_driver(drv) \
+       container_of(drv,struct of_platform_driver, driver)
+
+#include <asm/of_platform.h>
+
+extern struct of_device *of_find_device_by_node(struct device_node *np);
+
+extern int of_bus_type_init(struct bus_type *bus, const char *name);
+
+#endif /* _LINUX_OF_PLATFORM_H */
index 0d514b252454478a71e4706bc3b693e6b3d7941a..041bb31100f48fd780b9505cf21842be36cdb68f 100644 (file)
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
  
+/* Each escaped entry is prefixed by ESCAPE_CODE
+ * then one of the following codes, then the
+ * relevant data.
+ * These #defines live in this file so that arch-specific
+ * buffer sync'ing code can access them.
+ */
+#define ESCAPE_CODE                    ~0UL
+#define CTX_SWITCH_CODE                        1
+#define CPU_SWITCH_CODE                        2
+#define COOKIE_SWITCH_CODE             3
+#define KERNEL_ENTER_SWITCH_CODE       4
+#define KERNEL_EXIT_SWITCH_CODE                5
+#define MODULE_LOADED_CODE             6
+#define CTX_TGID_CODE                  7
+#define TRACE_BEGIN_CODE               8
+#define TRACE_END_CODE                 9
+#define XEN_ENTER_SWITCH_CODE          10
+#define SPU_PROFILING_CODE             11
+#define SPU_CTX_SWITCH_CODE            12
+
 struct super_block;
 struct dentry;
 struct file_operations;
@@ -35,6 +55,14 @@ struct oprofile_operations {
        int (*start)(void);
        /* Stop delivering interrupts. */
        void (*stop)(void);
+       /* Arch-specific buffer sync functions.
+        * Return value = 0:  Success
+        * Return value = -1: Failure
+        * Return value = 1:  Run generic sync function
+        */
+       int (*sync_start)(void);
+       int (*sync_stop)(void);
+
        /* Initiate a stack backtrace. Optional. */
        void (*backtrace)(struct pt_regs * const regs, unsigned int depth);
        /* CPU identification string. */
@@ -55,6 +83,13 @@ int oprofile_arch_init(struct oprofile_operations * ops);
  */
 void oprofile_arch_exit(void);
 
+/**
+ * Add data to the event buffer.
+ * The data passed is free-form, but typically consists of
+ * file offsets, dcookies, context information, and ESCAPE codes.
+ */
+void add_event_entry(unsigned long data);
+
 /**
  * Add a sample. This may be called from any context. Pass
  * smp_processor_id() as cpu.
index d9377ce9ffd1739b642095a298e854dbc537718a..9f38250146744a605736879d1ba23fe969a07ad0 100644 (file)
@@ -210,5 +210,6 @@ static inline void serio_unpin_driver(struct serio *serio)
 #define SERIO_TOUCHRIGHT       0x32
 #define SERIO_TOUCHWIN 0x33
 #define SERIO_TAOSEVM  0x34
+#define SERIO_FUJITSU  0x35
 
 #endif
index 7d0ecc1659f063df2f69550aa3d3b157cd36f1fd..d859354b9e51ea73952b31371b21172e2622097e 100644 (file)
@@ -40,7 +40,7 @@
  */
 #define ZERO_SIZE_PTR ((void *)16)
 
-#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) < \
+#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \
                                (unsigned long)ZERO_SIZE_PTR)
 
 /*
index 07f7e4cbcee3bc375e893b3ecdccdad148905a2a..124270df8734eb2b20e3f36adb115bc356692a15 100644 (file)
@@ -160,7 +160,7 @@ static inline struct kmem_cache *kmalloc_slab(size_t size)
 #define SLUB_DMA __GFP_DMA
 #else
 /* Disable DMA functionality */
-#define SLUB_DMA 0
+#define SLUB_DMA (__force gfp_t)0
 #endif
 
 void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
index 3387e44dfd13bdef5014e050aff8e85637387048..334d3141162966a4daacc7233d4bdf843b4d4e6a 100644 (file)
@@ -16,6 +16,20 @@ struct ads7846_platform_data {
        u16     vref_delay_usecs;       /* 0 for external vref; etc */
        int     keep_vref_on:1;         /* set to keep vref on for differential
                                         * measurements as well */
+
+       /* Settling time of the analog signals; a function of Vcc and the
+        * capacitance on the X/Y drivers.  If set to non-zero, two samples
+        * are taken with settle_delay us apart, and the second one is used.
+        * ~150 uSec with 0.01uF caps.
+        */
+       u16     settle_delay_usecs;
+
+       /* If set to non-zero, after samples are taken this delay is applied
+        * and penirq is rechecked, to help avoid false events.  This value
+        * is affected by the material used to build the touch layer.
+        */
+       u16     penirq_recheck_delay_usecs;
+
        u16     x_plate_ohms;
        u16     y_plate_ohms;
 
index 7a8b1e3322e072baf4f55550a1d746f91644121e..61def7c8fbb3c750677458d1d4e8a4f347e5beac 100644 (file)
@@ -549,7 +549,7 @@ asmlinkage long sys_inotify_rm_watch(int fd, u32 wd);
 asmlinkage long sys_spu_run(int fd, __u32 __user *unpc,
                                 __u32 __user *ustatus);
 asmlinkage long sys_spu_create(const char __user *name,
-               unsigned int flags, mode_t mode);
+               unsigned int flags, mode_t mode, int fd);
 
 asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode,
                            unsigned dev);
index da929dbbea2a1c9ab246ee134bb83dcd9ec5c935..37ac3ff90fafb16f7814297d247c2a3c28c59204 100644 (file)
@@ -224,66 +224,6 @@ static inline int ntp_synced(void)
        __x < 0 ? -(-__x >> __s) : __x >> __s;  \
 })
 
-
-#ifdef CONFIG_TIME_INTERPOLATION
-
-#define TIME_SOURCE_CPU 0
-#define TIME_SOURCE_MMIO64 1
-#define TIME_SOURCE_MMIO32 2
-#define TIME_SOURCE_FUNCTION 3
-
-/* For proper operations time_interpolator clocks must run slightly slower
- * than the standard clock since the interpolator may only correct by having
- * time jump forward during a tick. A slower clock is usually a side effect
- * of the integer divide of the nanoseconds in a second by the frequency.
- * The accuracy of the division can be increased by specifying a shift.
- * However, this may cause the clock not to be slow enough.
- * The interpolator will self-tune the clock by slowing down if no
- * resets occur or speeding up if the time jumps per analysis cycle
- * become too high.
- *
- * Setting jitter compensates for a fluctuating timesource by comparing
- * to the last value read from the timesource to insure that an earlier value
- * is not returned by a later call. The price to pay
- * for the compensation is that the timer routines are not as scalable anymore.
- */
-
-struct time_interpolator {
-       u16 source;                     /* time source flags */
-       u8 shift;                       /* increases accuracy of multiply by shifting. */
-                               /* Note that bits may be lost if shift is set too high */
-       u8 jitter;                      /* if set compensate for fluctuations */
-       u32 nsec_per_cyc;               /* set by register_time_interpolator() */
-       void *addr;                     /* address of counter or function */
-       cycles_t mask;                  /* mask the valid bits of the counter */
-       unsigned long offset;           /* nsec offset at last update of interpolator */
-       u64 last_counter;               /* counter value in units of the counter at last update */
-       cycles_t last_cycle;            /* Last timer value if TIME_SOURCE_JITTER is set */
-       u64 frequency;                  /* frequency in counts/second */
-       long drift;                     /* drift in parts-per-million (or -1) */
-       unsigned long skips;            /* skips forward */
-       unsigned long ns_skipped;       /* nanoseconds skipped */
-       struct time_interpolator *next;
-};
-
-extern void register_time_interpolator(struct time_interpolator *);
-extern void unregister_time_interpolator(struct time_interpolator *);
-extern void time_interpolator_reset(void);
-extern unsigned long time_interpolator_get_offset(void);
-extern void time_interpolator_update(long delta_nsec);
-
-#else /* !CONFIG_TIME_INTERPOLATION */
-
-static inline void time_interpolator_reset(void)
-{
-}
-
-static inline void time_interpolator_update(long delta_nsec)
-{
-}
-
-#endif /* !CONFIG_TIME_INTERPOLATION */
-
 #define TICK_LENGTH_SHIFT      32
 
 #ifdef CONFIG_NO_HZ
index d16a2b57dc8105806a07afa5e97e843cd0844274..c66c8a3410b926d10b0c2ac55e45d09277af96be 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/compiler.h> /* need __user */
 #else
 #define __user
+#include <sys/time.h>
 #endif
 #include <linux/types.h>
 
index aa49dda4f4104b4a58032516e72f690b94191627..fd0a6c46f497e69946137621a4f5ae7cf049125c 100644 (file)
@@ -43,6 +43,7 @@ struct snd_ak4xxx_ops {
 struct snd_akm4xxx_dac_channel {
        char *name;             /* mixer volume name */
        unsigned int num_channels;
+       char *switch_name;              /* mixer switch*/
 };
 
 /* ADC labels and channels */
index 685928e6f65a52d90d622f2c17127736d63de551..353910ce97556507ce6208c19cb1870f827d5769 100644 (file)
@@ -1723,6 +1723,10 @@ struct snd_cs46xx {
        struct snd_cs46xx_pcm *playback_pcm;
        unsigned int play_ctl;
 #endif
+
+#ifdef CONFIG_PM
+       u32 *saved_regs;
+#endif
 };
 
 int snd_cs46xx_create(struct snd_card *card,
index da934def31e9499942627e0c3327b626d857d448..d9da9e59cf37e7bb0f73602c1231ecc2a4c58432 100644 (file)
@@ -107,6 +107,7 @@ struct dsp_scb_descriptor {
        char scb_name[DSP_MAX_SCB_NAME];
        u32 address;
        int index;
+       u32 *data;
 
        struct dsp_scb_descriptor * sub_list_ptr;
        struct dsp_scb_descriptor * next_scb_ptr;
@@ -127,6 +128,7 @@ struct dsp_task_descriptor {
        int size;
        u32 address;
        int index;
+       u32 *data;
 };
 
 struct dsp_pcm_channel_descriptor {
index 23e45a4cf0e44ffe4a3074fe72e39c47e4518081..529d0a56436782fdf6ec61f00bd0e55784beb2cc 100644 (file)
 /************************************************************************************************/
 /* EMU1010m HANA Destinations                                                                  */
 /************************************************************************************************/
+/* 32-bit destinations of signal in the Hana FPGA. Destinations are either
+ * physical outputs of Hana, or outputs going to Alice2 (audigy) for capture
+ * - 16 x EMU_DST_ALICE2_EMU32_X.
+ */
+/* EMU32 = 32-bit serial channel between Alice2 (audigy) and Hana (FPGA) */
+/* EMU_DST_ALICE2_EMU32_X - data channels from Hana to Alice2 used for capture.
+ * Which data is fed into a EMU_DST_ALICE2_EMU32_X channel in Hana depends on
+ * setup of mixer control for each destination - see emumixer.c -
+ * snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[]
+ */
 #define EMU_DST_ALICE2_EMU32_0 0x000f  /* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_1 0x0000  /* 16 EMU32 channels to Alice2 +0 to +0xf */
 #define EMU_DST_ALICE2_EMU32_2 0x0001  /* 16 EMU32 channels to Alice2 +0 to +0xf */
 /************************************************************************************************/
 /* EMU1010m HANA Sources                                                                       */
 /************************************************************************************************/
+/* 32-bit sources of signal in the Hana FPGA. The sources are routed to
+ * destinations using mixer control for each destination - see emumixer.c
+ * Sources are either physical inputs of FPGA,
+ * or outputs from Alice (audigy) - 16 x EMU_SRC_ALICE_EMU32A +
+ * 16 x EMU_SRC_ALICE_EMU32B
+ */
 #define EMU_SRC_SILENCE                0x0000  /* Silence */
 #define EMU_SRC_DOCK_MIC_A1    0x0100  /* Audio Dock Mic A, 1st or 48kHz only */
 #define EMU_SRC_DOCK_MIC_A2    0x0101  /* Audio Dock Mic A, 2nd or 96kHz */
index 2dd5c8e5b4feabc027a48dfed2320421c26d4c26..3ad854b397d27234378276982d764ab649d55c27 100644 (file)
@@ -38,6 +38,7 @@ enum sb_hw_type {
        SB_HW_ALS100,           /* Avance Logic ALS100 chip */
        SB_HW_ALS4000,          /* Avance Logic ALS4000 chip */
        SB_HW_DT019X,           /* Diamond Tech. DT-019X / Avance Logic ALS-007 */
+       SB_HW_CS5530,           /* Cyrix/NatSemi 5530 VSA1 */
 };
 
 #define SB_OPEN_PCM                    0x01
index 8e5b2f0f594625f5a360489d6558373549b43343..6bbcfefd2c385f0193e49c683a0f14393737fb06 100644 (file)
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by alsa/ksync script.  */
 #define CONFIG_SND_VERSION "1.0.14"
-#define CONFIG_SND_DATE " (Thu May 31 09:03:25 2007 UTC)"
+#define CONFIG_SND_DATE " (Fri Jul 20 09:12:58 2007 UTC)"
diff --git a/include/sound/wavefront_fx.h b/include/sound/wavefront_fx.h
deleted file mode 100644 (file)
index cec92b1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __SOUND_WAVEFRONT_FX_H
-#define __SOUND_WAVEFRONT_FX_H
-
-extern int  snd_wavefront_fx_detect (snd_wavefront_t *);
-extern void snd_wavefront_fx_ioctl  (snd_synth_t *sdev, 
-                                    unsigned int cmd, 
-                                    unsigned long arg);
-
-#endif  __SOUND_WAVEFRONT_FX_H
index 2565e1b6dd7becc4def8504fd8b4cd65973a48b8..d0e5c48e18c78c3fe1fea8a2d87d26fe4973ca2c 100644 (file)
@@ -65,8 +65,8 @@ KERNEL_ATTR_RO(kexec_crash_loaded);
 /*
  * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
  */
-extern const char __start_notes __attribute__((weak));
-extern const char __stop_notes __attribute__((weak));
+extern const void __start_notes __attribute__((weak));
+extern const void __stop_notes __attribute__((weak));
 #define        notes_size (&__stop_notes - &__start_notes)
 
 static ssize_t notes_read(struct kobject *kobj, struct bin_attribute *bin_attr,
index ffe19149d77006cb6c22db392b0a828962c655d3..5b81da08bbdb48d9bb452784298a4e0c480664fb 100644 (file)
@@ -57,17 +57,14 @@ EXPORT_SYMBOL(sys_tz);
  */
 asmlinkage long sys_time(time_t __user * tloc)
 {
-       /*
-        * We read xtime.tv_sec atomically - it's updated
-        * atomically by update_wall_time(), so no need to
-        * even read-lock the xtime seqlock:
-        */
-       time_t i = xtime.tv_sec;
+       time_t i;
+       struct timespec tv;
 
-       smp_rmb(); /* sys_time() results are coherent */
+       getnstimeofday(&tv);
+       i = tv.tv_sec;
 
        if (tloc) {
-               if (put_user(i, tloc))
+               if (put_user(i,tloc))
                        i = -EFAULT;
        }
        return i;
@@ -136,7 +133,6 @@ static inline void warp_clock(void)
        write_seqlock_irq(&xtime_lock);
        wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
        xtime.tv_sec += sys_tz.tz_minuteswest * 60;
-       time_interpolator_reset();
        write_sequnlock_irq(&xtime_lock);
        clock_was_set();
 }
@@ -309,92 +305,6 @@ struct timespec timespec_trunc(struct timespec t, unsigned gran)
 }
 EXPORT_SYMBOL(timespec_trunc);
 
-#ifdef CONFIG_TIME_INTERPOLATION
-void getnstimeofday (struct timespec *tv)
-{
-       unsigned long seq,sec,nsec;
-
-       do {
-               seq = read_seqbegin(&xtime_lock);
-               sec = xtime.tv_sec;
-               nsec = xtime.tv_nsec+time_interpolator_get_offset();
-       } while (unlikely(read_seqretry(&xtime_lock, seq)));
-
-       while (unlikely(nsec >= NSEC_PER_SEC)) {
-               nsec -= NSEC_PER_SEC;
-               ++sec;
-       }
-       tv->tv_sec = sec;
-       tv->tv_nsec = nsec;
-}
-EXPORT_SYMBOL_GPL(getnstimeofday);
-
-int do_settimeofday (struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-
-       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-               return -EINVAL;
-
-       write_seqlock_irq(&xtime_lock);
-       {
-               wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-               wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-               set_normalized_timespec(&xtime, sec, nsec);
-               set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-               time_adjust = 0;                /* stop active adjtime() */
-               time_status |= STA_UNSYNC;
-               time_maxerror = NTP_PHASE_LIMIT;
-               time_esterror = NTP_PHASE_LIMIT;
-               time_interpolator_reset();
-       }
-       write_sequnlock_irq(&xtime_lock);
-       clock_was_set();
-       return 0;
-}
-EXPORT_SYMBOL(do_settimeofday);
-
-void do_gettimeofday (struct timeval *tv)
-{
-       unsigned long seq, nsec, usec, sec, offset;
-       do {
-               seq = read_seqbegin(&xtime_lock);
-               offset = time_interpolator_get_offset();
-               sec = xtime.tv_sec;
-               nsec = xtime.tv_nsec;
-       } while (unlikely(read_seqretry(&xtime_lock, seq)));
-
-       usec = (nsec + offset) / 1000;
-
-       while (unlikely(usec >= USEC_PER_SEC)) {
-               usec -= USEC_PER_SEC;
-               ++sec;
-       }
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
-
-       /*
-        * Make sure xtime.tv_sec [returned by sys_time()] always
-        * follows the gettimeofday() result precisely. This
-        * condition is extremely unlikely, it can hit at most
-        * once per second:
-        */
-       if (unlikely(xtime.tv_sec != tv->tv_sec)) {
-               unsigned long flags;
-
-               write_seqlock_irqsave(&xtime_lock, flags);
-               update_wall_time();
-               write_sequnlock_irqrestore(&xtime_lock, flags);
-       }
-}
-EXPORT_SYMBOL(do_gettimeofday);
-
-#else  /* CONFIG_TIME_INTERPOLATION */
-
 #ifndef CONFIG_GENERIC_TIME
 /*
  * Simulate gettimeofday using do_gettimeofday which only allows a timeval
@@ -410,7 +320,6 @@ void getnstimeofday(struct timespec *tv)
 }
 EXPORT_SYMBOL_GPL(getnstimeofday);
 #endif
-#endif /* CONFIG_TIME_INTERPOLATION */
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
index 438c6b723ee202bd3a22607f2ebf7d4b031d1f6b..b5e352597cbb628091718d2ac486b59564a95cfc 100644 (file)
@@ -116,11 +116,6 @@ void second_overflow(void)
                if (xtime.tv_sec % 86400 == 0) {
                        xtime.tv_sec--;
                        wall_to_monotonic.tv_sec++;
-                       /*
-                        * The timer interpolator will make time change
-                        * gradually instead of an immediate jump by one second
-                        */
-                       time_interpolator_update(-NSEC_PER_SEC);
                        time_state = TIME_OOP;
                        printk(KERN_NOTICE "Clock: inserting leap second "
                                        "23:59:60 UTC\n");
@@ -130,11 +125,6 @@ void second_overflow(void)
                if ((xtime.tv_sec + 1) % 86400 == 0) {
                        xtime.tv_sec++;
                        wall_to_monotonic.tv_sec--;
-                       /*
-                        * Use of time interpolator for a gradual change of
-                        * time
-                        */
-                       time_interpolator_update(NSEC_PER_SEC);
                        time_state = TIME_WAIT;
                        printk(KERN_NOTICE "Clock: deleting leap second "
                                        "23:59:59 UTC\n");
index 89698776613eb5c51d6dca9d385abc0dc0422bc3..88c81026e0039ae8cf16e3da6b1de223d3c96312 100644 (file)
@@ -466,10 +466,6 @@ void update_wall_time(void)
                        second_overflow();
                }
 
-               /* interpolator bits */
-               time_interpolator_update(clock->xtime_interval
-                                               >> clock->shift);
-
                /* accumulate error between NTP and clock interval */
                clock->error += current_tick_length();
                clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
index d1e8b975c7aede3bb6b690efe0258f0eb84d1585..6ce1952eea7dbf84d4d9a4c3a5d03f8fd5bffbf3 100644 (file)
@@ -1349,194 +1349,6 @@ void __init init_timers(void)
        open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
 }
 
-#ifdef CONFIG_TIME_INTERPOLATION
-
-struct time_interpolator *time_interpolator __read_mostly;
-static struct time_interpolator *time_interpolator_list __read_mostly;
-static DEFINE_SPINLOCK(time_interpolator_lock);
-
-static inline cycles_t time_interpolator_get_cycles(unsigned int src)
-{
-       unsigned long (*x)(void);
-
-       switch (src)
-       {
-               case TIME_SOURCE_FUNCTION:
-                       x = time_interpolator->addr;
-                       return x();
-
-               case TIME_SOURCE_MMIO64 :
-                       return readq_relaxed((void __iomem *)time_interpolator->addr);
-
-               case TIME_SOURCE_MMIO32 :
-                       return readl_relaxed((void __iomem *)time_interpolator->addr);
-
-               default: return get_cycles();
-       }
-}
-
-static inline u64 time_interpolator_get_counter(int writelock)
-{
-       unsigned int src = time_interpolator->source;
-
-       if (time_interpolator->jitter)
-       {
-               cycles_t lcycle;
-               cycles_t now;
-
-               do {
-                       lcycle = time_interpolator->last_cycle;
-                       now = time_interpolator_get_cycles(src);
-                       if (lcycle && time_after(lcycle, now))
-                               return lcycle;
-
-                       /* When holding the xtime write lock, there's no need
-                        * to add the overhead of the cmpxchg.  Readers are
-                        * force to retry until the write lock is released.
-                        */
-                       if (writelock) {
-                               time_interpolator->last_cycle = now;
-                               return now;
-                       }
-                       /* Keep track of the last timer value returned. The use of cmpxchg here
-                        * will cause contention in an SMP environment.
-                        */
-               } while (unlikely(cmpxchg(&time_interpolator->last_cycle, lcycle, now) != lcycle));
-               return now;
-       }
-       else
-               return time_interpolator_get_cycles(src);
-}
-
-void time_interpolator_reset(void)
-{
-       time_interpolator->offset = 0;
-       time_interpolator->last_counter = time_interpolator_get_counter(1);
-}
-
-#define GET_TI_NSECS(count,i) (((((count) - i->last_counter) & (i)->mask) * (i)->nsec_per_cyc) >> (i)->shift)
-
-unsigned long time_interpolator_get_offset(void)
-{
-       /* If we do not have a time interpolator set up then just return zero */
-       if (!time_interpolator)
-               return 0;
-
-       return time_interpolator->offset +
-               GET_TI_NSECS(time_interpolator_get_counter(0), time_interpolator);
-}
-
-#define INTERPOLATOR_ADJUST 65536
-#define INTERPOLATOR_MAX_SKIP 10*INTERPOLATOR_ADJUST
-
-void time_interpolator_update(long delta_nsec)
-{
-       u64 counter;
-       unsigned long offset;
-
-       /* If there is no time interpolator set up then do nothing */
-       if (!time_interpolator)
-               return;
-
-       /*
-        * The interpolator compensates for late ticks by accumulating the late
-        * time in time_interpolator->offset. A tick earlier than expected will
-        * lead to a reset of the offset and a corresponding jump of the clock
-        * forward. Again this only works if the interpolator clock is running
-        * slightly slower than the regular clock and the tuning logic insures
-        * that.
-        */
-
-       counter = time_interpolator_get_counter(1);
-       offset = time_interpolator->offset +
-                       GET_TI_NSECS(counter, time_interpolator);
-
-       if (delta_nsec < 0 || (unsigned long) delta_nsec < offset)
-               time_interpolator->offset = offset - delta_nsec;
-       else {
-               time_interpolator->skips++;
-               time_interpolator->ns_skipped += delta_nsec - offset;
-               time_interpolator->offset = 0;
-       }
-       time_interpolator->last_counter = counter;
-
-       /* Tuning logic for time interpolator invoked every minute or so.
-        * Decrease interpolator clock speed if no skips occurred and an offset is carried.
-        * Increase interpolator clock speed if we skip too much time.
-        */
-       if (jiffies % INTERPOLATOR_ADJUST == 0)
-       {
-               if (time_interpolator->skips == 0 && time_interpolator->offset > tick_nsec)
-                       time_interpolator->nsec_per_cyc--;
-               if (time_interpolator->ns_skipped > INTERPOLATOR_MAX_SKIP && time_interpolator->offset == 0)
-                       time_interpolator->nsec_per_cyc++;
-               time_interpolator->skips = 0;
-               time_interpolator->ns_skipped = 0;
-       }
-}
-
-static inline int
-is_better_time_interpolator(struct time_interpolator *new)
-{
-       if (!time_interpolator)
-               return 1;
-       return new->frequency > 2*time_interpolator->frequency ||
-           (unsigned long)new->drift < (unsigned long)time_interpolator->drift;
-}
-
-void
-register_time_interpolator(struct time_interpolator *ti)
-{
-       unsigned long flags;
-
-       /* Sanity check */
-       BUG_ON(ti->frequency == 0 || ti->mask == 0);
-
-       ti->nsec_per_cyc = ((u64)NSEC_PER_SEC << ti->shift) / ti->frequency;
-       spin_lock(&time_interpolator_lock);
-       write_seqlock_irqsave(&xtime_lock, flags);
-       if (is_better_time_interpolator(ti)) {
-               time_interpolator = ti;
-               time_interpolator_reset();
-       }
-       write_sequnlock_irqrestore(&xtime_lock, flags);
-
-       ti->next = time_interpolator_list;
-       time_interpolator_list = ti;
-       spin_unlock(&time_interpolator_lock);
-}
-
-void
-unregister_time_interpolator(struct time_interpolator *ti)
-{
-       struct time_interpolator *curr, **prev;
-       unsigned long flags;
-
-       spin_lock(&time_interpolator_lock);
-       prev = &time_interpolator_list;
-       for (curr = *prev; curr; curr = curr->next) {
-               if (curr == ti) {
-                       *prev = curr->next;
-                       break;
-               }
-               prev = &curr->next;
-       }
-
-       write_seqlock_irqsave(&xtime_lock, flags);
-       if (ti == time_interpolator) {
-               /* we lost the best time-interpolator: */
-               time_interpolator = NULL;
-               /* find the next-best interpolator */
-               for (curr = time_interpolator_list; curr; curr = curr->next)
-                       if (is_better_time_interpolator(curr))
-                               time_interpolator = curr;
-               time_interpolator_reset();
-       }
-       write_sequnlock_irqrestore(&xtime_lock, flags);
-       spin_unlock(&time_interpolator_lock);
-}
-#endif /* CONFIG_TIME_INTERPOLATION */
-
 /**
  * msleep - sleep safely even with waitqueue interruptions
  * @msecs: Time in milliseconds to sleep for
index 43cb3b3e1679ca4d9574f4a9d333f92b913bfb63..40954fb815988675a8b71c27cbea08c2f13f22e4 100644 (file)
@@ -138,7 +138,7 @@ static unsigned long __meminitdata dma_reserve;
 #endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
   unsigned long __initdata required_kernelcore;
   unsigned long __initdata required_movablecore;
-  unsigned long __initdata zone_movable_pfn[MAX_NUMNODES];
+  unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];
 
   /* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
   int movable_zone;
index b1179dd3d8c30cb6eabce77b7b501b36c4a918c3..ca10df40784f960c820b90ff029a103aeac5185a 100644 (file)
@@ -194,7 +194,7 @@ static struct nf_ct_ext_type helper_extend __read_mostly = {
        .id     = NF_CT_EXT_HELPER,
 };
 
-int nf_conntrack_helper_init()
+int nf_conntrack_helper_init(void)
 {
        int err;
 
@@ -216,7 +216,7 @@ err1:
        return err;
 }
 
-void nf_conntrack_helper_fini()
+void nf_conntrack_helper_fini(void)
 {
        nf_ct_extend_unregister(&helper_extend);
        nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc,
index 7d8d8896e309fb62a3585e39f546cb8df6be4d5b..9468ec7971db933e2594171ff66c8dd17c9368c8 100755 (executable)
@@ -1,2 +1,2 @@
 #!/bin/sh
-indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
+indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1 "$@"
index 04579a517900c8a53038b690de47ad9b2fb45139..5ab7914d30ef66f9d8880372ed47123a550ae168 100644 (file)
@@ -1076,6 +1076,7 @@ static int initexit_section_ref_ok(const char *name)
                ".plt",                 /* seen on ARCH=um build on x86_64. Harmless */
                ".smp_locks",
                ".stab",
+               ".m68k_fixup",
                NULL
        };
        /* Start of section names */
index 9ea473823418858f5d4b9e90cf0c14726507d9c1..e48b9b37d228ddec3c0b4172ec493d70ee2f4db4 100644 (file)
@@ -65,6 +65,8 @@ source "sound/arm/Kconfig"
 
 source "sound/mips/Kconfig"
 
+source "sound/sh/Kconfig"
+
 # the following will depend on the order of config.
 # here assuming USB is defined before ALSA
 source "sound/usb/Kconfig"
index b7c7fb7c24c8f33e6071be8405ed821495afdc48..3ead922bd9c6f50b39e650c3e4172fe31798bf80 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
index ded516717940b1d1cba175775cde0ea6aea3a16f..028852374f215de4c14e46f52ffaf4541e0db3d2 100644 (file)
@@ -661,7 +661,7 @@ static struct transfer_info onyx_transfers[] = {
                .tag = 2,
        },
 #ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
-Once alsa gets supports for this kind of thing we can add it...
+       /* Once alsa gets supports for this kind of thing we can add it... */
        {
                /* digital compressed output */
                .formats =  SNDRV_PCM_FMTBIT_COMPRESSED_16BE,
@@ -713,7 +713,7 @@ static int onyx_prepare(struct codec_info_item *cii,
        if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
                /* mute and lock analog output */
                onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
-               if (onyx_write_register(onyx
+               if (onyx_write_register(onyx,
                                        ONYX_REG_DAC_CONTROL,
                                        v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
                        goto out_unlock;
index a96733a5beb88aa6cdd556d7c2f19d8797f0bd51..59b29cd482aed51bb1fd0c5b8553dd3470ccb41a 100644 (file)
@@ -1487,7 +1487,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
 
        snd_pcm_stream_lock_irq(substream);
        /* resume pause */
-       if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
+       if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED)
                snd_pcm_pause(substream, 0);
 
        /* pre-start/stop - all running streams are changed to DRAINING state */
index f30d171b6d964a8eb9504de9178aa8c5754e3893..5efe6523a589ee228456be47b63223e6febd0d00 100644 (file)
@@ -109,7 +109,7 @@ void snd_seq_instr_list_free(struct snd_seq_kinstr_list **list_ptr)
                        spin_lock_irqsave(&list->lock, flags);
                        while (instr->use) {
                                spin_unlock_irqrestore(&list->lock, flags);
-                               schedule_timeout_interruptible(1);
+                               schedule_timeout(1);
                                spin_lock_irqsave(&list->lock, flags);
                        }                               
                        spin_unlock_irqrestore(&list->lock, flags);
@@ -199,7 +199,7 @@ int snd_seq_instr_list_free_cond(struct snd_seq_kinstr_list *list,
                        instr = flist;
                        flist = instr->next;
                        while (instr->use)
-                               schedule_timeout_interruptible(1);
+                               schedule_timeout(1);
                        if (snd_seq_instr_free(instr, atomic)<0)
                                snd_printk(KERN_WARNING "instrument free problem\n");
                        instr = next;
@@ -555,7 +555,7 @@ static int instr_free(struct snd_seq_kinstr_ops *ops,
                                           SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
                while (instr->use) {
                        spin_unlock_irqrestore(&list->lock, flags);
-                       schedule_timeout_interruptible(1);
+                       schedule_timeout(1);
                        spin_lock_irqsave(&list->lock, flags);
                }                               
                spin_unlock_irqrestore(&list->lock, flags);
index 67520b3c0042d6f08178a8ed9c9d4fdfb5f25289..f2bbacedd567eedb518c628e33fbdd8dd3691351 100644 (file)
@@ -1549,9 +1549,11 @@ static int snd_timer_user_info(struct file *file,
        int err = 0;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        t = tu->timeri->timer;
-       snd_assert(t != NULL, return -ENXIO);
+       if (!t)
+               return -EBADFD;
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (! info)
@@ -1579,9 +1581,11 @@ static int snd_timer_user_params(struct file *file,
        int err;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        t = tu->timeri->timer;
-       snd_assert(t != NULL, return -ENXIO);
+       if (!t)
+               return -EBADFD;
        if (copy_from_user(&params, _params, sizeof(params)))
                return -EFAULT;
        if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
@@ -1675,7 +1679,8 @@ static int snd_timer_user_status(struct file *file,
        struct snd_timer_status status;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        memset(&status, 0, sizeof(status));
        status.tstamp = tu->tstamp;
        status.resolution = snd_timer_resolution(tu->timeri);
@@ -1695,7 +1700,8 @@ static int snd_timer_user_start(struct file *file)
        struct snd_timer_user *tu;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        snd_timer_stop(tu->timeri);
        tu->timeri->lost = 0;
        tu->last_resolution = 0;
@@ -1708,7 +1714,8 @@ static int snd_timer_user_stop(struct file *file)
        struct snd_timer_user *tu;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
 }
 
@@ -1718,7 +1725,8 @@ static int snd_timer_user_continue(struct file *file)
        struct snd_timer_user *tu;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        tu->timeri->lost = 0;
        return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
 }
@@ -1729,7 +1737,8 @@ static int snd_timer_user_pause(struct file *file)
        struct snd_timer_user *tu;
 
        tu = file->private_data;
-       snd_assert(tu->timeri != NULL, return -ENXIO);
+       if (!tu->timeri)
+               return -EBADFD;
        return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
 }
 
index a0f28f51fc7eb89c0b7ea30da694a224390df8b8..4360ae9de19c4ec96ed7449f2ac525aec92e36a1 100644 (file)
@@ -659,7 +659,7 @@ static struct platform_driver snd_dummy_driver = {
        },
 };
 
-static void __init_or_module snd_dummy_unregister_all(void)
+static void snd_dummy_unregister_all(void)
 {
        int i;
 
index 1d563e515c177035daa9fad2ee0342902867535e..67c6e9745418b53748a9d67c21efdf7f603c54cf 100644 (file)
@@ -228,7 +228,7 @@ static struct pnp_driver snd_mpu401_pnp_driver = {
 static struct pnp_driver snd_mpu401_pnp_driver;
 #endif
 
-static void __init_or_module snd_mpu401_unregister_all(void)
+static void snd_mpu401_unregister_all(void)
 {
        int i;
 
index 497cafb57d9b6ec0b16dbadc03775e82009fa88a..0eb9b5cebfcdefb44546a06a86fdd3ed4584b70c 100644 (file)
@@ -833,7 +833,7 @@ static struct platform_driver snd_portman_driver = {
 /*********************************************************************
  * module init stuff
  *********************************************************************/
-static void __init_or_module snd_portman_unregister_all(void)
+static void snd_portman_unregister_all(void)
 {
        int i;
 
index 838a4277929d8060bc0fdda7389e0273cfc4bea7..d3e6a20edd3875bbd536844bca32893c5834f922 100644 (file)
@@ -998,7 +998,7 @@ static struct platform_driver snd_serial_driver = {
        },
 };
 
-static void __init_or_module snd_serial_unregister_all(void)
+static void snd_serial_unregister_all(void)
 {
        int i;
 
index 46f3d34860679c677abe9ee83a32316f5005e243..915c86773c21fbe0a4635a9f5508c2537834f1a8 100644 (file)
@@ -145,7 +145,7 @@ static struct platform_driver snd_virmidi_driver = {
        },
 };
 
-static void __init_or_module snd_virmidi_unregister_all(void)
+static void snd_virmidi_unregister_all(void)
 {
        int i;
 
index 8805110017a7ece661d519a2e19d737089245849..fd335159f8499ee9f5b50ed7fb8ccee9fc9fd7b0 100644 (file)
@@ -481,8 +481,8 @@ static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
        int addr = AK_GET_ADDR(kcontrol->private_value);
        int shift = AK_GET_SHIFT(kcontrol->private_value);
        int invert = AK_GET_INVERT(kcontrol->private_value);
-       unsigned char val = snd_akm4xxx_get(ak, chip, addr);
-
+       /* we observe the (1<<shift) bit only */
+       unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
        if (invert)
                val = ! val;
        ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
@@ -585,6 +585,26 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
 
        mixer_ch = 0;
        for (idx = 0; idx < ak->num_dacs; ) {
+               /* mute control for Revolution 7.1 - AK4381 */
+               if (ak->type == SND_AK4381 
+                               &&  ak->dac_info[mixer_ch].switch_name) {
+                       memset(&knew, 0, sizeof(knew));
+                       knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+                       knew.count = 1;
+                       knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+                       knew.name = ak->dac_info[mixer_ch].switch_name;
+                       knew.info = ak4xxx_switch_info;
+                       knew.get = ak4xxx_switch_get;
+                       knew.put = ak4xxx_switch_put;
+                       knew.access = 0;
+                       /* register 1, bit 0 (SMUTE): 0 = normal operation,
+                          1 = mute */
+                       knew.private_value =
+                               AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
+                       err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+                       if (err < 0)
+                               return err;
+               }
                memset(&knew, 0, sizeof(knew));
                if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
                        knew.name = "DAC Volume";
index cf3803cd579cab497e055f57bdfd4f8af5bb892b..ea5084abe60f788530802b48ff5ee84f2c502ced 100644 (file)
@@ -1,8 +1,5 @@
 # ALSA ISA drivers
 
-menu "ISA devices"
-       depends on SND!=n && ISA && ISA_DMA_API
-
 config SND_AD1848_LIB
         tristate
         select SND_PCM
@@ -11,6 +8,22 @@ config SND_CS4231_LIB
         tristate
         select SND_PCM
 
+config SND_SB_COMMON
+        tristate
+
+config SND_SB8_DSP
+        tristate
+        select SND_PCM
+        select SND_SB_COMMON
+
+config SND_SB16_DSP
+        tristate
+        select SND_PCM
+        select SND_SB_COMMON
+
+menu "ISA devices"
+       depends on SND!=n && ISA && ISA_DMA_API
+
 config SND_ADLIB
        tristate "AdLib FM card"
        depends on SND
@@ -55,7 +68,7 @@ config SND_ALS100
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB16_DSP
        help
          Say Y here to include support for soundcards based on Avance
          Logic ALS100, ALS110, ALS120 and ALS200 chips.
@@ -81,6 +94,7 @@ config SND_CMI8330
        tristate "C-Media CMI8330"
        depends on SND
        select SND_AD1848_LIB
+       select SND_SB16_DSP
        help
          Say Y here to include support for soundcards based on the
          C-Media CMI8330 chip.
@@ -132,7 +146,7 @@ config SND_DT019X
        select ISAPNP
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB16_DSP
        help
          Say Y here to include support for soundcards based on the
          Diamond Technologies DT-019X or Avance Logic ALS-007 chips.
@@ -145,7 +159,7 @@ config SND_ES968
        depends on SND && PNP && ISA
        select ISAPNP
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB8_DSP
        help
          Say Y here to include support for ESS AudioDrive ES968 chips.
 
@@ -321,7 +335,7 @@ config SND_SB8
        depends on SND
        select SND_OPL3_LIB
        select SND_RAWMIDI
-       select SND_PCM
+       select SND_SB8_DSP
        help
          Say Y here to include support for Creative Sound Blaster 1.0/
          2.0/Pro (8-bit) or 100% compatible soundcards.
@@ -334,7 +348,7 @@ config SND_SB16
        depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB16_DSP
        help
          Say Y here to include support for Sound Blaster 16 soundcards
          (including the Plug and Play version).
@@ -347,7 +361,7 @@ config SND_SBAWE
        depends on SND
        select SND_OPL3_LIB
        select SND_MPU401_UART
-       select SND_PCM
+       select SND_SB16_DSP
        help
          Say Y here to include support for Sound Blaster AWE soundcards
          (including the Plug and Play version).
index 8094282c2ae1992d76f588018b28ad2390d44e3e..1bc2e3fd5721974bbf7c407b76e601603cc3e812 100644 (file)
@@ -245,7 +245,7 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
                        snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n");
                        return;
                }
-               time = schedule_timeout_interruptible(time);
+               time = schedule_timeout(time);
                spin_lock_irqsave(&chip->reg_lock, flags);
        }
 #if 0
@@ -258,7 +258,7 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
                        snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
                        return;
                }
-               time = schedule_timeout_interruptible(time);
+               time = schedule_timeout(time);
                spin_lock_irqsave(&chip->reg_lock, flags);
        }
        spin_unlock_irqrestore(&chip->reg_lock, flags);
index 4f6800b43b0e99bcc72f9235a23574a8d203f123..e70db32991d966073e8655cfd96f67ad1883f7be 100644 (file)
@@ -164,6 +164,8 @@ static struct pnp_card_device_id snd_opl3sa2_pnpids[] = {
        { .id = "YMH0801", .devs = { { "YMH0021" } } },
        /* NeoMagic MagicWave 3DX */
        { .id = "NMX2200", .devs = { { "YMH2210" } } },
+       /* NeoMagic MagicWave 3D */
+       { .id = "NMX2200", .devs = { { "NMX2210" } } },
        /* --- */
        { .id = "" }    /* end */
 };
index 60c120ffb9de9a664afcfaa26f36a2670823ebba..049d479ce2b33f8fcafb5da595474097eb093ee0 100644 (file)
@@ -1927,10 +1927,12 @@ static struct snd_card *snd_opti9xx_card_new(void)
 static int __devinit snd_opti9xx_isa_match(struct device *devptr,
                                           unsigned int dev)
 {
+#ifdef CONFIG_PNP
        if (snd_opti9xx_pnp_is_probed)
                return 0;
        if (isapnp)
                return 0;
+#endif
        return 1;
 }
 
@@ -2096,6 +2098,7 @@ static int __init alsa_card_opti9xx_init(void)
        pnp_register_card_driver(&opti9xx_pnpc_driver);
        if (snd_opti9xx_pnp_is_probed)
                return 0;
+       pnp_unregister_card_driver(&opti9xx_pnpc_driver);
 #endif
        return isa_register_driver(&snd_opti9xx_driver, 1);
 }
index fd9d9c5726fc303ccdd36221617013a8002e051f..556e66928029f91af7f75d8cf101c9c4992fa3c7 100644 (file)
@@ -22,14 +22,13 @@ snd-es968-objs := es968.o
 sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_ALS100) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_CMI8330) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_DT019X) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
+obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
+obj-$(CONFIG_SND_SB16_DSP) += snd-sb16-dsp.o
+obj-$(CONFIG_SND_SB8_DSP) += snd-sb8-dsp.o
+obj-$(CONFIG_SND_SB8) += snd-sb8.o
+obj-$(CONFIG_SND_SB16) += snd-sb16.o
+obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
+obj-$(CONFIG_SND_ES968) += snd-es968.o
 ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
   obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
index 383911b9e74dcc709c1e32412953660b2c49796f..5d4d3aafe2d5aaae3c2ca204e8d4030c583826e7 100644 (file)
@@ -563,6 +563,11 @@ static int snd_sb16_playback_open(struct snd_pcm_substream *substream)
       __open_ok:
        if (chip->hardware == SB_HW_ALS100)
                runtime->hw.rate_max = 48000;
+       if (chip->hardware == SB_HW_CS5530) {
+               runtime->hw.buffer_bytes_max = 32 * 1024;
+               runtime->hw.periods_min = 2;
+               runtime->hw.rate_min = 44100;
+       }
        if (chip->mode & SB_RATE_LOCK)
                runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
        chip->playback_substream = substream;
@@ -633,6 +638,11 @@ static int snd_sb16_capture_open(struct snd_pcm_substream *substream)
       __open_ok:
        if (chip->hardware == SB_HW_ALS100)
                runtime->hw.rate_max = 48000;
+       if (chip->hardware == SB_HW_CS5530) {
+               runtime->hw.buffer_bytes_max = 32 * 1024;
+               runtime->hw.periods_min = 2;
+               runtime->hw.rate_min = 44100;
+       }
        if (chip->mode & SB_RATE_LOCK)
                runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
        chip->capture_substream = substream;
index 3094f3852167c57585ff58418d3d92b45e8a1aea..efa9d5c2558a7a5b4cfcf75890523fcf6faafb79 100644 (file)
@@ -128,7 +128,7 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
        minor = version & 0xff;
        snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
                    chip->port, major, minor);
-       
+
        switch (chip->hardware) {
        case SB_HW_AUTO:
                switch (major) {
@@ -168,6 +168,9 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
        case SB_HW_DT019X:
                str = "(DT019X/ALS007)";
                break;
+       case SB_HW_CS5530:
+               str = "16 (CS5530)";
+               break;
        default:
                return -ENODEV;
        }
index 490b1ca5cf5882c3cff630dca4f637697e32117c..3d4befcff28efaf732167059ab3120c2a43f08ce 100644 (file)
@@ -821,6 +821,7 @@ int snd_sbmixer_new(struct snd_sb *chip)
                break;
        case SB_HW_16:
        case SB_HW_ALS100:
+       case SB_HW_CS5530:
                if ((err = snd_sbmixer_init(chip,
                                            snd_sb16_controls,
                                            ARRAY_SIZE(snd_sb16_controls),
@@ -950,6 +951,7 @@ void snd_sbmixer_suspend(struct snd_sb *chip)
                break;
        case SB_HW_16:
        case SB_HW_ALS100:
+       case SB_HW_CS5530:
                save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
                break;
        case SB_HW_ALS4000:
@@ -975,6 +977,7 @@ void snd_sbmixer_resume(struct snd_sb *chip)
                break;
        case SB_HW_16:
        case SB_HW_ALS100:
+       case SB_HW_CS5530:
                restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
                break;
        case SB_HW_ALS4000:
index 9ea417bcf3e593da7fd9cd4b7724a7ebbd090671..cbad2a51cbaacc1159acf0cde0ee0122f65e17e0 100644 (file)
@@ -382,7 +382,7 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
                unsigned long flags;
                unsigned char x;
 
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
 
                spin_lock_irqsave(&s->lock, flags);
                x = inb(HOST_DATA_IO(s->io_base));
@@ -409,7 +409,7 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
                unsigned long flags;
                unsigned char x;
 
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
 
                spin_lock_irqsave(&s->lock, flags);
                x = inb(HOST_DATA_IO(s->io_base));
index 78020d832e042ba089cae9c71f94833f988ec111..bacc51c865873117aeb7ed3964448cb8607cb79b 100644 (file)
@@ -1780,7 +1780,7 @@ wavefront_should_cause_interrupt (snd_wavefront_t *dev,
        outb (val,port);
        spin_unlock_irq(&dev->irq_lock);
        while (1) {
-               if ((timeout = schedule_timeout_interruptible(timeout)) == 0)
+               if ((timeout = schedule_timeout(timeout)) == 0)
                        return;
                if (dev->irq_ok)
                        return;
index 61e35ecc57b8586eacc939111938a2ca2ad01c4b..c6b44102aa5bb41571e6823cde32065db835f926 100644 (file)
@@ -33,6 +33,7 @@ config SND_ALS4000
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_PCM
+       select SND_SB_COMMON
        help
          Say Y here to include support for soundcards based on Avance Logic
          ALS4000 chips.
@@ -215,6 +216,16 @@ config SND_CS46XX_NEW_DSP
 
          This works better than the old code, so say Y.
 
+config SND_CS5530
+       tristate "CS5530 Audio"
+       depends on SND && ISA_DMA_API
+       select SND_SB16_DSP
+       help
+         Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips.
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd-cs5530.
+
 config SND_CS5535AUDIO
        tristate "CS5535/CS5536 Audio"
        depends on SND && X86 && !X86_64
index e06736da9ef196e8fc766d2c2c96a8f7258ec94d..cd76e0293d06b53d2e74e1ccc87b1181e320c59a 100644 (file)
@@ -12,6 +12,7 @@ snd-azt3328-objs := azt3328.o
 snd-bt87x-objs := bt87x.o
 snd-cmipci-objs := cmipci.o
 snd-cs4281-objs := cs4281.o
+snd-cs5530-objs := cs5530.o
 snd-ens1370-objs := ens1370.o
 snd-ens1371-objs := ens1371.o
 snd-es1938-objs := es1938.o
@@ -36,6 +37,7 @@ obj-$(CONFIG_SND_AZT3328) += snd-azt3328.o
 obj-$(CONFIG_SND_BT87X) += snd-bt87x.o
 obj-$(CONFIG_SND_CMIPCI) += snd-cmipci.o
 obj-$(CONFIG_SND_CS4281) += snd-cs4281.o
+obj-$(CONFIG_SND_CS5530) += snd-cs5530.o
 obj-$(CONFIG_SND_ENS1370) += snd-ens1370.o
 obj-$(CONFIG_SND_ENS1371) += snd-ens1371.o
 obj-$(CONFIG_SND_ES1938) += snd-es1938.o
index 41543a4933e7031c849892326df2ac3d43abb220..05b4c869694188f5955a29449b19c469662fbc75 100644 (file)
@@ -239,7 +239,7 @@ struct snd_ali_image {
 
 
 struct snd_ali {
-       unsigned long   irq;
+       int             irq;
        unsigned long   port;
        unsigned char   revision;
 
@@ -731,8 +731,7 @@ static void snd_ali_detect_spdif_rate(struct snd_ali *codec)
                return;
        }
 
-       count = 0;
-       while (count++ <= 50000) {
+       for (count = 0; count <= 50000; count++) {
                snd_ali_delay(codec, 6);
                bval = inb(ALI_REG(codec,ALI_SPDIF_CTRL + 1));
                R2 = bval & 0x1F;
@@ -2343,7 +2342,7 @@ static int __devinit snd_ali_probe(struct pci_dev *pci,
        strcpy(card->driver, "ALI5451");
        strcpy(card->shortname, "ALI 5451");
        
-       sprintf(card->longname, "%s at 0x%lx, irq %li",
+       sprintf(card->longname, "%s at 0x%lx, irq %i",
                card->shortname, codec->port, codec->irq);
 
        snd_ali_printk("register card.\n");
index 8afcb98ca7bb8cd377670b13b9f761553cd2bdbc..48cc39b771d9c12244ae452c10e29b8dccfb2988 100644 (file)
@@ -88,8 +88,8 @@
 #define PLAYBACK_BLOCK_COUNTER 0x9A
 #define RECORD_BLOCK_COUNTER   0x9B
 
-#define DEBUG_CALLS    1
-#define DEBUG_PLAY_REC 1
+#define DEBUG_CALLS    0
+#define DEBUG_PLAY_REC 0
 
 #if DEBUG_CALLS
 #define snd_als300_dbgcalls(format, args...) printk(format, ##args)
@@ -733,7 +733,8 @@ static int __devinit snd_als300_create(struct snd_card *card,
 
        snd_als300_init(chip);
 
-       if (snd_als300_ac97(chip) < 0) {
+       err = snd_als300_ac97(chip);
+       if (err < 0) {
                snd_printk(KERN_WARNING "Could not create ac97\n");
                snd_als300_free(chip);
                return err;
index 9fd7b8a5b75ec00ae24675789805debdc92849bc..fcab8fb97e38c455be98ed0a7557ba75cae716e7 100644 (file)
@@ -168,6 +168,25 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
 #include "ca0106.h"
 
 static struct snd_ca0106_details ca0106_chip_details[] = {
+        /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */
+        /* It is really just a normal SB Live 24bit. */
+        /*
+         * CTRL:CA0111-WTLF
+         * ADC: WM8775SEDS
+         * DAC: CS4382-KQZ
+         */
+        /* Tested:
+         * Playback on front, rear, center/lfe speakers
+         * Capture from Mic in.
+         * Not-Tested:
+         * Capture from Line in.
+         * Playback to digital out.
+         */
+        { .serial = 0x10121102,
+          .name   = "X-Fi Extreme Audio [SB0790]",
+          .gpio_type = 1,
+          .i2c_adc = 1 } ,
+        /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97.  */
         /* AudigyLS[SB0310] */
         { .serial = 0x10021102,
           .name   = "AudigyLS [SB0310]",
index bef1f6d1859c210917b8e09f7ccaa4fbd2df8129..71d7aab9d86987c57f585737904a43337bd5b836 100644 (file)
@@ -2897,6 +2897,10 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
        }
 #endif
        
+#ifdef CONFIG_PM
+       kfree(chip->saved_regs);
+#endif
+
        pci_disable_device(chip->pci);
        kfree(chip);
        return 0;
@@ -3140,6 +3144,23 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
 /*
  *  start and load DSP 
  */
+
+static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip)
+{
+       unsigned int tmp;
+
+       snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
+        
+       tmp = snd_cs46xx_peek(chip, BA1_PFIE);
+       tmp &= ~0x0000f03f;
+       snd_cs46xx_poke(chip, BA1_PFIE, tmp);   /* playback interrupt enable */
+
+       tmp = snd_cs46xx_peek(chip, BA1_CIE);
+       tmp &= ~0x0000003f;
+       tmp |=  0x00000001;
+       snd_cs46xx_poke(chip, BA1_CIE, tmp);    /* capture interrupt enable */
+}
+
 int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
 {      
        unsigned int tmp;
@@ -3214,19 +3235,7 @@ int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
 
        snd_cs46xx_proc_start(chip);
 
-       /*
-        *  Enable interrupts on the part.
-        */
-       snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
-        
-       tmp = snd_cs46xx_peek(chip, BA1_PFIE);
-       tmp &= ~0x0000f03f;
-       snd_cs46xx_poke(chip, BA1_PFIE, tmp);   /* playback interrupt enable */
-
-       tmp = snd_cs46xx_peek(chip, BA1_CIE);
-       tmp &= ~0x0000003f;
-       tmp |=  0x00000001;
-       snd_cs46xx_poke(chip, BA1_CIE, tmp);    /* capture interrupt enable */
+       cs46xx_enable_stream_irqs(chip);
        
 #ifndef CONFIG_SND_CS46XX_NEW_DSP
        /* set the attenuation to 0dB */ 
@@ -3665,11 +3674,19 @@ static struct cs_card_type __devinitdata cards[] = {
  * APM support
  */
 #ifdef CONFIG_PM
+static unsigned int saved_regs[] = {
+       BA0_ACOSV,
+       BA0_ASER_FADDR,
+       BA0_ASER_MASTER,
+       BA1_PVOL,
+       BA1_CVOL,
+};
+
 int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state)
 {
        struct snd_card *card = pci_get_drvdata(pci);
        struct snd_cs46xx *chip = card->private_data;
-       int amp_saved;
+       int i, amp_saved;
 
        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
        chip->in_suspend = 1;
@@ -3680,6 +3697,10 @@ int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state)
        snd_ac97_suspend(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
        snd_ac97_suspend(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
 
+       /* save some registers */
+       for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
+               chip->saved_regs[i] = snd_cs46xx_peekBA0(chip, saved_regs[i]);
+
        amp_saved = chip->amplifier;
        /* turn off amp */
        chip->amplifier_ctrl(chip, -chip->amplifier);
@@ -3698,7 +3719,7 @@ int snd_cs46xx_resume(struct pci_dev *pci)
 {
        struct snd_card *card = pci_get_drvdata(pci);
        struct snd_cs46xx *chip = card->private_data;
-       int amp_saved;
+       int i, amp_saved;
 
        pci_set_power_state(pci, PCI_D0);
        pci_restore_state(pci);
@@ -3716,6 +3737,16 @@ int snd_cs46xx_resume(struct pci_dev *pci)
 
        snd_cs46xx_chip_init(chip);
 
+       snd_cs46xx_reset(chip);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+       cs46xx_dsp_resume(chip);
+       /* restore some registers */
+       for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
+               snd_cs46xx_pokeBA0(chip, saved_regs[i], chip->saved_regs[i]);
+#else
+       snd_cs46xx_download_image(chip);
+#endif
+
 #if 0
        snd_cs46xx_codec_write(chip, BA0_AC97_GENERAL_PURPOSE, 
                               chip->ac97_general_purpose);
@@ -3730,6 +3761,13 @@ int snd_cs46xx_resume(struct pci_dev *pci)
        snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
        snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
 
+       /* reset playback/capture */
+       snd_cs46xx_set_play_sample_rate(chip, 8000);
+       snd_cs46xx_set_capture_sample_rate(chip, 8000);
+       snd_cs46xx_proc_start(chip);
+
+       cs46xx_enable_stream_irqs(chip);
+
        if (amp_saved)
                chip->amplifier_ctrl(chip, 1); /* turn amp on */
        else
@@ -3896,6 +3934,15 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
        
        snd_cs46xx_proc_init(card, chip);
 
+#ifdef CONFIG_PM
+       chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *
+                                  ARRAY_SIZE(saved_regs), GFP_KERNEL);
+       if (!chip->saved_regs) {
+               snd_cs46xx_free(chip);
+               return -ENOMEM;
+       }
+#endif
+
        chip->active_ctrl(chip, -1); /* disable CLKRUN */
 
        snd_card_set_dev(card, &pci->dev);
index f75750c2bd245c31bbe30a22107c7ea804c52add..20dcd72f06c1fd7c168991a92478ccf23dc4f252 100644 (file)
@@ -86,6 +86,9 @@ static inline unsigned int snd_cs46xx_peekBA0(struct snd_cs46xx *chip, unsigned
 struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);
 void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module);
+#ifdef CONFIG_PM
+int cs46xx_dsp_resume(struct snd_cs46xx * chip);
+#endif
 struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name,
                                                   int symbol_type);
 #ifdef CONFIG_PROC_FS
index 336e77e2600c36a3f72bcb240fb7fee8f35380ea..590b35d91df24e3f4e2d0c445fcf01d17c7a4f03 100644 (file)
@@ -306,13 +306,59 @@ void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
        mutex_unlock(&chip->spos_mutex);
 }
 
+static int dsp_load_parameter(struct snd_cs46xx *chip,
+                             struct dsp_segment_desc *parameter)
+{
+       u32 doffset, dsize;
+
+       if (!parameter) {
+               snd_printdd("dsp_spos: module got no parameter segment\n");
+               return 0;
+       }
+
+       doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
+       dsize   = parameter->size * 4;
+
+       snd_printdd("dsp_spos: "
+                   "downloading parameter data to chip (%08x-%08x)\n",
+                   doffset,doffset + dsize);
+       if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
+               snd_printk(KERN_ERR "dsp_spos: "
+                          "failed to download parameter data to DSP\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int dsp_load_sample(struct snd_cs46xx *chip,
+                          struct dsp_segment_desc *sample)
+{
+       u32 doffset, dsize;
+
+       if (!sample) {
+               snd_printdd("dsp_spos: module got no sample segment\n");
+               return 0;
+       }
+
+       doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
+       dsize   =  sample->size * 4;
+
+       snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
+                   doffset,doffset + dsize);
+
+       if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
+               snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
        struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);
-       struct dsp_segment_desc * parameter = get_segment_desc (module,SEGTYPE_SP_PARAMETER);
-       struct dsp_segment_desc * sample = get_segment_desc (module,SEGTYPE_SP_SAMPLE);
        u32 doffset, dsize;
+       int err;
 
        if (ins->nmodules == DSP_MAX_MODULES - 1) {
                snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n");
@@ -326,49 +372,20 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
                snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
        }
   
-       if (parameter == NULL) {
-               snd_printdd("dsp_spos: module got no parameter segment\n");
-       } else {
-               if (ins->nmodules > 0) {
-                       snd_printk(KERN_WARNING "dsp_spos: WARNING current parameter data may be overwriten!\n");
-               }
-
-               doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
-               dsize   = parameter->size * 4;
-
-               snd_printdd("dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
-                           doffset,doffset + dsize);
-
-               if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
-                       snd_printk(KERN_ERR "dsp_spos: failed to download parameter data to DSP\n");
-                       return -EINVAL;
-               }
-       }
+       err = dsp_load_parameter(chip, get_segment_desc(module,
+                                                       SEGTYPE_SP_PARAMETER));
+       if (err < 0)
+               return err;
 
        if (ins->nmodules == 0) {
                snd_printdd("dsp_spos: clearing sample area\n");
                snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
        }
 
-       if (sample == NULL) {
-               snd_printdd("dsp_spos: module got no sample segment\n");
-       } else {
-               if (ins->nmodules > 0) {
-                       snd_printk(KERN_WARNING "dsp_spos: WARNING current sample data may be overwriten\n");
-               }
-
-               doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
-               dsize   =  sample->size * 4;
-
-               snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
-                           doffset,doffset + dsize);
-
-               if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
-                       snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
-                       return -EINVAL;
-               }
-       }
-
+       err = dsp_load_sample(chip, get_segment_desc(module,
+                                                    SEGTYPE_SP_SAMPLE));
+       if (err < 0)
+               return err;
 
        if (ins->nmodules == 0) {
                snd_printdd("dsp_spos: clearing code area\n");
@@ -986,7 +1003,10 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
                return NULL;
        }
 
-       strcpy(ins->tasks[ins->ntask].task_name,name);
+       if (name)
+               strcpy(ins->tasks[ins->ntask].task_name, name);
+       else
+               strcpy(ins->tasks[ins->ntask].task_name, "(NULL)");
        ins->tasks[ins->ntask].address = dest;
        ins->tasks[ins->ntask].size = size;
 
@@ -995,7 +1015,8 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
        desc = (ins->tasks + ins->ntask);
        ins->ntask++;
 
-       add_symbol (chip,name,dest,SYMBOL_PARAMETER);
+       if (name)
+               add_symbol (chip,name,dest,SYMBOL_PARAMETER);
        return desc;
 }
 
@@ -1006,6 +1027,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
 
        desc = _map_scb (chip,name,dest);
        if (desc) {
+               desc->data = scb_data;
                _dsp_create_scb(chip,scb_data,dest);
        } else {
                snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
@@ -1023,6 +1045,7 @@ cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_da
 
        desc = _map_task_tree (chip,name,dest,size);
        if (desc) {
+               desc->data = task_data;
                _dsp_create_task_tree(chip,task_data,dest,size);
        } else {
                snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n");
@@ -1320,8 +1343,10 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
                        0x0000ffff
                };
     
-               /* dirty hack ... */
-               _dsp_create_task_tree (chip,(u32 *)&mix2_ostream_spb,WRITE_BACK_SPB,2);
+               if (!cs46xx_dsp_create_task_tree(chip, NULL,
+                                                (u32 *)&mix2_ostream_spb,
+                                                WRITE_BACK_SPB, 2))
+                       goto _fail_end;
        }
 
        /* input sample converter */
@@ -1622,7 +1647,6 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
        return 0;
 }
 
-
 static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
@@ -1894,3 +1918,61 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
 
        return 0;
 }
+
+#ifdef CONFIG_PM
+int cs46xx_dsp_resume(struct snd_cs46xx * chip)
+{
+       struct dsp_spos_instance * ins = chip->dsp_spos_instance;
+       int i, err;
+
+       /* clear parameter, sample and code areas */
+       snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET,
+                            DSP_PARAMETER_BYTE_SIZE);
+       snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET,
+                            DSP_SAMPLE_BYTE_SIZE);
+       snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
+
+       for (i = 0; i < ins->nmodules; i++) {
+               struct dsp_module_desc *module = &ins->modules[i];
+               struct dsp_segment_desc *seg;
+               u32 doffset, dsize;
+
+               seg = get_segment_desc(module, SEGTYPE_SP_PARAMETER);
+               err = dsp_load_parameter(chip, seg);
+               if (err < 0)
+                       return err;
+
+               seg = get_segment_desc(module, SEGTYPE_SP_SAMPLE);
+               err = dsp_load_sample(chip, seg);
+               if (err < 0)
+                       return err;
+
+               seg = get_segment_desc(module, SEGTYPE_SP_PROGRAM);
+               if (!seg)
+                       continue;
+
+               doffset = seg->offset * 4 + module->load_address * 4
+                       + DSP_CODE_BYTE_OFFSET;
+               dsize   = seg->size * 4;
+               err = snd_cs46xx_download(chip,
+                                         ins->code.data + module->load_address,
+                                         doffset, dsize);
+               if (err < 0)
+                       return err;
+       }
+
+       for (i = 0; i < ins->ntask; i++) {
+               struct dsp_task_descriptor *t = &ins->tasks[i];
+               _dsp_create_task_tree(chip, t->data, t->address, t->size);
+       }
+
+       for (i = 0; i < ins->nscb; i++) {
+               struct dsp_scb_descriptor *s = &ins->scbs[i];
+               if (s->deleted)
+                       continue;
+               _dsp_create_scb(chip, s->data, s->address);
+       }
+
+       return 0;
+}
+#endif
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
new file mode 100644 (file)
index 0000000..240a0a4
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * cs5530.c - Initialisation code for Cyrix/NatSemi VSA1 softaudio
+ *
+ *     (C) Copyright 2007 Ash Willis <ashwillis@programmer.net>
+ *     (C) Copyright 2003 Red Hat Inc <alan@redhat.com>
+ *
+ * This driver was ported (shamelessly ripped ;) from oss/kahlua.c but I did
+ * mess with it a bit. The chip seems to have to have trouble with full duplex
+ * mode. If we're recording in 8bit 8000kHz, say, and we then attempt to
+ * simultaneously play back audio at 16bit 44100kHz, the device actually plays
+ * back in the same format in which it is capturing. By forcing the chip to
+ * always play/capture in 16/44100, we can let alsa-lib convert the samples and
+ * that way we can hack up some full duplex audio. 
+ * 
+ * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
+ * The older version (VSA1) provides fairly good soundblaster emulation
+ * although there are a couple of bugs: large DMA buffers break record,
+ * and the MPU event handling seems suspect. VSA2 allows the native driver
+ * to control the AC97 audio engine directly and requires a different driver.
+ *
+ * Thanks to National Semiconductor for providing the needed information
+ * on the XpressAudio(tm) internals.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * TO DO:
+ *     Investigate whether we can portably support Cognac (5520) in the
+ *     same manner.
+ */
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/sb.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Ash Willis");
+MODULE_DESCRIPTION("CS5530 Audio");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+struct snd_cs5530 {
+       struct snd_card *card;
+       struct pci_dev *pci;
+       struct snd_sb *sb;
+       unsigned long pci_base;
+};
+
+static struct pci_device_id snd_cs5530_ids[] = {
+       {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
+                                                       PCI_ANY_ID, 0, 0},
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, snd_cs5530_ids);
+
+static int snd_cs5530_free(struct snd_cs5530 *chip)
+{
+       pci_release_regions(chip->pci);
+       pci_disable_device(chip->pci);
+       kfree(chip);
+       return 0;
+}
+
+static int snd_cs5530_dev_free(struct snd_device *device)
+{
+       struct snd_cs5530 *chip = device->device_data;
+       return snd_cs5530_free(chip);
+}
+
+static void __devexit snd_cs5530_remove(struct pci_dev *pci)
+{
+       snd_card_free(pci_get_drvdata(pci));
+       pci_set_drvdata(pci, NULL);
+}
+
+static u8 __devinit snd_cs5530_mixer_read(unsigned long io, u8 reg)
+{
+       outb(reg, io + 4);
+       udelay(20);
+       reg = inb(io + 5);
+       udelay(20);
+       return reg;
+}
+
+static int __devinit snd_cs5530_create(struct snd_card *card,
+                                      struct pci_dev *pci,
+                                      struct snd_cs5530 **rchip)
+{
+       struct snd_cs5530 *chip;
+       unsigned long sb_base;
+       u8 irq, dma8, dma16 = 0;
+       u16 map;
+       void __iomem *mem;
+       int err;
+
+       static struct snd_device_ops ops = {
+               .dev_free = snd_cs5530_dev_free,
+       };
+       *rchip = NULL;
+
+       err = pci_enable_device(pci);
+       if (err < 0)
+               return err;
+
+       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               pci_disable_device(pci);
+               return -ENOMEM;
+       }
+
+       chip->card = card;
+       chip->pci = pci;
+
+       err = pci_request_regions(pci, "CS5530");
+       if (err < 0) {
+               kfree(chip); 
+               pci_disable_device(pci);
+               return err;
+       }
+       chip->pci_base = pci_resource_start(pci, 0);
+
+       mem = ioremap_nocache(chip->pci_base, pci_resource_len(pci, 0));
+       if (mem == NULL) {
+               kfree(chip);
+               pci_disable_device(pci);
+               return -EBUSY;
+       }
+
+       map = readw(mem + 0x18);
+       iounmap(mem);
+
+       /* Map bits
+               0:1     * 0x20 + 0x200 = sb base
+               2       sb enable
+               3       adlib enable
+               5       MPU enable 0x330
+               6       MPU enable 0x300
+
+          The other bits may be used internally so must be masked */
+
+       sb_base = 0x220 + 0x20 * (map & 3);
+
+       if (map & (1<<2))
+               printk(KERN_INFO "CS5530: XpressAudio at 0x%lx\n", sb_base);
+       else {
+               printk(KERN_ERR "Could not find XpressAudio!\n");
+               snd_cs5530_free(chip);
+               return -ENODEV;
+       }
+
+       if (map & (1<<5))
+               printk(KERN_INFO "CS5530: MPU at 0x300\n");
+       else if (map & (1<<6))
+               printk(KERN_INFO "CS5530: MPU at 0x330\n");
+
+       irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
+       dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
+
+       if (dma8 & 0x20)
+               dma16 = 5;
+       else if (dma8 & 0x40)
+               dma16 = 6;
+       else if (dma8 & 0x80)
+               dma16 = 7;
+       else {
+               printk(KERN_ERR "CS5530: No 16bit DMA enabled\n");
+               snd_cs5530_free(chip);
+               return -ENODEV;
+       }
+
+       if (dma8 & 0x01)
+               dma8 = 0;
+       else if (dma8 & 02)
+               dma8 = 1;
+       else if (dma8 & 0x08)
+               dma8 = 3;
+       else {
+               printk(KERN_ERR "CS5530: No 8bit DMA enabled\n");
+               snd_cs5530_free(chip);
+               return -ENODEV;
+       }
+
+       if (irq & 1)
+               irq = 9;
+       else if (irq & 2)
+               irq = 5;
+       else if (irq & 4)
+               irq = 7;
+       else if (irq & 8)
+               irq = 10;
+       else {
+               printk(KERN_ERR "CS5530: SoundBlaster IRQ not set\n");
+               snd_cs5530_free(chip);
+               return -ENODEV;
+       }
+
+       printk(KERN_INFO "CS5530: IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, 
+                                                                       dma16);
+
+       err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
+                                               dma16, SB_HW_CS5530, &chip->sb);
+       if (err < 0) {
+               printk(KERN_ERR "CS5530: Could not create SoundBlaster\n");
+               snd_cs5530_free(chip);
+               return err;
+       }
+
+       err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm);
+       if (err < 0) {
+               printk(KERN_ERR "CS5530: Could not create PCM\n");
+               snd_cs5530_free(chip);
+               return err;
+       }
+
+       err = snd_sbmixer_new(chip->sb);
+       if (err < 0) {
+               printk(KERN_ERR "CS5530: Could not create Mixer\n");
+               snd_cs5530_free(chip);
+               return err;
+       }
+
+       err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+       if (err < 0) {
+               snd_cs5530_free(chip);
+               return err;
+       }
+
+       snd_card_set_dev(card, &pci->dev);
+       *rchip = chip;
+       return 0;
+}
+
+static int __devinit snd_cs5530_probe(struct pci_dev *pci,
+                                       const struct pci_device_id *pci_id)
+{
+       static int dev;
+       struct snd_card *card;
+       struct snd_cs5530 *chip = NULL;
+       int err;
+
+       if (dev >= SNDRV_CARDS)
+               return -ENODEV;
+       if (!enable[dev]) {
+               dev++;
+               return -ENOENT;
+       }
+
+       card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+
+       if (card == NULL)
+               return -ENOMEM;
+
+       err = snd_cs5530_create(card, pci, &chip);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+
+       strcpy(card->driver, "CS5530");
+       strcpy(card->shortname, "CS5530 Audio");
+       sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
+
+       err = snd_card_register(card);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+       pci_set_drvdata(pci, card);
+       dev++;
+       return 0;
+}
+
+static struct pci_driver driver = {
+       .name = "CS5530_Audio",
+       .id_table = snd_cs5530_ids,
+       .probe = snd_cs5530_probe,
+       .remove = __devexit_p(snd_cs5530_remove),
+};
+
+static int __init alsa_card_cs5530_init(void)
+{
+       return pci_register_driver(&driver);
+}
+
+static void __exit alsa_card_cs5530_exit(void)
+{
+       pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_cs5530_init)
+module_exit(alsa_card_cs5530_exit)
+
index 4a9b59ad8ab12592a34420b961d1f118d4dbb346..404ae1be0a4b07c3a765fe05b0374bfc1e4e5c06 100644 (file)
 
 #define HANA_FILENAME "emu/hana.fw"
 #define DOCK_FILENAME "emu/audio_dock.fw"
+#define EMU1010B_FILENAME "emu/emu1010b.fw"
+#define MICRO_DOCK_FILENAME "emu/micro_dock.fw"
+#define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw"
 
 MODULE_FIRMWARE(HANA_FILENAME);
 MODULE_FIRMWARE(DOCK_FILENAME);
+MODULE_FIRMWARE(EMU1010B_FILENAME);
+MODULE_FIRMWARE(MICRO_DOCK_FILENAME);
+MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);
 
 
 /*************************************************************************
@@ -660,10 +666,12 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
                return err;
        }
        snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
+#if 0
        if (fw_entry->size != 0x133a4) {
                snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename);
                return -EINVAL;
        }
+#endif
 
        /* The FPGA is a Xilinx Spartan IIE XC2S50E */
        /* GPIO7 -> FPGA PGMN
@@ -694,6 +702,37 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
        return 0;
 }
 
+/*
+ * EMU-1010 - details found out from this driver, official MS Win drivers,
+ * testing the card:
+ *
+ * Audigy2 (aka Alice2):
+ * ---------------------
+ *     * communication over PCI
+ *     * conversion of 32-bit data coming over EMU32 links from HANA FPGA
+ *       to 2 x 16-bit, using internal DSP instructions
+ *     * slave mode, clock supplied by HANA
+ *     * linked to HANA using:
+ *             32 x 32-bit serial EMU32 output channels
+ *             16 x EMU32 input channels
+ *             (?) x I2S I/O channels (?)
+ *
+ * FPGA (aka HANA):
+ * ---------------
+ *     * provides all (?) physical inputs and outputs of the card
+ *             (ADC, DAC, SPDIF I/O, ADAT I/O, etc.)
+ *     * provides clock signal for the card and Alice2
+ *     * two crystals - for 44.1kHz and 48kHz multiples
+ *     * provides internal routing of signal sources to signal destinations
+ *     * inputs/outputs to Alice2 - see above
+ *
+ * Current status of the driver:
+ * ----------------------------
+ *     * only 44.1/48kHz supported (the MS Win driver supports up to 192 kHz)
+ *     * PCM device nb. 2:
+ *             16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops
+ *             16 x 32-bit capture - snd_emu10k1_capture_efx_ops
+ */
 static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
 {
        unsigned int i;
@@ -727,7 +766,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
        /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
        snd_printdd("reg1=0x%x\n",reg);
-       if (reg == 0x55) {
+       if ((reg & 0x3f) == 0x15) {
                /* FPGA netlist already present so clear it */
                /* Return to programming mode */
 
@@ -735,19 +774,32 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
        }
        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
        snd_printdd("reg2=0x%x\n",reg);
-       if (reg == 0x55) {
+       if ((reg & 0x3f) == 0x15) {
                /* FPGA failed to return to programming mode */
+               snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n");
                return -ENODEV;
        }
        snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
-       if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
-               snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
-               return err;
+       if (emu->card_capabilities->emu1010 == 1) {
+               if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
+                       snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
+                       return err;
+               }
+       } else if (emu->card_capabilities->emu1010 == 2) {
+               if ((err = snd_emu1010_load_firmware(emu, EMU1010B_FILENAME)) != 0) {
+                       snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010B_FILENAME);
+                       return err;
+               }
+       } else if (emu->card_capabilities->emu1010 == 3) {
+               if ((err = snd_emu1010_load_firmware(emu, EMU1010_NOTEBOOK_FILENAME)) != 0) {
+                       snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010_NOTEBOOK_FILENAME);
+                       return err;
+               }
        }
 
        /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
        snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
-       if (reg != 0x55) {
+       if ((reg & 0x3f) != 0x15) {
                /* FPGA failed to be programmed */
                snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg);
                return -ENODEV;
@@ -850,6 +902,27 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
                EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1);
        snd_emu1010_fpga_link_dst_src_write(emu,
                EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1);
+       /* Pavel Hofman - setting defaults for 8 more capture channels
+        * Defaults only, users will set their own values anyways, let's
+        * just copy/paste.
+        */
+       
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_9, EMU_SRC_DOCK_MIC_B1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_A, EMU_SRC_HAMOA_ADC_LEFT2);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_B, EMU_SRC_HAMOA_ADC_LEFT2);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_ADC1_LEFT1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_ADC1_RIGHT1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_E, EMU_SRC_DOCK_ADC2_LEFT1);
+       snd_emu1010_fpga_link_dst_src_write(emu,
+               EMU_DST_ALICE2_EMU32_F, EMU_SRC_DOCK_ADC2_RIGHT1);
 #endif
 #if 0
        /* Original */
@@ -943,16 +1016,27 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
                /* Return to Audio Dock programming mode */
                snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
                snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
-               if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
-                       return err;
+               if (emu->card_capabilities->emu1010 == 1) {
+                       if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
+                               return err;
+                       }
+               } else if (emu->card_capabilities->emu1010 == 2) {
+                       if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+                               return err;
+                       }
+               } else if (emu->card_capabilities->emu1010 == 3) {
+                       if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+                               return err;
+                       }
                }
+
                snd_emu1010_fpga_write(emu,  EMU_HANA_FPGA_CONFIG, 0 );
                snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
                snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
                /* ID, should read & 0x7f = 0x55 when FPGA programmed. */
                snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
                snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
-               if (reg != 0x55) {
+               if ((reg & 0x3f) != 0x15) {
                        /* FPGA failed to be programmed */
                        snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
                        return 0;
@@ -1227,9 +1311,15 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .emu10k2_chip = 1,
         .ca0108_chip = 1,
         .ca_cardbus_chip = 1,
-        .spi_dac = 1,
-        .i2c_adc = 1,
-        .spk71 = 1} ,
+        .spk71 = 1 ,
+        .emu1010 = 3} ,
+       {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
+        .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]", 
+        .id = "EMU1010",
+        .emu10k2_chip = 1,
+        .ca0108_chip = 1,
+        .spk71 = 1 ,
+        .emu1010 = 2} ,
        {.vendor = 0x1102, .device = 0x0008, 
         .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", 
         .id = "Audigy2",
@@ -1663,12 +1753,13 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
        emu->fx8010.extout_mask = extout_mask;
        emu->enable_ir = enable_ir;
 
+       if (emu->card_capabilities->ca_cardbus_chip) {
+               if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
+                       goto error;
+       }
        if (emu->card_capabilities->ecard) {
                if ((err = snd_emu10k1_ecard_init(emu)) < 0)
                        goto error;
-       } else if (emu->card_capabilities->ca_cardbus_chip) {
-               if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
-                       goto error;
        } else if (emu->card_capabilities->emu1010) {
                if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
                        snd_emu10k1_free(emu);
@@ -1814,10 +1905,10 @@ void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu)
 
 void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
 {
+       if (emu->card_capabilities->ca_cardbus_chip)
+               snd_emu10k1_cardbus_init(emu);
        if (emu->card_capabilities->ecard)
                snd_emu10k1_ecard_init(emu);
-       else if (emu->card_capabilities->ca_cardbus_chip)
-               snd_emu10k1_cardbus_init(emu);
        else if (emu->card_capabilities->emu1010)
                snd_emu10k1_emu1010_init(emu);
        else
index c02012cccd8ee767e0823539a6f287d2626c5362..7206c0fa06f28f8f27f303ee0dae80bcf747db00 100644 (file)
@@ -1123,6 +1123,11 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl
        ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
 }
 
+/*
+ * Used for emu1010 - conversion from 32-bit capture inputs from HANA
+ * to 2 x 16-bit registers in audigy - their values are read via DMA.
+ * Conversion is performed by Audigy DSP instructions of FX8010.
+ */
 static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
                                struct snd_emu10k1_fx8010_code *icode,
                                u32 *ptr, int tmp, int bit_shifter16,
@@ -1193,7 +1198,11 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
        snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
 
 #if 1
-       /* PCM front Playback Volume (independent from stereo mix) */
+       /* PCM front Playback Volume (independent from stereo mix)
+        * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
+        * where gpr contains attenuation from corresponding mixer control
+        * (snd_emu10k1_init_stereo_control)
+        */
        A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
        A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
        snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
@@ -1549,7 +1558,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
 
        if (emu->card_capabilities->emu1010) {
                snd_printk("EMU inputs on\n");
-               /* Capture 8 channels of S32_LE sound */
+               /* Capture 16 (originally 8) channels of S32_LE sound */
                
                /* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
                /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
@@ -1560,6 +1569,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
                /* Right ADC in 1 of 2 */
                gpr_map[gpr++] = 0x00000000;
+               /* Delaying by one sample: instead of copying the input
+                * value A_P16VIN to output A_FXBUS2 as in the first channel,
+                * we use an auxiliary register, delaying the value by one
+                * sample
+                */
                snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
                A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
                gpr_map[gpr++] = 0x00000000;
@@ -1583,6 +1597,66 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                gpr_map[gpr++] = 0x00000000;
                snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
                A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
+               /* Pavel Hofman - we still have voices, A_FXBUS2s, and
+                * A_P16VINs available -
+                * let's add 8 more capture channels - total of 16
+                */
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x10));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x12));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x14));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x16));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x18));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x1a));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x1c));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
+                    A_C_00000000, A_C_00000000);
+               gpr_map[gpr++] = 0x00000000;
+               snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+                                                         bit_shifter16,
+                                                         A_GPR(gpr - 1),
+                                                         A_FXBUS2(0x1e));
+               A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
+                    A_C_00000000, A_C_00000000);
 
 #if 0
                for (z = 4; z < 8; z++) {
index 4db6e1ca16653193f9dc3170d394ddefeff981b1..7b2c1dcc53376c76dbdd61928d2b8574043a51c4 100644 (file)
@@ -77,6 +77,10 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
+/*
+ * Items labels in enum mixer controls assigning source data to
+ * each destination
+ */
 static char *emu1010_src_texts[] = { 
        "Silence",
        "Dock Mic A",
@@ -133,6 +137,9 @@ static char *emu1010_src_texts[] = {
        "DSP 31",
 };
 
+/*
+ * List of data sources available for each destination
+ */
 static unsigned int emu1010_src_regs[] = {
        EMU_SRC_SILENCE,/* 0 */
        EMU_SRC_DOCK_MIC_A1, /* 1 */
@@ -189,6 +196,10 @@ static unsigned int emu1010_src_regs[] = {
        EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
 };
 
+/*
+ * Data destinations - physical EMU outputs.
+ * Each destination has an enum mixer control to choose a data source
+ */
 static unsigned int emu1010_output_dst[] = {
        EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
        EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
@@ -216,6 +227,11 @@ static unsigned int emu1010_output_dst[] = {
        EMU_DST_HANA_ADAT+7, /* 23 */
 };
 
+/*
+ * Data destinations - HANA outputs going to Alice2 (audigy) for
+ *   capture (EMU32 + I2S links)
+ * Each destination has an enum mixer control to choose a data source
+ */
 static unsigned int emu1010_input_dst[] = {
        EMU_DST_ALICE2_EMU32_0,
        EMU_DST_ALICE2_EMU32_1,
index ab4f5df5241b6f0471abbb23bda5be408cb9e9d8..eda5cb373ded3509e94279c5ea5c8ac7f1472ec4 100644 (file)
@@ -1233,24 +1233,26 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
        runtime->hw.rate_min = runtime->hw.rate_max = 48000;
        spin_lock_irq(&emu->reg_lock);
        if (emu->card_capabilities->emu1010) {
-               /* TODO 
+               /*  Nb. of channels has been increased to 16 */
+               /* TODO
                 * SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
                 * SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
                 * SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
                 * SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
                 * rate_min = 44100,
                 * rate_max = 192000,
-                * channels_min = 8,
-                * channels_max = 8,
+                * channels_min = 16,
+                * channels_max = 16,
                 * Need to add mixer control to fix sample rate
                 *                 
-                * There are 16 mono channels of 16bits each.
+                * There are 32 mono channels of 16bits each.
                 * 24bit Audio uses 2x channels over 16bit
                 * 96kHz uses 2x channels over 48kHz
                 * 192kHz uses 4x channels over 48kHz
-                * So, for 48kHz 24bit, one has 8 channels
-                * for 96kHz 24bit, one has 4 channels
-                * for 192kHz 24bit, one has 2 channels
+                * So, for 48kHz 24bit, one has 16 channels
+                * for 96kHz 24bit, one has 8 channels
+                * for 192kHz 24bit, one has 4 channels
+                *
                 */
 #if 1
                switch (emu->emu1010.internal_clock) {
@@ -1258,13 +1260,15 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
                        /* For 44.1kHz */
                        runtime->hw.rates = SNDRV_PCM_RATE_44100;
                        runtime->hw.rate_min = runtime->hw.rate_max = 44100;
-                       runtime->hw.channels_min = runtime->hw.channels_max = 8;
+                       runtime->hw.channels_min =
+                               runtime->hw.channels_max = 16;
                        break;
                case 1:
                        /* For 48kHz */
                        runtime->hw.rates = SNDRV_PCM_RATE_48000;
                        runtime->hw.rate_min = runtime->hw.rate_max = 48000;
-                       runtime->hw.channels_min = runtime->hw.channels_max = 8;
+                       runtime->hw.channels_min =
+                               runtime->hw.channels_max = 16;
                        break;
                };
 #endif
@@ -1282,7 +1286,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
 #endif
                runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
                /* efx_voices_mask[0] is expected to be zero
-                * efx_voices_mask[1] is expected to have 16bits set
+                * efx_voices_mask[1] is expected to have 32bits set
                 */
        } else {
                runtime->hw.channels_min = runtime->hw.channels_max = 0;
@@ -1787,11 +1791,24 @@ int __devinit snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct s
        /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */
        if (emu->audigy) {
                emu->efx_voices_mask[0] = 0;
-               emu->efx_voices_mask[1] = 0xffff;
+               if (emu->card_capabilities->emu1010)
+                       /* Pavel Hofman - 32 voices will be used for
+                        * capture (write mode) -
+                        * each bit = corresponding voice
+                        */
+                       emu->efx_voices_mask[1] = 0xffffffff;
+               else
+                       emu->efx_voices_mask[1] = 0xffff;
        } else {
                emu->efx_voices_mask[0] = 0xffff0000;
                emu->efx_voices_mask[1] = 0;
        }
+       /* For emu1010, the control has to set 32 upper bits (voices)
+        * out of the 64 bits (voices) to true for the 16-channels capture
+        * to work correctly. Correct A_FXWC2 initial value (0xffffffff)
+        * is already defined but the snd_emu10k1_pcm_efx_voices_mask
+        * control can override this register's value.
+        */
        kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
        if (!kctl)
                return -ENOMEM;
index 7c403965153b610780be5cc1c8c956d270f24ba6..21cb4268a59bf93645768a3a31850221a52a0462 100644 (file)
@@ -1607,8 +1607,8 @@ struct es1371_quirk {
        unsigned char rev;              /* revision */
 };
 
-static int __devinit es1371_quirk_lookup(struct ensoniq *ensoniq,
-                                        struct es1371_quirk *list)
+static int es1371_quirk_lookup(struct ensoniq *ensoniq,
+                               struct es1371_quirk *list)
 {
        while (list->vid != (unsigned short)PCI_ANY_ID) {
                if (ensoniq->pci->vendor == list->vid &&
index 2fa281cbef91c5698ef10c6df3ee6a7958db69b0..92bc8b3fa2a0b7b198f03b8d4c3d53f73b0cd469 100644 (file)
@@ -341,6 +341,9 @@ struct azx {
        unsigned int single_cmd :1;
        unsigned int polling_mode :1;
        unsigned int msi :1;
+
+       /* for debugging */
+       unsigned int last_cmd;  /* last issued command (to sync) */
 };
 
 /* driver types */
@@ -466,18 +469,10 @@ static void azx_free_cmd_io(struct azx *chip)
 }
 
 /* send a command */
-static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
-                            unsigned int verb, unsigned int para)
+static int azx_corb_send_cmd(struct hda_codec *codec, u32 val)
 {
        struct azx *chip = codec->bus->private_data;
        unsigned int wp;
-       u32 val;
-
-       val = (u32)(codec->addr & 0x0f) << 28;
-       val |= (u32)direct << 27;
-       val |= (u32)nid << 20;
-       val |= verb << 8;
-       val |= para;
 
        /* add command to corb */
        wp = azx_readb(chip, CORBWP);
@@ -538,12 +533,12 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
                }
                if (! chip->rirb.cmds)
                        return chip->rirb.res; /* the last value */
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
        } while (time_after_eq(timeout, jiffies));
 
        if (chip->msi) {
                snd_printk(KERN_WARNING "hda_intel: No response from codec, "
-                          "disabling MSI...\n");
+                          "disabling MSI: last cmd=0x%08x\n", chip->last_cmd);
                free_irq(chip->irq, chip);
                chip->irq = -1;
                pci_disable_msi(chip->pci);
@@ -555,13 +550,15 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
 
        if (!chip->polling_mode) {
                snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
-                          "switching to polling mode...\n");
+                          "switching to polling mode: last cmd=0x%08x\n",
+                          chip->last_cmd);
                chip->polling_mode = 1;
                goto again;
        }
 
        snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
-                  "switching to single_cmd mode...\n");
+                  "switching to single_cmd mode: last cmd=0x%08x\n",
+                  chip->last_cmd);
        chip->rirb.rp = azx_readb(chip, RIRBWP);
        chip->rirb.cmds = 0;
        /* switch to single_cmd mode */
@@ -581,20 +578,11 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
  */
 
 /* send a command */
-static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid,
-                              int direct, unsigned int verb,
-                              unsigned int para)
+static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
 {
        struct azx *chip = codec->bus->private_data;
-       u32 val;
        int timeout = 50;
 
-       val = (u32)(codec->addr & 0x0f) << 28;
-       val |= (u32)direct << 27;
-       val |= (u32)nid << 20;
-       val |= verb << 8;
-       val |= para;
-
        while (timeout--) {
                /* check ICB busy bit */
                if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) {
@@ -639,10 +627,19 @@ static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
                        unsigned int para)
 {
        struct azx *chip = codec->bus->private_data;
+       u32 val;
+
+       val = (u32)(codec->addr & 0x0f) << 28;
+       val |= (u32)direct << 27;
+       val |= (u32)nid << 20;
+       val |= verb << 8;
+       val |= para;
+       chip->last_cmd = val;
+
        if (chip->single_cmd)
-               return azx_single_send_cmd(codec, nid, direct, verb, para);
+               return azx_single_send_cmd(codec, val);
        else
-               return azx_corb_send_cmd(codec, nid, direct, verb, para);
+               return azx_corb_send_cmd(codec, val);
 }
 
 /* get a response */
@@ -1788,6 +1785,12 @@ static struct pci_device_id azx_ids[] = {
        { 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
        { 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
        { 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
+       { 0x10de, 0x07fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+       { 0x10de, 0x07fd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+       { 0x10de, 0x0774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+       { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+       { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+       { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, azx_ids);
index e313e685f1617bd664fbd1cf167dab6a7954cb16..ac15066fd300e7c62b706a48493930cc206c8893 100644 (file)
@@ -250,6 +250,12 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe
        snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
        snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
        snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
+
+       if (codec->mfg)
+               snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
+       else
+               snd_iprintf(buffer, "No Modem Function Group found\n");
+
        if (! codec->afg)
                return;
        snd_iprintf(buffer, "Default PCM:\n");
index 0e1a879663fa548b2ce8fde95f20c86ecb795262..4d7f8d11ad752c40688d4376c7fc69edf278bd80 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * HD audio interface patch for AD1981HD, AD1983, AD1986A, AD1988
+ * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
+ *   AD1986A, AD1988
  *
- * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de>
+ * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
  *
  *  This driver is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -61,7 +62,7 @@ struct ad198x_spec {
        int num_channel_mode;
 
        /* PCM information */
-       struct hda_pcm pcm_rec[2];      /* used in alc_build_pcms() */
+       struct hda_pcm pcm_rec[3];      /* used in alc_build_pcms() */
 
        struct mutex amp_mutex; /* PCM volume/mute control mutex */
        unsigned int spdif_route;
@@ -2774,12 +2775,635 @@ static int patch_ad1988(struct hda_codec *codec)
 }
 
 
+/*
+ * AD1884 / AD1984
+ *
+ * port-B - front line/mic-in
+ * port-E - aux in/out
+ * port-F - aux in/out
+ * port-C - rear line/mic-in
+ * port-D - rear line/hp-out
+ * port-A - front line/hp-out
+ *
+ * AD1984 = AD1884 + two digital mic-ins
+ *
+ * FIXME:
+ * For simplicity, we share the single DAC for both HP and line-outs
+ * right now.  The inidividual playbacks could be easily implemented,
+ * but no build-up framework is given, so far.
+ */
+
+static hda_nid_t ad1884_dac_nids[1] = {
+       0x04,
+};
+
+static hda_nid_t ad1884_adc_nids[2] = {
+       0x08, 0x09,
+};
+
+static hda_nid_t ad1884_capsrc_nids[2] = {
+       0x0c, 0x0d,
+};
+
+#define AD1884_SPDIF_OUT       0x02
+
+static struct hda_input_mux ad1884_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Front Mic", 0x0 },
+               { "Mic", 0x1 },
+               { "CD", 0x2 },
+               { "Mix", 0x3 },
+       },
+};
+
+static struct snd_kcontrol_new ad1884_base_mixers[] = {
+       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+       /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
+       /*
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
+       HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Digital Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+       */
+       HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = ad198x_mux_enum_info,
+               .get = ad198x_mux_enum_get,
+               .put = ad198x_mux_enum_put,
+       },
+       /* SPDIF controls */
+       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+               /* identical with ad1983 */
+               .info = ad1983_spdif_route_info,
+               .get = ad1983_spdif_route_get,
+               .put = ad1983_spdif_route_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
+       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
+                            HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
+                          HDA_INPUT),
+       { } /* end */
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1884_init_verbs[] = {
+       /* DACs; mute as default */
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* Port-A (HP) mixer */
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Port-A pin */
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* HP selector - select DAC2 */
+       {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* Port-D (Line-out) mixer */
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Port-D pin */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Mono-out mixer */
+       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Mono-out pin */
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Mono selector */
+       {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* Port-B (front mic) pin */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Port-C (rear mic) pin */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Analog mixer; mute as default */
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       /* Analog Mix output amp */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+       /* SPDIF output selector */
+       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+       { } /* end */
+};
+
+static int patch_ad1884(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       mutex_init(&spec->amp_mutex);
+       codec->spec = spec;
+
+       spec->multiout.max_channels = 2;
+       spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
+       spec->multiout.dac_nids = ad1884_dac_nids;
+       spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
+       spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
+       spec->adc_nids = ad1884_adc_nids;
+       spec->capsrc_nids = ad1884_capsrc_nids;
+       spec->input_mux = &ad1884_capture_source;
+       spec->num_mixers = 1;
+       spec->mixers[0] = ad1884_base_mixers;
+       spec->num_init_verbs = 1;
+       spec->init_verbs[0] = ad1884_init_verbs;
+       spec->spdif_route = 0;
+
+       codec->patch_ops = ad198x_patch_ops;
+
+       return 0;
+}
+
+/*
+ * Lenovo Thinkpad T61/X61
+ */
+static struct hda_input_mux ad1984_thinkpad_capture_source = {
+       .num_items = 3,
+       .items = {
+               { "Mic", 0x0 },
+               { "Internal Mic", 0x1 },
+               { "Mix", 0x3 },
+       },
+};
+
+static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
+       HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+       /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = ad198x_mux_enum_info,
+               .get = ad198x_mux_enum_get,
+               .put = ad198x_mux_enum_put,
+       },
+       { } /* end */
+};
+
+/* additional verbs */
+static struct hda_verb ad1984_thinkpad_init_verbs[] = {
+       /* Port-E (docking station mic) pin */
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* docking mic boost */
+       {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Analog mixer - docking mic; mute as default */
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       /* enable EAPD bit */
+       {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+       { } /* end */
+};
+
+/* Digial MIC ADC NID 0x05 + 0x06 */
+static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  unsigned int stream_tag,
+                                  unsigned int format,
+                                  struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
+                                  stream_tag, 0, format);
+       return 0;
+}
+
+static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
+                                  0, 0, 0);
+       return 0;
+}
+
+static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
+       .substreams = 2,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0x05,
+       .ops = {
+               .prepare = ad1984_pcm_dmic_prepare,
+               .cleanup = ad1984_pcm_dmic_cleanup
+       },
+};
+
+static int ad1984_build_pcms(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec = codec->spec;
+       struct hda_pcm *info;
+       int err;
+
+       err = ad198x_build_pcms(codec);
+       if (err < 0)
+               return err;
+
+       info = spec->pcm_rec + codec->num_pcms;
+       codec->num_pcms++;
+       info->name = "AD1984 Digital Mic";
+       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
+       return 0;
+}
+
+/* models */
+enum {
+       AD1984_BASIC,
+       AD1984_THINKPAD,
+       AD1984_MODELS
+};
+
+static const char *ad1984_models[AD1984_MODELS] = {
+       [AD1984_BASIC]          = "basic",
+       [AD1984_THINKPAD]       = "thinkpad",
+};
+
+static struct snd_pci_quirk ad1984_cfg_tbl[] = {
+       /* Lenovo Thinkpad T61/X61 */
+       SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
+       {}
+};
+
+static int patch_ad1984(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+       int board_config, err;
+
+       err = patch_ad1884(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+       board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
+                                                 ad1984_models, ad1984_cfg_tbl);
+       switch (board_config) {
+       case AD1984_BASIC:
+               /* additional digital mics */
+               spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
+               codec->patch_ops.build_pcms = ad1984_build_pcms;
+               break;
+       case AD1984_THINKPAD:
+               spec->multiout.dig_out_nid = 0;
+               spec->input_mux = &ad1984_thinkpad_capture_source;
+               spec->mixers[0] = ad1984_thinkpad_mixers;
+               spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
+               break;
+       }
+       return 0;
+}
+
+
+/*
+ * AD1882
+ *
+ * port-A - front hp-out
+ * port-B - front mic-in
+ * port-C - rear line-in, shared surr-out (3stack)
+ * port-D - rear line-out
+ * port-E - rear mic-in, shared clfe-out (3stack)
+ * port-F - rear surr-out (6stack)
+ * port-G - rear clfe-out (6stack)
+ */
+
+static hda_nid_t ad1882_dac_nids[3] = {
+       0x04, 0x03, 0x05
+};
+
+static hda_nid_t ad1882_adc_nids[2] = {
+       0x08, 0x09,
+};
+
+static hda_nid_t ad1882_capsrc_nids[2] = {
+       0x0c, 0x0d,
+};
+
+#define AD1882_SPDIF_OUT       0x02
+
+/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
+static struct hda_input_mux ad1882_capture_source = {
+       .num_items = 5,
+       .items = {
+               { "Front Mic", 0x1 },
+               { "Mic", 0x4 },
+               { "Line", 0x2 },
+               { "CD", 0x3 },
+               { "Mix", 0x7 },
+       },
+};
+
+static struct snd_kcontrol_new ad1882_base_mixers[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
+       HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = ad198x_mux_enum_info,
+               .get = ad198x_mux_enum_get,
+               .put = ad198x_mux_enum_put,
+       },
+       /* SPDIF controls */
+       HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+               /* identical with ad1983 */
+               .info = ad1983_spdif_route_info,
+               .get = ad1983_spdif_route_get,
+               .put = ad1983_spdif_route_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = ad198x_ch_mode_info,
+               .get = ad198x_ch_mode_get,
+               .put = ad198x_ch_mode_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
+       { } /* end */
+};
+
+static struct hda_verb ad1882_ch2_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       { } /* end */
+};
+
+static struct hda_verb ad1882_ch4_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       { } /* end */
+};
+
+static struct hda_verb ad1882_ch6_init[] = {
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       { } /* end */
+};
+
+static struct hda_channel_mode ad1882_modes[3] = {
+       { 2, ad1882_ch2_init },
+       { 4, ad1882_ch4_init },
+       { 6, ad1882_ch6_init },
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1882_init_verbs[] = {
+       /* DACs; mute as default */
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       /* Port-A (HP) mixer */
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Port-A pin */
+       {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* HP selector - select DAC2 */
+       {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
+       /* Port-D (Line-out) mixer */
+       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Port-D pin */
+       {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Mono-out mixer */
+       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       /* Mono-out pin */
+       {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Port-B (front mic) pin */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+       /* Port-C (line-in) pin */
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+       /* Port-C mixer - mute as input */
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Port-E (mic-in) pin */
+       {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+       /* Port-E mixer - mute as input */
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       /* Port-F (surround) */
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Port-G (CLFE) */
+       {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       /* Analog mixer; mute as default */
+       /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+       {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+       /* Analog Mix output amp */
+       {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+       /* SPDIF output selector */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+       {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+       { } /* end */
+};
+
+/* models */
+enum {
+       AD1882_3STACK,
+       AD1882_6STACK,
+       AD1882_MODELS
+};
+
+static const char *ad1882_models[AD1986A_MODELS] = {
+       [AD1882_3STACK]         = "3stack",
+       [AD1882_6STACK]         = "6stack",
+};
+
+
+static int patch_ad1882(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+       int board_config;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       mutex_init(&spec->amp_mutex);
+       codec->spec = spec;
+
+       spec->multiout.max_channels = 6;
+       spec->multiout.num_dacs = 3;
+       spec->multiout.dac_nids = ad1882_dac_nids;
+       spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
+       spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
+       spec->adc_nids = ad1882_adc_nids;
+       spec->capsrc_nids = ad1882_capsrc_nids;
+       spec->input_mux = &ad1882_capture_source;
+       spec->num_mixers = 1;
+       spec->mixers[0] = ad1882_base_mixers;
+       spec->num_init_verbs = 1;
+       spec->init_verbs[0] = ad1882_init_verbs;
+       spec->spdif_route = 0;
+
+       codec->patch_ops = ad198x_patch_ops;
+
+       /* override some parameters */
+       board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
+                                                 ad1882_models, NULL);
+       switch (board_config) {
+       default:
+       case AD1882_3STACK:
+               spec->num_mixers = 2;
+               spec->mixers[1] = ad1882_3stack_mixers;
+               spec->channel_mode = ad1882_modes;
+               spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
+               spec->need_dac_fix = 1;
+               spec->multiout.max_channels = 2;
+               spec->multiout.num_dacs = 1;
+               break;
+       case AD1882_6STACK:
+               spec->num_mixers = 2;
+               spec->mixers[1] = ad1882_6stack_mixers;
+               break;
+       }
+       return 0;
+}
+
+
 /*
  * patch entries
  */
 struct hda_codec_preset snd_hda_preset_analog[] = {
+       { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
+       { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
        { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
        { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
+       { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
        { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
        { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
        { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
index f8eb4c90f801a677700a62b048ffd82c85efcaa7..72d3ab9751ac3c5aebcbfc9fb94071ec0e5228be 100644 (file)
@@ -172,6 +172,7 @@ static int patch_atihdmi(struct hda_codec *codec)
  */
 struct hda_codec_preset snd_hda_preset_atihdmi[] = {
        { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
+       { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
        { .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
        { .id = 0x1002aa01, .name = "ATI R600 HDMI", .patch = patch_atihdmi },
        {} /* terminator */
index bef214bcdddfa2ad60c0fa02a9f8c9a16c0036af..4d8e8af5c819e67759ea44b11626fb21f8468451 100644 (file)
@@ -801,7 +801,9 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP),
        SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP),
        SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP),
+       SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP),
        SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_FUJITSU),
+       SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP),
        SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP),
        {}
 };
index 4776de93928b4b55fa78a2b570b40715a54b1f4d..9a47eec5a27bb27a7f24c00d7ab9189cb34ac98c 100644 (file)
@@ -94,10 +94,18 @@ enum {
        ALC262_HP_BPC_D7000_WF,
        ALC262_BENQ_ED8,
        ALC262_SONY_ASSAMD,
+       ALC262_BENQ_T31,
        ALC262_AUTO,
        ALC262_MODEL_LAST /* last tag */
 };
 
+/* ALC268 models */
+enum {
+       ALC268_3ST,
+       ALC268_AUTO,
+       ALC268_MODEL_LAST /* last tag */
+};
+
 /* ALC861 models */
 enum {
        ALC861_3ST,
@@ -115,6 +123,7 @@ enum {
 /* ALC861-VD models */
 enum {
        ALC660VD_3ST,
+       ALC660VD_3ST_DIG,
        ALC861VD_3ST,
        ALC861VD_3ST_DIG,
        ALC861VD_6ST_DIG,
@@ -144,6 +153,7 @@ enum {
        ALC882_TARGA,
        ALC882_ASUS_A7J,
        ALC885_MACPRO,
+       ALC885_IMAC24,
        ALC882_AUTO,
        ALC882_MODEL_LAST,
 };
@@ -163,6 +173,8 @@ enum {
        ALC883_LENOVO_101E_2ch,
        ALC883_LENOVO_NB0763,
        ALC888_LENOVO_MS7195_DIG,               
+       ALC888_6ST_HP,
+       ALC888_3ST_HP,
        ALC883_AUTO,
        ALC883_MODEL_LAST,
 };
@@ -712,6 +724,38 @@ static void alc_subsystem_id(struct hda_codec *codec,
        }
 }
 
+/*
+ * Fix-up pin default configurations
+ */
+
+struct alc_pincfg {
+       hda_nid_t nid;
+       u32 val;
+};
+
+static void alc_fix_pincfg(struct hda_codec *codec,
+                          const struct snd_pci_quirk *quirk,
+                          const struct alc_pincfg **pinfix)
+{
+       const struct alc_pincfg *cfg;
+
+       quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+       if (!quirk)
+               return;
+
+       cfg = pinfix[quirk->value];
+       for (; cfg->nid; cfg++) {
+               int i;
+               u32 val = cfg->val;
+               for (i = 0; i < 4; i++) {
+                       snd_hda_codec_write(codec, cfg->nid, 0,
+                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
+                                   val & 0xff);
+                       val >>= 8;
+               }
+       }
+}
+
 /*
  * ALC880 3-stack model
  *
@@ -1878,31 +1922,53 @@ static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
  * Pin assignment:
  *   Speaker-out: 0x14
  *   Mic-In: 0x18
- *   Built-in Mic-In: 0x19 (?)
- *   HP-Out: 0x1b
+ *   Built-in Mic-In: 0x19
+ *   Line-In: 0x1b
+ *   HP-Out: 0x1a
  *   SPDIF-Out: 0x1e
  */
 
-/* seems analog CD is not working */
 static struct hda_input_mux alc880_lg_lw_capture_source = {
-       .num_items = 2,
+       .num_items = 3,
        .items = {
                { "Mic", 0x0 },
                { "Internal Mic", 0x1 },
+               { "Line In", 0x2 },
        },
 };
 
+#define alc880_lg_lw_modes alc880_threestack_modes
+
 static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
-       HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
        HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
        HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
        HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Channel Mode",
+               .info = alc_ch_mode_info,
+               .get = alc_ch_mode_get,
+               .put = alc_ch_mode_put,
+       },
        { } /* end */
 };
 
 static struct hda_verb alc880_lg_lw_init_verbs[] = {
+       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+       {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+       {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
+
        /* set capture source to mic-in */
        {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1912,7 +1978,6 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = {
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        /* HP-out */
-       {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
        {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
        {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
        /* mic-in to input */
@@ -2856,11 +2921,11 @@ static struct alc_config_preset alc880_presets[] = {
                .mixers = { alc880_lg_lw_mixer },
                .init_verbs = { alc880_volume_init_verbs,
                                alc880_lg_lw_init_verbs },
-               .num_dacs = 1,
+               .num_dacs = ARRAY_SIZE(alc880_dac_nids),
                .dac_nids = alc880_dac_nids,
                .dig_out_nid = ALC880_DIGOUT_NID,
-               .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
-               .channel_mode = alc880_2_jack_modes,
+               .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
+               .channel_mode = alc880_lg_lw_modes,
                .input_mux = &alc880_lg_lw_capture_source,
                .unsol_event = alc880_lg_lw_unsol_event,
                .init_hook = alc880_lg_lw_automute,
@@ -5054,6 +5119,60 @@ static struct hda_verb alc882_macpro_init_verbs[] = {
        { }
 };
 
+/* iMac 24 mixer. */
+static struct snd_kcontrol_new alc885_imac24_mixer[] = {
+       HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
+       { } /* end */
+};
+
+/* iMac 24 init verbs. */
+static struct hda_verb alc885_imac24_init_verbs[] = {
+       /* Internal speakers: output 0 (0x0c) */
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Internal speakers: output 0 (0x0c) */
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* Headphone: output 0 (0x0c) */
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+       /* Front Mic: input vref at 80% */
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       { }
+};
+
+/* Toggle speaker-output according to the hp-jack state */
+static void alc885_imac24_automute(struct hda_codec *codec)
+{
+       unsigned int present;
+
+       present = snd_hda_codec_read(codec, 0x14, 0,
+                                    AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+       snd_hda_codec_amp_update(codec, 0x18, 0, HDA_OUTPUT, 0,
+                                0x80, present ? 0x80 : 0);
+       snd_hda_codec_amp_update(codec, 0x18, 1, HDA_OUTPUT, 0,
+                                0x80, present ? 0x80 : 0);
+       snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
+                                0x80, present ? 0x80 : 0);
+       snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
+                                0x80, present ? 0x80 : 0);
+}
+
+/* Processes unsolicited events. */
+static void alc885_imac24_unsol_event(struct hda_codec *codec,
+                                     unsigned int res)
+{
+       /* Headphone insertion or removal. */
+       if ((res >> 26) == ALC880_HP_EVENT)
+               alc885_imac24_automute(codec);
+}
+
 static struct hda_verb alc882_targa_verbs[] = {
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
        {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -5274,6 +5393,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
        [ALC882_ARIMA]          = "arima",
        [ALC882_W2JC]           = "w2jc",
        [ALC885_MACPRO]         = "macpro",
+       [ALC885_IMAC24]         = "imac24",
        [ALC882_AUTO]           = "auto",
 };
 
@@ -5284,6 +5404,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8  */
        SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
        SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
+       SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
        SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
        SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
        {}
@@ -5345,6 +5466,19 @@ static struct alc_config_preset alc882_presets[] = {
                .channel_mode = alc882_ch_modes,
                .input_mux = &alc882_capture_source,
        },
+       [ALC885_IMAC24] = {
+               .mixers = { alc885_imac24_mixer },
+               .init_verbs = { alc885_imac24_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+               .dac_nids = alc882_dac_nids,
+               .dig_out_nid = ALC882_DIGOUT_NID,
+               .dig_in_nid = ALC882_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+               .channel_mode = alc882_ch_modes,
+               .input_mux = &alc882_capture_source,
+               .unsol_event = alc885_imac24_unsol_event,
+               .init_hook = alc885_imac24_automute,
+       },
        [ALC882_TARGA] = {
                .mixers = { alc882_targa_mixer, alc882_chmode_mixer,
                            alc882_capture_mixer },
@@ -5378,6 +5512,29 @@ static struct alc_config_preset alc882_presets[] = {
 };
 
 
+/*
+ * Pin config fixes
+ */
+enum { 
+       PINFIX_ABIT_AW9D_MAX
+};
+
+static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
+       { 0x15, 0x01080104 }, /* side */
+       { 0x16, 0x01011012 }, /* rear */
+       { 0x17, 0x01016011 }, /* clfe */
+       { }
+};
+
+static const struct alc_pincfg *alc882_pin_fixes[] = {
+       [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+};
+
+static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+       SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+       {}
+};
+
 /*
  * BIOS auto configuration
  */
@@ -5494,6 +5651,9 @@ static int patch_alc882(struct hda_codec *codec)
                case 0x106b0c00: /* Mac Pro */
                        board_config = ALC885_MACPRO;
                        break;
+               case 0x106b1000: /* iMac 24 */
+                       board_config = ALC885_IMAC24;
+                       break;
                default:
                        printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
                                         "trying auto-probe from BIOS...\n");
@@ -5501,6 +5661,8 @@ static int patch_alc882(struct hda_codec *codec)
                }
        }
 
+       alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+
        if (board_config == ALC882_AUTO) {
                /* automatic parse from the BIOS config */
                err = alc882_parse_auto_config(codec);
@@ -5518,7 +5680,7 @@ static int patch_alc882(struct hda_codec *codec)
        if (board_config != ALC882_AUTO)
                setup_preset(spec, &alc882_presets[board_config]);
 
-       if (board_config == ALC885_MACPRO) {
+       if (board_config == ALC885_MACPRO || board_config == ALC885_IMAC24) {
                alc882_gpio_mute(codec, 0, 0);
                alc882_gpio_mute(codec, 1, 0);
        }
@@ -5995,6 +6157,84 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
        { } /* end */
 };     
 
+static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+       HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+       HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+       HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+       HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+       HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc883_mux_enum_info,
+               .get = alc883_mux_enum_get,
+               .put = alc883_mux_enum_put,
+       },
+       { } /* end */
+};
+
 static struct snd_kcontrol_new alc883_chmode_mixer[] = {
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -6126,6 +6366,42 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
        { } /* end */
 };
 
+static struct hda_verb alc888_6st_hp_verbs[] = {
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x02},  /* Rear : output 2 (0x0e) */
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x01},  /* CLFE : output 1 (0x0d) */
+       {0x17, AC_VERB_SET_CONNECT_SEL, 0x03},  /* Side : output 3 (0x0f) */
+       { }
+};
+
+static struct hda_verb alc888_3st_hp_verbs[] = {
+       {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},  /* Front: output 0 (0x0c) */
+       {0x18, AC_VERB_SET_CONNECT_SEL, 0x01},  /* Rear : output 1 (0x0d) */
+       {0x16, AC_VERB_SET_CONNECT_SEL, 0x02},  /* CLFE : output 2 (0x0e) */
+       { }
+};
+
+static struct hda_verb alc888_3st_hp_2ch_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       { }
+};
+
+static struct hda_verb alc888_3st_hp_6ch_init[] = {
+       { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+       { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+       { }
+};
+
+static struct hda_channel_mode alc888_3st_hp_modes[2] = {
+       { 2, alc888_3st_hp_2ch_init },
+       { 6, alc888_3st_hp_6ch_init },
+};
+
 /* toggle front-jack and RCA according to the hp-jack state */
 static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
 {
@@ -6368,11 +6644,14 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
        [ALC883_LENOVO_101E_2ch] = "lenovo-101e",
        [ALC883_LENOVO_NB0763]  = "lenovo-nb0763",
        [ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
+       [ALC888_6ST_HP]         = "6stack-hp",
+       [ALC888_3ST_HP]         = "3stack-hp",
        [ALC883_AUTO]           = "auto",
 };
 
 static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+       SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
        SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
        SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
@@ -6381,6 +6660,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
        SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
        SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
        SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
@@ -6400,6 +6681,9 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
        SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
        SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+       SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
+       SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
        SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
        {}
 };
@@ -6584,6 +6868,31 @@ static struct alc_config_preset alc883_presets[] = {
                .unsol_event = alc883_lenovo_ms7195_unsol_event,
                .init_hook = alc888_lenovo_ms7195_front_automute,
        },      
+       [ALC888_6ST_HP] = {
+               .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .dig_out_nid = ALC883_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .dig_in_nid = ALC883_DIGIN_NID,
+               .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+               .channel_mode = alc883_sixstack_modes,
+               .input_mux = &alc883_capture_source,
+       },
+       [ALC888_3ST_HP] = {
+               .mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
+               .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
+               .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+               .dac_nids = alc883_dac_nids,
+               .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+               .adc_nids = alc883_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
+               .channel_mode = alc888_3st_hp_modes,
+               .need_dac_fix = 1,
+               .input_mux = &alc883_capture_source,
+       },
 };
 
 
@@ -6857,7 +7166,16 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = {
        { } /* end */
 };
 
-
+static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+       HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+       HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+       { } /* end */
+};
 
 #define alc262_capture_mixer           alc882_capture_mixer
 #define alc262_capture_alt_mixer       alc882_capture_alt_mixer
@@ -7189,6 +7507,15 @@ static struct hda_verb alc262_EAPD_verbs[] = {
        {}
 };
 
+static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+
+       {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+       {0x20, AC_VERB_SET_PROC_COEF,  0x3050},
+       {}
+};
+
 /* add playback controls from the parsed DAC table */
 static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
                                             const struct auto_pin_cfg *cfg)
@@ -7584,7 +7911,8 @@ static const char *alc262_models[ALC262_MODEL_LAST] = {
        [ALC262_HP_BPC]         = "hp-bpc",
        [ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
        [ALC262_BENQ_ED8]       = "benq",
-       [ALC262_BENQ_ED8]       = "sony-assamd",
+       [ALC262_BENQ_T31]       = "benq-t31",
+       [ALC262_SONY_ASSAMD]    = "sony-assamd",
        [ALC262_AUTO]           = "auto",
 };
 
@@ -7592,8 +7920,12 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
        SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -7606,6 +7938,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
        SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
        SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
+       SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
        SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
        SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
@@ -7710,6 +8043,17 @@ static struct alc_config_preset alc262_presets[] = {
                .channel_mode = alc262_modes,
                .input_mux = &alc262_capture_source,
                .unsol_event = alc262_hippo_unsol_event,
+       },
+       [ALC262_BENQ_T31] = {
+               .mixers = { alc262_benq_t31_mixer },
+               .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
+               .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+               .dac_nids = alc262_dac_nids,
+               .hp_nid = 0x03,
+               .num_channel_mode = ARRAY_SIZE(alc262_modes),
+               .channel_mode = alc262_modes,
+               .input_mux = &alc262_capture_source,
+               .unsol_event = alc262_hippo_unsol_event,
        },      
 };
 
@@ -7800,31 +8144,540 @@ static int patch_alc262(struct hda_codec *codec)
 }
 
 /*
- *  ALC861 channel source setting (2/6 channel selection for 3-stack)
+ *  ALC268 channel source setting (2 channel)
  */
+#define ALC268_DIGOUT_NID      ALC880_DIGOUT_NID
+#define alc268_modes           alc260_modes
+       
+static hda_nid_t alc268_dac_nids[2] = {
+       /* front, hp */
+       0x02, 0x03
+};
 
-/*
- * set the path ways for 2 channel output
- * need to set the codec line out and mic 1 pin widgets to inputs
- */
-static struct hda_verb alc861_threestack_ch2_init[] = {
-       /* set pin widget 1Ah (line in) for input */
-       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
-       /* set pin widget 18h (mic1/2) for input, for mic also enable
-        * the vref
-        */
-       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+static hda_nid_t alc268_adc_nids[2] = {
+       /* ADC0-1 */
+       0x08, 0x07
+};
 
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
-#if 0
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
-       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
-#endif
-       { } /* end */
+static hda_nid_t alc268_adc_nids_alt[1] = {
+       /* ADC0 */
+       0x08
 };
-/*
- * 6ch mode
- * need to set the codec line out and mic 1 pin widgets to outputs
+
+static struct snd_kcontrol_new alc268_base_mixer[] = {
+       /* output mixer control */
+       HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+       { }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc268_base_init_verbs[] = {
+       /* Unmute DAC0-1 and set vol = 0 */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       /*
+        * Set up output mixers (0x0c - 0x0e)
+        */
+       /* set vol=0 to output mixers */
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+        {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+       {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+       {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+
+       /* FIXME: use matrix-type input source selection */
+       /* Mixer elements: 0x18, 19, 1a, 1c, 14, 15, 0b */
+       /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+       /* Input mixer2 */
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+       {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+       {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+       { }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc268_volume_init_verbs[] = {
+       /* set output DAC */
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+       {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+       {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+       {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+       {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+       /* set PCBEEP vol = 0 */
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))},
+
+       { }
+};
+
+#define alc268_mux_enum_info alc_mux_enum_info
+#define alc268_mux_enum_get alc_mux_enum_get
+
+static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct alc_spec *spec = codec->spec;
+       const struct hda_input_mux *imux = spec->input_mux;
+       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
+       hda_nid_t nid = capture_mixers[adc_idx];
+       unsigned int *cur_val = &spec->cur_mux[adc_idx];
+       unsigned int i, idx;
+
+       idx = ucontrol->value.enumerated.item[0];
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+       if (*cur_val == idx && !codec->in_resume)
+               return 0;
+       for (i = 0; i < imux->num_items; i++) {
+               unsigned int v = (i == idx) ? 0x7000 : 0x7080;
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   v | (imux->items[i].index << 8));
+                snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
+                                   idx );
+       }
+       *cur_val = idx;
+       return 1;
+}
+
+static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 1,
+               .info = alc268_mux_enum_info,
+               .get = alc268_mux_enum_get,
+               .put = alc268_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct snd_kcontrol_new alc268_capture_mixer[] = {
+       HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               /* The multiple "Capture Source" controls confuse alsamixer
+                * So call somewhat different..
+                * FIXME: the controls appear in the "playback" view!
+                */
+               /* .name = "Capture Source", */
+               .name = "Input Source",
+               .count = 2,
+               .info = alc268_mux_enum_info,
+               .get = alc268_mux_enum_get,
+               .put = alc268_mux_enum_put,
+       },
+       { } /* end */
+};
+
+static struct hda_input_mux alc268_capture_source = {
+       .num_items = 4,
+       .items = {
+               { "Mic", 0x0 },
+               { "Front Mic", 0x1 },
+               { "Line", 0x2 },
+               { "CD", 0x3 },
+       },
+};
+
+/* create input playback/capture controls for the given pin */
+static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
+                                   const char *ctlname, int idx)
+{
+       char name[32];
+       int err;
+
+       sprintf(name, "%s Playback Volume", ctlname);
+       if (nid == 0x14) {
+               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+                                 HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
+                                                     HDA_OUTPUT));
+               if (err < 0)
+                       return err;
+       } else if (nid == 0x15) {
+               err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+                                 HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
+                                                     HDA_OUTPUT));
+               if (err < 0)
+                       return err;
+       } else
+               return -1;
+       sprintf(name, "%s Playback Switch", ctlname);
+       err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+                         HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
+                                            const struct auto_pin_cfg *cfg)
+{
+       hda_nid_t nid;
+       int err;
+
+       spec->multiout.num_dacs = 2;    /* only use one dac */
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       spec->multiout.dac_nids[0] = 2;
+       spec->multiout.dac_nids[1] = 3;
+
+       nid = cfg->line_out_pins[0];
+       if (nid)
+               alc268_new_analog_output(spec, nid, "Front", 0);        
+
+       nid = cfg->speaker_pins[0];
+       if (nid == 0x1d) {
+               err = add_control(spec, ALC_CTL_WIDGET_VOL,
+                                 "Speaker Playback Volume",
+                                 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+               if (err < 0)
+                       return err;
+       }
+       nid = cfg->hp_pins[0];
+       if (nid)
+               alc268_new_analog_output(spec, nid, "Headphone", 0);
+
+       nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
+       if (nid == 0x16) {
+               err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+                                 "Mono Playback Switch",
+                                 HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
+               if (err < 0)
+                       return err;
+       }
+       return 0;       
+}
+
+/* create playback/capture controls for input pins */
+static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
+                                               const struct auto_pin_cfg *cfg)
+{
+       struct hda_input_mux *imux = &spec->private_imux;
+       int i, idx1;
+
+       for (i = 0; i < AUTO_PIN_LAST; i++) {
+               switch(cfg->input_pins[i]) {
+               case 0x18:
+                       idx1 = 0;       /* Mic 1 */
+                       break;
+               case 0x19:
+                       idx1 = 1;       /* Mic 2 */
+                       break;
+               case 0x1a:
+                       idx1 = 2;       /* Line In */
+                       break;
+               case 0x1c:      
+                       idx1 = 3;       /* CD */
+                       break;
+               default:
+                       continue;
+               }
+               imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
+               imux->items[imux->num_items].index = idx1;
+               imux->num_items++;      
+       }
+       return 0;
+}
+
+static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
+       hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
+       hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
+       unsigned int    dac_vol1, dac_vol2;
+
+       if (speaker_nid) {
+               snd_hda_codec_write(codec, speaker_nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               snd_hda_codec_write(codec, 0x0f, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_IN_UNMUTE(1));
+               snd_hda_codec_write(codec, 0x10, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_IN_UNMUTE(1));
+       } else {
+               snd_hda_codec_write(codec, 0x0f, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
+               snd_hda_codec_write(codec, 0x10, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
+       }
+
+       dac_vol1 = dac_vol2 = 0xb000 | 0x40;    /* set max volume  */
+       if (line_nid == 0x14)   
+               dac_vol2 = AMP_OUT_ZERO;
+       else if (line_nid == 0x15)
+               dac_vol1 = AMP_OUT_ZERO;
+       if (hp_nid == 0x14)     
+               dac_vol2 = AMP_OUT_ZERO;
+       else if (hp_nid == 0x15)
+               dac_vol1 = AMP_OUT_ZERO;
+       if (line_nid != 0x16 || hp_nid != 0x16 ||
+           spec->autocfg.line_out_pins[1] != 0x16 ||
+           spec->autocfg.line_out_pins[2] != 0x16)
+               dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
+
+       snd_hda_codec_write(codec, 0x02, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
+       snd_hda_codec_write(codec, 0x03, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
+}
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc268_pcm_analog_playback     alc880_pcm_analog_playback
+#define alc268_pcm_analog_capture      alc880_pcm_analog_capture
+#define alc268_pcm_digital_playback    alc880_pcm_digital_playback
+
+/*
+ * BIOS auto configuration
+ */
+static int alc268_parse_auto_config(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int err;
+       static hda_nid_t alc268_ignore[] = { 0 };
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+                                          alc268_ignore);
+       if (err < 0)
+               return err;
+       if (!spec->autocfg.line_outs)
+               return 0; /* can't find valid BIOS pin config */
+
+       err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+       err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       spec->multiout.max_channels = 2;
+
+       /* digital only support output */
+       if (spec->autocfg.dig_out_pin)
+               spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
+
+       if (spec->kctl_alloc)
+               spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+       spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
+       spec->num_mux_defs = 1;
+       spec->input_mux = &spec->private_imux;
+
+       return 1;
+}
+
+#define alc268_auto_init_multi_out     alc882_auto_init_multi_out
+#define alc268_auto_init_hp_out                alc882_auto_init_hp_out
+#define alc268_auto_init_analog_input  alc882_auto_init_analog_input
+
+/* init callback for auto-configuration model -- overriding the default init */
+static void alc268_auto_init(struct hda_codec *codec)
+{
+       alc268_auto_init_multi_out(codec);
+       alc268_auto_init_hp_out(codec);
+       alc268_auto_init_mono_speaker_out(codec);
+       alc268_auto_init_analog_input(codec);
+}
+
+/*
+ * configuration and preset
+ */
+static const char *alc268_models[ALC268_MODEL_LAST] = {
+       [ALC268_3ST]            = "3stack",
+       [ALC268_AUTO]           = "auto",
+};
+
+static struct snd_pci_quirk alc268_cfg_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
+       {}
+};
+
+static struct alc_config_preset alc268_presets[] = {
+       [ALC268_3ST] = {
+               .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+               .init_verbs = { alc268_base_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+               .dac_nids = alc268_dac_nids,
+                .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+                .adc_nids = alc268_adc_nids_alt,
+               .hp_nid = 0x03,
+               .dig_out_nid = ALC268_DIGOUT_NID,
+               .num_channel_mode = ARRAY_SIZE(alc268_modes),
+               .channel_mode = alc268_modes,
+               .input_mux = &alc268_capture_source,
+       },
+};
+
+static int patch_alc268(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int board_config;
+       int err;
+
+       spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+
+       board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
+                                                 alc268_models,
+                                                 alc268_cfg_tbl);
+
+       if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
+               printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
+                      "trying auto-probe from BIOS...\n");
+               board_config = ALC268_AUTO;
+       }
+
+       if (board_config == ALC268_AUTO) {
+               /* automatic parse from the BIOS config */
+               err = alc268_parse_auto_config(codec);
+               if (err < 0) {
+                       alc_free(codec);
+                       return err;
+               } else if (!err) {
+                       printk(KERN_INFO
+                              "hda_codec: Cannot set up configuration "
+                              "from BIOS.  Using base mode...\n");
+                       board_config = ALC268_3ST;
+               }
+       }
+
+       if (board_config != ALC268_AUTO)
+               setup_preset(spec, &alc268_presets[board_config]);
+
+       spec->stream_name_analog = "ALC268 Analog";
+       spec->stream_analog_playback = &alc268_pcm_analog_playback;
+       spec->stream_analog_capture = &alc268_pcm_analog_capture;
+
+       spec->stream_name_digital = "ALC268 Digital";
+       spec->stream_digital_playback = &alc268_pcm_digital_playback;
+
+       if (board_config == ALC268_AUTO) {
+               if (!spec->adc_nids && spec->input_mux) {
+                       /* check whether NID 0x07 is valid */
+                       unsigned int wcap = get_wcaps(codec, 0x07);
+
+                       /* get type */
+                       wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+                       if (wcap != AC_WID_AUD_IN) {
+                               spec->adc_nids = alc268_adc_nids_alt;
+                               spec->num_adc_nids =
+                                       ARRAY_SIZE(alc268_adc_nids_alt);
+                               spec->mixers[spec->num_mixers] =
+                                       alc268_capture_alt_mixer;
+                               spec->num_mixers++;
+                       } else {
+                               spec->adc_nids = alc268_adc_nids;
+                               spec->num_adc_nids =
+                                       ARRAY_SIZE(alc268_adc_nids);
+                               spec->mixers[spec->num_mixers] =
+                                       alc268_capture_mixer;
+                               spec->num_mixers++;
+                       }
+               }
+       }
+       codec->patch_ops = alc_patch_ops;
+       if (board_config == ALC268_AUTO)
+               spec->init_hook = alc268_auto_init;
+               
+       return 0;
+}
+
+/*
+ *  ALC861 channel source setting (2/6 channel selection for 3-stack)
+ */
+
+/*
+ * set the path ways for 2 channel output
+ * need to set the codec line out and mic 1 pin widgets to inputs
+ */
+static struct hda_verb alc861_threestack_ch2_init[] = {
+       /* set pin widget 1Ah (line in) for input */
+       { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
+       /* set pin widget 18h (mic1/2) for input, for mic also enable
+        * the vref
+        */
+       { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb00c },
+#if 0
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8)) }, /*mic*/
+       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8)) }, /*line-in*/
+#endif
+       { } /* end */
+};
+/*
+ * 6ch mode
+ * need to set the codec line out and mic 1 pin widgets to outputs
  */
 static struct hda_verb alc861_threestack_ch6_init[] = {
        /* set pin widget 1Ah (line in) for output (Back Surround)*/
@@ -8767,13 +9620,21 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
+       SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
        SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+       SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
        SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
-       SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA),
+       /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
+        *        Any other models that need this preset?
+        */
+       /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
        SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+       SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31),
        SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
        SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
        SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
+       SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
+       SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
        {}
 };
 
@@ -9464,6 +10325,7 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re
  */
 static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
        [ALC660VD_3ST]          = "3stack-660",
+       [ALC660VD_3ST_DIG]= "3stack-660-digout",
        [ALC861VD_3ST]          = "3stack",
        [ALC861VD_3ST_DIG]      = "3stack-digout",
        [ALC861VD_6ST_DIG]      = "6stack-digout",
@@ -9475,7 +10337,7 @@ static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
 static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
        SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
-       SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST),
+       SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
        SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
        SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
 
@@ -9483,6 +10345,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
        SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
        SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
        SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
+       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
        {}
 };
 
@@ -9499,6 +10362,19 @@ static struct alc_config_preset alc861vd_presets[] = {
                .channel_mode = alc861vd_3stack_2ch_modes,
                .input_mux = &alc861vd_capture_source,
        },
+       [ALC660VD_3ST_DIG] = {
+               .mixers = { alc861vd_3st_mixer },
+               .init_verbs = { alc861vd_volume_init_verbs,
+                                alc861vd_3stack_init_verbs },
+               .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+               .dac_nids = alc660vd_dac_nids,
+               .dig_out_nid = ALC861VD_DIGOUT_NID,
+               .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
+               .adc_nids = alc861vd_adc_nids,
+               .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+               .channel_mode = alc861vd_3stack_2ch_modes,
+               .input_mux = &alc861vd_capture_source,
+       },
        [ALC861VD_3ST] = {
                .mixers = { alc861vd_3st_mixer },
                .init_verbs = { alc861vd_volume_init_verbs,
@@ -10420,7 +11296,7 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
        for (i = 0; i < cfg->line_outs; i++) {
                if (!spec->multiout.dac_nids[i])
                        continue;
-               nid = alc880_idx_to_dac(i);
+               nid = alc880_idx_to_mixer(i);
                if (i == 2) {
                        /* Center/LFE */
                        err = add_control(spec, ALC_CTL_WIDGET_VOL,
@@ -10643,14 +11519,10 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
        spec->num_mux_defs = 1;
        spec->input_mux = &spec->private_imux;
        
-       if (err < 0)
-               return err;
-       else if (err > 0)
-               /* hack - override the init verbs */
-               spec->init_verbs[0] = alc662_auto_init_verbs;
+       spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
        spec->mixers[spec->num_mixers] = alc662_capture_mixer;
        spec->num_mixers++;
-       return err;
+       return 1;
 }
 
 /* additional initialization for auto-configuration model */
@@ -10687,7 +11559,7 @@ static int patch_alc662(struct hda_codec *codec)
                if (err < 0) {
                        alc_free(codec);
                        return err;
-               } else if (err) {
+               } else if (!err) {
                        printk(KERN_INFO
                               "hda_codec: Cannot set up configuration "
                               "from BIOS.  Using base mode...\n");
@@ -10724,6 +11596,7 @@ static int patch_alc662(struct hda_codec *codec)
 struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
        { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
+       { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
        { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
          .patch = patch_alc861 },
        { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
index 43f537ef40bf12a134c86b64cd7fa93b6d0f2de7..6d2ecc38905cebf17e34db6e7081135f1b215df8 100644 (file)
@@ -304,8 +304,12 @@ struct hda_codec_preset snd_hda_preset_si3054[] = {
        { .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 },
        { .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 },
        { .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 },
+       /* VIA HDA on Clevo m540 */
+       { .id = 0x11063288, .name = "Si3054", .patch = patch_si3054 },
        /* Asus A8J Modem (SM56) */
        { .id = 0x15433155, .name = "Si3054", .patch = patch_si3054 },
+       /* LG LW20 modem */
+       { .id = 0x18540018, .name = "Si3054", .patch = patch_si3054 },
        {}
 };
 
index e3964fc4c40521cb3914740fdd25f764e836209f..3f25de72966ba05e0cc7f02c347a0f731fd0e2f3 100644 (file)
@@ -44,6 +44,7 @@ enum {
 
 enum {
        STAC_9205_REF,
+       STAC_M43xx,
        STAC_9205_MODELS
 };
 
@@ -59,11 +60,19 @@ enum {
        STAC_D945_REF,
        STAC_D945GTP3,
        STAC_D945GTP5,
+       STAC_922X_DELL,
+       STAC_INTEL_MAC_V1,
+       STAC_INTEL_MAC_V2,
+       STAC_INTEL_MAC_V3,
+       STAC_INTEL_MAC_V4,
+       STAC_INTEL_MAC_V5,
+       /* for backward compitability */
        STAC_MACMINI,
        STAC_MACBOOK,
        STAC_MACBOOK_PRO_V1,
        STAC_MACBOOK_PRO_V2,
        STAC_IMAC_INTEL,
+       STAC_IMAC_INTEL_20,
        STAC_922X_MODELS
 };
 
@@ -210,7 +219,6 @@ static hda_nid_t stac9205_pin_nids[12] = {
        0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x14, 0x16, 0x17, 0x18,
        0x21, 0x22,
-       
 };
 
 static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
@@ -326,8 +334,6 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
 };
 
 static struct snd_kcontrol_new stac925x_mixer[] = {
-       HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT),
        {
                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
                .name = "Input Source",
@@ -549,44 +555,78 @@ static unsigned int d945gtp5_pin_configs[10] = {
        0x02a19320, 0x40000100,
 };
 
-static unsigned int macbook_pro_v1_pin_configs[10] = {
-       0x0321e230, 0x03a1e020, 0x9017e110, 0x01014010,
-       0x01a19021, 0x0381e021, 0x1345e240, 0x13c5e22e,
-       0x02a19320, 0x400000fb
+static unsigned int intel_mac_v1_pin_configs[10] = {
+       0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
+       0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
+       0x400000fc, 0x400000fb,
+};
+
+static unsigned int intel_mac_v2_pin_configs[10] = {
+       0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
+       0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
+       0x400000fc, 0x400000fb,
+};
+
+static unsigned int intel_mac_v3_pin_configs[10] = {
+       0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
+       0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
+       0x400000fc, 0x400000fb,
 };
 
-static unsigned int macbook_pro_v2_pin_configs[10] = {
-       0x0221401f, 0x90a70120, 0x01813024, 0x01014010,
-       0x400000fd, 0x01016011, 0x1345e240, 0x13c5e22e,
+static unsigned int intel_mac_v4_pin_configs[10] = {
+       0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
+       0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
        0x400000fc, 0x400000fb,
 };
 
-static unsigned int imac_intel_pin_configs[10] = {
-       0x0121e230, 0x90a70120, 0x9017e110, 0x400000fe,
-       0x400000fd, 0x0181e021, 0x1145e040, 0x400000fa,
+static unsigned int intel_mac_v5_pin_configs[10] = {
+       0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
+       0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
        0x400000fc, 0x400000fb,
 };
 
+static unsigned int stac922x_dell_pin_configs[10] = {
+       0x0221121e, 0x408103ff, 0x02a1123e, 0x90100310,
+       0x408003f1, 0x0221122f, 0x03451340, 0x40c003f2,
+       0x50a003f3, 0x405003f4
+};
+
 static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
        [STAC_D945_REF] = ref922x_pin_configs,
        [STAC_D945GTP3] = d945gtp3_pin_configs,
        [STAC_D945GTP5] = d945gtp5_pin_configs,
-       [STAC_MACMINI] = macbook_pro_v1_pin_configs,
-       [STAC_MACBOOK] = macbook_pro_v1_pin_configs,
-       [STAC_MACBOOK_PRO_V1] = macbook_pro_v1_pin_configs,
-       [STAC_MACBOOK_PRO_V2] = macbook_pro_v2_pin_configs,
-       [STAC_IMAC_INTEL] = imac_intel_pin_configs,
+       [STAC_922X_DELL] = stac922x_dell_pin_configs,
+       [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
+       [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
+       [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
+       [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
+       [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
+       /* for backward compitability */
+       [STAC_MACMINI] = intel_mac_v3_pin_configs,
+       [STAC_MACBOOK] = intel_mac_v5_pin_configs,
+       [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
+       [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
+       [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
+       [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
 };
 
 static const char *stac922x_models[STAC_922X_MODELS] = {
        [STAC_D945_REF] = "ref",
        [STAC_D945GTP5] = "5stack",
        [STAC_D945GTP3] = "3stack",
+       [STAC_922X_DELL] = "dell",
+       [STAC_INTEL_MAC_V1] = "intel-mac-v1",
+       [STAC_INTEL_MAC_V2] = "intel-mac-v2",
+       [STAC_INTEL_MAC_V3] = "intel-mac-v3",
+       [STAC_INTEL_MAC_V4] = "intel-mac-v4",
+       [STAC_INTEL_MAC_V5] = "intel-mac-v5",
+       /* for backward compitability */
        [STAC_MACMINI]  = "macmini",
        [STAC_MACBOOK]  = "macbook",
        [STAC_MACBOOK_PRO_V1]   = "macbook-pro-v1",
        [STAC_MACBOOK_PRO_V2]   = "macbook-pro",
        [STAC_IMAC_INTEL] = "imac-intel",
+       [STAC_IMAC_INTEL_20] = "imac-intel-20",
 };
 
 static struct snd_pci_quirk stac922x_cfg_tbl[] = {
@@ -649,7 +689,10 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
        /* other systems  */
        /* Apple Mac Mini (early 2006) */
        SND_PCI_QUIRK(0x8384, 0x7680,
-                     "Mac Mini", STAC_MACMINI),
+                     "Mac Mini", STAC_INTEL_MAC_V3),
+       /* Dell */
+       SND_PCI_QUIRK(0x1028, 0x01d7, "Dell XPS M1210", STAC_922X_DELL),
+
        {} /* terminator */
 };
 
@@ -730,7 +773,8 @@ static unsigned int ref9205_pin_configs[12] = {
 };
 
 static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
-       ref9205_pin_configs,
+       [STAC_REF] = ref9205_pin_configs,
+       [STAC_M43xx] = NULL,
 };
 
 static const char *stac9205_models[STAC_9205_MODELS] = {
@@ -741,6 +785,10 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
        /* SigmaTel reference board */
        SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
                      "DFI LanParty", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8,
+                     "Dell Precision", STAC_M43xx),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff,
+                     "Dell Precision", STAC_M43xx),
        {} /* terminator */
 };
 
@@ -770,33 +818,56 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
        return 0;
 }
 
+static void stac92xx_set_config_reg(struct hda_codec *codec,
+                                   hda_nid_t pin_nid, unsigned int pin_config)
+{
+       int i;
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
+                           pin_config & 0x000000ff);
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
+                           (pin_config & 0x0000ff00) >> 8);
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
+                           (pin_config & 0x00ff0000) >> 16);
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
+                           pin_config >> 24);
+       i = snd_hda_codec_read(codec, pin_nid, 0,
+                              AC_VERB_GET_CONFIG_DEFAULT,
+                              0x00);   
+       snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
+                   pin_nid, i);
+}
+
 static void stac92xx_set_config_regs(struct hda_codec *codec)
 {
        int i;
        struct sigmatel_spec *spec = codec->spec;
-       unsigned int pin_cfg;
 
-       if (! spec->pin_nids || ! spec->pin_configs)
-               return;
+       if (!spec->pin_configs)
+               return;
 
-       for (i = 0; i < spec->num_pins; i++) {
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
-                                   spec->pin_configs[i] & 0x000000ff);
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
-                                   (spec->pin_configs[i] & 0x0000ff00) >> 8);
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
-                                   (spec->pin_configs[i] & 0x00ff0000) >> 16);
-               snd_hda_codec_write(codec, spec->pin_nids[i], 0,
-                                   AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
-                                   spec->pin_configs[i] >> 24);
-               pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
-                                            AC_VERB_GET_CONFIG_DEFAULT,
-                                            0x00);     
-               snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg);
-       }
+       for (i = 0; i < spec->num_pins; i++)
+               stac92xx_set_config_reg(codec, spec->pin_nids[i],
+                                       spec->pin_configs[i]);
+}
+
+static void stac92xx_enable_gpio_mask(struct hda_codec *codec,
+                                     int gpio_mask, int gpio_data)
+{
+       /* Configure GPIOx as output */
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DIRECTION, gpio_mask);
+       /* Configure GPIOx as CMOS */
+       snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
+       /* Assert GPIOx */
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_DATA, gpio_data);
+       /* Enable GPIOx */
+       snd_hda_codec_write(codec, codec->afg, 0,
+                           AC_VERB_SET_GPIO_MASK, gpio_mask);
 }
 
 /*
@@ -1168,7 +1239,7 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
  * and 9202/925x. For those, dac_nids[] must be hard-coded.
  */
 static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
-                                      const struct auto_pin_cfg *cfg)
+                                      struct auto_pin_cfg *cfg)
 {
        struct sigmatel_spec *spec = codec->spec;
        int i, j, conn_len = 0; 
@@ -1193,6 +1264,13 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
                }
 
                if (j == conn_len) {
+                       if (spec->multiout.num_dacs > 0) {
+                               /* we have already working output pins,
+                                * so let's drop the broken ones again
+                                */
+                               cfg->line_outs = spec->multiout.num_dacs;
+                               break;
+                       }
                        /* error out, no available DAC found */
                        snd_printk(KERN_ERR
                                   "%s: No available DAC for pin 0x%x\n",
@@ -1334,7 +1412,15 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
                        continue;
                add_spec_dacs(spec, nid);
        }
-
+       for (i = 0; i < cfg->line_outs; i++) {
+               nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
+                                       AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+               if (check_in_dac_nids(spec, nid))
+                       nid = 0;
+               if (! nid)
+                       continue;
+               add_spec_dacs(spec, nid);
+       }
        for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
                static const char *pfxs[] = {
                        "Speaker", "External Speaker", "Speaker2",
@@ -1891,7 +1977,7 @@ static int patch_stac9200(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 8;
+       spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
        spec->pin_nids = stac9200_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
                                                        stac9200_models,
@@ -1941,7 +2027,7 @@ static int patch_stac925x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 8;
+       spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
        spec->pin_nids = stac925x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
                                                        stac925x_models,
@@ -2013,29 +2099,41 @@ static int patch_stac922x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 10;
+       spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
        spec->pin_nids = stac922x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
                                                        stac922x_models,
                                                        stac922x_cfg_tbl);
-       if (spec->board_config == STAC_MACMINI) {
+       if (spec->board_config == STAC_INTEL_MAC_V3) {
                spec->gpio_mute = 1;
                /* Intel Macs have all same PCI SSID, so we need to check
                 * codec SSID to distinguish the exact models
                 */
                printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
                switch (codec->subsystem_id) {
-               case 0x106b0a00: /* MacBook First generatoin */
-                       spec->board_config = STAC_MACBOOK;
+
+               case 0x106b0800:
+                       spec->board_config = STAC_INTEL_MAC_V1;
+                       break;
+               case 0x106b0600:
+               case 0x106b0700:
+                       spec->board_config = STAC_INTEL_MAC_V2;
                        break;
-               case 0x106b0200: /* MacBook Pro first generation */
-                       spec->board_config = STAC_MACBOOK_PRO_V1;
+               case 0x106b0e00:
+               case 0x106b0f00:
+               case 0x106b1600:
+               case 0x106b1700:
+               case 0x106b0200:
+               case 0x106b1e00:
+                       spec->board_config = STAC_INTEL_MAC_V3;
                        break;
-               case 0x106b1e00: /* MacBook Pro second generation */
-                       spec->board_config = STAC_MACBOOK_PRO_V2;
+               case 0x106b1a00:
+               case 0x00000100:
+                       spec->board_config = STAC_INTEL_MAC_V4;
                        break;
-               case 0x106b0700: /* Intel-based iMac */
-                       spec->board_config = STAC_IMAC_INTEL;
+               case 0x106b0a00:
+               case 0x106b2200:
+                       spec->board_config = STAC_INTEL_MAC_V5;
                        break;
                }
        }
@@ -2082,6 +2180,13 @@ static int patch_stac922x(struct hda_codec *codec)
 
        codec->patch_ops = stac92xx_patch_ops;
 
+       /* Fix Mux capture level; max to 2 */
+       snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
+                                 (0 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (0 << AC_AMPCAP_MUTE_SHIFT));
+
        return 0;
 }
 
@@ -2095,7 +2200,7 @@ static int patch_stac927x(struct hda_codec *codec)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 14;
+       spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
        spec->pin_nids = stac927x_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
                                                        stac927x_models,
@@ -2141,7 +2246,9 @@ static int patch_stac927x(struct hda_codec *codec)
        }
 
        spec->multiout.dac_nids = spec->dac_nids;
-
+       /* GPIO0 High = Enable EAPD */
+       stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001);
+       
        err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
        if (!err) {
                if (spec->board_config < 0) {
@@ -2159,27 +2266,20 @@ static int patch_stac927x(struct hda_codec *codec)
 
        codec->patch_ops = stac92xx_patch_ops;
 
-       /* Fix Mux capture level; max to 2 */
-       snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
-                                 (0 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (0 << AC_AMPCAP_MUTE_SHIFT));
-
        return 0;
 }
 
 static int patch_stac9205(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec;
-       int err;
+       int err, gpio_mask, gpio_data;
 
        spec  = kzalloc(sizeof(*spec), GFP_KERNEL);
        if (spec == NULL)
                return -ENOMEM;
 
        codec->spec = spec;
-       spec->num_pins = 14;
+       spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
        spec->pin_nids = stac9205_pin_nids;
        spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
                                                        stac9205_models,
@@ -2209,19 +2309,21 @@ static int patch_stac9205(struct hda_codec *codec)
        spec->mixer = stac9205_mixer;
 
        spec->multiout.dac_nids = spec->dac_nids;
+       
+       if (spec->board_config == STAC_M43xx) {
+               /* Enable SPDIF in/out */
+               stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
+               stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
+
+               gpio_mask = 0x00000007; /* GPIO0-2 */
+               /* GPIO0 High = EAPD, GPIO1 Low = DRM,
+                * GPIO2 High = Headphone Mute
+                */
+               gpio_data = 0x00000005;
+       } else
+               gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */
 
-       /* Configure GPIO0 as EAPD output */
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DIRECTION, 0x00000001);
-       /* Configure GPIO0 as CMOS */
-       snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
-       /* Assert GPIO0 high */
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_DATA, 0x00000001);
-       /* Enable GPIO0 */
-       snd_hda_codec_write(codec, codec->afg, 0,
-                           AC_VERB_SET_GPIO_MASK, 0x00000001);
-
+       stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data);
        err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
        if (!err) {
                if (spec->board_config < 0) {
@@ -2256,8 +2358,8 @@ static struct hda_input_mux vaio_mux = {
        .num_items = 2,
        .items = {
                /* { "HP", 0x0 }, */
-               { "Line", 0x1 },
-               { "Mic", 0x2 },
+               { "Mic Jack", 0x1 },
+               { "Internal Mic", 0x2 },
                { "PCM", 0x3 },
        }
 };
@@ -2268,7 +2370,7 @@ static struct hda_verb vaio_init[] = {
        {0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
        {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
        {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
@@ -2284,7 +2386,7 @@ static struct hda_verb vaio_ar_init[] = {
        {0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
 /*     {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
        {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
        {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
        {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
 /*     {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
index 690ceb34064444575578a982a04e1b51d428f9ed..d18a31e188a9a594ccbe8b0ed22a487bec783703 100644 (file)
@@ -186,7 +186,12 @@ static int revo51_i2c_init(struct snd_ice1712 *ice,
 #define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
 
 static const struct snd_akm4xxx_dac_channel revo71_front[] = {
-       AK_DAC("PCM Playback Volume", 2)
+       {
+               .name = "PCM Playback Volume",
+               .num_channels = 2,
+               /* front channels DAC supports muting */
+               .switch_name = "PCM Playback Switch",
+       },
 };
 
 static const struct snd_akm4xxx_dac_channel revo71_surround[] = {
index 03b3a4792f7345923cf0812d289b64ff14b4a89f..c7621bd770a6eb116c48056d9a2168c64315ea52 100644 (file)
@@ -1533,7 +1533,8 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
                                printk(KERN_ERR "  force the driver to load by "
                                       "passing in the module parameter\n");
                                printk(KERN_ERR "    force_ac97=1\n");
-                               printk(KERN_ERR "  or try sb16 or cs423x drivers instead.\n");
+                               printk(KERN_ERR "  or try sb16, opl3sa2, or "
+                                      "cs423x drivers instead.\n");
                                err = -ENXIO;
                                goto __error;
                        }
index bd7dbd267ed1b10e09c81023bce90ca9f57c2211..2de27405a0bdd587922d4a341cd94e9cf18c8a68 100644 (file)
@@ -406,7 +406,7 @@ static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652)
                } else if (!frag)
                        return 0;
                offset -= rme9652->max_jitter;
-               if (offset < 0)
+               if ((int)offset < 0)
                        offset += period_size * 2;
        } else {
                if (offset > period_size + rme9652->max_jitter) {
index 50c9f92cfd1bd5dd02f790830955ae952d660148..6ea09df0c73a0698817052f43c5dde24d2311892 100644 (file)
@@ -2098,7 +2098,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
                pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
                if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
                        break;
-               schedule_timeout_uninterruptible(1);
+               schedule_timeout(1);
        } while (time_before(jiffies, end_time));
 
        if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
@@ -2117,7 +2117,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
                        chip->ac97_secondary = 1;
                        goto __ac97_ok2;
                }
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
        } while (time_before(jiffies, end_time));
        /* This is ok, the most of motherboards have only one codec */
 
index 8cbf8eba4ae9dbf4bdda50e9fb933403108767e2..72425e73abaeb80699179dfd6402fb972a854f8c 100644 (file)
@@ -983,7 +983,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
                pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
                if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
                        break;
-               schedule_timeout_uninterruptible(1);
+               schedule_timeout(1);
        } while (time_before(jiffies, end_time));
 
        if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
@@ -1001,7 +1001,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
                        chip->ac97_secondary = 1;
                        goto __ac97_ok2;
                }
-               schedule_timeout_interruptible(1);
+               schedule_timeout(1);
        } while (time_before(jiffies, end_time));
        /* This is ok, the most of motherboards have only one codec */
 
index a3fb1496e4dc797609d0186af5d4ba5ae2b696ef..cacb0b1368833d6d2055ee0bffdba03db273dec1 100644 (file)
@@ -33,3 +33,23 @@ config SND_POWERMAC_AUTO_DRC
          option.
 
 endmenu
+
+menu "ALSA PowerPC devices"
+       depends on SND!=n && ( PPC64 || PPC32 )
+
+config SND_PS3
+       tristate "PS3 Audio support"
+       depends on SND && PS3_PS3AV
+       select SND_PCM
+       default m
+       help
+         Say Y here to include support for audio on the PS3
+
+         To compile this driver as a module, choose M here: the module
+         will be called snd_ps3.
+
+config SND_PS3_DEFAULT_START_DELAY
+       int "Startup delay time in ms"
+       depends on SND_PS3
+       default "2000"
+endmenu
index 4d95c652c8cacd7fdc7616d609cfbbf294784b4a..eacee2d0675cd6510ef951326df488fcaf2ad812 100644 (file)
@@ -6,4 +6,5 @@
 snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
+obj-$(CONFIG_SND_POWERMAC)     += snd-powermac.o
+obj-$(CONFIG_SND_PS3)          += snd_ps3.o
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
new file mode 100644 (file)
index 0000000..1aa0b46
--- /dev/null
@@ -0,0 +1,1125 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * All rights reserved.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the Licence.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/asound.h>
+#include <sound/memalloc.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <asm/firmware.h>
+#include <linux/io.h>
+#include <asm/dma.h>
+#include <asm/lv1call.h>
+#include <asm/ps3.h>
+#include <asm/ps3av.h>
+
+#include "snd_ps3_reg.h"
+#include "snd_ps3.h"
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 sound driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
+
+/* module  entries */
+static int __init snd_ps3_init(void);
+static void __exit snd_ps3_exit(void);
+
+/* ALSA snd driver ops */
+static int snd_ps3_pcm_open(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
+                                int cmd);
+static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream
+                                            *substream);
+static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params);
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream);
+
+
+/* ps3_system_bus_driver entries */
+static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev);
+static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev);
+
+/* address setup */
+static int snd_ps3_map_mmio(void);
+static void snd_ps3_unmap_mmio(void);
+static int snd_ps3_allocate_irq(void);
+static void snd_ps3_free_irq(void);
+static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start);
+
+/* interrupt handler */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id);
+
+
+/* set sampling rate/format */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream);
+/* take effect parameter change */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card);
+/* initialize avsetting and take it effect */
+static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card);
+/* setup dma */
+static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
+                              enum snd_ps3_dma_filltype filltype);
+static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card);
+
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void  *vaddr, int ch);
+
+
+module_init(snd_ps3_init);
+module_exit(snd_ps3_exit);
+
+/*
+ * global
+ */
+static struct snd_ps3_card_info the_card;
+
+static int snd_ps3_start_delay = CONFIG_SND_PS3_DEFAULT_START_DELAY;
+
+module_param_named(start_delay, snd_ps3_start_delay, uint, 0644);
+MODULE_PARM_DESC(start_delay, "time to insert silent data in milisec");
+
+static int index = SNDRV_DEFAULT_IDX1;
+static char *id = SNDRV_DEFAULT_STR1;
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for PS3 soundchip.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for PS3 soundchip.");
+
+
+/*
+ * PS3 audio register access
+ */
+static inline u32 read_reg(unsigned int reg)
+{
+       return in_be32(the_card.mapped_mmio_vaddr + reg);
+}
+static inline void write_reg(unsigned int reg, u32 val)
+{
+       out_be32(the_card.mapped_mmio_vaddr + reg, val);
+}
+static inline void update_reg(unsigned int reg, u32 or_val)
+{
+       u32 newval = read_reg(reg) | or_val;
+       write_reg(reg, newval);
+}
+static inline void update_mask_reg(unsigned int reg, u32 mask, u32 or_val)
+{
+       u32 newval = (read_reg(reg) & mask) | or_val;
+       write_reg(reg, newval);
+}
+
+/*
+ * ALSA defs
+ */
+const static struct snd_pcm_hardware snd_ps3_pcm_hw = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+                SNDRV_PCM_INFO_NONINTERLEAVED |
+                SNDRV_PCM_INFO_MMAP_VALID),
+       .formats = (SNDRV_PCM_FMTBIT_S16_BE |
+                   SNDRV_PCM_FMTBIT_S24_BE),
+       .rates = (SNDRV_PCM_RATE_44100 |
+                 SNDRV_PCM_RATE_48000 |
+                 SNDRV_PCM_RATE_88200 |
+                 SNDRV_PCM_RATE_96000),
+       .rate_min = 44100,
+       .rate_max = 96000,
+
+       .channels_min = 2, /* stereo only */
+       .channels_max = 2,
+
+       .buffer_bytes_max = PS3_AUDIO_FIFO_SIZE * 64,
+
+       /* interrupt by four stages */
+       .period_bytes_min = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
+       .period_bytes_max = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
+
+       .periods_min = 16,
+       .periods_max = 32, /* buffer_size_max/ period_bytes_max */
+
+       .fifo_size = PS3_AUDIO_FIFO_SIZE
+};
+
+static struct snd_pcm_ops snd_ps3_pcm_spdif_ops =
+{
+       .open = snd_ps3_pcm_open,
+       .close = snd_ps3_pcm_close,
+       .prepare = snd_ps3_pcm_prepare,
+       .ioctl = snd_pcm_lib_ioctl,
+       .trigger = snd_ps3_pcm_trigger,
+       .pointer = snd_ps3_pcm_pointer,
+       .hw_params = snd_ps3_pcm_hw_params,
+       .hw_free = snd_ps3_pcm_hw_free
+};
+
+static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card,
+                                  int count, int force_stop)
+{
+       int dma_ch, done, retries, stop_forced = 0;
+       uint32_t status;
+
+       for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
+               retries = count;
+               do {
+                       status = read_reg(PS3_AUDIO_KICK(dma_ch)) &
+                               PS3_AUDIO_KICK_STATUS_MASK;
+                       switch (status) {
+                       case PS3_AUDIO_KICK_STATUS_DONE:
+                       case PS3_AUDIO_KICK_STATUS_NOTIFY:
+                       case PS3_AUDIO_KICK_STATUS_CLEAR:
+                       case PS3_AUDIO_KICK_STATUS_ERROR:
+                               done = 1;
+                               break;
+                       default:
+                               done = 0;
+                               udelay(10);
+                       }
+               } while (!done && --retries);
+               if (!retries && force_stop) {
+                       pr_info("%s: DMA ch %d is not stopped.",
+                               __func__, dma_ch);
+                       /* last resort. force to stop dma.
+                        *  NOTE: this cause DMA done interrupts
+                        */
+                       update_reg(PS3_AUDIO_CONFIG, PS3_AUDIO_CONFIG_CLEAR);
+                       stop_forced = 1;
+               }
+       }
+       return stop_forced;
+}
+
+/*
+ * wait for all dma is done.
+ * NOTE: caller should reset card->running before call.
+ *       If not, the interrupt handler will re-start DMA,
+ *       then DMA is never stopped.
+ */
+static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card)
+{
+       int stop_forced;
+       /*
+        * wait for the last dma is done
+        */
+
+       /*
+        * expected maximum DMA done time is 5.7ms + something (DMA itself).
+        * 5.7ms is from 16bit/sample 2ch 44.1Khz; the time next
+        * DMA kick event would occur.
+        */
+       stop_forced = snd_ps3_verify_dma_stop(card, 700, 1);
+
+       /*
+        * clear outstanding interrupts.
+        */
+       update_reg(PS3_AUDIO_INTR_0, 0);
+       update_reg(PS3_AUDIO_AX_IS, 0);
+
+       /*
+        *revert CLEAR bit since it will not reset automatically after DMA stop
+        */
+       if (stop_forced)
+               update_mask_reg(PS3_AUDIO_CONFIG, ~PS3_AUDIO_CONFIG_CLEAR, 0);
+       /* ensure the hardware sees changes */
+       wmb();
+}
+
+static void snd_ps3_kick_dma(struct snd_ps3_card_info *card)
+{
+
+       update_reg(PS3_AUDIO_KICK(0), PS3_AUDIO_KICK_REQUEST);
+       /* ensure the hardware sees the change */
+       wmb();
+}
+
+/*
+ * convert virtual addr to ioif bus addr.
+ */
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *card,
+                          void * paddr,
+                          int ch)
+{
+       return card->dma_start_bus_addr[ch] +
+               (paddr - card->dma_start_vaddr[ch]);
+};
+
+
+/*
+ * increment ring buffer pointer.
+ * NOTE: caller must hold write spinlock
+ */
+static void snd_ps3_bump_buffer(struct snd_ps3_card_info *card,
+                               enum snd_ps3_ch ch, size_t byte_count,
+                               int stage)
+{
+       if (!stage)
+               card->dma_last_transfer_vaddr[ch] =
+                       card->dma_next_transfer_vaddr[ch];
+       card->dma_next_transfer_vaddr[ch] += byte_count;
+       if ((card->dma_start_vaddr[ch] + (card->dma_buffer_size / 2)) <=
+           card->dma_next_transfer_vaddr[ch]) {
+               card->dma_next_transfer_vaddr[ch] = card->dma_start_vaddr[ch];
+       }
+}
+/*
+ * setup dmac to send data to audio and attenuate samples on the ring buffer
+ */
+static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
+                              enum snd_ps3_dma_filltype filltype)
+{
+       /* this dmac does not support over 4G */
+       uint32_t dma_addr;
+       int fill_stages, dma_ch, stage;
+       enum snd_ps3_ch ch;
+       uint32_t ch0_kick_event = 0; /* initialize to mute gcc */
+       void *start_vaddr;
+       unsigned long irqsave;
+       int silent = 0;
+
+       switch (filltype) {
+       case SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL:
+               silent = 1;
+               /* intentionally fall thru */
+       case SND_PS3_DMA_FILLTYPE_FIRSTFILL:
+               ch0_kick_event = PS3_AUDIO_KICK_EVENT_ALWAYS;
+               break;
+
+       case SND_PS3_DMA_FILLTYPE_SILENT_RUNNING:
+               silent = 1;
+               /* intentionally fall thru */
+       case SND_PS3_DMA_FILLTYPE_RUNNING:
+               ch0_kick_event = PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY;
+               break;
+       }
+
+       snd_ps3_verify_dma_stop(card, 700, 0);
+       fill_stages = 4;
+       spin_lock_irqsave(&card->dma_lock, irqsave);
+       for (ch = 0; ch < 2; ch++) {
+               start_vaddr = card->dma_next_transfer_vaddr[0];
+               for (stage = 0; stage < fill_stages; stage ++) {
+                       dma_ch = stage * 2 + ch;
+                       if (silent)
+                               dma_addr = card->null_buffer_start_dma_addr;
+                       else
+                               dma_addr =
+                               v_to_bus(card,
+                                        card->dma_next_transfer_vaddr[ch],
+                                        ch);
+
+                       write_reg(PS3_AUDIO_SOURCE(dma_ch),
+                                 (PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY |
+                                  dma_addr));
+
+                       /* dst: fixed to 3wire#0 */
+                       if (ch == 0)
+                               write_reg(PS3_AUDIO_DEST(dma_ch),
+                                         (PS3_AUDIO_DEST_TARGET_AUDIOFIFO |
+                                          PS3_AUDIO_AO_3W_LDATA(0)));
+                       else
+                               write_reg(PS3_AUDIO_DEST(dma_ch),
+                                         (PS3_AUDIO_DEST_TARGET_AUDIOFIFO |
+                                          PS3_AUDIO_AO_3W_RDATA(0)));
+
+                       /* count always 1 DMA block (1/2 stage = 128 bytes) */
+                       write_reg(PS3_AUDIO_DMASIZE(dma_ch), 0);
+                       /* bump pointer if needed */
+                       if (!silent)
+                               snd_ps3_bump_buffer(card, ch,
+                                                   PS3_AUDIO_DMAC_BLOCK_SIZE,
+                                                   stage);
+
+                       /* kick event  */
+                       if (dma_ch == 0)
+                               write_reg(PS3_AUDIO_KICK(dma_ch),
+                                         ch0_kick_event);
+                       else
+                               write_reg(PS3_AUDIO_KICK(dma_ch),
+                                         PS3_AUDIO_KICK_EVENT_AUDIO_DMA(dma_ch
+                                                                        - 1) |
+                                         PS3_AUDIO_KICK_REQUEST);
+               }
+       }
+       /* ensure the hardware sees the change */
+       wmb();
+       spin_unlock_irqrestore(&card->dma_lock, irqsave);
+
+       return 0;
+}
+
+/*
+ * audio mute on/off
+ * mute_on : 0 output enabled
+ *           1 mute
+ */
+static int snd_ps3_mute(int mute_on)
+{
+       return ps3av_audio_mute(mute_on);
+}
+
+/*
+ * PCM operators
+ */
+static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       int pcm_index;
+
+       pcm_index = substream->pcm->device;
+       /* to retrieve substream/runtime in interrupt handler */
+       card->substream = substream;
+
+       runtime->hw = snd_ps3_pcm_hw;
+
+       card->start_delay = snd_ps3_start_delay;
+
+       /* mute off */
+       snd_ps3_mute(0); /* this function sleep */
+
+       snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                                  PS3_AUDIO_FIFO_STAGE_SIZE * 4 * 2);
+       return 0;
+};
+
+static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *hw_params)
+{
+       size_t size;
+
+       /* alloc transport buffer */
+       size = params_buffer_bytes(hw_params);
+       snd_pcm_lib_malloc_pages(substream, size);
+       return 0;
+};
+
+static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream,
+                                 unsigned int delay_ms)
+{
+       int ret;
+       int rate ;
+
+       rate = substream->runtime->rate;
+       ret = snd_pcm_format_size(substream->runtime->format,
+                                 rate * delay_ms / 1000)
+               * substream->runtime->channels;
+
+       pr_debug(KERN_ERR "%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n",
+                __func__,
+                delay_ms,
+                rate,
+                snd_pcm_format_size(substream->runtime->format, rate),
+                rate * delay_ms / 1000,
+                ret);
+
+       return ret;
+};
+
+static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       unsigned long irqsave;
+
+       if (!snd_ps3_set_avsetting(substream)) {
+               /* some parameter changed */
+               write_reg(PS3_AUDIO_AX_IE,
+                         PS3_AUDIO_AX_IE_ASOBEIE(0) |
+                         PS3_AUDIO_AX_IE_ASOBUIE(0));
+               /*
+                * let SPDIF device re-lock with SPDIF signal,
+                * start with some silence
+                */
+               card->silent = snd_ps3_delay_to_bytes(substream,
+                                                     card->start_delay) /
+                       (PS3_AUDIO_FIFO_STAGE_SIZE * 4); /* every 4 times */
+       }
+
+       /* restart ring buffer pointer */
+       spin_lock_irqsave(&card->dma_lock, irqsave);
+       {
+               card->dma_buffer_size = runtime->dma_bytes;
+
+               card->dma_last_transfer_vaddr[SND_PS3_CH_L] =
+                       card->dma_next_transfer_vaddr[SND_PS3_CH_L] =
+                       card->dma_start_vaddr[SND_PS3_CH_L] =
+                       runtime->dma_area;
+               card->dma_start_bus_addr[SND_PS3_CH_L] = runtime->dma_addr;
+
+               card->dma_last_transfer_vaddr[SND_PS3_CH_R] =
+                       card->dma_next_transfer_vaddr[SND_PS3_CH_R] =
+                       card->dma_start_vaddr[SND_PS3_CH_R] =
+                       runtime->dma_area + (runtime->dma_bytes / 2);
+               card->dma_start_bus_addr[SND_PS3_CH_R] =
+                       runtime->dma_addr + (runtime->dma_bytes / 2);
+
+               pr_debug("%s: vaddr=%p bus=%#lx\n", __func__,
+                        card->dma_start_vaddr[SND_PS3_CH_L],
+                        card->dma_start_bus_addr[SND_PS3_CH_L]);
+
+       }
+       spin_unlock_irqrestore(&card->dma_lock, irqsave);
+
+       /* ensure the hardware sees the change */
+       mb();
+
+       return 0;
+};
+
+static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
+                              int cmd)
+{
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       int ret = 0;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               /* clear outstanding interrupts  */
+               update_reg(PS3_AUDIO_AX_IS, 0);
+
+               spin_lock(&card->dma_lock);
+               {
+                       card->running = 1;
+               }
+               spin_unlock(&card->dma_lock);
+
+               snd_ps3_program_dma(card,
+                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+               snd_ps3_kick_dma(card);
+               while (read_reg(PS3_AUDIO_KICK(7)) &
+                      PS3_AUDIO_KICK_STATUS_MASK) {
+                       udelay(1);
+               }
+               snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+               snd_ps3_kick_dma(card);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+               spin_lock(&card->dma_lock);
+               {
+                       card->running = 0;
+               }
+               spin_unlock(&card->dma_lock);
+               snd_ps3_wait_for_dma_stop(card);
+               break;
+       default:
+               break;
+
+       }
+
+       return ret;
+};
+
+/*
+ * report current pointer
+ */
+static snd_pcm_uframes_t snd_ps3_pcm_pointer(
+       struct snd_pcm_substream *substream)
+{
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       size_t bytes;
+       snd_pcm_uframes_t ret;
+
+       spin_lock(&card->dma_lock);
+       {
+               bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] -
+                                card->dma_start_vaddr[SND_PS3_CH_L]);
+       }
+       spin_unlock(&card->dma_lock);
+
+       ret = bytes_to_frames(substream->runtime, bytes * 2);
+
+       return ret;
+};
+
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       int ret;
+       ret = snd_pcm_lib_free_pages(substream);
+       return ret;
+};
+
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
+{
+       /* mute on */
+       snd_ps3_mute(1);
+       return 0;
+};
+
+static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
+{
+       /*
+        * avsetting driver seems to never change the followings
+        * so, init them here once
+        */
+
+       /* no dma interrupt needed */
+       write_reg(PS3_AUDIO_INTR_EN_0, 0);
+
+       /* use every 4 buffer empty interrupt */
+       update_mask_reg(PS3_AUDIO_AX_IC,
+                       PS3_AUDIO_AX_IC_AASOIMD_MASK,
+                       PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
+
+       /* enable 3wire clocks */
+       update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+                       ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
+                         PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
+                       0);
+       update_reg(PS3_AUDIO_AO_3WMCTRL,
+                  PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
+}
+
+/*
+ * av setting
+ * NOTE: calling this function may generate audio interrupt.
+ */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
+{
+       int ret, retries, i;
+       pr_debug("%s: start\n", __func__);
+
+       ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
+                                 card->avs.avs_audio_rate,
+                                 card->avs.avs_audio_width,
+                                 card->avs.avs_audio_format,
+                                 card->avs.avs_audio_source);
+       /*
+        * Reset the following unwanted settings:
+        */
+
+       /* disable all 3wire buffers */
+       update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+                       ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
+                         PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
+                         PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
+                         PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
+                       0);
+       wmb();  /* ensure the hardware sees the change */
+       /* wait for actually stopped */
+       retries = 1000;
+       while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
+               (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
+                PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
+                PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
+                PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
+              --retries) {
+               udelay(1);
+       }
+
+       /* reset buffer pointer */
+       for (i = 0; i < 4; i++) {
+               update_reg(PS3_AUDIO_AO_3WCTRL(i),
+                          PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
+               udelay(10);
+       }
+       wmb(); /* ensure the hardware actually start resetting */
+
+       /* enable 3wire#0 buffer */
+       update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
+
+
+       /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
+       update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
+                       ~PS3_AUDIO_AO_3WCTRL_ASODF,
+                       PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
+       update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
+                       ~PS3_AUDIO_AO_SPDCTRL_SPODF,
+                       PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
+       /* ensure all the setting above is written back to register */
+       wmb();
+       /* avsetting driver altered AX_IE, caller must reset it if you want */
+       pr_debug("%s: end\n", __func__);
+       return ret;
+}
+
+static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
+{
+       int ret;
+       pr_debug("%s: start\n", __func__);
+       card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
+       card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+       card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+       card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
+       card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
+
+       ret = snd_ps3_change_avsetting(card);
+
+       snd_ps3_audio_fixup(card);
+
+       /* to start to generate SPDIF signal, fill data */
+       snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+       snd_ps3_kick_dma(card);
+       pr_debug("%s: end\n", __func__);
+       return ret;
+}
+
+/*
+ *  set sampling rate according to the substream
+ */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
+{
+       struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+       struct snd_ps3_avsetting_info avs;
+
+       avs = card->avs;
+
+       pr_debug("%s: called freq=%d width=%d\n", __func__,
+                substream->runtime->rate,
+                snd_pcm_format_width(substream->runtime->format));
+
+       pr_debug("%s: before freq=%d width=%d\n", __func__,
+                card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+       /* sample rate */
+       switch (substream->runtime->rate) {
+       case 44100:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
+               break;
+       case 48000:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+               break;
+       case 88200:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
+               break;
+       case 96000:
+               avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
+               break;
+       default:
+               pr_info("%s: invalid rate %d\n", __func__,
+                       substream->runtime->rate);
+               return 1;
+       }
+
+       /* width */
+       switch (snd_pcm_format_width(substream->runtime->format)) {
+       case 16:
+               avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+               break;
+       case 24:
+               avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
+               break;
+       default:
+               pr_info("%s: invalid width %d\n", __func__,
+                       snd_pcm_format_width(substream->runtime->format));
+               return 1;
+       }
+
+       if ((card->avs.avs_audio_width != avs.avs_audio_width) ||
+           (card->avs.avs_audio_rate != avs.avs_audio_rate)) {
+               card->avs = avs;
+               snd_ps3_change_avsetting(card);
+
+               pr_debug("%s: after freq=%d width=%d\n", __func__,
+                        card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+               return 0;
+       } else
+               return 1;
+}
+
+
+
+static int snd_ps3_map_mmio(void)
+{
+       the_card.mapped_mmio_vaddr =
+               ioremap(the_card.ps3_dev->m_region->bus_addr,
+                       the_card.ps3_dev->m_region->len);
+
+       if (!the_card.mapped_mmio_vaddr) {
+               pr_info("%s: ioremap 0 failed p=%#lx l=%#lx \n",
+                      __func__, the_card.ps3_dev->m_region->lpar_addr,
+                      the_card.ps3_dev->m_region->len);
+               return -ENXIO;
+       }
+
+       return 0;
+};
+
+static void snd_ps3_unmap_mmio(void)
+{
+       iounmap(the_card.mapped_mmio_vaddr);
+       the_card.mapped_mmio_vaddr = NULL;
+}
+
+static int snd_ps3_allocate_irq(void)
+{
+       int ret;
+       u64 lpar_addr, lpar_size;
+       u64 __iomem *mapped;
+
+       /* FIXME: move this to device_init (H/W probe) */
+
+       /* get irq outlet */
+       ret = lv1_gpu_device_map(1, &lpar_addr, &lpar_size);
+       if (ret) {
+               pr_info("%s: device map 1 failed %d\n", __func__,
+                       ret);
+               return -ENXIO;
+       }
+
+       mapped = ioremap(lpar_addr, lpar_size);
+       if (!mapped) {
+               pr_info("%s: ioremap 1 failed \n", __func__);
+               return -ENXIO;
+       }
+
+       the_card.audio_irq_outlet = in_be64(mapped);
+
+       iounmap(mapped);
+       ret = lv1_gpu_device_unmap(1);
+       if (ret)
+               pr_info("%s: unmap 1 failed\n", __func__);
+
+       /* irq */
+       ret = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY,
+                                the_card.audio_irq_outlet,
+                                &the_card.irq_no);
+       if (ret) {
+               pr_info("%s:ps3_alloc_irq failed (%d)\n", __func__, ret);
+               return ret;
+       }
+
+       ret = request_irq(the_card.irq_no, snd_ps3_interrupt, IRQF_DISABLED,
+                         SND_PS3_DRIVER_NAME, &the_card);
+       if (ret) {
+               pr_info("%s: request_irq failed (%d)\n", __func__, ret);
+               goto cleanup_irq;
+       }
+
+       return 0;
+
+ cleanup_irq:
+       ps3_irq_plug_destroy(the_card.irq_no);
+       return ret;
+};
+
+static void snd_ps3_free_irq(void)
+{
+       free_irq(the_card.irq_no, &the_card);
+       ps3_irq_plug_destroy(the_card.irq_no);
+}
+
+static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
+{
+       uint64_t val;
+       int ret;
+
+       val = (ioaddr_start & (0x0fUL << 32)) >> (32 - 20) |
+               (0x03UL << 24) |
+               (0x0fUL << 12) |
+               (PS3_AUDIO_IOID);
+
+       ret = lv1_gpu_attribute(0x100, 0x007, val, 0, 0);
+       if (ret)
+               pr_info("%s: gpu_attribute failed %d\n", __func__,
+                       ret);
+}
+
+static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
+{
+       int ret;
+       u64 lpar_addr, lpar_size;
+
+       BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1));
+       BUG_ON(dev->match_id != PS3_MATCH_ID_SOUND);
+
+       the_card.ps3_dev = dev;
+
+       ret = ps3_open_hv_device(dev);
+
+       if (ret)
+               return -ENXIO;
+
+       /* setup MMIO */
+       ret = lv1_gpu_device_map(2, &lpar_addr, &lpar_size);
+       if (ret) {
+               pr_info("%s: device map 2 failed %d\n", __func__, ret);
+               goto clean_open;
+       }
+       ps3_mmio_region_init(dev, dev->m_region, lpar_addr, lpar_size,
+               PAGE_SHIFT);
+
+       ret = snd_ps3_map_mmio();
+       if (ret)
+               goto clean_dev_map;
+
+       /* setup DMA area */
+       ps3_dma_region_init(dev, dev->d_region,
+                           PAGE_SHIFT, /* use system page size */
+                           0, /* dma type; not used */
+                           NULL,
+                           _ALIGN_UP(SND_PS3_DMA_REGION_SIZE, PAGE_SIZE));
+       dev->d_region->ioid = PS3_AUDIO_IOID;
+
+       ret = ps3_dma_region_create(dev->d_region);
+       if (ret) {
+               pr_info("%s: region_create\n", __func__);
+               goto clean_mmio;
+       }
+
+       snd_ps3_audio_set_base_addr(dev->d_region->bus_addr);
+
+       /* CONFIG_SND_PS3_DEFAULT_START_DELAY */
+       the_card.start_delay = snd_ps3_start_delay;
+
+       /* irq */
+       if (snd_ps3_allocate_irq()) {
+               ret = -ENXIO;
+               goto clean_dma_region;
+       }
+
+       /* create card instance */
+       the_card.card = snd_card_new(index, id, THIS_MODULE, 0);
+       if (!the_card.card) {
+               ret = -ENXIO;
+               goto clean_irq;
+       }
+
+       strcpy(the_card.card->driver, "PS3");
+       strcpy(the_card.card->shortname, "PS3");
+       strcpy(the_card.card->longname, "PS3 sound");
+       /* create PCM devices instance */
+       /* NOTE:this driver works assuming pcm:substream = 1:1 */
+       ret = snd_pcm_new(the_card.card,
+                         "SPDIF",
+                         0, /* instance index, will be stored pcm.device*/
+                         1, /* output substream */
+                         0, /* input substream */
+                         &(the_card.pcm));
+       if (ret)
+               goto clean_card;
+
+       the_card.pcm->private_data = &the_card;
+       strcpy(the_card.pcm->name, "SPDIF");
+
+       /* set pcm ops */
+       snd_pcm_set_ops(the_card.pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_ps3_pcm_spdif_ops);
+
+       the_card.pcm->info_flags = SNDRV_PCM_INFO_NONINTERLEAVED;
+       /* pre-alloc PCM DMA buffer*/
+       ret = snd_pcm_lib_preallocate_pages_for_all(the_card.pcm,
+                                       SNDRV_DMA_TYPE_DEV,
+                                       &dev->core,
+                                       SND_PS3_PCM_PREALLOC_SIZE,
+                                       SND_PS3_PCM_PREALLOC_SIZE);
+       if (ret < 0) {
+               pr_info("%s: prealloc failed\n", __func__);
+               goto clean_card;
+       }
+
+       /*
+        * allocate null buffer
+        * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2
+        * PAGE_SIZE is enogh
+        */
+       if (!(the_card.null_buffer_start_vaddr =
+             dma_alloc_coherent(&the_card.ps3_dev->core,
+                                PAGE_SIZE,
+                                &the_card.null_buffer_start_dma_addr,
+                                GFP_KERNEL))) {
+               pr_info("%s: nullbuffer alloc failed\n", __func__);
+               goto clean_preallocate;
+       }
+       pr_debug("%s: null vaddr=%p dma=%#lx\n", __func__,
+                the_card.null_buffer_start_vaddr,
+                the_card.null_buffer_start_dma_addr);
+       /* set default sample rate/word width */
+       snd_ps3_init_avsetting(&the_card);
+
+       /* register the card */
+       ret = snd_card_register(the_card.card);
+       if (ret < 0)
+               goto clean_dma_map;
+
+       pr_info("%s started. start_delay=%dms\n",
+               the_card.card->longname, the_card.start_delay);
+       return 0;
+
+clean_dma_map:
+       dma_free_coherent(&the_card.ps3_dev->core,
+                         PAGE_SIZE,
+                         the_card.null_buffer_start_vaddr,
+                         the_card.null_buffer_start_dma_addr);
+clean_preallocate:
+       snd_pcm_lib_preallocate_free_for_all(the_card.pcm);
+clean_card:
+       snd_card_free(the_card.card);
+clean_irq:
+       snd_ps3_free_irq();
+clean_dma_region:
+       ps3_dma_region_free(dev->d_region);
+clean_mmio:
+       snd_ps3_unmap_mmio();
+clean_dev_map:
+       lv1_gpu_device_unmap(2);
+clean_open:
+       ps3_close_hv_device(dev);
+       /*
+        * there is no destructor function to pcm.
+        * midlayer automatically releases if the card removed
+        */
+       return ret;
+}; /* snd_ps3_probe */
+
+/* called when module removal */
+static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev)
+{
+       int ret;
+       pr_info("%s:start id=%d\n", __func__,  dev->match_id);
+       if (dev->match_id != PS3_MATCH_ID_SOUND)
+               return -ENXIO;
+
+       /*
+        * ctl and preallocate buffer will be freed in
+        * snd_card_free
+        */
+       ret = snd_card_free(the_card.card);
+       if (ret)
+               pr_info("%s: ctl freecard=%d\n", __func__, ret);
+
+       dma_free_coherent(&dev->core,
+                         PAGE_SIZE,
+                         the_card.null_buffer_start_vaddr,
+                         the_card.null_buffer_start_dma_addr);
+
+       ps3_dma_region_free(dev->d_region);
+
+       snd_ps3_free_irq();
+       snd_ps3_unmap_mmio();
+
+       lv1_gpu_device_unmap(2);
+       ps3_close_hv_device(dev);
+       pr_info("%s:end id=%d\n", __func__, dev->match_id);
+       return 0;
+} /* snd_ps3_remove */
+
+static struct ps3_system_bus_driver snd_ps3_bus_driver_info = {
+       .match_id = PS3_MATCH_ID_SOUND,
+       .probe = snd_ps3_driver_probe,
+       .remove = snd_ps3_driver_remove,
+       .shutdown = snd_ps3_driver_remove,
+       .core = {
+               .name = SND_PS3_DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
+{
+
+       uint32_t port_intr;
+       int underflow_occured = 0;
+       struct snd_ps3_card_info *card = dev_id;
+
+       if (!card->running) {
+               update_reg(PS3_AUDIO_AX_IS, 0);
+               update_reg(PS3_AUDIO_INTR_0, 0);
+               return IRQ_HANDLED;
+       }
+
+       port_intr = read_reg(PS3_AUDIO_AX_IS);
+       /*
+        *serial buffer empty detected (every 4 times),
+        *program next dma and kick it
+        */
+       if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
+               write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
+               if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+                       write_reg(PS3_AUDIO_AX_IS, port_intr);
+                       underflow_occured = 1;
+               }
+               if (card->silent) {
+                       /* we are still in silent time */
+                       snd_ps3_program_dma(card,
+                               (underflow_occured) ?
+                               SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
+                               SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+                       snd_ps3_kick_dma(card);
+                       card->silent --;
+               } else {
+                       snd_ps3_program_dma(card,
+                               (underflow_occured) ?
+                               SND_PS3_DMA_FILLTYPE_FIRSTFILL :
+                               SND_PS3_DMA_FILLTYPE_RUNNING);
+                       snd_ps3_kick_dma(card);
+                       snd_pcm_period_elapsed(card->substream);
+               }
+       } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+               write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
+               /*
+                * serial out underflow, but buffer empty not detected.
+                * in this case, fill fifo with 0 to recover.  After
+                * filling dummy data, serial automatically start to
+                * consume them and then will generate normal buffer
+                * empty interrupts.
+                * If both buffer underflow and buffer empty are occured,
+                * it is better to do nomal data transfer than empty one
+                */
+               snd_ps3_program_dma(card,
+                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+               snd_ps3_kick_dma(card);
+               snd_ps3_program_dma(card,
+                                   SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+               snd_ps3_kick_dma(card);
+       }
+       /* clear interrupt cause */
+       return IRQ_HANDLED;
+};
+
+/*
+ * module/subsystem initialize/terminate
+ */
+static int __init snd_ps3_init(void)
+{
+       int ret;
+
+       if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+               return -ENXIO;
+
+       memset(&the_card, 0, sizeof(the_card));
+       spin_lock_init(&the_card.dma_lock);
+
+       /* register systembus DRIVER, this calls our probe() func */
+       ret = ps3_system_bus_driver_register(&snd_ps3_bus_driver_info);
+
+       return ret;
+}
+
+static void __exit snd_ps3_exit(void)
+{
+       ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info);
+}
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND);
diff --git a/sound/ppc/snd_ps3.h b/sound/ppc/snd_ps3.h
new file mode 100644 (file)
index 0000000..4b7e6fb
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * All rights reserved.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the Licence.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU 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
+ */
+
+#if !defined(_SND_PS3_H_)
+#define _SND_PS3_H_
+
+#include <linux/irqreturn.h>
+
+#define SND_PS3_DRIVER_NAME "snd_ps3"
+
+enum snd_ps3_out_channel {
+       SND_PS3_OUT_SPDIF_0,
+       SND_PS3_OUT_SPDIF_1,
+       SND_PS3_OUT_SERIAL_0,
+       SND_PS3_OUT_DEVS
+};
+
+enum snd_ps3_dma_filltype {
+       SND_PS3_DMA_FILLTYPE_FIRSTFILL,
+       SND_PS3_DMA_FILLTYPE_RUNNING,
+       SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL,
+       SND_PS3_DMA_FILLTYPE_SILENT_RUNNING
+};
+
+enum snd_ps3_ch {
+       SND_PS3_CH_L = 0,
+       SND_PS3_CH_R = 1,
+       SND_PS3_CH_MAX = 2
+};
+
+struct snd_ps3_avsetting_info {
+       uint32_t avs_audio_ch;     /* fixed */
+       uint32_t avs_audio_rate;
+       uint32_t avs_audio_width;
+       uint32_t avs_audio_format; /* fixed */
+       uint32_t avs_audio_source; /* fixed */
+};
+/*
+ * PS3 audio 'card' instance
+ * there should be only ONE hardware.
+ */
+struct snd_ps3_card_info {
+       struct ps3_system_bus_device *ps3_dev;
+       struct snd_card *card;
+
+       struct snd_pcm *pcm;
+       struct snd_pcm_substream *substream;
+
+       /* hvc info */
+       u64 audio_lpar_addr;
+       u64 audio_lpar_size;
+
+       /* registers */
+       void __iomem *mapped_mmio_vaddr;
+
+       /* irq */
+       u64 audio_irq_outlet;
+       unsigned int irq_no;
+
+       /* remember avsetting */
+       struct snd_ps3_avsetting_info avs;
+
+       /* dma buffer management */
+       spinlock_t dma_lock;
+               /* dma_lock start */
+               void * dma_start_vaddr[2]; /* 0 for L, 1 for R */
+               dma_addr_t dma_start_bus_addr[2];
+               size_t dma_buffer_size;
+               void * dma_last_transfer_vaddr[2];
+               void * dma_next_transfer_vaddr[2];
+               int    silent;
+               /* dma_lock end */
+
+       int running;
+
+       /* null buffer */
+       void *null_buffer_start_vaddr;
+       dma_addr_t null_buffer_start_dma_addr;
+
+       /* start delay */
+       unsigned int start_delay;
+
+};
+
+
+/* PS3 audio DMAC block size in bytes */
+#define PS3_AUDIO_DMAC_BLOCK_SIZE (128)
+/* one stage (stereo)  of audio FIFO in bytes */
+#define PS3_AUDIO_FIFO_STAGE_SIZE (256)
+/* how many stages the fifo have */
+#define PS3_AUDIO_FIFO_STAGE_COUNT (8)
+/* fifo size 128 bytes * 8 stages * stereo (2ch) */
+#define PS3_AUDIO_FIFO_SIZE \
+       (PS3_AUDIO_FIFO_STAGE_SIZE * PS3_AUDIO_FIFO_STAGE_COUNT)
+
+/* PS3 audio DMAC max block count in one dma shot = 128 (0x80) blocks*/
+#define PS3_AUDIO_DMAC_MAX_BLOCKS  (PS3_AUDIO_DMASIZE_BLOCKS_MASK + 1)
+
+#define PS3_AUDIO_NORMAL_DMA_START_CH (0)
+#define PS3_AUDIO_NORMAL_DMA_COUNT    (8)
+#define PS3_AUDIO_NULL_DMA_START_CH \
+       (PS3_AUDIO_NORMAL_DMA_START_CH + PS3_AUDIO_NORMAL_DMA_COUNT)
+#define PS3_AUDIO_NULL_DMA_COUNT      (2)
+
+#define SND_PS3_MAX_VOL (0x0F)
+#define SND_PS3_MIN_VOL (0x00)
+#define SND_PS3_MIN_ATT SND_PS3_MIN_VOL
+#define SND_PS3_MAX_ATT SND_PS3_MAX_VOL
+
+#define SND_PS3_PCM_PREALLOC_SIZE \
+       (PS3_AUDIO_DMAC_BLOCK_SIZE * PS3_AUDIO_DMAC_MAX_BLOCKS * 4)
+
+#define SND_PS3_DMA_REGION_SIZE \
+       (SND_PS3_PCM_PREALLOC_SIZE + PAGE_SIZE)
+
+#define PS3_AUDIO_IOID       (1UL)
+
+#endif /* _SND_PS3_H_ */
diff --git a/sound/ppc/snd_ps3_reg.h b/sound/ppc/snd_ps3_reg.h
new file mode 100644 (file)
index 0000000..03fdee4
--- /dev/null
@@ -0,0 +1,891 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2006, 2007 Sony Corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/*
+ * interrupt / configure registers
+ */
+
+#define PS3_AUDIO_INTR_0                 (0x00000100)
+#define PS3_AUDIO_INTR_EN_0              (0x00000140)
+#define PS3_AUDIO_CONFIG                 (0x00000200)
+
+/*
+ * DMAC registers
+ * n:0..9
+ */
+#define PS3_AUDIO_DMAC_REGBASE(x)         (0x0000210 + 0x20 * (x))
+
+#define PS3_AUDIO_KICK(n)                 (PS3_AUDIO_DMAC_REGBASE(n) + 0x00)
+#define PS3_AUDIO_SOURCE(n)               (PS3_AUDIO_DMAC_REGBASE(n) + 0x04)
+#define PS3_AUDIO_DEST(n)                 (PS3_AUDIO_DMAC_REGBASE(n) + 0x08)
+#define PS3_AUDIO_DMASIZE(n)              (PS3_AUDIO_DMAC_REGBASE(n) + 0x0C)
+
+/*
+ * mute control
+ */
+#define PS3_AUDIO_AX_MCTRL                (0x00004000)
+#define PS3_AUDIO_AX_ISBP                 (0x00004004)
+#define PS3_AUDIO_AX_AOBP                 (0x00004008)
+#define PS3_AUDIO_AX_IC                   (0x00004010)
+#define PS3_AUDIO_AX_IE                   (0x00004014)
+#define PS3_AUDIO_AX_IS                   (0x00004018)
+
+/*
+ * three wire serial
+ * n:0..3
+ */
+#define PS3_AUDIO_AO_MCTRL                (0x00006000)
+#define PS3_AUDIO_AO_3WMCTRL              (0x00006004)
+
+#define PS3_AUDIO_AO_3WCTRL(n)            (0x00006200 + 0x200 * (n))
+
+/*
+ * S/PDIF
+ * n:0..1
+ * x:0..11
+ * y:0..5
+ */
+#define PS3_AUDIO_AO_SPD_REGBASE(n)       (0x00007200 + 0x200 * (n))
+
+#define PS3_AUDIO_AO_SPDCTRL(n) \
+       (PS3_AUDIO_AO_SPD_REGBASE(n) + 0x00)
+#define PS3_AUDIO_AO_SPDUB(n, x) \
+       (PS3_AUDIO_AO_SPD_REGBASE(n) + 0x04 + 0x04 * (x))
+#define PS3_AUDIO_AO_SPDCS(n, y) \
+       (PS3_AUDIO_AO_SPD_REGBASE(n) + 0x34 + 0x04 * (y))
+
+
+/*
+  PS3_AUDIO_INTR_0 register tells an interrupt handler which audio
+  DMA channel triggered the interrupt.  The interrupt status for a channel
+  can be cleared by writing a '1' to the corresponding bit.  A new interrupt
+  cannot be generated until the previous interrupt has been cleared.
+
+  Note that the status reported by PS3_AUDIO_INTR_0 is independent of the
+  value of PS3_AUDIO_INTR_EN_0.
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+#define PS3_AUDIO_INTR_0_CHAN(n)       (1 << ((n) * 2))
+#define PS3_AUDIO_INTR_0_CHAN9     PS3_AUDIO_INTR_0_CHAN(9)
+#define PS3_AUDIO_INTR_0_CHAN8     PS3_AUDIO_INTR_0_CHAN(8)
+#define PS3_AUDIO_INTR_0_CHAN7     PS3_AUDIO_INTR_0_CHAN(7)
+#define PS3_AUDIO_INTR_0_CHAN6     PS3_AUDIO_INTR_0_CHAN(6)
+#define PS3_AUDIO_INTR_0_CHAN5     PS3_AUDIO_INTR_0_CHAN(5)
+#define PS3_AUDIO_INTR_0_CHAN4     PS3_AUDIO_INTR_0_CHAN(4)
+#define PS3_AUDIO_INTR_0_CHAN3     PS3_AUDIO_INTR_0_CHAN(3)
+#define PS3_AUDIO_INTR_0_CHAN2     PS3_AUDIO_INTR_0_CHAN(2)
+#define PS3_AUDIO_INTR_0_CHAN1     PS3_AUDIO_INTR_0_CHAN(1)
+#define PS3_AUDIO_INTR_0_CHAN0     PS3_AUDIO_INTR_0_CHAN(0)
+
+/*
+  The PS3_AUDIO_INTR_EN_0 register specifies which DMA channels can generate
+  an interrupt to the PU.  Each bit of PS3_AUDIO_INTR_EN_0 is ANDed with the
+  corresponding bit in PS3_AUDIO_INTR_0.  The resulting bits are OR'd together
+  to generate the Audio interrupt.
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_EN_0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+  Bit assignments are same as PS3_AUDIO_INTR_0
+*/
+
+/*
+  PS3_AUDIO_CONFIG
+  31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 C|0 0 0 0 0 0 0 0| CONFIG
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+
+/* The CLEAR field cancels all pending transfers, and stops any running DMA
+   transfers.  Any interrupts associated with the canceled transfers
+   will occur as if the transfer had finished.
+   Since this bit is designed to recover from DMA related issues
+   which are caused by unpredictable situations, it is prefered to wait
+   for normal DMA transfer end without using this bit.
+*/
+#define PS3_AUDIO_CONFIG_CLEAR          (1 << 8)  /* RWIVF */
+
+/*
+  PS3_AUDIO_AX_MCTRL: Audio Port Mute Control Register
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|A|A|0 0 0 0 0 0 0|S|S|A|A|A|A| AX_MCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/* 3 Wire Audio Serial Output Channel Mutes (0..3)  */
+#define PS3_AUDIO_AX_MCTRL_ASOMT(n)     (1 << (3 - (n)))  /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO3MT       (1 << 0)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO2MT       (1 << 1)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO1MT       (1 << 2)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO0MT       (1 << 3)          /* RWIVF */
+
+/* S/PDIF mutes (0,1)*/
+#define PS3_AUDIO_AX_MCTRL_SPOMT(n)     (1 << (5 - (n)))  /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_SPO1MT       (1 << 4)          /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_SPO0MT       (1 << 5)          /* RWIVF */
+
+/* All 3 Wire Serial Outputs Mute */
+#define PS3_AUDIO_AX_MCTRL_AASOMT       (1 << 13)         /* RWIVF */
+
+/* All S/PDIF Mute */
+#define PS3_AUDIO_AX_MCTRL_ASPOMT       (1 << 14)         /* RWIVF */
+
+/* All Audio Outputs Mute */
+#define PS3_AUDIO_AX_MCTRL_AAOMT        (1 << 15)         /* RWIVF */
+
+/*
+  S/PDIF Outputs Buffer Read/Write Pointer Register
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B|0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B| AX_ISBP
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+/*
+ S/PDIF Output Channel Read Buffer Numbers
+ Buffer number is  value of field.
+ Indicates current read access buffer ID from Audio Data
+ Transfer controller of S/PDIF Output
+*/
+
+#define PS3_AUDIO_AX_ISBP_SPOBRN_MASK(n) (0x7 << 4 * (1 - (n))) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO1BRN_MASK         (0x7 << 0) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO0BRN_MASK         (0x7 << 4) /* R-IUF */
+
+/*
+S/PDIF Output Channel Buffer Write Numbers
+Indicates current write access buffer ID from bus master.
+*/
+#define PS3_AUDIO_AX_ISBP_SPOBWN_MASK(n) (0x7 <<  4 * (5 - (n))) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO1BWN_MASK         (0x7 << 16) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO0BWN_MASK         (0x7 << 20) /* R-IUF */
+
+/*
+  3 Wire Audio Serial Outputs Buffer Read/Write
+  Pointer Register
+  Buffer number is  value of field
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B|0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B| AX_AOBP
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+3 Wire Audio Serial Output Channel Buffer Read Numbers
+Indicates current read access buffer Id from Audio Data Transfer
+Controller of 3 Wire Audio Serial Output Channels
+*/
+#define PS3_AUDIO_AX_AOBP_ASOBRN_MASK(n) (0x7 << 4 * (3 - (n))) /* R-IUF */
+
+#define PS3_AUDIO_AX_AOBP_ASO3BRN_MASK (0x7 << 0) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO2BRN_MASK (0x7 << 4) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO1BRN_MASK (0x7 << 8) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO0BRN_MASK (0x7 << 12) /* R-IUF */
+
+/*
+3 Wire Audio Serial Output Channel Buffer Write Numbers
+Indicates current write access buffer ID from bus master.
+*/
+#define PS3_AUDIO_AX_AOBP_ASOBWN_MASK(n) (0x7 << 4 * (7 - (n))) /* R-IUF */
+
+#define PS3_AUDIO_AX_AOBP_ASO3BWN_MASK        (0x7 << 16) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO2BWN_MASK        (0x7 << 20) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO1BWN_MASK        (0x7 << 24) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO0BWN_MASK        (0x7 << 28) /* R-IUF */
+
+
+
+/*
+Audio Port Interrupt Condition Register
+For the fields in this register, the following values apply:
+0 = Interrupt is generated every interrupt event.
+1 = Interrupt is generated every 2 interrupt events.
+2 = Interrupt is generated every 4 interrupt events.
+3 = Reserved
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0 0|SPO|0 0|SPO|0 0|AAS|0 0 0 0 0 0 0 0 0 0 0 0| AX_IC
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+All 3-Wire Audio Serial Outputs Interrupt Mode
+Configures the Interrupt and Signal Notification
+condition of all 3-wire Audio Serial Outputs.
+*/
+#define PS3_AUDIO_AX_IC_AASOIMD_MASK          (0x3 << 12) /* RWIVF */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY1        (0x0 << 12) /* RWI-V */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY2        (0x1 << 12) /* RW--V */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY4        (0x2 << 12) /* RW--V */
+
+/*
+S/PDIF Output Channel Interrupt Modes
+Configures the Interrupt and signal Notification
+conditions of S/PDIF output channels.
+*/
+#define PS3_AUDIO_AX_IC_SPO1IMD_MASK          (0x3 << 16) /* RWIVF */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY1        (0x0 << 16) /* RWI-V */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY2        (0x1 << 16) /* RW--V */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY4        (0x2 << 16) /* RW--V */
+
+#define PS3_AUDIO_AX_IC_SPO0IMD_MASK          (0x3 << 20) /* RWIVF */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY1        (0x0 << 20) /* RWI-V */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY2        (0x1 << 20) /* RW--V */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY4        (0x2 << 20) /* RW--V */
+
+/*
+Audio Port interrupt Enable Register
+Configures whether to enable or disable each Interrupt Generation.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+
+/*
+3 Wire Audio Serial Output Channel Buffer Underflow
+Interrupt Enables
+Select enable/disable of Buffer Underflow Interrupts for
+3-Wire Audio Serial Output Channels
+DISABLED=Interrupt generation disabled.
+*/
+#define PS3_AUDIO_AX_IE_ASOBUIE(n)      (1 << (3 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO3BUIE        (1 << 0) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO2BUIE        (1 << 1) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO1BUIE        (1 << 2) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO0BUIE        (1 << 3) /* RWIVF */
+
+/* S/PDIF Output Channel Buffer Underflow Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBUIE(n)      (1 << (7 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BUIE        (1 << 6) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BUIE        (1 << 7) /* RWIVF */
+
+/* S/PDIF Output Channel One Block Transfer Completion Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBTCIE(n)     (1 << (11 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BTCIE       (1 << 10) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BTCIE       (1 << 11) /* RWIVF */
+
+/* 3-Wire Audio Serial Output Channel Buffer Empty Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_ASOBEIE(n)      (1 << (19 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO3BEIE        (1 << 16) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO2BEIE        (1 << 17) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO1BEIE        (1 << 18) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO0BEIE        (1 << 19) /* RWIVF */
+
+/* S/PDIF Output Channel Buffer Empty Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBEIE(n)      (1 << (23 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BEIE        (1 << 22) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BEIE        (1 << 23) /* RWIVF */
+
+/*
+Audio Port Interrupt Status Register
+Indicates Interrupt status, which interrupt has occured, and can clear
+each interrupt in this register.
+Writing 1b to a field containing 1b clears field and de-asserts interrupt.
+Writing 0b to a field has no effect.
+Field vaules are the following:
+0 - Interrupt hasn't occured.
+1 - Interrupt has occured.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IS
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+ Bit assignment are same as AX_IE
+*/
+
+/*
+Audio Output Master Control Register
+Configures Master Clock and other master Audio Output Settings
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0|SCKSE|0|SCKSE|  MR0  |  MR1  |MCL|MCL|0 0 0 0|0 0 0 0 0 0 0 0| AO_MCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+MCLK Output Control
+Controls mclko[1] output.
+0 - Disable output (fixed at High)
+1 - Output clock produced by clock selected
+with scksel1 by mr1
+2 - Reserved
+3 - Reserved
+*/
+
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_MASK         (0x3 << 12) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_DISABLED     (0x0 << 12) /* RWI-V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_ENABLED      (0x1 << 12) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD2       (0x2 << 12) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD3       (0x3 << 12) /* RW--V */
+
+/*
+MCLK Output Control
+Controls mclko[0] output.
+0 - Disable output (fixed at High)
+1 - Output clock produced by clock selected
+with SCKSEL0 by MR0
+2 - Reserved
+3 - Reserved
+*/
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_MASK         (0x3 << 14) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_DISABLED     (0x0 << 14) /* RWI-V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_ENABLED      (0x1 << 14) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD2       (0x2 << 14) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD3       (0x3 << 14) /* RW--V */
+/*
+Master Clock Rate 1
+Sets the divide ration of Master Clock1 (clock output from
+mclko[1] for the input clock selected by scksel1.
+*/
+#define PS3_AUDIO_AO_MCTRL_MR1_MASK    (0xf << 16)
+#define PS3_AUDIO_AO_MCTRL_MR1_DEFAULT (0x0 << 16) /* RWI-V */
+/*
+Master Clock Rate 0
+Sets the divide ratio of Master Clock0 (clock output from
+mclko[0] for the input clock selected by scksel0).
+*/
+#define PS3_AUDIO_AO_MCTRL_MR0_MASK    (0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MR0_DEFAULT (0x0 << 20) /* RWI-V */
+/*
+System Clock Select 0/1
+Selects the system clock to be used as Master Clock 0/1
+Input the system clock that is appropriate for the sampling
+rate.
+*/
+#define PS3_AUDIO_AO_MCTRL_SCKSEL1_MASK                (0x7 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_SCKSEL1_DEFAULT     (0x2 << 24) /* RWI-V */
+
+#define PS3_AUDIO_AO_MCTRL_SCKSEL0_MASK                (0x7 << 28) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_SCKSEL0_DEFAULT     (0x2 << 28) /* RWI-V */
+
+
+/*
+3-Wire Audio Output Master Control Register
+Configures clock, 3-Wire Audio Serial Output Enable, and
+other 3-Wire Audio Serial Output Master Settings
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |A|A|A|A|0 0 0|A| ASOSR |0 0 0 0|A|A|A|A|A|A|0|1|0 0 0 0 0 0 0 0| AO_3WMCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+
+/*
+LRCKO Polarity
+0 - Reserved
+1 - default
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK          (1 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT  (1 << 8) /* RW--V */
+
+/* LRCK Output Disable */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD          (1 << 10) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_ENABLED  (0 << 10) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED (1 << 10) /* RWI-V */
+
+/* Bit Clock Output Disable */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD          (1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_ENABLED  (0 << 11) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED (1 << 11) /* RWI-V */
+
+/*
+3-Wire Audio Serial Output Channel 0-3 Operational
+Status.  Each bit becomes 1 after each 3-Wire Audio
+Serial Output Channel N is in action by setting 1 to
+asoen.
+Each bit becomes 0 after each 3-Wire Audio Serial Output
+Channel N is out of action by setting 0 to asoen.
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN(n)         (1 << (15 - (n))) /* R-IVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(n) (0 << (15 - (n))) /* R-I-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(n) (1 << (15 - (n))) /* R---V */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0           \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_STOPPED   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_RUNNING   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1           \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_STOPPED   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_RUNNING   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2           \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_STOPPED   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_RUNNING   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3           \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN(3)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_STOPPED   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(3)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_RUNNING   \
+       PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(3)
+
+/*
+Sampling Rate
+Specifies the divide ratio of the bit clock (clock output
+from bclko) used by the 3-wire Audio Output Clock, whcih
+is applied to the master clock selected by mcksel.
+Data output is synchronized with this clock.
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_MASK                (0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV2                (0x1 << 20) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV4                (0x2 << 20) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV8                (0x4 << 20) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV12       (0x6 << 20) /* RW--V */
+
+/*
+Master Clock Select
+0 - Master Clock 0
+1 - Master Clock 1
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL         (1 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK0    (0 << 24) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK1    (1 << 24) /* RW--V */
+
+/*
+Enables and disables 4ch 3-Wire Audio Serial Output
+operation.  Each Bit from 0 to 3 corresponds to an
+output channel, which means that each output channel
+can be enabled or disabled individually.  When
+multiple channels are enabled at the same time, output
+operations are performed in synchronization.
+Bit 0 - Output Channel 0 (SDOUT[0])
+Bit 1 - Output Channel 1 (SDOUT[1])
+Bit 2 - Output Channel 2 (SDOUT[2])
+Bit 3 - Output Channel 3 (SDOUT[3])
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN(n)          (1 << (31 - (n))) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(n) (0 << (31 - (n))) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(n)  (1 << (31 - (n))) /* RW--V */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0 \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN(0) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_DISABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(0) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_ENABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(0) /* RW--V */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0 \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN(1) /* RWIVF */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_DISABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(1) /* RWI-V */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_ENABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(1) /* RW--V */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0 \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN(2) /* RWIVF */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_DISABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(2) /* RWI-V */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_ENABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(2) /* RW--V */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0 \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN(3) /* RWIVF */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_DISABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(3) /* RWI-V */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_ENABLED \
+       PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(3) /* RW--V */
+
+/*
+3-Wire Audio Serial output Channel 0-3 Control Register
+Configures settings for 3-Wire Serial Audio Output Channel 0-3
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|0 0 0 0|A|0|ASO|0 0 0|0|0|0|0|0| AO_3WCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+/*
+Data Bit Mode
+Specifies the number of data bits
+0 - 16 bits
+1 - reserved
+2 - 20 bits
+3 - 24 bits
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASODB_MASK (0x3 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_16BIT        (0x0 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_RESVD        (0x1 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_20BIT        (0x2 << 8) /* RW--V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_24BIT        (0x3 << 8) /* RW--V */
+/*
+Data Format Mode
+Specifies the data format where (LSB side or MSB) the data(in 20 bit
+or 24 bit resolution mode) is put in a 32 bit field.
+0 - Data put on LSB side
+1 - Data put on MSB side
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASODF      (1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASODF_LSB  (0 << 11) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODF_MSB  (1 << 11) /* RW--V */
+/*
+Buffer Reset
+Performs buffer reset.  Writing 1 to this bit initializes the
+corresponding 3-Wire Audio Output buffers(both L and R).
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST            (1 << 16) /* CWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST_IDLE       (0 << 16) /* -WI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET      (1 << 16) /* -W--T */
+
+/*
+S/PDIF Audio Output Channel 0/1 Control Register
+Configures settings for S/PDIF Audio Output Channel 0/1.
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |S|0 0 0|S|0 0|S| SPOSR |0 0|SPO|0 0 0 0|S|0|SPO|0 0 0 0 0 0 0|S| AO_SPDCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+Buffer reset.  Writing 1 to this bit initializes the
+corresponding S/PDIF output buffer pointer.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST           (1 << 0) /* CWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_IDLE      (0 << 0) /* -WI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_RESET     (1 << 0) /* -W--T */
+
+/*
+Data Bit Mode
+Specifies number of data bits
+0 - 16 bits
+1 - Reserved
+2 - 20 bits
+3 - 24 bits
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_MASK                (0x3 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_16BIT       (0x0 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_RESVD       (0x1 << 8) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_20BIT       (0x2 << 8) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_24BIT       (0x3 << 8) /* RW--V */
+/*
+Data format Mode
+Specifies the data format, where (LSB side or MSB)
+the data(in 20 or 24 bit resolution) is put in the
+32 bit field.
+0 - LSB Side
+1 - MSB Side
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPODF     (1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPODF_LSB (0 << 11) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODF_MSB (1 << 11) /* RW--V */
+/*
+Source Select
+Specifies the source of the S/PDIF output.  When 0, output
+operation is controlled by 3wen[0] of AO_3WMCTRL register.
+The SR must have the same setting as the a0_3wmctrl reg.
+0 - 3-Wire Audio OUT Ch0 Buffer
+1 - S/PDIF buffer
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_MASK                (0x3 << 16) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_3WEN                (0x0 << 16) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_SPDIF       (0x1 << 16) /* RW--V */
+/*
+Sampling Rate
+Specifies the divide ratio of the bit clock (clock output
+from bclko) used by the S/PDIF Output Clock, which
+is applied to the master clock selected by mcksel.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR             (0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV2                (0x1 << 20) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV4                (0x2 << 20) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV8                (0x4 << 20) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV12       (0x6 << 20) /* RW--V */
+/*
+Master Clock Select
+0 - Master Clock 0
+1 - Master Clock 1
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL         (1 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK0    (0 << 24) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK1    (1 << 24) /* RW--V */
+
+/*
+S/PDIF Output Channel Operational Status
+This bit becomes 1 after S/PDIF Output Channel is in
+action by setting 1 to spoen.  This bit becomes 0
+after S/PDIF Output Channel is out of action by setting
+0 to spoen.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN            (1 << 27) /* R-IVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN_STOPPED    (0 << 27) /* R-I-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN_RUNNING    (1 << 27) /* R---V */
+
+/*
+S/PDIF Audio Output Channel Output Enable
+Enables and disables output operation.  This bit is used
+only when sposs = 1
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN             (1 << 31) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN_DISABLED    (0 << 31) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN_ENABLED     (1 << 31) /* RW--V */
+
+/*
+S/PDIF Audio Output Channel Channel Status
+Setting Registers.
+Configures channel status bit settings for each block
+(192 bits).
+Output is performed from the MSB(AO_SPDCS0 register bit 31).
+The same value is added for subframes within the same frame.
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                             SPOCS                             | AO_SPDCS
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+S/PDIF Audio Output Channel User Bit Setting
+Configures user bit settings for each block (384 bits).
+Output is performed from the MSB(ao_spdub0 register bit 31).
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                             SPOUB                             | AO_SPDUB
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*****************************************************************************
+ *
+ * DMAC register
+ *
+ *****************************************************************************/
+/*
+The PS3_AUDIO_KICK register is used to initiate a DMA transfer and monitor
+its status
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0|STATU|0 0 0|  EVENT  |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|R| KICK
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+The REQUEST field is written to ACTIVE to initiate a DMA request when EVENT
+occurs.
+It will return to the DONE state when the request is completed.
+The registers for a DMA channel should only be written if REQUEST is IDLE.
+*/
+
+#define PS3_AUDIO_KICK_REQUEST                (1 << 0) /* RWIVF */
+#define PS3_AUDIO_KICK_REQUEST_IDLE           (0 << 0) /* RWI-V */
+#define PS3_AUDIO_KICK_REQUEST_ACTIVE         (1 << 0) /* -W--T */
+
+/*
+ *The EVENT field is used to set the event in which
+ *the DMA request becomes active.
+ */
+#define PS3_AUDIO_KICK_EVENT_MASK             (0x1f << 16) /* RWIVF */
+#define PS3_AUDIO_KICK_EVENT_ALWAYS           (0x00 << 16) /* RWI-V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY (0x01 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_UNDERFLOW      (0x02 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_EMPTY          (0x03 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_UNDERFLOW      (0x04 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_EMPTY          (0x05 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_UNDERFLOW      (0x06 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_EMPTY          (0x07 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_UNDERFLOW      (0x08 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_BLOCKTRANSFERCOMPLETE \
+       (0x09 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_UNDERFLOW          (0x0A << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_EMPTY              (0x0B << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_BLOCKTRANSFERCOMPLETE \
+       (0x0C << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_UNDERFLOW          (0x0D << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_EMPTY              (0x0E << 16) /* RW--V */
+
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA(n) \
+       ((0x13 + (n)) << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA0         (0x13 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA1         (0x14 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA2         (0x15 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA3         (0x16 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA4         (0x17 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA5         (0x18 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA6         (0x19 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA7         (0x1A << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA8         (0x1B << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA9         (0x1C << 16) /* RW--V */
+
+/*
+The STATUS field can be used to monitor the progress of a DMA request.
+DONE indicates the previous request has completed.
+EVENT indicates that the DMA engine is waiting for the EVENT to occur.
+PENDING indicates that the DMA engine has not started processing this
+request, but the EVENT has occured.
+DMA indicates that the data transfer is in progress.
+NOTIFY indicates that the notifier signalling end of transfer is being written.
+CLEAR indicated that the previous transfer was cleared.
+ERROR indicates the previous transfer requested an unsupported
+source/destination combination.
+*/
+
+#define PS3_AUDIO_KICK_STATUS_MASK     (0x7 << 24) /* R-IVF */
+#define PS3_AUDIO_KICK_STATUS_DONE     (0x0 << 24) /* R-I-V */
+#define PS3_AUDIO_KICK_STATUS_EVENT    (0x1 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_PENDING  (0x2 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_DMA      (0x3 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_NOTIFY   (0x4 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_CLEAR    (0x5 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_ERROR    (0x6 << 24) /* R---V */
+
+/*
+The PS3_AUDIO_SOURCE register specifies the source address for transfers.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                      START                      |0 0 0 0 0|TAR| SOURCE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
+to a 128 byte boundary.  The low seven bits are assumed to be 0.
+*/
+
+#define PS3_AUDIO_SOURCE_START_MASK    (0x01FFFFFF << 7) /* RWIUF */
+
+/*
+The TARGET field specifies the memory space containing the source address.
+*/
+
+#define PS3_AUDIO_SOURCE_TARGET_MASK           (3 << 0) /* RWIVF */
+#define PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY  (2 << 0) /* RW--V */
+
+/*
+The PS3_AUDIO_DEST register specifies the destination address for transfers.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |                      START                      |0 0 0 0 0|TAR| DEST
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
+to a 128 byte boundary.  The low seven bits are assumed to be 0.
+*/
+
+#define PS3_AUDIO_DEST_START_MASK      (0x01FFFFFF << 7) /* RWIUF */
+
+/*
+The TARGET field specifies the memory space containing the destination address
+AUDIOFIFO = Audio WriteData FIFO,
+*/
+
+#define PS3_AUDIO_DEST_TARGET_MASK             (3 << 0) /* RWIVF */
+#define PS3_AUDIO_DEST_TARGET_AUDIOFIFO                (1 << 0) /* RW--V */
+
+/*
+PS3_AUDIO_DMASIZE specifies the number of 128-byte blocks + 1 to transfer.
+So a value of 0 means 128-bytes will get transfered.
+
+
+ 31            24 23           16 15            8 7             0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|   BLOCKS    | DMASIZE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+
+#define PS3_AUDIO_DMASIZE_BLOCKS_MASK  (0x7f << 0) /* RWIUF */
+
+/*
+ * source/destination address for internal fifos
+ */
+#define PS3_AUDIO_AO_3W_LDATA(n)       (0x1000 + (0x100 * (n)))
+#define PS3_AUDIO_AO_3W_RDATA(n)       (0x1080 + (0x100 * (n)))
+
+#define PS3_AUDIO_AO_SPD_DATA(n)       (0x2000 + (0x400 * (n)))
+
+
+/*
+ * field attiribute
+ *
+ *     Read
+ *       ' ' = Other Information
+ *       '-' = Field is part of a write-only register
+ *       'C' = Value read is always the same, constant value line follows (C)
+ *       'R' = Value is read
+ *
+ *     Write
+ *       ' ' = Other Information
+ *       '-' = Must not be written (D), value ignored when written (R,A,F)
+ *       'W' = Can be written
+ *
+ *     Internal State
+ *       ' ' = Other Information
+ *       '-' = No internal state
+ *       'X' = Internal state, initial value is unknown
+ *       'I' = Internal state, initial value is known and follows (I)
+ *
+ *     Declaration/Size
+ *       ' ' = Other Information
+ *       '-' = Does Not Apply
+ *       'V' = Type is void
+ *       'U' = Type is unsigned integer
+ *       'S' = Type is signed integer
+ *       'F' = Type is IEEE floating point
+ *       '1' = Byte size (008)
+ *       '2' = Short size (016)
+ *       '3' = Three byte size (024)
+ *       '4' = Word size (032)
+ *       '8' = Double size (064)
+ *
+ *     Define Indicator
+ *       ' ' = Other Information
+ *       'D' = Device
+ *       'M' = Memory
+ *       'R' = Register
+ *       'A' = Array of Registers
+ *       'F' = Field
+ *       'V' = Value
+ *       'T' = Task
+ */
+
diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig
new file mode 100644 (file)
index 0000000..b7e08ef
--- /dev/null
@@ -0,0 +1,14 @@
+# ALSA SH drivers
+
+menu "SUPERH devices"
+       depends on SND!=n && SUPERH
+
+config SND_AICA
+       tristate "Dreamcast Yamaha AICA sound"
+       depends on SH_DREAMCAST && SND
+       select SND_PCM
+       help
+         ALSA Sound driver for the SEGA Dreamcast console.
+
+endmenu
+
diff --git a/sound/sh/Makefile b/sound/sh/Makefile
new file mode 100644 (file)
index 0000000..8fdcb6e
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+#
+
+snd-aica-objs := aica.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_AICA) += snd-aica.o
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
new file mode 100644 (file)
index 0000000..7397865
--- /dev/null
@@ -0,0 +1,665 @@
+/*
+* This code is licenced under 
+* the General Public Licence
+* version 2
+*
+* Copyright Adrian McMenamin 2005, 2006, 2007
+* <adrian@mcmen.demon.co.uk>
+* Requires firmware (BSD licenced) available from:
+* http://linuxdc.cvs.sourceforge.net/linuxdc/linux-sh-dc/sound/oss/aica/firmware/
+* or the maintainer
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*
+*/
+
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/dreamcast/sysasic.h>
+#include "aica.h"
+
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}");
+
+/* module parameters */
+#define CARD_NAME "AICA"
+static int index = -1;
+static char *id;
+static int enable = 1;
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param(enable, bool, 0644);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+/* Use workqueue */
+static struct workqueue_struct *aica_queue;
+
+/* Simple platform device */
+static struct platform_device *pd;
+static struct resource aica_memory_space[2] = {
+       {
+        .name = "AICA ARM CONTROL",
+        .start = ARM_RESET_REGISTER,
+        .flags = IORESOURCE_MEM,
+        .end = ARM_RESET_REGISTER + 3,
+        },
+       {
+        .name = "AICA Sound RAM",
+        .start = SPU_MEMORY_BASE,
+        .flags = IORESOURCE_MEM,
+        .end = SPU_MEMORY_BASE + 0x200000 - 1,
+        },
+};
+
+/* SPU specific functions */
+/* spu_write_wait - wait for G2-SH FIFO to clear */
+static void spu_write_wait(void)
+{
+       int time_count;
+       time_count = 0;
+       while (1) {
+               if (!(readl(G2_FIFO) & 0x11))
+                       break;
+               /* To ensure hardware failure doesn't wedge kernel */
+               time_count++;
+               if (time_count > 0x10000) {
+                       snd_printk
+                           ("WARNING: G2 FIFO appears to be blocked.\n");
+                       break;
+               }
+       }
+}
+
+/* spu_memset - write to memory in SPU address space */
+static void spu_memset(u32 toi, u32 what, int length)
+{
+       int i;
+       snd_assert(length % 4 == 0, return);
+       for (i = 0; i < length; i++) {
+               if (!(i % 8))
+                       spu_write_wait();
+               writel(what, toi + SPU_MEMORY_BASE);
+               toi++;
+       }
+}
+
+/* spu_memload - write to SPU address space */
+static void spu_memload(u32 toi, void *from, int length)
+{
+       u32 *froml = from;
+       u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
+       int i;
+       u32 val;
+       length = DIV_ROUND_UP(length, 4);
+       spu_write_wait();
+       for (i = 0; i < length; i++) {
+               if (!(i % 8))
+                       spu_write_wait();
+               val = *froml;
+               writel(val, to);
+               froml++;
+               to++;
+       }
+}
+
+/* spu_disable - set spu registers to stop sound output */
+static void spu_disable(void)
+{
+       int i;
+       u32 regval;
+       spu_write_wait();
+       regval = readl(ARM_RESET_REGISTER);
+       regval |= 1;
+       spu_write_wait();
+       writel(regval, ARM_RESET_REGISTER);
+       for (i = 0; i < 64; i++) {
+               spu_write_wait();
+               regval = readl(SPU_REGISTER_BASE + (i * 0x80));
+               regval = (regval & ~0x4000) | 0x8000;
+               spu_write_wait();
+               writel(regval, SPU_REGISTER_BASE + (i * 0x80));
+       }
+}
+
+/* spu_enable - set spu registers to enable sound output */
+static void spu_enable(void)
+{
+       u32 regval = readl(ARM_RESET_REGISTER);
+       regval &= ~1;
+       spu_write_wait();
+       writel(regval, ARM_RESET_REGISTER);
+}
+
+/* 
+ * Halt the sound processor, clear the memory,
+ * load some default ARM7 code, and then restart ARM7
+*/
+static void spu_reset(void)
+{
+       spu_disable();
+       spu_memset(0, 0, 0x200000 / 4);
+       /* Put ARM7 in endless loop */
+       ctrl_outl(0xea000002, SPU_MEMORY_BASE);
+       spu_enable();
+}
+
+/* aica_chn_start - write to spu to start playback */
+static void aica_chn_start(void)
+{
+       spu_write_wait();
+       writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
+}
+
+/* aica_chn_halt - write to spu to halt playback */
+static void aica_chn_halt(void)
+{
+       spu_write_wait();
+       writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
+}
+
+/* ALSA code below */
+static struct snd_pcm_hardware snd_pcm_aica_playback_hw = {
+       .info = (SNDRV_PCM_INFO_NONINTERLEAVED),
+       .formats =
+           (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
+            SNDRV_PCM_FMTBIT_IMA_ADPCM),
+       .rates = SNDRV_PCM_RATE_8000_48000,
+       .rate_min = 8000,
+       .rate_max = 48000,
+       .channels_min = 1,
+       .channels_max = 2,
+       .buffer_bytes_max = AICA_BUFFER_SIZE,
+       .period_bytes_min = AICA_PERIOD_SIZE,
+       .period_bytes_max = AICA_PERIOD_SIZE,
+       .periods_min = AICA_PERIOD_NUMBER,
+       .periods_max = AICA_PERIOD_NUMBER,
+};
+
+static int aica_dma_transfer(int channels, int buffer_size,
+                            struct snd_pcm_substream *substream)
+{
+       int q, err, period_offset;
+       struct snd_card_aica *dreamcastcard;
+       struct snd_pcm_runtime *runtime;
+       err = 0;
+       dreamcastcard = substream->pcm->private_data;
+       period_offset = dreamcastcard->clicks;
+       period_offset %= (AICA_PERIOD_NUMBER / channels);
+       runtime = substream->runtime;
+       for (q = 0; q < channels; q++) {
+               err = dma_xfer(AICA_DMA_CHANNEL,
+                              (unsigned long) (runtime->dma_area +
+                                               (AICA_BUFFER_SIZE * q) /
+                                               channels +
+                                               AICA_PERIOD_SIZE *
+                                               period_offset),
+                              AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
+                              AICA_PERIOD_SIZE * period_offset,
+                              buffer_size / channels, AICA_DMA_MODE);
+               if (unlikely(err < 0))
+                       break;
+               dma_wait_for_completion(AICA_DMA_CHANNEL);
+       }
+       return err;
+}
+
+static void startup_aica(struct snd_card_aica *dreamcastcard)
+{
+       spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+                   dreamcastcard->channel, sizeof(struct aica_channel));
+       aica_chn_start();
+}
+
+static void run_spu_dma(struct work_struct *work)
+{
+       int buffer_size;
+       struct snd_pcm_runtime *runtime;
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard =
+           container_of(work, struct snd_card_aica, spu_dma_work);
+       runtime = dreamcastcard->substream->runtime;
+       if (unlikely(dreamcastcard->dma_check == 0)) {
+               buffer_size =
+                   frames_to_bytes(runtime, runtime->buffer_size);
+               if (runtime->channels > 1)
+                       dreamcastcard->channel->flags |= 0x01;
+               aica_dma_transfer(runtime->channels, buffer_size,
+                                 dreamcastcard->substream);
+               startup_aica(dreamcastcard);
+               dreamcastcard->clicks =
+                   buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
+               return;
+       } else {
+               aica_dma_transfer(runtime->channels,
+                                 AICA_PERIOD_SIZE * runtime->channels,
+                                 dreamcastcard->substream);
+               snd_pcm_period_elapsed(dreamcastcard->substream);
+               dreamcastcard->clicks++;
+               if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
+                       dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
+               mod_timer(&dreamcastcard->timer, jiffies + 1);
+       }
+}
+
+static void aica_period_elapsed(unsigned long timer_var)
+{
+       /*timer function - so cannot sleep */
+       int play_period;
+       struct snd_pcm_runtime *runtime;
+       struct snd_pcm_substream *substream;
+       struct snd_card_aica *dreamcastcard;
+       substream = (struct snd_pcm_substream *) timer_var;
+       runtime = substream->runtime;
+       dreamcastcard = substream->pcm->private_data;
+       /* Have we played out an additional period? */
+       play_period =
+           frames_to_bytes(runtime,
+                           readl
+                           (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) /
+           AICA_PERIOD_SIZE;
+       if (play_period == dreamcastcard->current_period) {
+               /* reschedule the timer */
+               mod_timer(&(dreamcastcard->timer), jiffies + 1);
+               return;
+       }
+       if (runtime->channels > 1)
+               dreamcastcard->current_period = play_period;
+       if (unlikely(dreamcastcard->dma_check == 0))
+               dreamcastcard->dma_check = 1;
+       queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
+}
+
+static void spu_begin_dma(struct snd_pcm_substream *substream)
+{
+       struct snd_card_aica *dreamcastcard;
+       struct snd_pcm_runtime *runtime;
+       runtime = substream->runtime;
+       dreamcastcard = substream->pcm->private_data;
+       /*get the queue to do the work */
+       queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
+       /* Timer may already be running */
+       if (unlikely(dreamcastcard->timer.data)) {
+               mod_timer(&dreamcastcard->timer, jiffies + 4);
+               return;
+       }
+       init_timer(&(dreamcastcard->timer));
+       dreamcastcard->timer.data = (unsigned long) substream;
+       dreamcastcard->timer.function = aica_period_elapsed;
+       dreamcastcard->timer.expires = jiffies + 4;
+       add_timer(&(dreamcastcard->timer));
+}
+
+static int snd_aicapcm_pcm_open(struct snd_pcm_substream
+                               *substream)
+{
+       struct snd_pcm_runtime *runtime;
+       struct aica_channel *channel;
+       struct snd_card_aica *dreamcastcard;
+       if (!enable)
+               return -ENOENT;
+       dreamcastcard = substream->pcm->private_data;
+       channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);
+       if (!channel)
+               return -ENOMEM;
+       /* set defaults for channel */
+       channel->sfmt = SM_8BIT;
+       channel->cmd = AICA_CMD_START;
+       channel->vol = dreamcastcard->master_volume;
+       channel->pan = 0x80;
+       channel->pos = 0;
+       channel->flags = 0;     /* default to mono */
+       dreamcastcard->channel = channel;
+       runtime = substream->runtime;
+       runtime->hw = snd_pcm_aica_playback_hw;
+       spu_enable();
+       dreamcastcard->clicks = 0;
+       dreamcastcard->current_period = 0;
+       dreamcastcard->dma_check = 0;
+       return 0;
+}
+
+static int snd_aicapcm_pcm_close(struct snd_pcm_substream
+                                *substream)
+{
+       struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+       flush_workqueue(aica_queue);
+       if (dreamcastcard->timer.data)
+               del_timer(&dreamcastcard->timer);
+       kfree(dreamcastcard->channel);
+       spu_disable();
+       return 0;
+}
+
+static int snd_aicapcm_pcm_hw_free(struct snd_pcm_substream
+                                  *substream)
+{
+       /* Free the DMA buffer */
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_aicapcm_pcm_hw_params(struct snd_pcm_substream
+                                    *substream, struct snd_pcm_hw_params
+                                    *hw_params)
+{
+       /* Allocate a DMA buffer using ALSA built-ins */
+       return
+           snd_pcm_lib_malloc_pages(substream,
+                                    params_buffer_bytes(hw_params));
+}
+
+static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream
+                                  *substream)
+{
+       struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+       if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)
+               dreamcastcard->channel->sfmt = SM_16BIT;
+       dreamcastcard->channel->freq = substream->runtime->rate;
+       dreamcastcard->substream = substream;
+       return 0;
+}
+
+static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
+                                  *substream, int cmd)
+{
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               spu_begin_dma(substream);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               aica_chn_halt();
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream
+                                            *substream)
+{
+       return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);
+}
+
+static struct snd_pcm_ops snd_aicapcm_playback_ops = {
+       .open = snd_aicapcm_pcm_open,
+       .close = snd_aicapcm_pcm_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_aicapcm_pcm_hw_params,
+       .hw_free = snd_aicapcm_pcm_hw_free,
+       .prepare = snd_aicapcm_pcm_prepare,
+       .trigger = snd_aicapcm_pcm_trigger,
+       .pointer = snd_aicapcm_pcm_pointer,
+};
+
+/* TO DO: set up to handle more than one pcm instance */
+static int __init snd_aicapcmchip(struct snd_card_aica
+                                 *dreamcastcard, int pcm_index)
+{
+       struct snd_pcm *pcm;
+       int err;
+       /* AICA has no capture ability */
+       err =
+           snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0,
+                       &pcm);
+       if (unlikely(err < 0))
+               return err;
+       pcm->private_data = dreamcastcard;
+       strcpy(pcm->name, "AICA PCM");
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_aicapcm_playback_ops);
+       /* Allocate the DMA buffers */
+       err =
+           snd_pcm_lib_preallocate_pages_for_all(pcm,
+                                                 SNDRV_DMA_TYPE_CONTINUOUS,
+                                                 snd_dma_continuous_data
+                                                 (GFP_KERNEL),
+                                                 AICA_BUFFER_SIZE,
+                                                 AICA_BUFFER_SIZE);
+       return err;
+}
+
+/* Mixer controls */
+static int aica_pcmswitch_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = 1;   /* TO DO: Fix me */
+       return 0;
+}
+
+static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       if (ucontrol->value.integer.value[0] == 1)
+               return 0;       /* TO DO: Fix me */
+       else
+               aica_chn_halt();
+       return 0;
+}
+
+static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 0xFF;
+       return 0;
+}
+
+static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard = kcontrol->private_data;
+       if (unlikely(!dreamcastcard->channel))
+               return -ETXTBSY;        /* we've not yet been set up */
+       ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
+       return 0;
+}
+
+static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard = kcontrol->private_data;
+       if (unlikely(!dreamcastcard->channel))
+               return -ETXTBSY;
+       if (unlikely(dreamcastcard->channel->vol ==
+                    ucontrol->value.integer.value[0]))
+               return 0;
+       dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
+       dreamcastcard->master_volume = ucontrol->value.integer.value[0];
+       spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+                   dreamcastcard->channel, sizeof(struct aica_channel));
+       return 1;
+}
+
+static struct snd_kcontrol_new snd_aica_pcmswitch_control __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "PCM Playback Switch",
+       .index = 0,
+       .info = aica_pcmswitch_info,
+       .get = aica_pcmswitch_get,
+       .put = aica_pcmswitch_put
+};
+
+static struct snd_kcontrol_new snd_aica_pcmvolume_control __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "PCM Playback Volume",
+       .index = 0,
+       .info = aica_pcmvolume_info,
+       .get = aica_pcmvolume_get,
+       .put = aica_pcmvolume_put
+};
+
+static int load_aica_firmware(void)
+{
+       int err;
+       const struct firmware *fw_entry;
+       spu_reset();
+       err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
+       if (unlikely(err))
+               return err;
+       /* write firware into memory */
+       spu_disable();
+       spu_memload(0, fw_entry->data, fw_entry->size);
+       spu_enable();
+       release_firmware(fw_entry);
+       return err;
+}
+
+static int __devinit add_aicamixer_controls(struct snd_card_aica
+                                           *dreamcastcard)
+{
+       int err;
+       err = snd_ctl_add
+           (dreamcastcard->card,
+            snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));
+       if (unlikely(err < 0))
+               return err;
+       err = snd_ctl_add
+           (dreamcastcard->card,
+            snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));
+       if (unlikely(err < 0))
+               return err;
+       return 0;
+}
+
+static int snd_aica_remove(struct platform_device *devptr)
+{
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard = platform_get_drvdata(devptr);
+       if (unlikely(!dreamcastcard))
+               return -ENODEV;
+       snd_card_free(dreamcastcard->card);
+       kfree(dreamcastcard);
+       platform_set_drvdata(devptr, NULL);
+       return 0;
+}
+
+static int __init snd_aica_probe(struct platform_device *devptr)
+{
+       int err;
+       struct snd_card_aica *dreamcastcard;
+       dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
+       if (unlikely(!dreamcastcard))
+               return -ENOMEM;
+       dreamcastcard->card =
+           snd_card_new(index, SND_AICA_DRIVER, THIS_MODULE, 0);
+       if (unlikely(!dreamcastcard->card)) {
+               kfree(dreamcastcard);
+               return -ENODEV;
+       }
+       strcpy(dreamcastcard->card->driver, "snd_aica");
+       strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
+       strcpy(dreamcastcard->card->longname,
+              "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
+       /* Prepare to use the queue */
+       INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
+       /* Load the PCM 'chip' */
+       err = snd_aicapcmchip(dreamcastcard, 0);
+       if (unlikely(err < 0))
+               goto freedreamcast;
+       snd_card_set_dev(dreamcastcard->card, &devptr->dev);
+       dreamcastcard->timer.data = 0;
+       dreamcastcard->channel = NULL;
+       /* Add basic controls */
+       err = add_aicamixer_controls(dreamcastcard);
+       if (unlikely(err < 0))
+               goto freedreamcast;
+       /* Register the card with ALSA subsystem */
+       err = snd_card_register(dreamcastcard->card);
+       if (unlikely(err < 0))
+               goto freedreamcast;
+       platform_set_drvdata(devptr, dreamcastcard);
+       aica_queue = create_workqueue(CARD_NAME);
+       if (unlikely(!aica_queue))
+               goto freedreamcast;
+       snd_printk
+           ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
+       return 0;
+      freedreamcast:
+       snd_card_free(dreamcastcard->card);
+       kfree(dreamcastcard);
+       return err;
+}
+
+static struct platform_driver snd_aica_driver = {
+       .probe = snd_aica_probe,
+       .remove = snd_aica_remove,
+       .driver = {
+                  .name = SND_AICA_DRIVER},
+};
+
+static int __init aica_init(void)
+{
+       int err;
+       err = platform_driver_register(&snd_aica_driver);
+       if (unlikely(err < 0))
+               return err;
+       pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
+                                            aica_memory_space, 2);
+       if (unlikely(IS_ERR(pd))) {
+               platform_driver_unregister(&snd_aica_driver);
+               return PTR_ERR(pd);
+       }
+       /* Load the firmware */
+       return load_aica_firmware();
+}
+
+static void __exit aica_exit(void)
+{
+       /* Destroy the aica kernel thread            *
+        * being extra cautious to check if it exists*/
+       if (likely(aica_queue))
+               destroy_workqueue(aica_queue);
+       platform_device_unregister(pd);
+       platform_driver_unregister(&snd_aica_driver);
+       /* Kill any sound still playing and reset ARM7 to safe state */
+       spu_reset();
+}
+
+module_init(aica_init);
+module_exit(aica_exit);
diff --git a/sound/sh/aica.h b/sound/sh/aica.h
new file mode 100644 (file)
index 0000000..8c11e3d
--- /dev/null
@@ -0,0 +1,81 @@
+/* aica.h
+ * Header file for ALSA driver for
+ * Sega Dreamcast Yamaha AICA sound
+ * Copyright Adrian McMenamin
+ * <adrian@mcmen.demon.co.uk>
+ * 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/* SPU memory and register constants etc */
+#define G2_FIFO 0xa05f688c
+#define SPU_MEMORY_BASE 0xA0800000
+#define ARM_RESET_REGISTER 0xA0702C00
+#define SPU_REGISTER_BASE 0xA0700000
+
+/* AICA channels stuff */
+#define AICA_CONTROL_POINT 0xA0810000
+#define AICA_CONTROL_CHANNEL_SAMPLE_NUMBER 0xA0810008
+#define AICA_CHANNEL0_CONTROL_OFFSET 0x10004
+
+/* Command values */
+#define AICA_CMD_KICK 0x80000000
+#define AICA_CMD_NONE 0
+#define AICA_CMD_START 1
+#define AICA_CMD_STOP 2
+#define AICA_CMD_VOL 3
+
+/* Sound modes */
+#define SM_8BIT                1
+#define SM_16BIT       0
+#define SM_ADPCM       2
+
+/* Buffer and period size */
+#define AICA_BUFFER_SIZE 0x8000
+#define AICA_PERIOD_SIZE 0x800
+#define AICA_PERIOD_NUMBER 16
+
+#define AICA_CHANNEL0_OFFSET 0x11000
+#define AICA_CHANNEL1_OFFSET 0x21000
+#define CHANNEL_OFFSET 0x10000
+
+#define AICA_DMA_CHANNEL 0
+#define AICA_DMA_MODE 5
+
+#define SND_AICA_DRIVER "AICA"
+
+struct aica_channel {
+       uint32_t cmd;           /* Command ID           */
+       uint32_t pos;           /* Sample position      */
+       uint32_t length;        /* Sample length        */
+       uint32_t freq;          /* Frequency            */
+       uint32_t vol;           /* Volume 0-255         */
+       uint32_t pan;           /* Pan 0-255            */
+       uint32_t sfmt;          /* Sound format         */
+       uint32_t flags;         /* Bit flags            */
+};
+
+struct snd_card_aica {
+       struct work_struct spu_dma_work;
+       struct snd_card *card;
+       struct aica_channel *channel;
+       struct snd_pcm_substream *substream;
+       int clicks;
+       int current_period;
+       struct timer_list timer;
+       int master_volume;
+       int dma_check;
+};
index 10cffc0871816597f7ee65f9560bc41fce26208d..97b255233175769191aa6a2348e9fc20a58ef280 100644 (file)
@@ -27,6 +27,7 @@ config SND_SOC
 source "sound/soc/at91/Kconfig"
 source "sound/soc/pxa/Kconfig"
 source "sound/soc/s3c24xx/Kconfig"
+source "sound/soc/sh/Kconfig"
 
 # Supported codecs
 source "sound/soc/codecs/Kconfig"
index 0ae2e49036f9050bffa9701129cb1bd4f69665d6..30414037763213500810946e5e05aa6fc1357cce 100644 (file)
@@ -1,4 +1,4 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o
 
 obj-$(CONFIG_SND_SOC)  += snd-soc-core.o
-obj-$(CONFIG_SND_SOC)  += codecs/ at91/ pxa/ s3c24xx/
+obj-$(CONFIG_SND_SOC)  += codecs/ at91/ pxa/ s3c24xx/ sh/
index 044a3712077a952a68bedde88efa51084c79bd8d..e97c68306a9a59ee13fa9c5e90ab7a643af7657f 100644 (file)
@@ -1,6 +1,7 @@
 config SND_S3C24XX_SOC
        tristate "SoC Audio for the Samsung S3C24XX chips"
        depends on ARCH_S3C2410 && SND_SOC
+       select SND_PCM
        help
          Say Y or M if you want to add support for codecs attached to
          the S3C24XX AC97, I2S or SSP interface. You will also need
@@ -8,3 +9,29 @@ config SND_S3C24XX_SOC
 
 config SND_S3C24XX_SOC_I2S
        tristate
+
+config SND_S3C2443_SOC_AC97
+       tristate
+       select AC97_BUS
+       select SND_AC97_CODEC
+       select SND_SOC_AC97_BUS
+       
+config SND_S3C24XX_SOC_NEO1973_WM8753
+       tristate "SoC I2S Audio support for NEO1973 - WM8753"
+       depends on SND_S3C24XX_SOC && MACH_GTA01
+       select SND_S3C24XX_SOC_I2S
+       select SND_SOC_WM8753
+       help
+         Say Y if you want to add support for SoC audio on smdk2440
+         with the WM8753.
+
+config SND_S3C24XX_SOC_SMDK2443_WM9710
+       tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
+       depends on SND_S3C24XX_SOC && MACH_SMDK2443
+       select SND_S3C2443_SOC_AC97
+       select SND_SOC_AC97_CODEC
+       help
+         Say Y if you want to add support for SoC audio on smdk2443
+         with the WM9710.
+
+
index 6f0fffcb30f54aa6a18de25a487655b705b0eef2..13c92f0fa1e4a1905ea44b7a8019161eb0f78212 100644 (file)
@@ -1,6 +1,15 @@
 # S3c24XX Platform Support
 snd-soc-s3c24xx-objs := s3c24xx-pcm.o
 snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
+snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
+obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
+
+# S3C24XX Machine Support
+snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
+snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
+
+obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
+obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
diff --git a/sound/soc/s3c24xx/lm4857.h b/sound/soc/s3c24xx/lm4857.h
new file mode 100644 (file)
index 0000000..0cf5b70
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * lm4857.h  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    18th Jun 2007   Initial version.
+ */
+
+#ifndef LM4857_H_
+#define LM4857_H_
+
+/* The register offsets in the cache array */
+#define LM4857_MVOL 0
+#define LM4857_LVOL 1
+#define LM4857_RVOL 2
+#define LM4857_CTRL 3
+
+/* the shifts required to set these bits */
+#define LM4857_3D 5
+#define LM4857_WAKEUP 5
+#define LM4857_EPGAIN 4
+
+#endif /*LM4857_H_*/
+
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
new file mode 100644 (file)
index 0000000..d5a8fc2
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * neo1973_wm8753.c  --  SoC audio for Neo1973
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    20th Jan 2007   Initial version.
+ *    05th Feb 2007   Rename all to Neo1973
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/hardware.h>
+#include <asm/arch/audio.h>
+#include <asm/io.h>
+#include <asm/arch/spi-gpio.h>
+#include "../codecs/wm8753.h"
+#include "lm4857.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-i2s.h"
+
+/* define the scenarios */
+#define NEO_AUDIO_OFF                  0
+#define NEO_GSM_CALL_AUDIO_HANDSET     1
+#define NEO_GSM_CALL_AUDIO_HEADSET     2
+#define NEO_GSM_CALL_AUDIO_BLUETOOTH   3
+#define NEO_STEREO_TO_SPEAKERS         4
+#define NEO_STEREO_TO_HEADPHONES       5
+#define NEO_CAPTURE_HANDSET            6
+#define NEO_CAPTURE_HEADSET            7
+#define NEO_CAPTURE_BLUETOOTH          8
+
+static struct snd_soc_machine neo1973;
+static struct i2c_client *i2c;
+
+static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+       unsigned int pll_out = 0, bclk = 0;
+       int ret = 0;
+       unsigned long iis_clkrate;
+
+       iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+       switch (params_rate(params)) {
+       case 8000:
+       case 16000:
+               pll_out = 12288000;
+               break;
+       case 48000:
+               bclk = WM8753_BCLK_DIV_4;
+               pll_out = 12288000;
+               break;
+       case 96000:
+               bclk = WM8753_BCLK_DIV_2;
+               pll_out = 12288000;
+               break;
+       case 11025:
+               bclk = WM8753_BCLK_DIV_16;
+               pll_out = 11289600;
+               break;
+       case 22050:
+               bclk = WM8753_BCLK_DIV_8;
+               pll_out = 11289600;
+               break;
+       case 44100:
+               bclk = WM8753_BCLK_DIV_4;
+               pll_out = 11289600;
+               break;
+       case 88200:
+               bclk = WM8753_BCLK_DIV_2;
+               pll_out = 11289600;
+               break;
+       }
+
+       /* set codec DAI configuration */
+       ret = codec_dai->dai_ops.set_fmt(codec_dai,
+               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+               SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set cpu DAI configuration */
+       ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
+               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+               SND_SOC_DAIFMT_CBM_CFM);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+               SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set MCLK division for sample rate */
+       ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+               S3C2410_IISMOD_32FS );
+       if (ret < 0)
+               return ret;
+
+       /* set codec BCLK division for sample rate */
+       ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
+       if (ret < 0)
+               return ret;
+
+       /* set prescaler division for sample rate */
+       ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+               S3C24XX_PRESCALE(4,4));
+       if (ret < 0)
+               return ret;
+
+       /* codec PLL input is PCLK/4 */
+       ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1,
+               iis_clkrate / 4, pll_out);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+
+       /* disable the PLL */
+       return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);
+}
+
+/*
+ * Neo1973 WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops neo1973_hifi_ops = {
+       .hw_params = neo1973_hifi_hw_params,
+       .hw_free = neo1973_hifi_hw_free,
+};
+
+static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+       unsigned int pcmdiv = 0;
+       int ret = 0;
+       unsigned long iis_clkrate;
+
+       iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+       if (params_rate(params) != 8000)
+               return -EINVAL;
+       if (params_channels(params) != 1)
+               return -EINVAL;
+
+       pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+
+       /* todo: gg check mode (DSP_B) against CSR datasheet */
+       /* set codec DAI configuration */
+       ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
+               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+       if (ret < 0)
+               return ret;
+
+       /* set the codec system clock for DAC and ADC */
+       ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
+               SND_SOC_CLOCK_IN);
+       if (ret < 0)
+               return ret;
+
+       /* set codec PCM division for sample rate */
+       ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
+       if (ret < 0)
+               return ret;
+
+       /* configue and enable PLL for 12.288MHz output */
+       ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2,
+               iis_clkrate / 4, 12288000);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+
+       /* disable the PLL */
+       return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);
+}
+
+static struct snd_soc_ops neo1973_voice_ops = {
+       .hw_params = neo1973_voice_hw_params,
+       .hw_free = neo1973_voice_hw_free,
+};
+
+static int neo1973_scenario = 0;
+
+static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = neo1973_scenario;
+       return 0;
+}
+
+static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
+{
+       switch(neo1973_scenario) {
+       case NEO_AUDIO_OFF:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               break;
+       case NEO_GSM_CALL_AUDIO_HANDSET:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  1);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     1);
+               break;
+       case NEO_GSM_CALL_AUDIO_HEADSET:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  1);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  1);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               break;
+       case NEO_GSM_CALL_AUDIO_BLUETOOTH:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  1);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               break;
+       case NEO_STEREO_TO_SPEAKERS:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               break;
+       case NEO_STEREO_TO_HEADPHONES:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    1);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               break;
+       case NEO_CAPTURE_HANDSET:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     1);
+               break;
+       case NEO_CAPTURE_HEADSET:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  1);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               break;
+       case NEO_CAPTURE_BLUETOOTH:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+               break;
+       default:
+               snd_soc_dapm_set_endpoint(codec, "Audio Out",    0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+               snd_soc_dapm_set_endpoint(codec, "GSM Line In",  0);
+               snd_soc_dapm_set_endpoint(codec, "Headset Mic",  0);
+               snd_soc_dapm_set_endpoint(codec, "Call Mic",     0);
+       }
+
+       snd_soc_dapm_sync_endpoints(codec);
+
+       return 0;
+}
+
+static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       if (neo1973_scenario == ucontrol->value.integer.value[0])
+               return 0;
+
+       neo1973_scenario = ucontrol->value.integer.value[0];
+       set_scenario_endpoints(codec, neo1973_scenario);
+       return 1;
+}
+
+static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
+
+static void lm4857_write_regs(void)
+{
+       if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
+               printk(KERN_ERR "lm4857: i2c write failed\n");
+}
+
+static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       int reg=kcontrol->private_value & 0xFF;
+       int shift = (kcontrol->private_value >> 8) & 0x0F;
+       int mask = (kcontrol->private_value >> 16) & 0xFF;
+
+       ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
+       return 0;
+}
+
+static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       int reg = kcontrol->private_value & 0xFF;
+       int shift = (kcontrol->private_value >> 8) & 0x0F;
+       int mask = (kcontrol->private_value >> 16) & 0xFF;
+
+       if (((lm4857_regs[reg] >> shift ) & mask) ==
+               ucontrol->value.integer.value[0])
+               return 0;
+
+       lm4857_regs[reg] &= ~ (mask << shift);
+       lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
+       lm4857_write_regs();
+       return 1;
+}
+
+static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
+
+       if (value)
+               value -= 5;
+
+       ucontrol->value.integer.value[0] = value;
+       return 0;
+}
+
+static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       u8 value = ucontrol->value.integer.value[0];
+
+       if (value)
+               value += 5;
+
+       if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
+               return 0;
+
+       lm4857_regs[LM4857_CTRL] &= 0xF0;
+       lm4857_regs[LM4857_CTRL] |= value;
+       lm4857_write_regs();
+       return 1;
+}
+
+static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
+       SND_SOC_DAPM_LINE("Audio Out", NULL),
+       SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+       SND_SOC_DAPM_LINE("GSM Line In", NULL),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Call Mic", NULL),
+};
+
+
+/* example machine audio_mapnections */
+static const char* audio_map[][3] = {
+
+       /* Connections to the lm4857 amp */
+       {"Audio Out", NULL, "LOUT1"},
+       {"Audio Out", NULL, "ROUT1"},
+
+       /* Connections to the GSM Module */
+       {"GSM Line Out", NULL, "MONO1"},
+       {"GSM Line Out", NULL, "MONO2"},
+       {"RXP", NULL, "GSM Line In"},
+       {"RXN", NULL, "GSM Line In"},
+
+       /* Connections to Headset */
+       {"MIC1", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Headset Mic"},
+
+       /* Call Mic */
+       {"MIC2", NULL, "Mic Bias"},
+       {"MIC2N", NULL, "Mic Bias"},
+       {"Mic Bias", NULL, "Call Mic"},
+
+       /* Connect the ALC pins */
+       {"ACIN", NULL, "ACOP"},
+
+       {NULL, NULL, NULL},
+};
+
+static const char *lm4857_mode[] = {
+       "Off",
+       "Call Speaker",
+       "Stereo Speakers",
+       "Stereo Speakers + Headphones",
+       "Headphones"
+};
+
+static const struct soc_enum lm4857_mode_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
+};
+
+static const char *neo_scenarios[] = {
+       "Off",
+       "GSM Handset",
+       "GSM Headset",
+       "GSM Bluetooth",
+       "Speakers",
+       "Headphones",
+       "Capture Handset",
+       "Capture Headset",
+       "Capture Bluetooth"
+};
+
+static const struct soc_enum neo_scenario_enum[] = {
+       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios),neo_scenarios),
+};
+
+static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
+       SOC_SINGLE_EXT("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
+               lm4857_get_mode, lm4857_set_mode),
+       SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
+               neo1973_get_scenario, neo1973_set_scenario),
+       SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+       SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
+               lm4857_get_reg, lm4857_set_reg),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * neo1973 II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int neo1973_wm8753_init(struct snd_soc_codec *codec)
+{
+       int i, err;
+
+       /* set up NC codec pins */
+       snd_soc_dapm_set_endpoint(codec, "LOUT2", 0);
+       snd_soc_dapm_set_endpoint(codec, "ROUT2", 0);
+       snd_soc_dapm_set_endpoint(codec, "OUT3",  0);
+       snd_soc_dapm_set_endpoint(codec, "OUT4",  0);
+       snd_soc_dapm_set_endpoint(codec, "LINE1", 0);
+       snd_soc_dapm_set_endpoint(codec, "LINE2", 0);
+
+
+       /* set endpoints to default mode */
+       set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
+       /* Add neo1973 specific widgets */
+       for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++)
+               snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]);
+
+       /* add neo1973 specific controls */
+       for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
+               err = snd_ctl_add(codec->card,
+                               snd_soc_cnew(&wm8753_neo1973_controls[i],
+                               codec, NULL));
+               if (err < 0)
+                       return err;
+       }
+
+       /* set up neo1973 specific audio path audio_mapnects */
+       for (i = 0; audio_map[i][0] != NULL; i++) {
+               snd_soc_dapm_connect_input(codec, audio_map[i][0],
+                       audio_map[i][1], audio_map[i][2]);
+       }
+
+       snd_soc_dapm_sync_endpoints(codec);
+       return 0;
+}
+
+/*
+ * BT Codec DAI
+ */
+static struct snd_soc_cpu_dai bt_dai =
+{      .name = "Bluetooth",
+       .id = 0,
+       .type = SND_SOC_DAI_PCM,
+       .playback = {
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = SNDRV_PCM_RATE_8000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_dai_link neo1973_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+       .name = "WM8753",
+       .stream_name = "WM8753 HiFi",
+       .cpu_dai = &s3c24xx_i2s_dai,
+       .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+       .init = neo1973_wm8753_init,
+       .ops = &neo1973_hifi_ops,
+},
+{ /* Voice via BT */
+       .name = "Bluetooth",
+       .stream_name = "Voice",
+       .cpu_dai = &bt_dai,
+       .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+       .ops = &neo1973_voice_ops,
+},
+};
+
+static struct snd_soc_machine neo1973 = {
+       .name = "neo1973",
+       .dai_link = neo1973_dai,
+       .num_links = ARRAY_SIZE(neo1973_dai),
+};
+
+static struct wm8753_setup_data neo1973_wm8753_setup = {
+       .i2c_address = 0x1a,
+};
+
+static struct snd_soc_device neo1973_snd_devdata = {
+       .machine = &neo1973,
+       .platform = &s3c24xx_soc_platform,
+       .codec_dev = &soc_codec_dev_wm8753,
+       .codec_data = &neo1973_wm8753_setup,
+};
+
+static struct i2c_client client_template;
+
+static unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+       int ret;
+
+       client_template.adapter = adap;
+       client_template.addr = addr;
+
+       i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+       if (i2c == NULL)
+               return -ENOMEM;
+
+       ret = i2c_attach_client(i2c);
+       if (ret < 0) {
+               printk(KERN_ERR "LM4857 failed to attach at addr %x\n", addr);
+               goto exit_err;
+       }
+
+       lm4857_write_regs();
+       return ret;
+
+exit_err:
+       kfree(i2c);
+       return ret;
+}
+
+static int lm4857_i2c_detach(struct i2c_client *client)
+{
+       i2c_detach_client(client);
+       kfree(client);
+       return 0;
+}
+
+static int lm4857_i2c_attach(struct i2c_adapter *adap)
+{
+       return i2c_probe(adap, &addr_data, lm4857_amp_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver lm4857_i2c_driver = {
+       .driver = {
+               .name = "LM4857 I2C Amp",
+               .owner = THIS_MODULE,
+       },
+       .id =             I2C_DRIVERID_LM4857,
+       .attach_adapter = lm4857_i2c_attach,
+       .detach_client =  lm4857_i2c_detach,
+       .command =        NULL,
+};
+
+static struct i2c_client client_template = {
+       .name =   "LM4857",
+       .driver = &lm4857_i2c_driver,
+};
+
+static struct platform_device *neo1973_snd_device;
+
+static int __init neo1973_init(void)
+{
+       int ret;
+
+       neo1973_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!neo1973_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
+       neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
+       ret = platform_device_add(neo1973_snd_device);
+
+       if (ret)
+               platform_device_put(neo1973_snd_device);
+
+       ret = i2c_add_driver(&lm4857_i2c_driver);
+       if (ret != 0)
+               printk(KERN_ERR "can't add i2c driver");
+
+       return ret;
+}
+
+static void __exit neo1973_exit(void)
+{
+       platform_device_unregister(neo1973_snd_device);
+}
+
+module_init(neo1973_init);
+module_exit(neo1973_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
new file mode 100644 (file)
index 0000000..75acf7e
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * s3c2443-ac97.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 2007 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  Copyright (C) 2005, Sean Choi <sh428.choi@samsung.com>
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  Revision history
+ *     21st Mar 2007   Initial Version
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/audio.h>
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-ac97.h"
+
+struct s3c24xx_ac97_info {
+       void __iomem    *regs;
+       struct clk      *ac97_clk;
+};
+static struct s3c24xx_ac97_info s3c24xx_ac97;
+
+DECLARE_COMPLETION(ac97_completion);
+static u32 codec_ready;
+static DECLARE_MUTEX(ac97_mutex);
+
+static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97,
+       unsigned short reg)
+{
+       u32 ac_glbctrl;
+       u32 ac_codec_cmd;
+       u32 stat, addr, data;
+
+       down(&ac97_mutex);
+
+       codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
+       ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
+       writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       udelay(50);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       wait_for_completion(&ac97_completion);
+
+       stat = readl(s3c24xx_ac97.regs + S3C_AC97_STAT);
+       addr = (stat >> 16) & 0x7f;
+       data = (stat & 0xffff);
+
+       if (addr != reg)
+               printk(KERN_ERR "s3c24xx-ac97: req addr = %02x,"
+                               " rep addr = %02x\n", reg, addr);
+
+       up(&ac97_mutex);
+
+       return (unsigned short)data;
+}
+
+static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+       unsigned short val)
+{
+       u32 ac_glbctrl;
+       u32 ac_codec_cmd;
+
+       down(&ac97_mutex);
+
+       codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
+       ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
+       writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       udelay(50);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       wait_for_completion(&ac97_completion);
+
+       ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+       ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
+       writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+       up(&ac97_mutex);
+
+}
+
+static void s3c2443_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       u32 ac_glbctrl;
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_WARMRESET;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = 0;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+}
+
+static void s3c2443_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+       u32 ac_glbctrl;
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = 0;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA |
+               S3C_AC97_GLBCTRL_PCMINTM_DMA | S3C_AC97_GLBCTRL_MICINTM_DMA;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+}
+
+static irqreturn_t s3c2443_ac97_irq(int irq, void *dev_id)
+{
+       int status;
+       u32 ac_glbctrl;
+
+       status = readl(s3c24xx_ac97.regs + S3C_AC97_GLBSTAT) & codec_ready;
+
+       if (status) {
+               ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
+               writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+               complete(&ac97_completion);
+       }
+       return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read   = s3c2443_ac97_read,
+       .write  = s3c2443_ac97_write,
+       .warm_reset     = s3c2443_ac97_warm_reset,
+       .reset  = s3c2443_ac97_cold_reset,
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_out = {
+       .name = "AC97 PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_in = {
+       .name = "AC97 PCM Stereo in"
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_micin = {
+       .name = "AC97 Mic Mono in"
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_out = {
+       .client         = &s3c2443_dma_client_out,
+       .channel        = DMACH_PCM_OUT,
+       .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+       .dma_size       = 4,
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_in = {
+       .client         = &s3c2443_dma_client_in,
+       .channel        = DMACH_PCM_IN,
+       .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+       .dma_size       = 4,
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = {
+       .client         = &s3c2443_dma_client_micin,
+       .channel        = DMACH_MIC_IN,
+       .dma_addr       = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
+       .dma_size       = 4,
+};
+
+static int s3c2443_ac97_probe(struct platform_device *pdev)
+{
+       int ret;
+       u32 ac_glbctrl;
+
+       s3c24xx_ac97.regs = ioremap(S3C2440_PA_AC97, 0x100);
+       if (s3c24xx_ac97.regs == NULL)
+               return -ENXIO;
+
+       s3c24xx_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+       if (s3c24xx_ac97.ac97_clk == NULL) {
+               printk(KERN_ERR "s3c2443-ac97 failed to get ac97_clock\n");
+               iounmap(s3c24xx_ac97.regs);
+               return -ENODEV;
+       }
+       clk_enable(s3c24xx_ac97.ac97_clk);
+
+       s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2443_GPE0_AC_nRESET);
+       s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2443_GPE1_AC_SYNC);
+       s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2443_GPE2_AC_BITCLK);
+       s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2443_GPE3_AC_SDI);
+       s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2443_GPE4_AC_SDO);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = 0;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       msleep(1);
+
+       ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       ret = request_irq(IRQ_S3C2443_AC97, s3c2443_ac97_irq,
+               IRQF_DISABLED, "AC97", NULL);
+       if (ret < 0) {
+               printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n");
+               clk_disable(s3c24xx_ac97.ac97_clk);
+               clk_put(s3c24xx_ac97.ac97_clk);
+               iounmap(s3c24xx_ac97.regs);
+       }
+       return ret;
+}
+
+static void s3c2443_ac97_remove(struct platform_device *pdev)
+{
+       free_irq(IRQ_S3C2443_AC97, NULL);
+       clk_disable(s3c24xx_ac97.ac97_clk);
+       clk_put(s3c24xx_ac97.ac97_clk);
+       iounmap(s3c24xx_ac97.regs);
+}
+
+static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out;
+       else
+               cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_in;
+
+       return 0;
+}
+
+static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       u32 ac_glbctrl;
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       switch(cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+               else
+                       ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+                       ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+               else
+                       ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
+               break;
+       }
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       return 0;
+}
+
+static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return -ENODEV;
+       else
+               cpu_dai->dma_data = &s3c2443_ac97_mic_mono_in;
+
+       return 0;
+}
+
+static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
+       int cmd)
+{
+       u32 ac_glbctrl;
+
+       ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+       switch(cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+       }
+       writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+       return 0;
+}
+
+#define s3c2443_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+               SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+               SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+struct snd_soc_cpu_dai s3c2443_ac97_dai[] = {
+{
+       .name = "s3c2443-ac97",
+       .id = 0,
+       .type = SND_SOC_DAI_AC97,
+       .probe = s3c2443_ac97_probe,
+       .remove = s3c2443_ac97_remove,
+       .playback = {
+               .stream_name = "AC97 Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = s3c2443_AC97_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .capture = {
+               .stream_name = "AC97 Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = s3c2443_AC97_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = {
+               .hw_params = s3c2443_ac97_hw_params,
+               .trigger = s3c2443_ac97_trigger},
+},
+{
+       .name = "pxa2xx-ac97-mic",
+       .id = 1,
+       .type = SND_SOC_DAI_AC97,
+       .capture = {
+               .stream_name = "AC97 Mic Capture",
+               .channels_min = 1,
+               .channels_max = 1,
+               .rates = s3c2443_AC97_RATES,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+       .ops = {
+               .hw_params = s3c2443_ac97_hw_mic_params,
+               .trigger = s3c2443_ac97_mic_trigger,},
+},
+};
+
+EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h
new file mode 100644 (file)
index 0000000..2b835e8
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * s3c24xx-ac97.c  --  ALSA Soc Audio Layer
+ *
+ * (c) 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    10th Nov 2006   Initial version.
+ */
+
+#ifndef S3C24XXAC97_H_
+#define S3C24XXAC97_H_
+
+#define AC_CMD_ADDR(x) (x << 16)
+#define AC_CMD_DATA(x) (x & 0xffff)
+
+extern struct snd_soc_cpu_dai s3c2443_ac97_dai[];
+
+#endif /*S3C24XXAC97_H_*/
index 8ca314dc8891c04ebca6323dafb4709d4b7c8203..39f02462e07d8797671869b482a7ad654e9c40f8 100644 (file)
@@ -344,11 +344,11 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
        DBG("Entered %s\n", __FUNCTION__);
 
        switch (div_id) {
-       case S3C24XX_DIV_MCLK:
+       case S3C24XX_DIV_BCLK:
                reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
                writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
                break;
-       case S3C24XX_DIV_BCLK:
+       case S3C24XX_DIV_MCLK:
                reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
                writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
                break;
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
new file mode 100644 (file)
index 0000000..d46cd81
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * smdk2443_wm9710.c  --  SoC audio for smdk2443
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ *         graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  Revision history
+ *    8th Mar 2007   Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/ac97.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-ac97.h"
+
+static struct snd_soc_machine smdk2443;
+
+static struct snd_soc_dai_link smdk2443_dai[] = {
+{
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       .cpu_dai = &s3c2443_ac97_dai[0],
+       .codec_dai = &ac97_dai,
+},
+};
+
+static struct snd_soc_machine smdk2443 = {
+       .name = "SMDK2443",
+       .dai_link = smdk2443_dai,
+       .num_links = ARRAY_SIZE(smdk2443_dai),
+};
+
+static struct snd_soc_device smdk2443_snd_ac97_devdata = {
+       .machine = &smdk2443,
+       .platform = &s3c24xx_soc_platform,
+       .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *smdk2443_snd_ac97_device;
+
+static int __init smdk2443_init(void)
+{
+       int ret;
+
+       smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+       if (!smdk2443_snd_ac97_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(smdk2443_snd_ac97_device,
+                               &smdk2443_snd_ac97_devdata);
+       smdk2443_snd_ac97_devdata.dev = &smdk2443_snd_ac97_device->dev;
+       ret = platform_device_add(smdk2443_snd_ac97_device);
+
+       if (ret)
+               platform_device_put(smdk2443_snd_ac97_device);
+
+       return ret;
+}
+
+static void __exit smdk2443_exit(void)
+{
+       platform_device_unregister(smdk2443_snd_ac97_device);
+}
+
+module_init(smdk2443_init);
+module_exit(smdk2443_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
new file mode 100644 (file)
index 0000000..f03220d
--- /dev/null
@@ -0,0 +1,38 @@
+menu "SoC Audio support for SuperH"
+
+config SND_SOC_PCM_SH7760
+       tristate "SoC Audio support for Renesas SH7760"
+       depends on CPU_SUBTYPE_SH7760 && SND_SOC && SH_DMABRG
+       help
+         Enable this option for SH7760 AC97/I2S audio support.
+
+
+##
+## Audio unit modules
+##
+
+config SND_SOC_SH4_HAC
+       select AC97_BUS
+       select SND_SOC_AC97_BUS
+       select SND_AC97_CODEC
+       tristate
+
+config SND_SOC_SH4_SSI
+       tristate
+
+
+
+##
+## Boards
+##
+
+config SND_SH7760_AC97
+       tristate "SH7760 AC97 sound support"
+       depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760
+       select SND_SOC_SH4_HAC
+       select SND_SOC_AC97_CODEC
+       help
+         This option enables generic sound support for the first
+         AC97 unit of the SH7760.
+
+endmenu
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
new file mode 100644 (file)
index 0000000..a8e8ab8
--- /dev/null
@@ -0,0 +1,14 @@
+## DMA engines
+snd-soc-dma-sh7760-objs        := dma-sh7760.o
+obj-$(CONFIG_SND_SOC_PCM_SH7760)       += snd-soc-dma-sh7760.o
+
+## audio units found on some SH-4
+snd-soc-hac-objs       := hac.o
+snd-soc-ssi-objs       := ssi.o
+obj-$(CONFIG_SND_SOC_SH4_HAC)  += snd-soc-hac.o
+obj-$(CONFIG_SND_SOC_SH4_SSI)  += snd-soc-ssi.o
+
+## boards
+snd-soc-sh7760-ac97-objs       := sh7760-ac97.o
+
+obj-$(CONFIG_SND_SH7760_AC97)  += snd-soc-sh7760-ac97.o
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
new file mode 100644 (file)
index 0000000..cdee374
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * SH7760 ("camelot") DMABRG audio DMA unit support
+ *
+ * Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *  licensed under the terms outlined in the file COPYING at the root
+ *  of the linux kernel sources.
+ *
+ * The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
+ * trigger an interrupt when one half of the programmed transfer size
+ * has been xmitted.
+ *
+ * FIXME: little-endian only for now
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/dmabrg.h>
+
+
+/* registers and bits */
+#define BRGATXSAR      0x00
+#define BRGARXDAR      0x04
+#define BRGATXTCR      0x08
+#define BRGARXTCR      0x0C
+#define BRGACR         0x10
+#define BRGATXTCNT     0x14
+#define BRGARXTCNT     0x18
+
+#define ACR_RAR                (1 << 18)
+#define ACR_RDS                (1 << 17)
+#define ACR_RDE                (1 << 16)
+#define ACR_TAR                (1 << 2)
+#define ACR_TDS                (1 << 1)
+#define ACR_TDE                (1 << 0)
+
+/* receiver/transmitter data alignment */
+#define ACR_RAM_NONE   (0 << 24)
+#define ACR_RAM_4BYTE  (1 << 24)
+#define ACR_RAM_2WORD  (2 << 24)
+#define ACR_TAM_NONE   (0 << 8)
+#define ACR_TAM_4BYTE  (1 << 8)
+#define ACR_TAM_2WORD  (2 << 8)
+
+
+struct camelot_pcm {
+       unsigned long mmio;  /* DMABRG audio channel control reg MMIO */
+       unsigned int txid;    /* ID of first DMABRG IRQ for this unit */
+
+       struct snd_pcm_substream *tx_ss;
+       unsigned long tx_period_size;
+       unsigned int  tx_period;
+
+       struct snd_pcm_substream *rx_ss;
+       unsigned long rx_period_size;
+       unsigned int  rx_period;
+
+} cam_pcm_data[2] = {
+       {
+               .mmio   =       0xFE3C0040,
+               .txid   =       DMABRGIRQ_A0TXF,
+       },
+       {
+               .mmio   =       0xFE3C0060,
+               .txid   =       DMABRGIRQ_A1TXF,
+       },
+};
+
+#define BRGREG(x)      (*(unsigned long *)(cam->mmio + (x)))
+
+/*
+ * set a minimum of 16kb per period, to avoid interrupt-"storm" and
+ * resulting skipping. In general, the bigger the minimum size, the
+ * better for overall system performance. (The SH7760 is a puny CPU
+ * with a slow SDRAM interface and poor internal bus bandwidth,
+ * *especially* when the LCDC is active).  The minimum for the DMAC
+ * is 8 bytes; 16kbytes are enough to get skip-free playback of a
+ * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain
+ * reasonable responsiveness in MPlayer.
+ */
+#define DMABRG_PERIOD_MIN              16 * 1024
+#define DMABRG_PERIOD_MAX              0x03fffffc
+#define DMABRG_PREALLOC_BUFFER         32 * 1024
+#define DMABRG_PREALLOC_BUFFER_MAX     32 * 1024
+
+/* support everything the SSI supports */
+#define DMABRG_RATES   \
+       SNDRV_PCM_RATE_8000_192000
+
+#define DMABRG_FMTS    \
+       (SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |  \
+        SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |  \
+        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |  \
+        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |  \
+        SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
+
+static struct snd_pcm_hardware camelot_pcm_hardware = {
+       .info = (SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+               SNDRV_PCM_INFO_MMAP_VALID),
+       .formats =      DMABRG_FMTS,
+       .rates =        DMABRG_RATES,
+       .rate_min =             8000,
+       .rate_max =             192000,
+       .channels_min =         2,
+       .channels_max =         8,              /* max of the SSI */
+       .buffer_bytes_max =     DMABRG_PERIOD_MAX,
+       .period_bytes_min =     DMABRG_PERIOD_MIN,
+       .period_bytes_max =     DMABRG_PERIOD_MAX / 2,
+       .periods_min =          2,
+       .periods_max =          2,
+       .fifo_size =            128,
+};
+
+static void camelot_txdma(void *data)
+{
+       struct camelot_pcm *cam = data;
+       cam->tx_period ^= 1;
+       snd_pcm_period_elapsed(cam->tx_ss);
+}
+
+static void camelot_rxdma(void *data)
+{
+       struct camelot_pcm *cam = data;
+       cam->rx_period ^= 1;
+       snd_pcm_period_elapsed(cam->rx_ss);
+}
+
+static int camelot_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       int ret, dmairq;
+
+       snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware);
+
+       /* DMABRG buffer half/full events */
+       dmairq = (recv) ? cam->txid + 2 : cam->txid;
+       if (recv) {
+               cam->rx_ss = substream;
+               ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
+               if (unlikely(ret)) {
+                       pr_debug("audio unit %d irqs already taken!\n",
+                            rtd->dai->cpu_dai->id);
+                       return -EBUSY;
+               }
+               (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
+       } else {
+               cam->tx_ss = substream;
+               ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
+               if (unlikely(ret)) {
+                       pr_debug("audio unit %d irqs already taken!\n",
+                            rtd->dai->cpu_dai->id);
+                       return -EBUSY;
+               }
+               (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
+       }
+       return 0;
+}
+
+static int camelot_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       int dmairq;
+
+       dmairq = (recv) ? cam->txid + 2 : cam->txid;
+
+       if (recv)
+               cam->rx_ss = NULL;
+       else
+               cam->tx_ss = NULL;
+
+       dmabrg_free_irq(dmairq + 1);
+       dmabrg_free_irq(dmairq);
+
+       return 0;
+}
+
+static int camelot_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       int ret;
+
+       ret = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       if (ret < 0)
+               return ret;
+
+       if (recv) {
+               cam->rx_period_size = params_period_bytes(hw_params);
+               cam->rx_period = 0;
+       } else {
+               cam->tx_period_size = params_period_bytes(hw_params);
+               cam->tx_period = 0;
+       }
+       return 0;
+}
+
+static int camelot_hw_free(struct snd_pcm_substream *substream)
+{
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int camelot_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+
+       pr_debug("PCM data: addr 0x%08ulx len %d\n",
+                (u32)runtime->dma_addr, runtime->dma_bytes);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
+               BRGREG(BRGATXTCR) = runtime->dma_bytes;
+       } else {
+               BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area;
+               BRGREG(BRGARXTCR) = runtime->dma_bytes;
+       }
+
+       return 0;
+}
+
+static inline void dmabrg_play_dma_start(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* start DMABRG engine: XFER start, auto-addr-reload */
+       BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD;
+}
+
+static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* forcibly terminate data transmission */
+       BRGREG(BRGACR) = acr | ACR_TDS;
+}
+
+static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* start DMABRG engine: recv start, auto-reload */
+       BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD;
+}
+
+static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
+{
+       unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+       /* forcibly terminate data receiver */
+       BRGREG(BRGACR) = acr | ACR_RDS;
+}
+
+static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               if (recv)
+                       dmabrg_rec_dma_start(cam);
+               else
+                       dmabrg_play_dma_start(cam);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               if (recv)
+                       dmabrg_rec_dma_stop(cam);
+               else
+                       dmabrg_play_dma_stop(cam);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+       int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+       unsigned long pos;
+
+       /* cannot use the DMABRG pointer register: under load, by the
+        * time ALSA comes around to read the register, it is already
+        * far ahead (or worse, already done with the fragment) of the
+        * position at the time the IRQ was triggered, which results in
+        * fast-playback sound in my test application (ScummVM)
+        */
+       if (recv)
+               pos = cam->rx_period ? cam->rx_period_size : 0;
+       else
+               pos = cam->tx_period ? cam->tx_period_size : 0;
+
+       return bytes_to_frames(runtime, pos);
+}
+
+static struct snd_pcm_ops camelot_pcm_ops = {
+       .open           = camelot_pcm_open,
+       .close          = camelot_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = camelot_hw_params,
+       .hw_free        = camelot_hw_free,
+       .prepare        = camelot_prepare,
+       .trigger        = camelot_trigger,
+       .pointer        = camelot_pos,
+};
+
+static void camelot_pcm_free(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int camelot_pcm_new(struct snd_card *card,
+                          struct snd_soc_codec_dai *dai,
+                          struct snd_pcm *pcm)
+{
+       /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
+        * in MMAP mode (i.e. aplay -M)
+        */
+       snd_pcm_lib_preallocate_pages_for_all(pcm,
+               SNDRV_DMA_TYPE_CONTINUOUS,
+               snd_dma_continuous_data(GFP_KERNEL),
+               DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX);
+
+       return 0;
+}
+
+struct snd_soc_platform sh7760_soc_platform = {
+       .name           = "sh7760-pcm",
+       .pcm_ops        = &camelot_pcm_ops,
+       .pcm_new        = camelot_pcm_new,
+       .pcm_free       = camelot_pcm_free,
+};
+EXPORT_SYMBOL_GPL(sh7760_soc_platform);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
new file mode 100644 (file)
index 0000000..8e3f039
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Hitachi Audio Controller (AC97) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *  licensed under the terms outlined in the file COPYING at the root
+ *  of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable HAC output pins!
+ */
+
+/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
+ * the FIRST can be used since ASoC does not pass any information to the
+ * ac97_read/write() functions regarding WHICH unit to use.  You'll have
+ * to edit the code a bit to use the other AC97 unit.          --mlau
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+/* regs and bits */
+#define HACCR          0x08
+#define HACCSAR                0x20
+#define HACCSDR                0x24
+#define HACPCML                0x28
+#define HACPCMR                0x2C
+#define HACTIER                0x50
+#define        HACTSR          0x54
+#define HACRIER                0x58
+#define HACRSR         0x5C
+#define HACACR         0x60
+
+#define CR_CR          (1 << 15)       /* "codec-ready" indicator */
+#define CR_CDRT                (1 << 11)       /* cold reset */
+#define CR_WMRT                (1 << 10)       /* warm reset */
+#define CR_B9          (1 << 9)        /* the mysterious "bit 9" */
+#define CR_ST          (1 << 5)        /* AC97 link start bit */
+
+#define CSAR_RD                (1 << 19)       /* AC97 data read bit */
+#define CSAR_WR                (0)
+
+#define TSR_CMDAMT     (1 << 31)
+#define TSR_CMDDMT     (1 << 30)
+
+#define RSR_STARY      (1 << 22)
+#define RSR_STDRY      (1 << 21)
+
+#define ACR_DMARX16    (1 << 30)
+#define ACR_DMATX16    (1 << 29)
+#define ACR_TX12ATOM   (1 << 26)
+#define ACR_DMARX20    ((1 << 24) | (1 << 22))
+#define ACR_DMATX20    ((1 << 23) | (1 << 21))
+
+#define CSDR_SHIFT     4
+#define CSDR_MASK      (0xffff << CSDR_SHIFT)
+#define CSAR_SHIFT     12
+#define CSAR_MASK      (0x7f << CSAR_SHIFT)
+
+#define AC97_WRITE_RETRY       1
+#define AC97_READ_RETRY                5
+
+/* manual-suggested AC97 codec access timeouts (us) */
+#define TMO_E1 500     /* 21 < E1 < 1000 */
+#define TMO_E2 13      /* 13 < E2 */
+#define TMO_E3 21      /* 21 < E3 */
+#define TMO_E4 500     /* 21 < E4 < 1000 */
+
+struct hac_priv {
+       unsigned long mmio;     /* HAC base address */
+} hac_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+       {
+               .mmio   = 0xFE240000,
+       },
+       {
+               .mmio   = 0xFE250000,
+       },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+       {
+               .mmio   = 0xFFE40000,
+       },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+#define HACREG(reg)    (*(unsigned long *)(hac->mmio + (reg)))
+
+/*
+ * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906)
+ */
+static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
+                             unsigned short *v)
+{
+       unsigned int to1, to2, i;
+       unsigned short adr;
+
+       for (i = 0; i < AC97_READ_RETRY; ++i) {
+               *v = 0;
+               /* wait for HAC to receive something from the codec */
+               for (to1 = TMO_E4;
+                    to1 && !(HACREG(HACRSR) & RSR_STARY);
+                    --to1)
+                       udelay(1);
+               for (to2 = TMO_E4; 
+                    to2 && !(HACREG(HACRSR) & RSR_STDRY);
+                    --to2)
+                       udelay(1);
+
+               if (!to1 && !to2)
+                       return 0;       /* codec comm is down */
+
+               adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT);
+               *v  = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT);
+
+               HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+
+               if (r == adr)
+                       break;
+
+               /* manual says: wait at least 21 usec before retrying */
+               udelay(21);
+       }
+       HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+       return (i < AC97_READ_RETRY);
+}
+
+static unsigned short hac_read_codec_aux(struct hac_priv *hac,
+                                        unsigned short reg)
+{
+       unsigned short val;
+       unsigned int i, to;
+
+       for (i = 0; i < AC97_READ_RETRY; i++) {
+               /* send_read_request */
+               local_irq_disable();
+               HACREG(HACTSR) &= ~(TSR_CMDAMT);
+               HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD;
+               local_irq_enable();
+
+               for (to = TMO_E3;
+                    to && !(HACREG(HACTSR) & TSR_CMDAMT);
+                    --to)
+                       udelay(1);
+
+               HACREG(HACTSR) &= ~TSR_CMDAMT;
+               val = 0;
+               if (hac_get_codec_data(hac, reg, &val) != 0)
+                       break;
+       }
+
+       if (i == AC97_READ_RETRY)
+               return ~0;
+
+       return val;
+}
+
+static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+                          unsigned short val)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac = &hac_cpu_data[unit_id];
+       unsigned int i, to;
+       /* write_codec_aux */
+       for (i = 0; i < AC97_WRITE_RETRY; i++) {
+               /* send_write_request */
+               local_irq_disable();
+               HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
+               HACREG(HACCSDR) = (val << CSDR_SHIFT);
+               HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD);
+               local_irq_enable();
+
+               /* poll-wait for CMDAMT and CMDDMT */
+               for (to = TMO_E1;
+                    to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT));
+                    --to)
+                       udelay(1);
+
+               HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT);
+               if (to)
+                       break;
+               /* timeout, try again */
+       }
+}
+
+static unsigned short hac_ac97_read(struct snd_ac97 *ac97,
+                                   unsigned short reg)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac = &hac_cpu_data[unit_id];
+       return hac_read_codec_aux(hac, reg);
+}
+
+static void hac_ac97_warmrst(struct snd_ac97 *ac97)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac = &hac_cpu_data[unit_id];
+       unsigned int tmo;
+
+       HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9;
+       msleep(10);
+       HACREG(HACCR) = CR_ST | CR_B9;
+       for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--)
+               udelay(1);
+
+       if (!tmo)
+               printk(KERN_INFO "hac: reset: AC97 link down!\n");
+       /* settings this bit lets us have a conversation with codec */
+       HACREG(HACACR) |= ACR_TX12ATOM;
+}
+
+static void hac_ac97_coldrst(struct snd_ac97 *ac97)
+{
+       int unit_id = 0 /* ac97->private_data */;
+       struct hac_priv *hac;
+       hac = &hac_cpu_data[unit_id];
+
+       HACREG(HACCR) = 0;
+       HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9;
+       msleep(10);
+       hac_ac97_warmrst(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+       .read   = hac_ac97_read,
+       .write  = hac_ac97_write,
+       .reset  = hac_ac97_coldrst,
+       .warm_reset = hac_ac97_warmrst,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int hac_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
+       int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+       switch (params->msbits) {
+       case 16:
+               HACREG(HACACR) |= d ?  ACR_DMARX16 :  ACR_DMATX16;
+               HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20;
+               break;
+       case 20:
+               HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16;
+               HACREG(HACACR) |= d ?  ACR_DMARX20 :  ACR_DMATX20;
+               break;
+       default:
+               pr_debug("hac: invalid depth %d bit\n", params->msbits);
+               return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+#define AC97_RATES     \
+       SNDRV_PCM_RATE_8000_192000
+
+#define AC97_FMTS      \
+       SNDRV_PCM_FMTBIT_S16_LE
+
+struct snd_soc_cpu_dai sh4_hac_dai[] = {
+{
+       .name                   = "HAC0",
+       .id                     = 0,
+       .type                   = SND_SOC_DAI_AC97,
+       .playback = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .capture = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .ops = {
+               .hw_params      = hac_hw_params,
+       },
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+       .name                   = "HAC1",
+       .id                     = 1,
+       .type                   = SND_SOC_DAI_AC97,
+       .playback = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .capture = {
+               .rates          = AC97_RATES,
+               .formats        = AC97_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 2,
+       },
+       .ops = {
+               .hw_params      = hac_hw_params,
+       },
+
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_hac_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
new file mode 100644 (file)
index 0000000..5563f14
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Generic AC97 sound support for SH7760
+ *
+ * (c) 2007 Manuel Lauss
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+
+#include "../codecs/ac97.h"
+
+#define IPSEL 0xFE400034
+
+/* platform specific structs can be declared here */
+extern struct snd_soc_cpu_dai sh4_hac_dai[2];
+extern struct snd_soc_platform sh7760_soc_platform;
+
+static int machine_init(struct snd_soc_codec *codec)
+{
+       snd_soc_dapm_sync_endpoints(codec);
+       return 0;
+}
+
+static struct snd_soc_dai_link sh7760_ac97_dai = {
+       .name = "AC97",
+       .stream_name = "AC97 HiFi",
+       .cpu_dai = &sh4_hac_dai[0],     /* HAC0 */
+       .codec_dai = &ac97_dai,
+       .init = machine_init,
+       .ops = NULL,
+};
+
+static struct snd_soc_machine sh7760_ac97_soc_machine  = {
+       .name = "SH7760 AC97",
+       .dai_link = &sh7760_ac97_dai,
+       .num_links = 1,
+};
+
+static struct snd_soc_device sh7760_ac97_snd_devdata = {
+       .machine = &sh7760_ac97_soc_machine,
+       .platform = &sh7760_soc_platform,
+       .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *sh7760_ac97_snd_device;
+
+static int __init sh7760_ac97_init(void)
+{
+       int ret;
+       unsigned short ipsel;
+
+       /* enable both AC97 controllers in pinmux reg */
+       ipsel = ctrl_inw(IPSEL);
+       ctrl_outw(ipsel | (3 << 10), IPSEL);
+
+       ret = -ENOMEM;
+       sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!sh7760_ac97_snd_device)
+               goto out;
+
+       platform_set_drvdata(sh7760_ac97_snd_device,
+                            &sh7760_ac97_snd_devdata);
+       sh7760_ac97_snd_devdata.dev = &sh7760_ac97_snd_device->dev;
+       ret = platform_device_add(sh7760_ac97_snd_device);
+
+       if (ret)
+               platform_device_put(sh7760_ac97_snd_device);
+
+out:
+       return ret;
+}
+
+static void __exit sh7760_ac97_exit(void)
+{
+       platform_device_unregister(sh7760_ac97_snd_device);
+}
+
+module_init(sh7760_ac97_init);
+module_exit(sh7760_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
new file mode 100644 (file)
index 0000000..b72bc31
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Serial Sound Interface (I2S) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *
+ *  licensed under the terms outlined in the file COPYING at the root
+ *  of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable SSI output pins!
+ */
+
+/*
+ * LIMITATIONS:
+ *     The SSI unit has only one physical data line, so full duplex is
+ *     impossible.  This can be remedied  on the  SH7760 by  using the
+ *     other SSI unit for recording; however the SH7780 has only 1 SSI
+ *     unit, and its pins are shared with the AC97 unit,  among others.
+ *
+ * FEATURES:
+ *     The SSI features "compressed mode": in this mode it continuously
+ *     streams PCM data over the I2S lines and uses LRCK as a handshake
+ *     signal.  Can be used to send compressed data (AC3/DTS) to a DSP.
+ *     The number of bits sent over the wire in a frame can be adjusted
+ *     and can be independent from the actual sample bit depth. This is
+ *     useful to support TDM mode codecs like the AD1939 which have a
+ *     fixed TDM slot size, regardless of sample resolution.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/io.h>
+
+#define SSICR  0x00
+#define SSISR  0x04
+
+#define CR_DMAEN       (1 << 28)
+#define CR_CHNL_SHIFT  22
+#define CR_CHNL_MASK   (3 << CR_CHNL_SHIFT)
+#define CR_DWL_SHIFT   19
+#define CR_DWL_MASK    (7 << CR_DWL_SHIFT)
+#define CR_SWL_SHIFT   16
+#define CR_SWL_MASK    (7 << CR_SWL_SHIFT)
+#define CR_SCK_MASTER  (1 << 15)       /* bitclock master bit */
+#define CR_SWS_MASTER  (1 << 14)       /* wordselect master bit */
+#define CR_SCKP                (1 << 13)       /* I2Sclock polarity */
+#define CR_SWSP                (1 << 12)       /* LRCK polarity */
+#define CR_SPDP                (1 << 11)
+#define CR_SDTA                (1 << 10)       /* i2s alignment (msb/lsb) */
+#define CR_PDTA                (1 << 9)        /* fifo data alignment */
+#define CR_DEL         (1 << 8)        /* delay data by 1 i2sclk */
+#define CR_BREN                (1 << 7)        /* clock gating in burst mode */
+#define CR_CKDIV_SHIFT 4
+#define CR_CKDIV_MASK  (7 << CR_CKDIV_SHIFT)   /* bitclock divider */
+#define CR_MUTE                (1 << 3)        /* SSI mute */
+#define CR_CPEN                (1 << 2)        /* compressed mode */
+#define CR_TRMD                (1 << 1)        /* transmit/receive select */
+#define CR_EN          (1 << 0)        /* enable SSI */
+
+#define SSIREG(reg)    (*(unsigned long *)(ssi->mmio + (reg)))
+
+struct ssi_priv {
+       unsigned long mmio;
+       unsigned long sysclk;
+       int inuse;
+} ssi_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+       {
+               .mmio   = 0xFE680000,
+       },
+       {
+               .mmio   = 0xFE690000,
+       },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+       {
+               .mmio   = 0xFFE70000,
+       },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+/*
+ * track usage of the SSI; it is simplex-only so prevent attempts of
+ * concurrent playback + capture. FIXME: any locking required?
+ */
+static int ssi_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       if (ssi->inuse) {
+               pr_debug("ssi: already in use!\n");
+               return -EBUSY;
+       } else
+               ssi->inuse = 1;
+       return 0;
+}
+
+static void ssi_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+       ssi->inuse = 0;
+}
+
+static int ssi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               SSIREG(SSICR) |= CR_DMAEN | CR_EN;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ssi_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+       unsigned long ssicr = SSIREG(SSICR);
+       unsigned int bits, channels, swl, recv, i;
+
+       channels = params_channels(params);
+       bits = params->msbits;
+       recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
+
+       pr_debug("ssi_hw_params() enter\nssicr was    %08lx\n", ssicr);
+       pr_debug("bits: %d channels: %d\n", bits, channels);
+
+       ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
+                  CR_SWL_MASK);
+
+       /* direction (send/receive) */
+       if (!recv)
+               ssicr |= CR_TRMD;       /* transmit */
+
+       /* channels */
+       if ((channels < 2) || (channels > 8) || (channels & 1)) {
+               pr_debug("ssi: invalid number of channels\n");
+               return -EINVAL;
+       }
+       ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT;
+
+       /* DATA WORD LENGTH (DWL): databits in audio sample */
+       i = 0;
+       switch (bits) {
+       case 32: ++i;
+       case 24: ++i;
+       case 22: ++i;
+       case 20: ++i;
+       case 18: ++i;
+       case 16: ++i;
+                ssicr |= i << CR_DWL_SHIFT;
+       case 8:  break;
+       default:
+               pr_debug("ssi: invalid sample width\n");
+               return -EINVAL;
+       }
+
+       /*
+        * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S
+        * wires. This is usually bits_per_sample x channels/2;  i.e. in
+        * Stereo mode  the SWL equals DWL.  SWL can  be bigger than the
+        * product of (channels_per_slot x samplebits), e.g.  for codecs
+        * like the AD1939 which  only accept 32bit wide TDM slots.  For
+        * "standard" I2S operation we set SWL = chans / 2 * DWL here.
+        * Waiting for ASoC to get TDM support ;-)
+        */
+       if ((bits > 16) && (bits <= 24)) {
+               bits = 24;      /* these are padded by the SSI */
+               /*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */
+       }
+       i = 0;
+       swl = (bits * channels) / 2;
+       switch (swl) {
+       case 256: ++i;
+       case 128: ++i;
+       case 64:  ++i;
+       case 48:  ++i;
+       case 32:  ++i;
+       case 16:  ++i;
+                 ssicr |= i << CR_SWL_SHIFT;
+       case 8:   break;
+       default:
+               pr_debug("ssi: invalid system word length computed\n");
+               return -EINVAL;
+       }
+
+       SSIREG(SSICR) = ssicr;
+
+       pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr);
+       return 0;
+}
+
+static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id,
+                         unsigned int freq, int dir)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
+
+       ssi->sysclk = freq;
+
+       return 0;
+}
+
+/*
+ * This divider is used to generate the SSI_SCK (I2S bitclock) from the
+ * clock at the HAC_BIT_CLK ("oversampling clock") pin.
+ */
+static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+       unsigned long ssicr;
+       int i;
+
+       i = 0;
+       ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK;
+       switch (div) {
+       case 16: ++i;
+       case 8:  ++i;
+       case 4:  ++i;
+       case 2:  ++i;
+                SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT);
+       case 1:  break;
+       default:
+               pr_debug("ssi: invalid sck divider %d\n", div);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt)
+{
+       struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+       unsigned long ssicr = SSIREG(SSICR);
+
+       pr_debug("ssi_set_fmt()\nssicr was    0x%08lx\n", ssicr);
+
+       ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP |
+                  CR_SWS_MASTER | CR_SCK_MASTER);
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               ssicr |= CR_DEL | CR_PDTA;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               ssicr |= CR_DEL;
+               break;
+       default:
+               pr_debug("ssi: unsupported format\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+       case SND_SOC_DAIFMT_CONT:
+               break;
+       case SND_SOC_DAIFMT_GATED:
+               ssicr |= CR_BREN;
+               break;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               ssicr |= CR_SCKP;       /* sample data at low clkedge */
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               ssicr |= CR_SCKP | CR_SWSP;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               ssicr |= CR_SWSP;       /* word select starts low */
+               break;
+       default:
+               pr_debug("ssi: invalid inversion\n");
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               break;
+       case SND_SOC_DAIFMT_CBS_CFM:
+               ssicr |= CR_SCK_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               ssicr |= CR_SWS_MASTER;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
+               break;
+       default:
+               pr_debug("ssi: invalid master/slave configuration\n");
+               return -EINVAL;
+       }
+
+       SSIREG(SSICR) = ssicr;
+       pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr);
+
+       return 0;
+}
+
+/* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in
+ * Master mode,  so really this is board specific;  the SSI can do any
+ * rate with the right bitclk and divider settings.
+ */
+#define SSI_RATES      \
+       SNDRV_PCM_RATE_8000_192000
+
+/* the SSI can do 8-32 bit samples, with 8 possible channels */
+#define SSI_FMTS       \
+       (SNDRV_PCM_FMTBIT_S8      | SNDRV_PCM_FMTBIT_U8      |  \
+        SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_U16_LE  |  \
+        SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE |  \
+        SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE |  \
+        SNDRV_PCM_FMTBIT_S32_LE  | SNDRV_PCM_FMTBIT_U32_LE)
+
+struct snd_soc_cpu_dai sh4_ssi_dai[] = {
+{
+       .name                   = "SSI0",
+       .id                     = 0,
+       .type                   = SND_SOC_DAI_I2S,
+       .playback = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .capture = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .ops = {
+               .startup        = ssi_startup,
+               .shutdown       = ssi_shutdown,
+               .trigger        = ssi_trigger,
+               .hw_params      = ssi_hw_params,
+       },
+       .dai_ops = {
+               .set_sysclk     = ssi_set_sysclk,
+               .set_clkdiv     = ssi_set_clkdiv,
+               .set_fmt        = ssi_set_fmt,
+       },
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+       .name                   = "SSI1",
+       .id                     = 1,
+       .type                   = SND_SOC_DAI_I2S,
+       .playback = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .capture = {
+               .rates          = SSI_RATES,
+               .formats        = SSI_FMTS,
+               .channels_min   = 2,
+               .channels_max   = 8,
+       },
+       .ops = {
+               .startup        = ssi_startup,
+               .shutdown       = ssi_shutdown,
+               .trigger        = ssi_trigger,
+               .hw_params      = ssi_hw_params,
+       },
+       .dai_ops = {
+               .set_sysclk     = ssi_set_sysclk,
+               .set_clkdiv     = ssi_set_clkdiv,
+               .set_fmt        = ssi_set_fmt,
+       },
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_ssi_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
index 8ebc1adb5ed9818ddb9c6d8cfef453ca418110cd..7bd5852fcc0d1aa1cd0056c083929f2f69197369 100644 (file)
@@ -2350,7 +2350,9 @@ static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *
                        return 1;
                break;
        case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
-               return 1;
+               if (device_setup[chip->index] == 0x00 ||
+                   fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3)
+                       return 1;
        }
        return 0;
 }
@@ -2530,7 +2532,18 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *
                 *        but we give normal PCM format to get the existing
                 *        apps working...
                 */
-               pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+               switch (chip->usb_id) {
+
+               case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
+                       if (device_setup[chip->index] == 0x00 && 
+                           fp->altsetting == 6)
+                               pcm_format = SNDRV_PCM_FORMAT_S16_BE;
+                       else
+                               pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+                       break;
+               default:
+                       pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+               }
        } else {
                pcm_format = parse_audio_format_i_type(chip, fp, format, fmt);
                if (pcm_format < 0)
@@ -3251,6 +3264,11 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
 static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
                                         int iface, int altno)
 {
+       /* Reset ALL ifaces to 0 altsetting.
+        * Call it for every possible altsetting of every interface.
+        */
+       usb_set_interface(chip->dev, iface, 0);
+
        if (device_setup[chip->index] & AUDIOPHILE_SET) {
                if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS)
                    && altno != 6)
index 374fbf657a2de382f0ad6c26c95bd019e58b104b..5a2f518c66295d7dcab60453969959065cf09d12 100644 (file)
        .bInterfaceClass = USB_CLASS_AUDIO,
        .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
 },
+{
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .idVendor = 0x046d,
+       .idProduct = 0x08ae,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+},
+{
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+                      USB_DEVICE_ID_MATCH_INT_CLASS |
+                      USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+       .idVendor = 0x046d,
+       .idProduct = 0x08c6,
+       .bInterfaceClass = USB_CLASS_AUDIO,
+       .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+},
 {
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
                       USB_DEVICE_ID_MATCH_INT_CLASS |
@@ -1051,7 +1069,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                .type = QUIRK_MIDI_STANDARD_INTERFACE
        }
 },
-       /* TODO: add Roland EXR support */
+{
+       USB_DEVICE(0x0582, 0x0060),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Roland",
+               .product_name = "EXR Series",
+               .ifnum = 0,
+               .type = QUIRK_MIDI_STANDARD_INTERFACE
+       }
+},
 {
        /* has ID 0x0067 when not in "Advanced Driver" mode */
        USB_DEVICE(0x0582, 0x0065),
@@ -1094,6 +1120,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       USB_DEVICE(0x582, 0x00a6),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Roland",
+               .product_name = "Juno-G",
+               .ifnum = 0,
+               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+               .data = & (const struct snd_usb_midi_endpoint_info) {
+                       .out_cables = 0x0001,
+                       .in_cables  = 0x0001
+               }
+       }
+},
 {      /*
         * This quirk is for the "Advanced" modes of the Edirol UA-25.
         * If the switch is not in an advanced setting, the UA-25 has
@@ -1230,6 +1269,37 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        }
 },
        /* TODO: add Edirol MD-P1 support */
+{
+       /* Roland SH-201 */
+       USB_DEVICE(0x0582, 0x00ad),
+       .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+               .vendor_name = "Roland",
+               .product_name = "SH-201",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_MIDI_FIXED_ENDPOINT,
+                               .data = & (const struct snd_usb_midi_endpoint_info) {
+                                       .out_cables = 0x0001,
+                                       .in_cables  = 0x0001
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 /* Guillemot devices */
 {
index 0a352e46862f37abbdc1b94c2475f8d185e99d63..48e9aa3f18c94ac7dc3ecd57b53bfd749e9c3779 100644 (file)
@@ -935,10 +935,9 @@ static struct snd_pcm_ops snd_usX2Y_pcm_ops =
  */
 static void usX2Y_audio_stream_free(struct snd_usX2Y_substream **usX2Y_substream)
 {
-       if (NULL != usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]) {
-               kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);
-               usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;
-       }
+       kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);
+       usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;
+
        kfree(usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]);
        usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE] = NULL;
 }