summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS2
-rw-r--r--Documentation/DocBook/Makefile48
-rw-r--r--Documentation/DocBook/kernel-api.tmpl6
-rw-r--r--Documentation/DocBook/stylesheet.xsl1
-rw-r--r--Documentation/atomic_ops.txt27
-rw-r--r--Documentation/block/biodoc.txt4
-rw-r--r--Documentation/feature-removal-schedule.txt9
-rw-r--r--Documentation/oops-tracing.txt7
-rw-r--r--Documentation/video4linux/CARDLIST.bttv1
-rw-r--r--Documentation/video4linux/CARDLIST.saa71342
-rw-r--r--Documentation/video4linux/CARDLIST.tuner1
-rw-r--r--Documentation/x86_64/boot-options.txt12
-rw-r--r--Documentation/x86_64/mm.txt6
-rw-r--r--MAINTAINERS12
-rw-r--r--Makefile13
-rw-r--r--README5
-rw-r--r--arch/arm/Kconfig20
-rw-r--r--arch/arm/common/locomo.c4
-rw-r--r--arch/arm/common/sa1111.c2
-rw-r--r--arch/arm/common/scoop.c2
-rw-r--r--arch/arm/kernel/apm.c1
-rw-r--r--arch/arm/kernel/smp.c4
-rw-r--r--arch/arm/mach-footbridge/common.c24
-rw-r--r--arch/arm/mach-pxa/Kconfig6
-rw-r--r--arch/arm/mach-pxa/Makefile5
-rw-r--r--arch/arm/mach-pxa/akita-ioexp.c223
-rw-r--r--arch/arm/mach-pxa/corgi_pm.c228
-rw-r--r--arch/arm/mach-pxa/sharpsl.h8
-rw-r--r--arch/arm/mach-pxa/sharpsl_pm.c109
-rw-r--r--arch/arm/mach-pxa/spitz.c49
-rw-r--r--arch/arm/mach-pxa/spitz_pm.c233
-rw-r--r--arch/frv/kernel/pm.c1
-rw-r--r--arch/i386/Kconfig2
-rw-r--r--arch/i386/kernel/acpi/boot.c17
-rw-r--r--arch/i386/kernel/apm.c1
-rw-r--r--arch/i386/kernel/cpu/amd.c12
-rw-r--r--arch/i386/kernel/cpu/common.c40
-rw-r--r--arch/i386/kernel/cpu/intel.c50
-rw-r--r--arch/i386/kernel/cpu/intel_cacheinfo.c46
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c8
-rw-r--r--arch/i386/kernel/cpu/proc.c7
-rw-r--r--arch/i386/kernel/crash.c7
-rw-r--r--arch/i386/kernel/entry.S7
-rw-r--r--arch/i386/kernel/smpboot.c73
-rw-r--r--arch/i386/kernel/srat.c4
-rw-r--r--arch/i386/kernel/timers/timer_pit.c5
-rw-r--r--arch/i386/mm/init.c3
-rw-r--r--arch/ia64/Kconfig4
-rw-r--r--arch/ia64/kernel/process.c15
-rw-r--r--arch/m68k/fpsp040/skeleton.S6
-rw-r--r--arch/m68k/ifpsp060/iskeleton.S6
-rw-r--r--arch/m68k/kernel/asm-offsets.c10
-rw-r--r--arch/m68k/kernel/entry.S78
-rw-r--r--arch/m68k/kernel/ptrace.c15
-rw-r--r--arch/mips/au1000/common/power.c1
-rw-r--r--arch/mips/au1000/common/usbdev.c4
-rw-r--r--arch/powerpc/Kconfig5
-rw-r--r--arch/powerpc/Makefile2
-rw-r--r--arch/powerpc/configs/pseries_defconfig206
-rw-r--r--arch/powerpc/kernel/Makefile20
-rw-r--r--arch/powerpc/kernel/asm-offsets.c6
-rw-r--r--arch/powerpc/kernel/dma_64.c (renamed from arch/ppc64/kernel/dma.c)0
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S2
-rw-r--r--arch/powerpc/kernel/iomap.c (renamed from arch/ppc64/kernel/iomap.c)0
-rw-r--r--arch/powerpc/kernel/iommu.c (renamed from arch/ppc64/kernel/iommu.c)0
-rw-r--r--arch/powerpc/kernel/irq.c9
-rw-r--r--arch/powerpc/kernel/kprobes.c (renamed from arch/ppc64/kernel/kprobes.c)0
-rw-r--r--arch/powerpc/kernel/lparcfg.c51
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c (renamed from arch/ppc64/kernel/machine_kexec.c)63
-rw-r--r--arch/powerpc/kernel/module_64.c (renamed from arch/ppc64/kernel/module.c)0
-rw-r--r--arch/powerpc/kernel/pci_64.c (renamed from arch/ppc64/kernel/pci.c)0
-rw-r--r--arch/powerpc/kernel/pci_direct_iommu.c (renamed from arch/ppc64/kernel/pci_direct_iommu.c)0
-rw-r--r--arch/powerpc/kernel/pci_dn.c (renamed from arch/ppc64/kernel/pci_dn.c)0
-rw-r--r--arch/powerpc/kernel/pci_iommu.c (renamed from arch/ppc64/kernel/pci_iommu.c)0
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c7
-rw-r--r--arch/powerpc/kernel/prom.c2
-rw-r--r--arch/powerpc/kernel/rtas-rtc.c105
-rw-r--r--arch/powerpc/kernel/setup_32.c4
-rw-r--r--arch/powerpc/kernel/setup_64.c5
-rw-r--r--arch/powerpc/kernel/signal_32.c7
-rw-r--r--arch/powerpc/kernel/signal_64.c6
-rw-r--r--arch/powerpc/kernel/vdso32/datapage.S3
-rw-r--r--arch/powerpc/kernel/vdso32/gettimeofday.S12
-rw-r--r--arch/powerpc/kernel/vdso64/datapage.S1
-rw-r--r--arch/powerpc/kernel/vdso64/gettimeofday.S31
-rw-r--r--arch/powerpc/mm/fsl_booke_mmu.c2
-rw-r--r--arch/powerpc/mm/mem.c8
-rw-r--r--arch/powerpc/mm/numa.c5
-rw-r--r--arch/powerpc/oprofile/op_model_fsl_booke.c2
-rw-r--r--arch/powerpc/platforms/iseries/irq.c25
-rw-r--r--arch/powerpc/platforms/iseries/setup.c6
-rw-r--r--arch/powerpc/platforms/powermac/time.c9
-rw-r--r--arch/powerpc/platforms/pseries/Makefile5
-rw-r--r--arch/powerpc/platforms/pseries/hvconsole.c (renamed from arch/ppc64/kernel/hvconsole.c)0
-rw-r--r--arch/powerpc/platforms/pseries/hvcserver.c (renamed from arch/ppc64/kernel/hvcserver.c)0
-rw-r--r--arch/powerpc/platforms/pseries/setup.c26
-rw-r--r--arch/powerpc/xmon/xmon.c1
-rw-r--r--arch/ppc/kernel/head_fsl_booke.S2
-rw-r--r--arch/ppc/mm/fsl_booke_mmu.c2
-rw-r--r--arch/ppc/platforms/83xx/mpc834x_sys.c17
-rw-r--r--arch/ppc/platforms/83xx/mpc834x_sys.h2
-rw-r--r--arch/ppc/platforms/85xx/mpc8540_ads.c2
-rw-r--r--arch/ppc/platforms/85xx/mpc8540_ads.h2
-rw-r--r--arch/ppc/platforms/85xx/mpc8555_cds.h2
-rw-r--r--arch/ppc/platforms/85xx/mpc8560_ads.c2
-rw-r--r--arch/ppc/platforms/85xx/mpc8560_ads.h2
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_ads_common.c2
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_ads_common.h2
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_cds_common.c2
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_cds_common.h2
-rw-r--r--arch/ppc/platforms/85xx/sbc8560.c2
-rw-r--r--arch/ppc/platforms/pmac_feature.c8
-rw-r--r--arch/ppc/platforms/pq2ads.c2
-rw-r--r--arch/ppc/syslib/ipic.h2
-rw-r--r--arch/ppc/syslib/mpc83xx_devices.c2
-rw-r--r--arch/ppc/syslib/mpc83xx_sys.c2
-rw-r--r--arch/ppc/syslib/mpc85xx_devices.c2
-rw-r--r--arch/ppc/syslib/mpc85xx_sys.c2
-rw-r--r--arch/ppc/syslib/mpc8xx_devices.c2
-rw-r--r--arch/ppc/syslib/mpc8xx_sys.c2
-rw-r--r--arch/ppc/syslib/ppc83xx_setup.c2
-rw-r--r--arch/ppc/syslib/ppc83xx_setup.h2
-rw-r--r--arch/ppc/syslib/ppc85xx_common.c2
-rw-r--r--arch/ppc/syslib/ppc85xx_common.h2
-rw-r--r--arch/ppc/syslib/ppc85xx_setup.c2
-rw-r--r--arch/ppc/syslib/ppc85xx_setup.h2
-rw-r--r--arch/ppc/syslib/ppc_sys.c2
-rw-r--r--arch/ppc/syslib/pq2_devices.c2
-rw-r--r--arch/ppc/syslib/pq2_sys.c2
-rw-r--r--arch/ppc64/Kconfig520
-rw-r--r--arch/ppc64/kernel/Makefile41
-rw-r--r--arch/ppc64/kernel/asm-offsets.c195
-rw-r--r--arch/ppc64/kernel/btext.c792
-rw-r--r--arch/ppc64/kernel/head.S2007
-rw-r--r--arch/ppc64/kernel/misc.S940
-rw-r--r--arch/ppc64/kernel/ppc_ksyms.c76
-rw-r--r--arch/ppc64/kernel/prom.c1954
-rw-r--r--arch/ppc64/kernel/prom_init.c2051
-rw-r--r--arch/ppc64/kernel/rtc.c358
-rw-r--r--arch/ppc64/kernel/semaphore.c136
-rw-r--r--arch/ppc64/kernel/vdso.c625
-rw-r--r--arch/ppc64/kernel/vmlinux.lds.S151
-rw-r--r--arch/ppc64/xmon/privinst.h64
-rw-r--r--arch/sparc/lib/atomic32.c34
-rw-r--r--arch/sparc/lib/bitext.c1
-rw-r--r--arch/um/Kconfig10
-rw-r--r--arch/um/Kconfig.i38610
-rw-r--r--arch/um/Makefile-i3861
-rw-r--r--arch/um/drivers/chan_kern.c5
-rw-r--r--arch/um/drivers/chan_user.c2
-rw-r--r--arch/um/drivers/daemon_user.c6
-rw-r--r--arch/um/drivers/fd.c9
-rw-r--r--arch/um/drivers/mcast_user.c20
-rw-r--r--arch/um/drivers/port_user.c9
-rw-r--r--arch/um/drivers/pty.c11
-rw-r--r--arch/um/drivers/tty.c9
-rw-r--r--arch/um/drivers/xterm.c9
-rw-r--r--arch/um/include/chan_user.h4
-rw-r--r--arch/um/include/um_uaccess.h19
-rw-r--r--arch/um/kernel/skas/include/uaccess-skas.h10
-rw-r--r--arch/um/kernel/skas/uaccess.c8
-rw-r--r--arch/um/kernel/trap_kern.c9
-rw-r--r--arch/um/kernel/tt/include/uaccess-tt.h8
-rw-r--r--arch/um/kernel/tt/uaccess.c8
-rw-r--r--arch/v850/Kconfig8
-rw-r--r--arch/v850/kernel/irq.c715
-rw-r--r--arch/x86_64/Kconfig57
-rw-r--r--arch/x86_64/Kconfig.debug9
-rw-r--r--arch/x86_64/defconfig98
-rw-r--r--arch/x86_64/ia32/ia32_aout.c3
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c4
-rw-r--r--arch/x86_64/kernel/Makefile1
-rw-r--r--arch/x86_64/kernel/aperture.c2
-rw-r--r--arch/x86_64/kernel/apic.c10
-rw-r--r--arch/x86_64/kernel/e820.c3
-rw-r--r--arch/x86_64/kernel/entry.S3
-rw-r--r--arch/x86_64/kernel/head.S37
-rw-r--r--arch/x86_64/kernel/head64.c14
-rw-r--r--arch/x86_64/kernel/i8259.c4
-rw-r--r--arch/x86_64/kernel/io_apic.c80
-rw-r--r--arch/x86_64/kernel/mce.c17
-rw-r--r--arch/x86_64/kernel/mce_amd.c538
-rw-r--r--arch/x86_64/kernel/mpparse.c23
-rw-r--r--arch/x86_64/kernel/pci-gart.c8
-rw-r--r--arch/x86_64/kernel/process.c47
-rw-r--r--arch/x86_64/kernel/reboot.c7
-rw-r--r--arch/x86_64/kernel/setup.c89
-rw-r--r--arch/x86_64/kernel/setup64.c2
-rw-r--r--arch/x86_64/kernel/signal.c17
-rw-r--r--arch/x86_64/kernel/smp.c7
-rw-r--r--arch/x86_64/kernel/smpboot.c111
-rw-r--r--arch/x86_64/kernel/sys_x86_64.c14
-rw-r--r--arch/x86_64/kernel/traps.c44
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S2
-rw-r--r--arch/x86_64/kernel/x8664_ksyms.c3
-rw-r--r--arch/x86_64/lib/clear_page.S38
-rw-r--r--arch/x86_64/lib/copy_page.S87
-rw-r--r--arch/x86_64/lib/memcpy.S93
-rw-r--r--arch/x86_64/lib/memset.S94
-rw-r--r--arch/x86_64/mm/fault.c19
-rw-r--r--arch/x86_64/mm/init.c129
-rw-r--r--arch/x86_64/mm/k8topology.c1
-rw-r--r--arch/x86_64/mm/numa.c122
-rw-r--r--arch/x86_64/mm/srat.c6
-rw-r--r--drivers/acpi/bus.c3
-rw-r--r--drivers/base/firmware_class.c15
-rw-r--r--drivers/block/cciss_scsi.c2
-rw-r--r--drivers/block/pktcdvd.c2
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/agp/amd64-agp.c17
-rw-r--r--drivers/char/agp/uninorth-agp.c4
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c2
-rw-r--r--drivers/char/pcmcia/Kconfig24
-rw-r--r--drivers/char/pcmcia/Makefile2
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c2078
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c841
-rw-r--r--drivers/char/pcmcia/cm4040_cs.h47
-rw-r--r--drivers/char/synclink.c31
-rw-r--r--drivers/char/tpm/tpm.c14
-rw-r--r--drivers/char/tpm/tpm.h7
-rw-r--r--drivers/char/tpm/tpm_atmel.c108
-rw-r--r--drivers/char/tpm/tpm_atmel.h129
-rw-r--r--drivers/char/watchdog/booke_wdt.c2
-rw-r--r--drivers/ide/pci/sl82c105.c83
-rw-r--r--drivers/ide/ppc/pmac.c11
-rw-r--r--drivers/isdn/hisax/hfc_usb.c32
-rw-r--r--drivers/md/md.c19
-rw-r--r--drivers/media/common/ir-common.c60
-rw-r--r--drivers/media/video/Kconfig14
-rw-r--r--drivers/media/video/Makefile5
-rw-r--r--drivers/media/video/bttv-cards.c24
-rw-r--r--drivers/media/video/bttv-driver.c4
-rw-r--r--drivers/media/video/bttv-gpio.c18
-rw-r--r--drivers/media/video/bttv.h3
-rw-r--r--drivers/media/video/bttvp.h2
-rw-r--r--drivers/media/video/cx25840/Makefile6
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c368
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c1020
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c167
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c315
-rw-r--r--drivers/media/video/cx25840/cx25840.h85
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c3
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c3
-rw-r--r--drivers/media/video/ir-kbd-gpio.c292
-rw-r--r--drivers/media/video/ir-kbd-i2c.c52
-rw-r--r--drivers/media/video/saa7115.c1376
-rw-r--r--drivers/media/video/saa711x.c1
-rw-r--r--drivers/media/video/saa7127.c849
-rw-r--r--drivers/media/video/saa7134/Kconfig3
-rw-r--r--drivers/media/video/saa7134/Makefile7
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c448
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c32
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c121
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c109
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c161
-rw-r--r--drivers/media/video/saa7134/saa7134.h2
-rw-r--r--drivers/media/video/tda8290.c4
-rw-r--r--drivers/media/video/tuner-core.c11
-rw-r--r--drivers/media/video/tuner-simple.c4
-rw-r--r--drivers/media/video/wm8775.c7
-rw-r--r--drivers/mmc/mmci.c1
-rw-r--r--drivers/net/3c509.c13
-rw-r--r--drivers/net/gianfar.c2
-rw-r--r--drivers/net/gianfar.h2
-rw-r--r--drivers/net/gianfar_ethtool.c2
-rw-r--r--drivers/net/gianfar_mii.c2
-rw-r--r--drivers/net/gianfar_mii.h2
-rw-r--r--drivers/net/irda/ali-ircc.c1
-rw-r--r--drivers/net/irda/nsc-ircc.c1
-rw-r--r--drivers/net/smc91x.h16
-rw-r--r--drivers/net/sungem.c2
-rw-r--r--drivers/net/wan/sdladrv.c2
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c2
-rw-r--r--drivers/pci/hotplug/rpaphp_pci.c2
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c2
-rw-r--r--drivers/pcmcia/cs.c6
-rw-r--r--drivers/pcmcia/ds.c3
-rw-r--r--drivers/pcmcia/i82365.c20
-rw-r--r--drivers/serial/68328serial.c7
-rw-r--r--drivers/serial/8250.c5
-rw-r--r--drivers/serial/8250_pnp.c2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c2
-rw-r--r--drivers/serial/dz.c48
-rw-r--r--drivers/serial/mpc52xx_uart.c4
-rw-r--r--drivers/serial/sa1100.c4
-rw-r--r--drivers/serial/serial_core.c84
-rw-r--r--drivers/video/console/fbcon.c15
-rw-r--r--drivers/video/console/fbcon.h3
-rw-r--r--drivers/video/console/fbcon_ccw.c14
-rw-r--r--drivers/video/console/fbcon_cw.c14
-rw-r--r--drivers/video/console/fbcon_ud.c22
-rw-r--r--drivers/video/nvidia/nv_proto.h2
-rw-r--r--drivers/video/nvidia/nvidia.c2
-rw-r--r--drivers/video/vesafb.c2
-rw-r--r--drivers/video/w100fb.c2
-rw-r--r--fs/aio.c44
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/ext3/inode.c4
-rw-r--r--fs/proc/task_mmu.c2
-rw-r--r--include/asm-alpha/atomic.h12
-rw-r--r--include/asm-arm/arch-pxa/akita.h2
-rw-r--r--include/asm-arm/atomic.h42
-rw-r--r--include/asm-arm26/atomic.h29
-rw-r--r--include/asm-cris/atomic.h27
-rw-r--r--include/asm-frv/atomic.h12
-rw-r--r--include/asm-generic/sections.h1
-rw-r--r--include/asm-h8300/atomic.h27
-rw-r--r--include/asm-i386/atomic.h21
-rw-r--r--include/asm-i386/mach-default/mach_reboot.h2
-rw-r--r--include/asm-i386/processor.h4
-rw-r--r--include/asm-i386/system.h42
-rw-r--r--include/asm-ia64/atomic.h12
-rw-r--r--include/asm-m68k/atomic.h12
-rw-r--r--include/asm-m68k/processor.h14
-rw-r--r--include/asm-m68k/thread_info.h91
-rw-r--r--include/asm-m68knommu/atomic.h12
-rw-r--r--include/asm-mips/atomic.h21
-rw-r--r--include/asm-parisc/atomic.h20
-rw-r--r--include/asm-powerpc/atomic.h27
-rw-r--r--include/asm-powerpc/btext.h (renamed from include/asm-ppc64/btext.h)0
-rw-r--r--include/asm-powerpc/delay.h (renamed from include/asm-ppc64/delay.h)19
-rw-r--r--include/asm-powerpc/eeh.h (renamed from include/asm-ppc64/eeh.h)0
-rw-r--r--include/asm-powerpc/floppy.h (renamed from include/asm-ppc64/floppy.h)25
-rw-r--r--include/asm-powerpc/hvconsole.h (renamed from include/asm-ppc64/hvconsole.h)0
-rw-r--r--include/asm-powerpc/hvcserver.h (renamed from include/asm-ppc64/hvcserver.h)0
-rw-r--r--include/asm-powerpc/kexec.h1
-rw-r--r--include/asm-powerpc/machdep.h4
-rw-r--r--include/asm-powerpc/nvram.h (renamed from include/asm-ppc64/nvram.h)17
-rw-r--r--include/asm-powerpc/page.h179
-rw-r--r--include/asm-powerpc/page_32.h40
-rw-r--r--include/asm-powerpc/page_64.h174
-rw-r--r--include/asm-powerpc/serial.h (renamed from include/asm-ppc64/serial.h)19
-rw-r--r--include/asm-powerpc/vdso_datapage.h2
-rw-r--r--include/asm-ppc/immap_85xx.h2
-rw-r--r--include/asm-ppc/ipic.h2
-rw-r--r--include/asm-ppc/mpc83xx.h2
-rw-r--r--include/asm-ppc/mpc85xx.h2
-rw-r--r--include/asm-ppc/nvram.h73
-rw-r--r--include/asm-ppc/ppc_sys.h2
-rw-r--r--include/asm-ppc64/page.h328
-rw-r--r--include/asm-ppc64/prom.h220
-rw-r--r--include/asm-ppc64/system.h310
-rw-r--r--include/asm-s390/atomic.h12
-rw-r--r--include/asm-sh/atomic.h29
-rw-r--r--include/asm-sh64/atomic.h29
-rw-r--r--include/asm-sparc/atomic.h4
-rw-r--r--include/asm-sparc64/atomic.h12
-rw-r--r--include/asm-v850/atomic.h30
-rw-r--r--include/asm-v850/hardirq.h4
-rw-r--r--include/asm-x86_64/apic.h2
-rw-r--r--include/asm-x86_64/atomic.h21
-rw-r--r--include/asm-x86_64/cache.h2
-rw-r--r--include/asm-x86_64/desc.h16
-rw-r--r--include/asm-x86_64/dma.h11
-rw-r--r--include/asm-x86_64/hpet.h35
-rw-r--r--include/asm-x86_64/hw_irq.h2
-rw-r--r--include/asm-x86_64/ia32.h5
-rw-r--r--include/asm-x86_64/mce.h10
-rw-r--r--include/asm-x86_64/mmzone.h9
-rw-r--r--include/asm-x86_64/mpspec.h7
-rw-r--r--include/asm-x86_64/msr.h2
-rw-r--r--include/asm-x86_64/numa.h2
-rw-r--r--include/asm-x86_64/page.h2
-rw-r--r--include/asm-x86_64/pda.h1
-rw-r--r--include/asm-x86_64/pgtable.h5
-rw-r--r--include/asm-x86_64/processor.h4
-rw-r--r--include/asm-x86_64/proto.h4
-rw-r--r--include/asm-x86_64/rwsem.h283
-rw-r--r--include/asm-x86_64/smp.h3
-rw-r--r--include/asm-x86_64/spinlock.h12
-rw-r--r--include/asm-x86_64/topology.h2
-rw-r--r--include/asm-x86_64/unistd.h3
-rw-r--r--include/asm-xtensa/atomic.h20
-rw-r--r--include/linux/acct.h2
-rw-r--r--include/linux/aio.h13
-rw-r--r--include/linux/bitops.h10
-rw-r--r--include/linux/cm4000_cs.h66
-rw-r--r--include/linux/file.h10
-rw-r--r--include/linux/fsl_devices.h2
-rw-r--r--include/linux/gfp.h16
-rw-r--r--include/linux/hardirq.h2
-rw-r--r--include/linux/hugetlb.h4
-rw-r--r--include/linux/i2c-id.h1
-rw-r--r--include/linux/init_task.h1
-rw-r--r--include/linux/interrupt.h1
-rw-r--r--include/linux/mm.h10
-rw-r--r--include/linux/mmzone.h22
-rw-r--r--include/linux/netfilter/nfnetlink.h6
-rw-r--r--include/linux/pagemap.h4
-rw-r--r--include/linux/pci_ids.h4
-rw-r--r--include/linux/percpu.h2
-rw-r--r--include/linux/pm.h49
-rw-r--r--include/linux/pm_legacy.h56
-rw-r--r--include/linux/preempt.h1
-rw-r--r--include/linux/sched.h32
-rw-r--r--include/linux/smp_lock.h3
-rw-r--r--include/linux/sysctl.h2
-rw-r--r--include/linux/thread_info.h47
-rw-r--r--include/linux/time.h2
-rw-r--r--include/linux/usb.h6
-rw-r--r--include/linux/videodev2.h1
-rw-r--r--include/media/ir-common.h1
-rw-r--r--include/media/ir-kbd-i2c.h2
-rw-r--r--include/media/tuner.h1
-rw-r--r--include/media/v4l2-common.h110
-rw-r--r--include/net/llc_pdu.h2
-rw-r--r--include/net/tcp.h4
-rw-r--r--kernel/cpuset.c5
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c8
-rw-r--r--kernel/posix-timers.c10
-rw-r--r--kernel/power/Kconfig9
-rw-r--r--kernel/power/Makefile3
-rw-r--r--kernel/power/pm.c1
-rw-r--r--kernel/printk.c16
-rw-r--r--kernel/ptrace.c2
-rw-r--r--kernel/rcutorture.c4
-rw-r--r--kernel/sched.c10
-rw-r--r--kernel/signal.c11
-rw-r--r--kernel/stop_machine.c6
-rw-r--r--mm/filemap.c2
-rw-r--r--mm/memory.c89
-rw-r--r--mm/page_alloc.c245
-rw-r--r--mm/slab.c55
-rw-r--r--mm/vmscan.c6
-rw-r--r--net/Makefile2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c66
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_tcp.c7
-rw-r--r--net/ipv4/tcp_input.c4
-rw-r--r--net/ipv6/addrconf.c5
-rw-r--r--net/ipv6/ipv6_sockglue.c2
-rw-r--r--net/ipv6/netfilter/Kconfig50
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c8
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c50
-rw-r--r--net/llc/af_llc.c5
-rw-r--r--net/llc/llc_c_ac.c20
-rw-r--r--net/netfilter/nf_conntrack_core.c7
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c6
-rw-r--r--net/netfilter/nf_conntrack_standalone.c2
-rw-r--r--net/netfilter/nfnetlink.c28
-rw-r--r--net/netfilter/nfnetlink_log.c6
-rw-r--r--net/netfilter/nfnetlink_queue.c9
-rw-r--r--net/sunrpc/svcsock.c1
-rwxr-xr-xscripts/kernel-doc13
-rw-r--r--sound/oss/ad1848.c1
-rw-r--r--sound/oss/cs4281/cs4281m.c1
-rw-r--r--sound/oss/maestro.c1
-rw-r--r--sound/oss/nm256_audio.c1
-rw-r--r--sound/oss/opl3sa2.c18
451 files changed, 13491 insertions, 14550 deletions
diff --git a/CREDITS b/CREDITS
index 7fb4c73e022..192f749eba2 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1097,7 +1097,7 @@ S: 80050-430 - Curitiba - Paraná
S: Brazil
N: Kumar Gala
-E: kumar.gala@freescale.com
+E: galak@kernel.crashing.org
D: Embedded PowerPC 6xx/7xx/74xx/82xx/83xx/85xx support
S: Austin, Texas 78729
S: USA
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 7018f5c6a44..1c955883cf5 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -20,6 +20,12 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
# +--> DIR=file (htmldocs)
# +--> man/ (mandocs)
+
+# for PDF and PS output you can choose between xmlto and docbook-utils tools
+PDF_METHOD = $(prefer-db2x)
+PS_METHOD = $(prefer-db2x)
+
+
###
# The targets that may be used.
.PHONY: xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs
@@ -93,27 +99,39 @@ C-procfs-example = procfs_example.xml
C-procfs-example2 = $(addprefix $(obj)/,$(C-procfs-example))
$(obj)/procfs-guide.xml: $(C-procfs-example2)
-###
-# Rules to generate postscript, PDF and HTML
-# db2html creates a directory. Generate a html file used for timestamp
+notfoundtemplate = echo "*** You have to install docbook-utils or xmlto ***"; \
+ exit 1
+db2xtemplate = db2TYPE -o $(dir $@) $<
+xmltotemplate = xmlto TYPE $(XMLTOFLAGS) -o $(dir $@) $<
+
+# determine which methods are available
+ifeq ($(shell which db2ps >/dev/null 2>&1 && echo found),found)
+ use-db2x = db2x
+ prefer-db2x = db2x
+else
+ use-db2x = notfound
+ prefer-db2x = $(use-xmlto)
+endif
+ifeq ($(shell which xmlto >/dev/null 2>&1 && echo found),found)
+ use-xmlto = xmlto
+ prefer-xmlto = xmlto
+else
+ use-xmlto = notfound
+ prefer-xmlto = $(use-db2x)
+endif
-quiet_cmd_db2ps = XMLTO $@
- cmd_db2ps = xmlto ps $(XMLTOFLAGS) -o $(dir $@) $<
+# the commands, generated from the chosen template
+quiet_cmd_db2ps = PS $@
+ cmd_db2ps = $(subst TYPE,ps, $($(PS_METHOD)template))
%.ps : %.xml
- @(which xmlto > /dev/null 2>&1) || \
- (echo "*** You need to install xmlto ***"; \
- exit 1)
$(call cmd,db2ps)
-quiet_cmd_db2pdf = XMLTO $@
- cmd_db2pdf = xmlto pdf $(XMLTOFLAGS) -o $(dir $@) $<
+quiet_cmd_db2pdf = PDF $@
+ cmd_db2pdf = $(subst TYPE,pdf, $($(PDF_METHOD)template))
%.pdf : %.xml
- @(which xmlto > /dev/null 2>&1) || \
- (echo "*** You need to install xmlto ***"; \
- exit 1)
$(call cmd,db2pdf)
-quiet_cmd_db2html = XMLTO $@
+quiet_cmd_db2html = HTML $@
cmd_db2html = xmlto xhtml $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \
echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/index.html"> \
Goto $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
@@ -127,7 +145,7 @@ quiet_cmd_db2html = XMLTO $@
@if [ ! -z "$(PNG-$(basename $(notdir $@)))" ]; then \
cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi
-quiet_cmd_db2man = XMLTO $@
+quiet_cmd_db2man = MAN $@
cmd_db2man = if grep -q refentry $<; then xmlto man $(XMLTOFLAGS) -o $(obj)/man $< ; gzip -f $(obj)/man/*.9; fi
%.9 : %.xml
@(which xmlto > /dev/null 2>&1) || \
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index a8316b1a3e3..096aed62c32 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -68,9 +68,7 @@ X!Iinclude/linux/kobject.h
<sect1><title>Kernel utility functions</title>
!Iinclude/linux/kernel.h
-<!-- This needs to clean up to make kernel-doc happy
-X!Ekernel/printk.c
- -->
+!Ekernel/printk.c
!Ekernel/panic.c
!Ekernel/sys.c
!Ekernel/rcupdate.c
@@ -388,7 +386,7 @@ X!Edrivers/pnp/system.c
<chapter id="blkdev">
<title>Block Devices</title>
-!Edrivers/block/ll_rw_blk.c
+!Eblock/ll_rw_blk.c
</chapter>
<chapter id="miscdev">
diff --git a/Documentation/DocBook/stylesheet.xsl b/Documentation/DocBook/stylesheet.xsl
index 64be9f7ee3b..3ccce886c34 100644
--- a/Documentation/DocBook/stylesheet.xsl
+++ b/Documentation/DocBook/stylesheet.xsl
@@ -3,4 +3,5 @@
<param name="chunk.quietly">1</param>
<param name="funcsynopsis.style">ansi</param>
<param name="funcsynopsis.tabular.threshold">80</param>
+<!-- <param name="paper.type">A4</param> -->
</stylesheet>
diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt
index 8eedaa24f5e..23a1c2402bc 100644
--- a/Documentation/atomic_ops.txt
+++ b/Documentation/atomic_ops.txt
@@ -115,6 +115,33 @@ boolean is return which indicates whether the resulting counter value
is negative. It requires explicit memory barrier semantics around the
operation.
+Then:
+
+ int atomic_cmpxchg(atomic_t *v, int old, int new);
+
+This performs an atomic compare exchange operation on the atomic value v,
+with the given old and new values. Like all atomic_xxx operations,
+atomic_cmpxchg will only satisfy its atomicity semantics as long as all
+other accesses of *v are performed through atomic_xxx operations.
+
+atomic_cmpxchg requires explicit memory barriers around the operation.
+
+The semantics for atomic_cmpxchg are the same as those defined for 'cas'
+below.
+
+Finally:
+
+ int atomic_add_unless(atomic_t *v, int a, int u);
+
+If the atomic value v is not equal to u, this function adds a to v, and
+returns non zero. If v is equal to u then it returns zero. This is done as
+an atomic operation.
+
+atomic_add_unless requires explicit memory barriers around the operation.
+
+atomic_inc_not_zero, equivalent to atomic_add_unless(v, 1, 0)
+
+
If a caller requires memory barrier semantics around an atomic_t
operation which does not return a value, a set of interfaces are
defined which accomplish this:
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index 2d65c218216..0fe01c80548 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -1063,8 +1063,8 @@ Aside:
4.4 I/O contexts
I/O contexts provide a dynamically allocated per process data area. They may
be used in I/O schedulers, and in the block layer (could be used for IO statis,
-priorities for example). See *io_context in drivers/block/ll_rw_blk.c, and
-as-iosched.c for an example of usage in an i/o scheduler.
+priorities for example). See *io_context in block/ll_rw_blk.c, and as-iosched.c
+for an example of usage in an i/o scheduler.
5. Scalability related changes
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 429db4bf98e..24fe8edad30 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -140,3 +140,12 @@ What: EXPORT_SYMBOL(lookup_hash)
When: January 2006
Why: Too low-level interface. Use lookup_one_len or lookup_create instead.
Who: Christoph Hellwig <hch@lst.de>
+
+---------------------------
+
+What: START_ARRAY ioctl for md
+When: July 2006
+Files: drivers/md/md.c
+Why: Not reliable by design - can fail when most needed.
+ Alternatives exist
+Who: NeilBrown <neilb@suse.de>
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
index c563842ed80..05960f8a748 100644
--- a/Documentation/oops-tracing.txt
+++ b/Documentation/oops-tracing.txt
@@ -30,7 +30,12 @@ the disk is not available then you have three options :-
(1) Hand copy the text from the screen and type it in after the machine
has restarted. Messy but it is the only option if you have not
- planned for a crash.
+ planned for a crash. Alternatively, you can take a picture of
+ the screen with a digital camera - not nice, but better than
+ nothing. If the messages scroll off the top of the console, you
+ may find that booting with a higher resolution (eg, vga=791)
+ will allow you to read more of the text. (Caveat: This needs vesafb,
+ so won't help for 'early' oopses)
(2) Boot with a serial console (see Documentation/serial-console.txt),
run a null modem to a second machine and capture the output there
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index 2404099996a..330246ac80f 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -140,3 +140,4 @@
139 -> Prolink PixelView PlayTV MPEG2 PV-M4900
140 -> Osprey 440 [0070:ff07]
141 -> Asound Skyeye PCTV
+142 -> Sabrent TV-FM (bttv version)
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 57c9d631db5..efb708ec116 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -80,3 +80,5 @@
79 -> Sedna/MuchTV PC TV Cardbus TV/Radio (ITO25 Rev:2B)
80 -> ASUS Digimatrix TV [1043:0210]
81 -> Philips Tiger reference design [1131:2018]
+ 82 -> MSI TV@Anywhere plus [1462:6231]
+
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index ec840ca6f45..9d6544ea9f4 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -67,3 +67,4 @@ tuner=65 - Ymec TVF66T5-B/DFF
tuner=66 - LG NTSC (TALN mini series)
tuner=67 - Philips TD1316 Hybrid Tuner
tuner=68 - Philips TUV1236D ATSC/NTSC dual in
+tuner=69 - Tena TNF 5335 MF
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index ffe1c062088..e566affeed7 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -7,10 +7,12 @@ Machine check
mce=off disable machine check
mce=bootlog Enable logging of machine checks left over from booting.
- Disabled by default because some BIOS leave bogus ones.
+ Disabled by default on AMD because some BIOS leave bogus ones.
If your BIOS doesn't do that it's a good idea to enable though
to make sure you log even machine check events that result
- in a reboot.
+ in a reboot. On Intel systems it is enabled by default.
+ mce=nobootlog
+ Disable boot machine check logging.
mce=tolerancelevel (number)
0: always panic, 1: panic if deadlock possible,
2: try to avoid panic, 3: never panic or exit (for testing)
@@ -122,6 +124,9 @@ SMP
cpumask=MASK only use cpus with bits set in mask
+ additional_cpus=NUM Allow NUM more CPUs for hotplug
+ (defaults are specified by the BIOS or half the available CPUs)
+
NUMA
numa=off Only set up a single NUMA node spanning all memory.
@@ -188,6 +193,9 @@ Debugging
kstack=N Print that many words from the kernel stack in oops dumps.
+ pagefaulttrace Dump all page faults. Only useful for extreme debugging
+ and will create a lot of output.
+
Misc
noreplacement Don't replace instructions with more appropiate ones
diff --git a/Documentation/x86_64/mm.txt b/Documentation/x86_64/mm.txt
index 662b73971a6..133561b9cb0 100644
--- a/Documentation/x86_64/mm.txt
+++ b/Documentation/x86_64/mm.txt
@@ -6,7 +6,7 @@ Virtual memory map with 4 level page tables:
0000000000000000 - 00007fffffffffff (=47bits) user space, different per mm
hole caused by [48:63] sign extension
ffff800000000000 - ffff80ffffffffff (=40bits) guard hole
-ffff810000000000 - ffffc0ffffffffff (=46bits) direct mapping of phys. memory
+ffff810000000000 - ffffc0ffffffffff (=46bits) direct mapping of all phys. memory
ffffc10000000000 - ffffc1ffffffffff (=40bits) hole
ffffc20000000000 - ffffe1ffffffffff (=45bits) vmalloc/ioremap space
... unused hole ...
@@ -14,6 +14,10 @@ ffffffff80000000 - ffffffff82800000 (=40MB) kernel text mapping, from phys 0
... unused hole ...
ffffffff88000000 - fffffffffff00000 (=1919MB) module mapping space
+The direct mapping covers all memory in the system upto the highest
+memory address (this means in some cases it can also include PCI memory
+holes)
+
vmalloc space is lazily synchronized into the different PML4 pages of
the processes using the page fault handler, with init_level4_pgt as
reference.
diff --git a/MAINTAINERS b/MAINTAINERS
index 2313de23b0d..509927e40bb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1565,7 +1565,7 @@ S: Maintained
LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX
P: Kumar Gala
-M: kumar.gala@freescale.com
+M: galak@kernel.crashing.org
W: http://www.penguinppc.org/
L: linuxppc-embedded@ozlabs.org
S: Maintained
@@ -1873,6 +1873,16 @@ L: linux-tr@linuxtr.net
W: http://www.linuxtr.net
S: Maintained
+OMNIKEY CARDMAN 4000 DRIVER
+P: Harald Welte
+M: laforge@gnumonks.org
+S: Maintained
+
+OMNIKEY CARDMAN 4040 DRIVER
+P: Harald Welte
+M: laforge@gnumonks.org
+S: Maintained
+
ONSTREAM SCSI TAPE DRIVER
P: Willem Riede
M: osst@riede.org
diff --git a/Makefile b/Makefile
index 8560b79268b..c3191440095 100644
--- a/Makefile
+++ b/Makefile
@@ -1193,6 +1193,17 @@ else
__srctree = $(srctree)/
endif
+ifeq ($(ALLSOURCE_ARCHS),)
+ifeq ($(ARCH),um)
+ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH)
+else
+ALLINCLUDE_ARCHS := $(ARCH)
+endif
+else
+#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour.
+ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS)
+endif
+
ALLSOURCE_ARCHS := $(ARCH)
define all-sources
@@ -1208,7 +1219,7 @@ define all-sources
find $(__srctree)include $(RCS_FIND_IGNORE) \
\( -name config -o -name 'asm-*' \) -prune \
-o -name '*.[chS]' -print; \
- for ARCH in $(ALLSOURCE_ARCHS) ; do \
+ for ARCH in $(ALLINCLUDE_ARCHS) ; do \
find $(__srctree)include/asm-$${ARCH} $(RCS_FIND_IGNORE) \
-name '*.[chS]' -print; \
done ; \
diff --git a/README b/README
index 4ee7dda88ba..61c4f742923 100644
--- a/README
+++ b/README
@@ -81,6 +81,11 @@ INSTALLING the kernel:
failed patches (xxx# or xxx.rej). If there are, either you or me has
made a mistake.
+ Unlike patches for the 2.6.x kernels, patches for the 2.6.x.y kernels
+ (also known as the -stable kernels) are not incremental but instead apply
+ directly to the base 2.6.x kernel. Please read
+ Documentation/applying-patches.txt for more information.
+
Alternatively, the script patch-kernel can be used to automate this
process. It determines the current kernel version and applies any
patches found.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3df7cbd924a..4b15f5f1e25 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -652,25 +652,11 @@ endmenu
menu "Power management options"
-config PM
- bool "Power Management support"
- ---help---
- "Power Management" means that parts of your computer are shut
- off or put into a power conserving "sleep" mode if they are not
- being used. There are two competing standards for doing this: APM
- and ACPI. If you want to use either one, say Y here and then also
- to the requisite support below.
-
- Power Management is most important for battery powered laptop
- computers; if you have a laptop, check out the Linux Laptop home
- page on the WWW at <http://www.linux-on-laptops.com/> or
- Tuxmobil - Linux on Mobile Computers at <http://www.tuxmobil.org/>
- and the Battery Powered Linux mini-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+source "kernel/power/Kconfig"
config APM
tristate "Advanced Power Management Emulation"
- depends on PM
+ depends on PM_LEGACY
---help---
APM is a BIOS specification for saving power using several different
techniques. This is mostly useful for battery powered laptops with
@@ -702,6 +688,8 @@ menu "Device Drivers"
source "drivers/base/Kconfig"
+source "drivers/connector/Kconfig"
+
if ALIGNMENT_TRAP
source "drivers/mtd/Kconfig"
endif
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index 557e52c1c86..1b7eaab02b9 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -623,8 +623,6 @@ static int locomo_resume(struct platform_device *dev)
locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD);
spin_unlock_irqrestore(&lchip->lock, flags);
-
- dev->power.saved_state = NULL;
kfree(save);
return 0;
@@ -775,7 +773,7 @@ static int locomo_probe(struct platform_device *dev)
static int locomo_remove(struct platform_device *dev)
{
- struct locomo *lchip = platform__get_drvdata(dev);
+ struct locomo *lchip = platform_get_drvdata(dev);
if (lchip) {
__locomo_remove(lchip);
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 7b07acb03f3..39a6eea300a 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -1266,7 +1266,7 @@ static void __exit sa1111_exit(void)
bus_unregister(&sa1111_bus_type);
}
-module_init(sa1111_init);
+subsys_initcall(sa1111_init);
module_exit(sa1111_exit);
MODULE_DESCRIPTION("Intel Corporation SA1111 core driver");
diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c
index 32924c6714f..0c3cbd9a388 100644
--- a/arch/arm/common/scoop.c
+++ b/arch/arm/common/scoop.c
@@ -153,7 +153,7 @@ int __init scoop_probe(struct platform_device *pdev)
printk("Sharp Scoop Device found at 0x%08x -> 0x%08x\n",(unsigned int)mem->start,(unsigned int)devptr->base);
SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140;
- reset_scoop(dev);
+ reset_scoop(&pdev->dev);
SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff;
SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff;
diff --git a/arch/arm/kernel/apm.c b/arch/arm/kernel/apm.c
index b0bbd1e62eb..a2843be0555 100644
--- a/arch/arm/kernel/apm.c
+++ b/arch/arm/kernel/apm.c
@@ -20,6 +20,7 @@
#include <linux/apm_bios.h>
#include <linux/sched.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/list.h>
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index e55ea952f7a..373c0959bc2 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -256,9 +256,7 @@ void __cpuexit cpu_die(void)
asmlinkage void __cpuinit secondary_start_kernel(void)
{
struct mm_struct *mm = &init_mm;
- unsigned int cpu;
-
- cpu = smp_processor_id();
+ unsigned int cpu = smp_processor_id();
printk("CPU%u: Booted secondary processor\n", cpu);
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index dc09fd200c1..bbe6e4a0bf6 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -132,14 +132,14 @@ void __init footbridge_init_irq(void)
static struct map_desc fb_common_io_desc[] __initdata = {
{
.virtual = ARMCSR_BASE,
- .pfn = DC21285_ARMCSR_BASE,
+ .pfn = __phys_to_pfn(DC21285_ARMCSR_BASE),
.length = ARMCSR_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = XBUS_BASE,
.pfn = __phys_to_pfn(0x40000000),
.length = XBUS_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}
};
@@ -153,28 +153,28 @@ static struct map_desc ebsa285_host_io_desc[] __initdata = {
.virtual = PCIMEM_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_MEM),
.length = PCIMEM_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCICFG0_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_TYPE_0_CONFIG),
.length = PCICFG0_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCICFG1_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_TYPE_1_CONFIG),
.length = PCICFG1_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCIIACK_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_IACK),
.length = PCIIACK_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCIO_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_IO),
.length = PCIO_SIZE,
- .type = MT_DEVICE
- }
+ .type = MT_DEVICE,
+ },
#endif
};
@@ -187,13 +187,13 @@ static struct map_desc co285_io_desc[] __initdata = {
.virtual = PCIO_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_IO),
.length = PCIO_SIZE,
- .type = MT_DEVICE
+ .type = MT_DEVICE,
}, {
.virtual = PCIMEM_BASE,
.pfn = __phys_to_pfn(DC21285_PCI_MEM),
.length = PCIMEM_SIZE,
- .type = MT_DEVICE
- }
+ .type = MT_DEVICE,
+ },
#endif
};
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index e201aa9765b..cd506646801 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -72,6 +72,12 @@ config MACH_HUSKY
depends PXA_SHARPSL_25x
select PXA_SHARP_C7xx
+config MACH_AKITA
+ bool "Enable Sharp SL-1000 (Akita) Support"
+ depends PXA_SHARPSL_27x
+ select PXA_SHARP_Cxx00
+ select MACH_SPITZ
+
config MACH_SPITZ
bool "Enable Sharp Zaurus SL-3000 (Spitz) Support"
depends PXA_SHARPSL_27x
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index d210bd5032c..32526a0a6f8 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -11,8 +11,9 @@ obj-$(CONFIG_PXA27x) += pxa27x.o
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
-obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o
-obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o
+obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o corgi_pm.o
+obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o
+obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o
obj-$(CONFIG_MACH_POODLE) += poodle.o
obj-$(CONFIG_MACH_TOSA) += tosa.o
diff --git a/arch/arm/mach-pxa/akita-ioexp.c b/arch/arm/mach-pxa/akita-ioexp.c
new file mode 100644
index 00000000000..f6d73cc01f7
--- /dev/null
+++ b/arch/arm/mach-pxa/akita-ioexp.c
@@ -0,0 +1,223 @@
+/*
+ * Support for the Extra GPIOs on the Sharp SL-C1000 (Akita)
+ * (uses a Maxim MAX7310 8 Port IO Expander)
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <asm/arch/akita.h>
+
+/* MAX7310 Regiser Map */
+#define MAX7310_INPUT 0x00
+#define MAX7310_OUTPUT 0x01
+#define MAX7310_POLINV 0x02
+#define MAX7310_IODIR 0x03 /* 1 = Input, 0 = Output */
+#define MAX7310_TIMEOUT 0x04
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
+
+/* I2C Magic */
+I2C_CLIENT_INSMOD;
+
+static int max7310_write(struct i2c_client *client, int address, int data);
+static struct i2c_client max7310_template;
+static void akita_ioexp_work(void *private_);
+
+static struct device *akita_ioexp_device;
+static unsigned char ioexp_output_value = AKITA_IOEXP_IO_OUT;
+DECLARE_WORK(akita_ioexp, akita_ioexp_work, NULL);
+
+
+/*
+ * MAX7310 Access
+ */
+static int max7310_config(struct device *dev, int iomode, int polarity)
+{
+ int ret;
+ struct i2c_client *client = to_i2c_client(dev);
+
+ ret = max7310_write(client, MAX7310_POLINV, polarity);
+ if (ret < 0)
+ return ret;
+ ret = max7310_write(client, MAX7310_IODIR, iomode);
+ return ret;
+}
+
+static int max7310_set_ouputs(struct device *dev, int outputs)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return max7310_write(client, MAX7310_OUTPUT, outputs);
+}
+
+/*
+ * I2C Functions
+ */
+static int max7310_write(struct i2c_client *client, int address, int value)
+{
+ u8 data[2];
+
+ data[0] = address & 0xff;
+ data[1] = value & 0xff;
+
+ if (i2c_master_send(client, data, 2) == 2)
+ return 0;
+ return -1;
+}
+
+static int max7310_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *new_client;
+ int err;
+
+ if (!(new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
+ return -ENOMEM;
+
+ max7310_template.adapter = adapter;
+ max7310_template.addr = address;
+
+ memcpy(new_client, &max7310_template, sizeof(struct i2c_client));
+
+ if ((err = i2c_attach_client(new_client))) {
+ kfree(new_client);
+ return err;
+ }
+
+ max7310_config(&new_client->dev, AKITA_IOEXP_IO_DIR, 0);
+ akita_ioexp_device = &new_client->dev;
+ schedule_work(&akita_ioexp);
+
+ return 0;
+}
+
+static int max7310_attach_adapter(struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, max7310_detect);
+}
+
+static int max7310_detach_client(struct i2c_client *client)
+{
+ int err;
+
+ akita_ioexp_device = NULL;
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(client);
+ return 0;
+}
+
+static struct i2c_driver max7310_i2c_driver = {
+ .owner = THIS_MODULE,
+ .name = "akita-max7310",
+ .id = I2C_DRIVERID_AKITAIOEXP,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = max7310_attach_adapter,
+ .detach_client = max7310_detach_client,
+};
+
+static struct i2c_client max7310_template = {
+ name: "akita-max7310",
+ flags: I2C_CLIENT_ALLOW_USE,
+ driver: &max7310_i2c_driver,
+};
+
+void akita_set_ioexp(struct device *dev, unsigned char bit)
+{
+ ioexp_output_value |= bit;
+
+ if (akita_ioexp_device)
+ schedule_work(&akita_ioexp);
+ return;
+}
+
+void akita_reset_ioexp(struct device *dev, unsigned char bit)
+{
+ ioexp_output_value &= ~bit;
+
+ if (akita_ioexp_device)
+ schedule_work(&akita_ioexp);
+ return;
+}
+
+EXPORT_SYMBOL(akita_set_ioexp);
+EXPORT_SYMBOL(akita_reset_ioexp);
+
+static void akita_ioexp_work(void *private_)
+{
+ if (akita_ioexp_device)
+ max7310_set_ouputs(akita_ioexp_device, ioexp_output_value);
+}
+
+
+#ifdef CONFIG_PM
+static int akita_ioexp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ flush_scheduled_work();
+ return 0;
+}
+
+static int akita_ioexp_resume(struct platform_device *pdev)
+{
+ schedule_work(&akita_ioexp);
+ return 0;
+}
+#else
+#define akita_ioexp_suspend NULL
+#define akita_ioexp_resume NULL
+#endif
+
+static int __init akita_ioexp_probe(struct platform_device *pdev)
+{
+ return i2c_add_driver(&max7310_i2c_driver);
+}
+
+static int akita_ioexp_remove(struct platform_device *pdev)
+{
+ i2c_del_driver(&max7310_i2c_driver);
+ return 0;
+}
+
+static struct platform_driver akita_ioexp_driver = {
+ .probe = akita_ioexp_probe,
+ .remove = akita_ioexp_remove,
+ .suspend = akita_ioexp_suspend,
+ .resume = akita_ioexp_resume,
+ .driver = {
+ .name = "akita-ioexp",
+ },
+};
+
+static int __init akita_ioexp_init(void)
+{
+ return platform_driver_register(&akita_ioexp_driver);
+}
+
+static void __exit akita_ioexp_exit(void)
+{
+ platform_driver_unregister(&akita_ioexp_driver);
+}
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
+MODULE_DESCRIPTION("Akita IO-Expander driver");
+MODULE_LICENSE("GPL");
+
+fs_initcall(akita_ioexp_init);
+module_exit(akita_ioexp_exit);
+
diff --git a/arch/arm/mach-pxa/corgi_pm.c b/arch/arm/mach-pxa/corgi_pm.c
new file mode 100644
index 00000000000..599be14754f
--- /dev/null
+++ b/arch/arm/mach-pxa/corgi_pm.c
@@ -0,0 +1,228 @@
+/*
+ * Battery and Power Management code for the Sharp SL-C7xx
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/apm.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/hardware/scoop.h>
+
+#include <asm/arch/sharpsl.h>
+#include <asm/arch/corgi.h>
+#include <asm/arch/pxa-regs.h>
+#include "sharpsl.h"
+
+static void corgi_charger_init(void)
+{
+ pxa_gpio_mode(CORGI_GPIO_ADC_TEMP_ON | GPIO_OUT);
+ pxa_gpio_mode(CORGI_GPIO_CHRG_ON | GPIO_OUT);
+ pxa_gpio_mode(CORGI_GPIO_CHRG_UKN | GPIO_OUT);
+ pxa_gpio_mode(CORGI_GPIO_KEY_INT | GPIO_IN);
+}
+
+static void corgi_charge_led(int val)
+{
+ if (val == SHARPSL_LED_ERROR) {
+ dev_dbg(sharpsl_pm.dev, "Charge LED Error\n");
+ } else if (val == SHARPSL_LED_ON) {
+ dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
+ GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+ } else {
+ dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
+ GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE);
+ }
+}
+
+static void corgi_measure_temp(int on)
+{
+ if (on)
+ GPSR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
+ else
+ GPCR(CORGI_GPIO_ADC_TEMP_ON) = GPIO_bit(CORGI_GPIO_ADC_TEMP_ON);
+}
+
+static void corgi_charge(int on)
+{
+ if (on) {
+ if (machine_is_corgi() && (sharpsl_pm.flags & SHARPSL_SUSPENDED)) {
+ GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
+ GPSR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
+ } else {
+ GPSR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
+ GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
+ }
+ } else {
+ GPCR(CORGI_GPIO_CHRG_ON) = GPIO_bit(CORGI_GPIO_CHRG_ON);
+ GPCR(CORGI_GPIO_CHRG_UKN) = GPIO_bit(CORGI_GPIO_CHRG_UKN);
+ }
+}
+
+static void corgi_discharge(int on)
+{
+ if (on)
+ GPSR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
+ else
+ GPCR(CORGI_GPIO_DISCHARGE_ON) = GPIO_bit(CORGI_GPIO_DISCHARGE_ON);
+}
+
+static void corgi_presuspend(void)
+{
+ int i;
+ unsigned long wakeup_mask;
+
+ /* charging , so CHARGE_ON bit is HIGH during OFF. */
+ if (READ_GPIO_BIT(CORGI_GPIO_CHRG_ON))
+ PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_ON);
+ else
+ PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_ON);
+
+ if (READ_GPIO_BIT(CORGI_GPIO_LED_ORANGE))
+ PGSR0 |= GPIO_bit(CORGI_GPIO_LED_ORANGE);
+ else
+ PGSR0 &= ~GPIO_bit(CORGI_GPIO_LED_ORANGE);
+
+ if (READ_GPIO_BIT(CORGI_GPIO_CHRG_UKN))
+ PGSR1 |= GPIO_bit(CORGI_GPIO_CHRG_UKN);
+ else
+ PGSR1 &= ~GPIO_bit(CORGI_GPIO_CHRG_UKN);
+
+ /* Resume on keyboard power key */
+ PGSR2 = (PGSR2 & ~CORGI_GPIO_ALL_STROBE_BIT) | CORGI_GPIO_STROBE_BIT(0);
+
+ wakeup_mask = GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) | GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_CHRG_FULL);
+
+ if (!machine_is_corgi())
+ wakeup_mask |= GPIO_bit(CORGI_GPIO_MAIN_BAT_LOW);
+
+ PWER = wakeup_mask | PWER_RTC;
+ PRER = wakeup_mask;
+ PFER = wakeup_mask;
+
+ for (i = 0; i <=15; i++) {
+ if (PRER & PFER & GPIO_bit(i)) {
+ if (GPLR0 & GPIO_bit(i) )
+ PRER &= ~GPIO_bit(i);
+ else
+ PFER &= ~GPIO_bit(i);
+ }
+ }
+}
+
+static void corgi_postsuspend(void)
+{
+}
+
+/*
+ * Check what brought us out of the suspend.
+ * Return: 0 to sleep, otherwise wake
+ */
+static int corgi_should_wakeup(unsigned int resume_on_alarm)
+{
+ int is_resume = 0;
+
+ dev_dbg(sharpsl_pm.dev, "GPLR0 = %x,%x\n", GPLR0, PEDR);
+
+ if ((PEDR & GPIO_bit(CORGI_GPIO_AC_IN))) {
+ if (STATUS_AC_IN()) {
+ /* charge on */
+ dev_dbg(sharpsl_pm.dev, "ac insert\n");
+ sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
+ } else {
+ /* charge off */
+ dev_dbg(sharpsl_pm.dev, "ac remove\n");
+ CHARGE_LED_OFF();
+ CHARGE_OFF();
+ sharpsl_pm.charge_mode = CHRG_OFF;
+ }
+ }
+
+ if ((PEDR & GPIO_bit(CORGI_GPIO_CHRG_FULL)))
+ dev_dbg(sharpsl_pm.dev, "Charge full interrupt\n");
+
+ if (PEDR & GPIO_bit(CORGI_GPIO_KEY_INT))
+ is_resume |= GPIO_bit(CORGI_GPIO_KEY_INT);
+
+ if (PEDR & GPIO_bit(CORGI_GPIO_WAKEUP))
+ is_resume |= GPIO_bit(CORGI_GPIO_WAKEUP);
+
+ if (resume_on_alarm && (PEDR & PWER_RTC))
+ is_resume |= PWER_RTC;
+
+ dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);
+ return is_resume;
+}
+
+static unsigned long corgi_charger_wakeup(void)
+{
+ return ~GPLR0 & ( GPIO_bit(CORGI_GPIO_AC_IN) | GPIO_bit(CORGI_GPIO_KEY_INT) | GPIO_bit(CORGI_GPIO_WAKEUP) );
+}
+
+static int corgi_acin_status(void)
+{
+ return ((GPLR(CORGI_GPIO_AC_IN) & GPIO_bit(CORGI_GPIO_AC_IN)) != 0);
+}
+
+static struct sharpsl_charger_machinfo corgi_pm_machinfo = {
+ .init = corgi_charger_init,
+ .gpio_batlock = CORGI_GPIO_BAT_COVER,
+ .gpio_acin = CORGI_GPIO_AC_IN,
+ .gpio_batfull = CORGI_GPIO_CHRG_FULL,
+ .status_acin = corgi_acin_status,
+ .discharge = corgi_discharge,
+ .charge = corgi_charge,
+ .chargeled = corgi_charge_led,
+ .measure_temp = corgi_measure_temp,
+ .presuspend = corgi_presuspend,
+ .postsuspend = corgi_postsuspend,
+ .charger_wakeup = corgi_charger_wakeup,
+ .should_wakeup = corgi_should_wakeup,
+ .bat_levels = 40,
+ .bat_levels_noac = spitz_battery_levels_noac,
+ .bat_levels_acin = spitz_battery_levels_acin,
+ .status_high_acin = 188,
+ .status_low_acin = 178,
+ .status_high_noac = 185,
+ .status_low_noac = 175,
+};
+
+static struct platform_device *corgipm_device;
+
+static int __devinit corgipm_init(void)
+{
+ int ret;
+
+ corgipm_device = platform_device_alloc("sharpsl-pm", -1);
+ if (!corgipm_device)
+ return -ENOMEM;
+
+ corgipm_device->dev.platform_data = &corgi_pm_machinfo;
+ ret = platform_device_add(corgipm_device);
+
+ if (ret)
+ platform_device_put(corgipm_device);
+
+ return ret;
+}
+
+static void corgipm_exit(void)
+{
+ platform_device_unregister(corgipm_device);
+}
+
+module_init(corgipm_init);
+module_exit(corgipm_exit);
diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h
index 4879c0f7da7..b0c40a1d667 100644
--- a/arch/arm/mach-pxa/sharpsl.h
+++ b/arch/arm/mach-pxa/sharpsl.h
@@ -115,7 +115,7 @@ extern struct battery_thresh spitz_battery_levels_noac[];
#define CHARGE_LED_ERR() sharpsl_pm.machinfo->chargeled(SHARPSL_LED_ERROR)
#define DISCHARGE_ON() sharpsl_pm.machinfo->discharge(1)
#define DISCHARGE_OFF() sharpsl_pm.machinfo->discharge(0)
-#define STATUS_AC_IN sharpsl_pm.machinfo->status_acin()
-#define STATUS_BATT_LOCKED READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock)
-#define STATUS_CHRG_FULL READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull)
-#define STATUS_FATAL READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal)
+#define STATUS_AC_IN() sharpsl_pm.machinfo->status_acin()
+#define STATUS_BATT_LOCKED() READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batlock)
+#define STATUS_CHRG_FULL() READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_batfull)
+#define STATUS_FATAL() READ_GPIO_BIT(sharpsl_pm.machinfo->gpio_fatal)
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
index 6c9e871c53d..c10be00fb52 100644
--- a/arch/arm/mach-pxa/sharpsl_pm.c
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
@@ -21,7 +21,7 @@
#include <linux/apm_bios.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/device.h>
+#include <linux/platform_device.h>
#include <asm/hardware.h>
#include <asm/hardware/scoop.h>
@@ -45,15 +45,15 @@
#define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */
#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */
#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT 10 /* 10 msec */
-#define SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD 10 /* 10 msec */
+#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN 10 /* 10 msec */
#define SHARPSL_CHARGE_WAIT_TIME 15 /* 15 msec */
#define SHARPSL_CHARGE_CO_CHECK_TIME 5 /* 5 msec */
#define SHARPSL_CHARGE_RETRY_CNT 1 /* eqv. 10 min */
#define SHARPSL_CHARGE_ON_VOLT 0x99 /* 2.9V */
#define SHARPSL_CHARGE_ON_TEMP 0xe0 /* 2.9V */
-#define SHARPSL_CHARGE_ON_JKVAD_HIGH 0x9b /* 6V */
-#define SHARPSL_CHARGE_ON_JKVAD_LOW 0x34 /* 2V */
+#define SHARPSL_CHARGE_ON_ACIN_HIGH 0x9b /* 6V */
+#define SHARPSL_CHARGE_ON_ACIN_LOW 0x34 /* 2V */
#define SHARPSL_FATAL_ACIN_VOLT 182 /* 3.45V */
#define SHARPSL_FATAL_NOACIN_VOLT 170 /* 3.40V */
@@ -160,9 +160,10 @@ struct battery_thresh spitz_battery_levels_noac[] = {
/*
* Prototypes
*/
-static int sharpsl_read_MainBattery(void);
+static int sharpsl_read_main_battery(void);
static int sharpsl_off_charge_battery(void);
-static int sharpsl_check_battery(int mode);
+static int sharpsl_check_battery_temp(void);
+static int sharpsl_check_battery_voltage(void);
static int sharpsl_ac_check(void);
static int sharpsl_fatal_check(void);
static int sharpsl_average_value(int ad);
@@ -228,7 +229,7 @@ static void sharpsl_battery_thread(void *private_)
if (!sharpsl_pm.machinfo)
return;
- sharpsl_pm.battstat.ac_status = (!(STATUS_AC_IN) ? APM_AC_OFFLINE : APM_AC_ONLINE);
+ sharpsl_pm.battstat.ac_status = (STATUS_AC_IN() ? APM_AC_ONLINE : APM_AC_OFFLINE);
/* Corgi cannot confirm when battery fully charged so periodically kick! */
if (machine_is_corgi() && (sharpsl_pm.charge_mode == CHRG_ON)
@@ -236,7 +237,7 @@ static void sharpsl_battery_thread(void *private_)
schedule_work(&toggle_charger);
while(1) {
- voltage = sharpsl_read_MainBattery();
+ voltage = sharpsl_read_main_battery();
if (voltage > 0) break;
if (i++ > 5) {
voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
@@ -317,10 +318,10 @@ static void sharpsl_charge_toggle(void *private_)
{
dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
- if (STATUS_AC_IN == 0) {
+ if (STATUS_AC_IN() == 0) {
sharpsl_charge_off();
return;
- } else if ((sharpsl_check_battery(1) < 0) || (sharpsl_ac_check() < 0)) {
+ } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
sharpsl_charge_error();
return;
}
@@ -335,7 +336,7 @@ static void sharpsl_charge_toggle(void *private_)
static void sharpsl_ac_timer(unsigned long data)
{
- int acin = STATUS_AC_IN;
+ int acin = STATUS_AC_IN();
dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);
@@ -364,7 +365,7 @@ static void sharpsl_chrg_full_timer(unsigned long data)
sharpsl_pm.full_count++;
- if (STATUS_AC_IN == 0) {
+ if (STATUS_AC_IN() == 0) {
dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
if (sharpsl_pm.charge_mode == CHRG_ON)
sharpsl_charge_off();
@@ -399,12 +400,12 @@ static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp)
{
int is_fatal = 0;
- if (STATUS_BATT_LOCKED == 0) {
+ if (STATUS_BATT_LOCKED() == 0) {
dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
is_fatal = 1;
}
- if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL == 0)) {
+ if (sharpsl_pm.machinfo->gpio_fatal && (STATUS_FATAL() == 0)) {
dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
is_fatal = 1;
}
@@ -461,12 +462,12 @@ static int read_max1111(int channel)
| MAXCTRL_SGL | MAXCTRL_UNI | MAXCTRL_STR);
}
-static int sharpsl_read_MainBattery(void)
+static int sharpsl_read_main_battery(void)
{
return read_max1111(BATT_AD);
}
-static int sharpsl_read_Temp(void)
+static int sharpsl_read_temp(void)
{
int temp;
@@ -480,7 +481,7 @@ static int sharpsl_read_Temp(void)
return temp;
}
-static int sharpsl_read_jkvad(void)
+static int sharpsl_read_acin(void)
{
return read_max1111(JK_VAD);
}
@@ -522,16 +523,14 @@ static int get_select_val(int *val)
return (sum/3);
}
-/* mode 0 - Check temperature and voltage
- * 1 - Check temperature only */
-static int sharpsl_check_battery(int mode)
+static int sharpsl_check_battery_temp(void)
{
int val, i, buff[5];
/* Check battery temperature */
for (i=0; i<5; i++) {
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
- buff[i] = sharpsl_read_Temp();
+ buff[i] = sharpsl_read_temp();
}
val = get_select_val(buff);
@@ -539,8 +538,13 @@ static int sharpsl_check_battery(int mode)
dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
if (val > SHARPSL_CHARGE_ON_TEMP)
return -1;
- if (mode == 1)
- return 0;
+
+ return 0;
+}
+
+static int sharpsl_check_battery_voltage(void)
+{
+ int val, i, buff[5];
/* disable charge, enable discharge */
CHARGE_OFF();
@@ -552,7 +556,7 @@ static int sharpsl_check_battery(int mode)
/* Check battery voltage */
for (i=0; i<5; i++) {
- buff[i] = sharpsl_read_MainBattery();
+ buff[i] = sharpsl_read_main_battery();
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
}
@@ -575,14 +579,14 @@ static int sharpsl_ac_check(void)
int temp, i, buff[5];
for (i=0; i<5; i++) {
- buff[i] = sharpsl_read_jkvad();
- mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_JKVAD);
+ buff[i] = sharpsl_read_acin();
+ mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
}
temp = get_select_val(buff);
dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp);
- if ((temp > SHARPSL_CHARGE_ON_JKVAD_HIGH) || (temp < SHARPSL_CHARGE_ON_JKVAD_LOW)) {
+ if ((temp > SHARPSL_CHARGE_ON_ACIN_HIGH) || (temp < SHARPSL_CHARGE_ON_ACIN_LOW)) {
dev_err(sharpsl_pm.dev, "Error: AC check failed.\n");
return -1;
}
@@ -591,7 +595,7 @@ static int sharpsl_ac_check(void)
}
#ifdef CONFIG_PM
-static int sharpsl_pm_suspend(struct device *dev, pm_message_t state)
+static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
{
sharpsl_pm.flags |= SHARPSL_SUSPENDED;
flush_scheduled_work();
@@ -604,7 +608,7 @@ static int sharpsl_pm_suspend(struct device *dev, pm_message_t state)
return 0;
}
-static int sharpsl_pm_resume(struct device *dev)
+static int sharpsl_pm_resume(struct platform_device *pdev)
{
/* Clear the reset source indicators as they break the bootloader upon reboot */
RCSR = 0x0f;
@@ -622,7 +626,7 @@ static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable
dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
/* not charging and AC-IN! */
- if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (STATUS_AC_IN != 0)) {
+ if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (STATUS_AC_IN() != 0)) {
dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
sharpsl_pm.charge_mode = CHRG_OFF;
sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
@@ -671,7 +675,7 @@ static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enab
dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
}
- if ((STATUS_BATT_LOCKED == 0) || (sharpsl_fatal_check() < 0) )
+ if ((STATUS_BATT_LOCKED() == 0) || (sharpsl_fatal_check() < 0) )
{
dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
corgi_goto_sleep(alarm_time, alarm_enable, state);
@@ -711,7 +715,7 @@ static int sharpsl_fatal_check(void)
dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
/* Check AC-Adapter */
- acin = STATUS_AC_IN;
+ acin = STATUS_AC_IN();
if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
CHARGE_OFF();
@@ -725,7 +729,7 @@ static int sharpsl_fatal_check(void)
/* Check battery : check inserting battery ? */
for (i=0; i<5; i++) {
- buff[i] = sharpsl_read_MainBattery();
+ buff[i] = sharpsl_read_main_battery();
mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
}
@@ -739,7 +743,7 @@ static int sharpsl_fatal_check(void)
}
temp = get_select_val(buff);
- dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_read_MainBattery());
+ dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %d\n", acin, temp, sharpsl_read_main_battery());
if ((acin && (temp < SHARPSL_FATAL_ACIN_VOLT)) ||
(!acin && (temp < SHARPSL_FATAL_NOACIN_VOLT)))
@@ -771,7 +775,7 @@ static int sharpsl_off_charge_battery(void)
dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
/* AC Check */
- if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery(1) < 0))
+ if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
return sharpsl_off_charge_error();
/* Start Charging */
@@ -793,7 +797,7 @@ static int sharpsl_off_charge_battery(void)
dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
- if (sharpsl_check_battery(0) < 0)
+ if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
return sharpsl_off_charge_error();
CHARGE_OFF();
@@ -811,7 +815,7 @@ static int sharpsl_off_charge_battery(void)
/* Check for timeout */
if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
return 1;
- if (STATUS_CHRG_FULL) {
+ if (STATUS_CHRG_FULL()) {
dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occured. Retrying to check\n");
sharpsl_pm.full_count++;
CHARGE_OFF();
@@ -840,7 +844,7 @@ static int sharpsl_off_charge_battery(void)
sharpsl_pm.full_count++;
return 1;
}
- if (STATUS_CHRG_FULL) {
+ if (STATUS_CHRG_FULL()) {
dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
CHARGE_LED_OFF();
CHARGE_OFF();
@@ -886,13 +890,13 @@ static struct pm_ops sharpsl_pm_ops = {
.finish = pxa_pm_finish,
};
-static int __init sharpsl_pm_probe(struct device *dev)
+static int __init sharpsl_pm_probe(struct platform_device *pdev)
{
- if (!dev->platform_data)
+ if (!pdev->dev.platform_data)
return -EINVAL;
- sharpsl_pm.dev = dev;
- sharpsl_pm.machinfo = dev->platform_data;
+ sharpsl_pm.dev = &pdev->dev;
+ sharpsl_pm.machinfo = pdev->dev.platform_data;
sharpsl_pm.charge_mode = CHRG_OFF;
sharpsl_pm.flags = 0;
@@ -935,8 +939,8 @@ static int __init sharpsl_pm_probe(struct device *dev)
else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQT_RISING);
}
- device_create_file(dev, &dev_attr_battery_percentage);
- device_create_file(dev, &dev_attr_battery_voltage);
+ device_create_file(&pdev->dev, &dev_attr_battery_percentage);
+ device_create_file(&pdev->dev, &dev_attr_battery_voltage);
apm_get_power_status = sharpsl_apm_get_power_status;
@@ -947,12 +951,12 @@ static int __init sharpsl_pm_probe(struct device *dev)
return 0;
}
-static int sharpsl_pm_remove(struct device *dev)
+static int sharpsl_pm_remove(struct platform_device *pdev)
{
pm_set_ops(NULL);
- device_remove_file(dev, &dev_attr_battery_percentage);
- device_remove_file(dev, &dev_attr_battery_voltage);
+ device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
+ device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr);
free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr);
@@ -969,23 +973,24 @@ static int sharpsl_pm_remove(struct device *dev)
return 0;
}
-static struct device_driver sharpsl_pm_driver = {
- .name = "sharpsl-pm",
- .bus = &platform_bus_type,
+static struct platform_driver sharpsl_pm_driver = {
.probe = sharpsl_pm_probe,
.remove = sharpsl_pm_remove,
.suspend = sharpsl_pm_suspend,
.resume = sharpsl_pm_resume,
+ .driver = {
+ .name = "sharpsl-pm",
+ },
};
static int __devinit sharpsl_pm_init(void)
{
- return driver_register(&sharpsl_pm_driver);
+ return platform_driver_register(&sharpsl_pm_driver);
}
static void sharpsl_pm_exit(void)
{
- driver_unregister(&sharpsl_pm_driver);
+ platform_driver_unregister(&sharpsl_pm_driver);
}
late_initcall(sharpsl_pm_init);
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 4e9a699ee42..2df1b56615b 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -345,6 +345,16 @@ static void spitz_irda_transceiver_mode(struct device *dev, int mode)
reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_IR_ON);
}
+#ifdef CONFIG_MACH_AKITA
+static void akita_irda_transceiver_mode(struct device *dev, int mode)
+{
+ if (mode & IR_OFF)
+ akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
+ else
+ akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_IR_ON);
+}
+#endif
+
static struct pxaficp_platform_data spitz_ficp_platform_data = {
.transceiver_cap = IR_SIRMODE | IR_OFF,
.transceiver_mode = spitz_irda_transceiver_mode,
@@ -417,6 +427,32 @@ static void __init spitz_init(void)
platform_device_register(&spitzscoop2_device);
}
+#ifdef CONFIG_MACH_AKITA
+/*
+ * Akita IO Expander
+ */
+struct platform_device akitaioexp_device = {
+ .name = "akita-ioexp",
+ .id = -1,
+};
+
+static void __init akita_init(void)
+{
+ spitz_ficp_platform_data.transceiver_mode = akita_irda_transceiver_mode;
+
+ /* We just pretend the second element of the array doesn't exist */
+ spitz_pcmcia_config.num_devs = 1;
+ platform_scoop_config = &spitz_pcmcia_config;
+ spitz_bl_machinfo.set_bl_intensity = akita_bl_set_intensity;
+
+ platform_device_register(&akitaioexp_device);
+
+ spitzscoop_device.dev.parent = &akitaioexp_device.dev;
+ common_init();
+}
+#endif
+
+
static void __init fixup_spitz(struct machine_desc *desc,
struct tag *tags, char **cmdline, struct meminfo *mi)
{
@@ -452,3 +488,16 @@ MACHINE_START(BORZOI, "SHARP Borzoi")
.timer = &pxa_timer,
MACHINE_END
#endif
+
+#ifdef CONFIG_MACH_AKITA
+MACHINE_START(AKITA, "SHARP Akita")
+ .phys_ram = 0xa0000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .fixup = fixup_spitz,
+ .map_io = pxa_map_io,
+ .init_irq = pxa_init_irq,
+ .init_machine = akita_init,
+ .timer = &pxa_timer,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c
new file mode 100644
index 00000000000..3ce7486daa5
--- /dev/null
+++ b/arch/arm/mach-pxa/spitz_pm.c
@@ -0,0 +1,233 @@
+/*
+ * Battery and Power Management code for the Sharp SL-Cxx00
+ *
+ * Copyright (c) 2005 Richard Purdie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/apm.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+#include <asm/hardware/scoop.h>
+
+#include <asm/arch/sharpsl.h>
+#include <asm/arch/spitz.h>
+#include <asm/arch/pxa-regs.h>
+#include "sharpsl.h"
+
+static int spitz_last_ac_status;
+
+static void spitz_charger_init(void)
+{
+ pxa_gpio_mode(SPITZ_GPIO_KEY_INT | GPIO_IN);
+ pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN);
+}
+
+static void spitz_charge_led(int val)
+{
+ if (val == SHARPSL_LED_ERROR) {
+ dev_dbg(sharpsl_pm.dev, "Charge LED Error\n");
+ } else if (val == SHARPSL_LED_ON) {
+ dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+ } else {
+ dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE);
+ }
+}
+
+static void spitz_measure_temp(int on)
+{
+ if (on)
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_ADC_TEMP_ON);
+ else
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_ADC_TEMP_ON);
+}
+
+static void spitz_charge(int on)
+{
+ if (on) {
+ if (sharpsl_pm.flags & SHARPSL_SUSPENDED) {
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+ } else {
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+ }
+ } else {
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_B);
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CHRG_ON);
+ }
+}
+
+static void spitz_discharge(int on)
+{
+ if (on)
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_A);
+ else
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_JK_A);
+}
+
+/* HACK - For unknown reasons, accurate voltage readings are only made with a load
+ on the power bus which the green led on spitz provides */
+static void spitz_discharge1(int on)
+{
+ if (on)
+ set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+ else
+ reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN);
+}
+
+static void spitz_presuspend(void)
+{
+ spitz_last_ac_status = STATUS_AC_IN();
+
+ /* GPIO Sleep Register */
+ PGSR0 = 0x00144018;
+ PGSR1 = 0x00EF0000;
+ if (machine_is_akita()) {
+ PGSR2 = 0x2121C000;
+ PGSR3 = 0x00600400;
+ } else {
+ PGSR2 = 0x0121C000;
+ PGSR3 = 0x00600000;
+ }
+
+ PGSR0 &= ~SPITZ_GPIO_G0_STROBE_BIT;
+ PGSR1 &= ~SPITZ_GPIO_G1_STROBE_BIT;
+ PGSR2 &= ~SPITZ_GPIO_G2_STROBE_BIT;
+ PGSR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
+ PGSR2 |= GPIO_bit(SPITZ_GPIO_KEY_STROBE0);
+
+ pxa_gpio_mode(GPIO18_RDY|GPIO_OUT | GPIO_DFLT_HIGH);
+
+ PRER = GPIO_bit(SPITZ_GPIO_KEY_INT);
+ PFER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
+ PWER = GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET) | PWER_RTC;
+ PKWR = GPIO_bit(SPITZ_GPIO_SYNC) | GPIO_bit(SPITZ_GPIO_KEY_INT) | GPIO_bit(SPITZ_GPIO_RESET);
+ PKSR = 0xffffffff; // clear
+
+ /* nRESET_OUT Disable */
+ PSLR |= PSLR_SL_ROD;
+
+ /* Clear reset status */
+ RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
+
+ /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
+ PCFR = PCFR_GPR_EN | PCFR_OPDE;
+}
+
+static void spitz_postsuspend(void)
+{
+ pxa_gpio_mode(GPIO18_RDY_MD);
+ pxa_gpio_mode(10 | GPIO_IN);
+}
+
+static int spitz_should_wakeup(unsigned int resume_on_alarm)
+{
+ int is_resume = 0;
+ int acin = STATUS_AC_IN();
+
+ if (spitz_last_ac_status != acin) {
+ if (acin) {
+ /* charge on */
+ sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
+ dev_dbg(sharpsl_pm.dev, "AC Inserted\n");
+ } else {
+ /* charge off */
+ dev_dbg(sharpsl_pm.dev, "AC Removed\n");
+ CHARGE_LED_OFF();
+ CHARGE_OFF();
+ sharpsl_pm.charge_mode = CHRG_OFF;
+ }
+ spitz_last_ac_status = acin;
+ /* Return to suspend as this must be what we were woken for */
+ return 0;
+ }
+
+ if (PEDR & GPIO_bit(SPITZ_GPIO_KEY_INT))
+ is_resume |= GPIO_bit(SPITZ_GPIO_KEY_INT);
+
+ if (PKSR & GPIO_bit(SPITZ_GPIO_SYNC))
+ is_resume |= GPIO_bit(SPITZ_GPIO_SYNC);
+
+ if (resume_on_alarm && (PEDR & PWER_RTC))
+ is_resume |= PWER_RTC;
+
+ dev_dbg(sharpsl_pm.dev, "is_resume: %x\n",is_resume);
+ return is_resume;
+}
+
+static unsigned long spitz_charger_wakeup(void)
+{
+ return (~GPLR0 & GPIO_bit(SPITZ_GPIO_KEY_INT)) | (GPLR0 & GPIO_bit(SPITZ_GPIO_SYNC));
+}
+
+static int spitz_acin_status(void)
+{
+ return (((~GPLR(SPITZ_GPIO_AC_IN)) & GPIO_bit(SPITZ_GPIO_AC_IN)) != 0);
+}
+
+struct sharpsl_charger_machinfo spitz_pm_machinfo = {
+ .init = spitz_charger_init,
+ .gpio_batlock = SPITZ_GPIO_BAT_COVER,
+ .gpio_acin = SPITZ_GPIO_AC_IN,
+ .gpio_batfull = SPITZ_GPIO_CHRG_FULL,
+ .gpio_fatal = SPITZ_GPIO_FATAL_BAT,
+ .status_acin = spitz_acin_status,
+ .discharge = spitz_discharge,
+ .discharge1 = spitz_discharge1,
+ .charge = spitz_charge,
+ .chargeled = spitz_charge_led,
+ .measure_temp = spitz_measure_temp,
+ .presuspend = spitz_presuspend,
+ .postsuspend = spitz_postsuspend,
+ .charger_wakeup = spitz_charger_wakeup,
+ .should_wakeup = spitz_should_wakeup,
+ .bat_levels = 40,
+ .bat_levels_noac = spitz_battery_levels_noac,
+ .bat_levels_acin = spitz_battery_levels_acin,
+ .status_high_acin = 188,
+ .status_low_acin = 178,
+ .status_high_noac = 185,
+ .status_low_noac = 175,
+};
+
+static struct platform_device *spitzpm_device;
+
+static int __devinit spitzpm_init(void)
+{
+ int ret;
+
+ spitzpm_device = platform_device_alloc("sharpsl-pm", -1);
+ if (!spitzpm_device)
+ return -ENOMEM;
+
+ spitzpm_device->dev.platform_data = &spitz_pm_machinfo;
+ ret = platform_device_add(spitzpm_device);
+
+ if (ret)
+ platform_device_put(spitzpm_device);
+
+ return ret;
+}
+
+static void spitzpm_exit(void)
+{
+ platform_device_unregister(spitzpm_device);
+}
+
+module_init(spitzpm_init);
+module_exit(spitzpm_exit);
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index 1a1e8a119c3..712c3c24c95 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -14,6 +14,7 @@
#include <linux/config.h>
#include <linux/init.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/sysctl.h>
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index dbf90ad6eac..6004bb0795e 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -699,7 +699,7 @@ depends on PM && !X86_VISWS
config APM
tristate "APM (Advanced Power Management) BIOS support"
- depends on PM
+ depends on PM && PM_LEGACY
---help---
APM is a BIOS specification for saving power using several different
techniques. This is mostly useful for battery powered laptops with
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index b66c13c0cc0..f36677241ec 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -39,17 +39,14 @@
#ifdef CONFIG_X86_64
-static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
-}
extern void __init clustered_apic_check(void);
-static inline int ioapic_setup_disabled(void)
-{
- return 0;
-}
+extern int gsi_irq_sharing(int gsi);
#include <asm/proto.h>
+static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return 0; }
+
+
#else /* X86 */
#ifdef CONFIG_X86_LOCAL_APIC
@@ -57,6 +54,8 @@ static inline int ioapic_setup_disabled(void)
#include <mach_mpparse.h>
#endif /* CONFIG_X86_LOCAL_APIC */
+static inline int gsi_irq_sharing(int gsi) { return gsi; }
+
#endif /* X86 */
#define BAD_MADT_ENTRY(entry, end) ( \
@@ -459,7 +458,7 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
*irq = IO_APIC_VECTOR(gsi);
else
#endif
- *irq = gsi;
+ *irq = gsi_irq_sharing(gsi);
return 0;
}
@@ -543,7 +542,7 @@ acpi_scan_rsdp(unsigned long start, unsigned long length)
* RSDP signature.
*/
for (offset = 0; offset < length; offset += 16) {
- if (strncmp((char *)(start + offset), "RSD PTR ", sig_len))
+ if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len))
continue;
return (start + offset);
}
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 003548b8735..1e60acbed3c 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -218,6 +218,7 @@
#include <linux/time.h>
#include <linux/sched.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/smp.h>
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index 53a1681cd96..e344ef88cfc 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -206,9 +206,9 @@ static void __init init_amd(struct cpuinfo_x86 *c)
display_cacheinfo(c);
if (cpuid_eax(0x80000000) >= 0x80000008) {
- c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
- if (c->x86_num_cores & (c->x86_num_cores - 1))
- c->x86_num_cores = 1;
+ c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
+ if (c->x86_max_cores & (c->x86_max_cores - 1))
+ c->x86_max_cores = 1;
}
#ifdef CONFIG_X86_HT
@@ -217,15 +217,15 @@ static void __init init_amd(struct cpuinfo_x86 *c)
* distingush the cores. Assumes number of cores is a power
* of two.
*/
- if (c->x86_num_cores > 1) {
+ if (c->x86_max_cores > 1) {
int cpu = smp_processor_id();
unsigned bits = 0;
- while ((1 << bits) < c->x86_num_cores)
+ while ((1 << bits) < c->x86_max_cores)
bits++;
cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1);
phys_proc_id[cpu] >>= bits;
printk(KERN_INFO "CPU %d(%d) -> Core %d\n",
- cpu, c->x86_num_cores, cpu_core_id[cpu]);
+ cpu, c->x86_max_cores, cpu_core_id[cpu]);
}
#endif
}
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index c145fb30002..31e344b26ba 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -231,10 +231,10 @@ static void __init early_cpu_detect(void)
cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
c->x86 = (tfms >> 8) & 15;
c->x86_model = (tfms >> 4) & 15;
- if (c->x86 == 0xf) {
+ if (c->x86 == 0xf)
c->x86 += (tfms >> 20) & 0xff;
+ if (c->x86 >= 0x6)
c->x86_model += ((tfms >> 16) & 0xF) << 4;
- }
c->x86_mask = tfms & 15;
if (cap0 & (1<<19))
c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8;
@@ -333,7 +333,7 @@ void __devinit identify_cpu(struct cpuinfo_x86 *c)
c->x86_model = c->x86_mask = 0; /* So far unknown... */
c->x86_vendor_id[0] = '\0'; /* Unset */
c->x86_model_id[0] = '\0'; /* Unset */
- c->x86_num_cores = 1;
+ c->x86_max_cores = 1;
memset(&c->x86_capability, 0, sizeof c->x86_capability);
if (!have_cpuid_p()) {
@@ -443,52 +443,44 @@ void __devinit identify_cpu(struct cpuinfo_x86 *c)
void __devinit detect_ht(struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
- int index_msb, tmp;
+ int index_msb, core_bits;
int cpu = smp_processor_id();
+ cpuid(1, &eax, &ebx, &ecx, &edx);
+
+ c->apicid = phys_pkg_id((ebx >> 24) & 0xFF, 0);
+
if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
return;
- cpuid(1, &eax, &ebx, &ecx, &edx);
smp_num_siblings = (ebx & 0xff0000) >> 16;
if (smp_num_siblings == 1) {
printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
} else if (smp_num_siblings > 1 ) {
- index_msb = 31;
if (smp_num_siblings > NR_CPUS) {
printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
smp_num_siblings = 1;
return;
}
- tmp = smp_num_siblings;
- while ((tmp & 0x80000000 ) == 0) {
- tmp <<=1 ;
- index_msb--;
- }
- if (smp_num_siblings & (smp_num_siblings - 1))
- index_msb++;
+
+ index_msb = get_count_order(smp_num_siblings);
phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
phys_proc_id[cpu]);
- smp_num_siblings = smp_num_siblings / c->x86_num_cores;
+ smp_num_siblings = smp_num_siblings / c->x86_max_cores;
- tmp = smp_num_siblings;
- index_msb = 31;
- while ((tmp & 0x80000000) == 0) {
- tmp <<=1 ;
- index_msb--;
- }
+ index_msb = get_count_order(smp_num_siblings) ;
- if (smp_num_siblings & (smp_num_siblings - 1))
- index_msb++;
+ core_bits = get_count_order(c->x86_max_cores);
- cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb);
+ cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb) &
+ ((1 << core_bits) - 1);
- if (c->x86_num_cores > 1)
+ if (c->x86_max_cores > 1)
printk(KERN_INFO "CPU: Processor Core ID: %d\n",
cpu_core_id[cpu]);
}
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index 43601de0f63..5e2da704f0f 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -6,6 +6,7 @@
#include <linux/bitops.h>
#include <linux/smp.h>
#include <linux/thread_info.h>
+#include <linux/module.h>
#include <asm/processor.h>
#include <asm/msr.h>
@@ -157,7 +158,7 @@ static void __devinit init_intel(struct cpuinfo_x86 *c)
if ( p )
strcpy(c->x86_model_id, p);
- c->x86_num_cores = num_cpu_cores(c);
+ c->x86_max_cores = num_cpu_cores(c);
detect_ht(c);
@@ -264,5 +265,52 @@ __init int intel_cpu_init(void)
return 0;
}
+#ifndef CONFIG_X86_CMPXCHG
+unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
+{
+ u8 prev;
+ unsigned long flags;
+
+ /* Poor man's cmpxchg for 386. Unsuitable for SMP */
+ local_irq_save(flags);
+ prev = *(u8 *)ptr;
+ if (prev == old)
+ *(u8 *)ptr = new;
+ local_irq_restore(flags);
+ return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u8);
+
+unsigned long cmpxchg_386_u16(volatile void *ptr, u16 old, u16 new)
+{
+ u16 prev;
+ unsigned long flags;
+
+ /* Poor man's cmpxchg for 386. Unsuitable for SMP */
+ local_irq_save(flags);
+ prev = *(u16 *)ptr;
+ if (prev == old)
+ *(u16 *)ptr = new;
+ local_irq_restore(flags);
+ return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u16);
+
+unsigned long cmpxchg_386_u32(volatile void *ptr, u32 old, u32 new)
+{
+ u32 prev;
+ unsigned long flags;
+
+ /* Poor man's cmpxchg for 386. Unsuitable for SMP */
+ local_irq_save(flags);
+ prev = *(u32 *)ptr;
+ if (prev == old)
+ *(u32 *)ptr = new;
+ local_irq_restore(flags);
+ return prev;
+}
+EXPORT_SYMBOL(cmpxchg_386_u32);
+#endif
+
// arch_initcall(intel_cpu_init);
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index 4dc42a189ae..fbfd374aa33 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -293,29 +293,45 @@ static struct _cpuid4_info *cpuid4_info[NR_CPUS];
#ifdef CONFIG_SMP
static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
{
- struct _cpuid4_info *this_leaf;
+ struct _cpuid4_info *this_leaf, *sibling_leaf;
unsigned long num_threads_sharing;
-#ifdef CONFIG_X86_HT
- struct cpuinfo_x86 *c = cpu_data + cpu;
-#endif
+ int index_msb, i;
+ struct cpuinfo_x86 *c = cpu_data;
this_leaf = CPUID4_INFO_IDX(cpu, index);
num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing;
if (num_threads_sharing == 1)
cpu_set(cpu, this_leaf->shared_cpu_map);
-#ifdef CONFIG_X86_HT
- else if (num_threads_sharing == smp_num_siblings)
- this_leaf->shared_cpu_map = cpu_sibling_map[cpu];
- else if (num_threads_sharing == (c->x86_num_cores * smp_num_siblings))
- this_leaf->shared_cpu_map = cpu_core_map[cpu];
- else
- printk(KERN_DEBUG "Number of CPUs sharing cache didn't match "
- "any known set of CPUs\n");
-#endif
+ else {
+ index_msb = get_count_order(num_threads_sharing);
+
+ for_each_online_cpu(i) {
+ if (c[i].apicid >> index_msb ==
+ c[cpu].apicid >> index_msb) {
+ cpu_set(i, this_leaf->shared_cpu_map);
+ if (i != cpu && cpuid4_info[i]) {
+ sibling_leaf = CPUID4_INFO_IDX(i, index);
+ cpu_set(cpu, sibling_leaf->shared_cpu_map);
+ }
+ }
+ }
+ }
+}
+static void __devinit cache_remove_shared_cpu_map(unsigned int cpu, int index)
+{
+ struct _cpuid4_info *this_leaf, *sibling_leaf;
+ int sibling;
+
+ this_leaf = CPUID4_INFO_IDX(cpu, index);
+ for_each_cpu_mask(sibling, this_leaf->shared_cpu_map) {
+ sibling_leaf = CPUID4_INFO_IDX(sibling, index);
+ cpu_clear(cpu, sibling_leaf->shared_cpu_map);
+ }
}
#else
static void __init cache_shared_cpu_map_setup(unsigned int cpu, int index) {}
+static void __init cache_remove_shared_cpu_map(unsigned int cpu, int index) {}
#endif
static void free_cache_attributes(unsigned int cpu)
@@ -574,8 +590,10 @@ static void __cpuexit cache_remove_dev(struct sys_device * sys_dev)
unsigned int cpu = sys_dev->id;
unsigned long i;
- for (i = 0; i < num_cache_leaves; i++)
+ for (i = 0; i < num_cache_leaves; i++) {
+ cache_remove_shared_cpu_map(cpu, i);
kobject_unregister(&(INDEX_KOBJECT_PTR(cpu,i)->kobj));
+ }
kobject_unregister(cache_kobject[cpu]);
cpuid4_cache_sysfs_exit(cpu);
return;
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index dd4ebd6af7e..1e9db198c44 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -626,6 +626,14 @@ void __init mtrr_bp_init(void)
if (cpuid_eax(0x80000000) >= 0x80000008) {
u32 phys_addr;
phys_addr = cpuid_eax(0x80000008) & 0xff;
+ /* CPUID workaround for Intel 0F33/0F34 CPU */
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+ boot_cpu_data.x86 == 0xF &&
+ boot_cpu_data.x86_model == 0x3 &&
+ (boot_cpu_data.x86_mask == 0x3 ||
+ boot_cpu_data.x86_mask == 0x4))
+ phys_addr = 36;
+
size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
size_and_mask = ~size_or_mask & 0xfff00000;
} else if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR &&
diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
index 41b871ecf4b..e7921315ae9 100644
--- a/arch/i386/kernel/cpu/proc.c
+++ b/arch/i386/kernel/cpu/proc.c
@@ -94,12 +94,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if (c->x86_cache_size >= 0)
seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
#ifdef CONFIG_X86_HT
- if (c->x86_num_cores * smp_num_siblings > 1) {
+ if (c->x86_max_cores * smp_num_siblings > 1) {
seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]);
- seq_printf(m, "siblings\t: %d\n",
- c->x86_num_cores * smp_num_siblings);
+ seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[n]));
seq_printf(m, "core id\t\t: %d\n", cpu_core_id[n]);
- seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores);
+ seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
}
#endif
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index af809ccf5fb..0248e084017 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -21,6 +21,7 @@
#include <asm/hardirq.h>
#include <asm/nmi.h>
#include <asm/hw_irq.h>
+#include <asm/apic.h>
#include <mach_ipi.h>
@@ -147,6 +148,7 @@ static int crash_nmi_callback(struct pt_regs *regs, int cpu)
regs = &fixed_regs;
}
crash_save_this_cpu(regs, cpu);
+ disable_local_APIC();
atomic_dec(&waiting_for_crash_ipi);
/* Assume hlt works */
halt();
@@ -186,6 +188,7 @@ static void nmi_shootdown_cpus(void)
}
/* Leave the nmi callback set */
+ disable_local_APIC();
}
#else
static void nmi_shootdown_cpus(void)
@@ -210,5 +213,9 @@ void machine_crash_shutdown(struct pt_regs *regs)
/* Make a note of crashing cpu. Will be used in NMI callback.*/
crashing_cpu = smp_processor_id();
nmi_shootdown_cpus();
+ lapic_shutdown();
+#if defined(CONFIG_X86_IO_APIC)
+ disable_IO_APIC();
+#endif
crash_save_self(regs);
}
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 9e24f7b207e..e50b9315524 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -560,11 +560,10 @@ nmi_stack_fixup:
nmi_debug_stack_check:
cmpw $__KERNEL_CS,16(%esp)
jne nmi_stack_correct
- cmpl $debug - 1,(%esp)
- jle nmi_stack_correct
+ cmpl $debug,(%esp)
+ jb nmi_stack_correct
cmpl $debug_esp_fix_insn,(%esp)
- jle nmi_debug_stack_fixup
-nmi_debug_stack_fixup:
+ ja nmi_stack_correct
FIX_STACK(24,nmi_stack_correct, 1)
jmp nmi_stack_correct
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index bc5a9d97466..d16520da455 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -72,9 +72,11 @@ int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
/* Core ID of each logical CPU */
int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
+/* representing HT siblings of each logical CPU */
cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_sibling_map);
+/* representing HT and core siblings of each logical CPU */
cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_core_map);
@@ -442,35 +444,60 @@ static void __devinit smp_callin(void)
static int cpucount;
+/* representing cpus for which sibling maps can be computed */
+static cpumask_t cpu_sibling_setup_map;
+
static inline void
set_cpu_sibling_map(int cpu)
{
int i;
+ struct cpuinfo_x86 *c = cpu_data;
+
+ cpu_set(cpu, cpu_sibling_setup_map);
if (smp_num_siblings > 1) {
- for (i = 0; i < NR_CPUS; i++) {
- if (!cpu_isset(i, cpu_callout_map))
- continue;
- if (cpu_core_id[cpu] == cpu_core_id[i]) {
+ for_each_cpu_mask(i, cpu_sibling_setup_map) {
+ if (phys_proc_id[cpu] == phys_proc_id[i] &&
+ cpu_core_id[cpu] == cpu_core_id[i]) {
cpu_set(i, cpu_sibling_map[cpu]);
cpu_set(cpu, cpu_sibling_map[i]);
+ cpu_set(i, cpu_core_map[cpu]);
+ cpu_set(cpu, cpu_core_map[i]);
}
}
} else {
cpu_set(cpu, cpu_sibling_map[cpu]);
}
- if (current_cpu_data.x86_num_cores > 1) {
- for (i = 0; i < NR_CPUS; i++) {
- if (!cpu_isset(i, cpu_callout_map))
- continue;
- if (phys_proc_id[cpu] == phys_proc_id[i]) {
- cpu_set(i, cpu_core_map[cpu]);
- cpu_set(cpu, cpu_core_map[i]);
- }
- }
- } else {
+ if (current_cpu_data.x86_max_cores == 1) {
cpu_core_map[cpu] = cpu_sibling_map[cpu];
+ c[cpu].booted_cores = 1;
+ return;
+ }
+
+ for_each_cpu_mask(i, cpu_sibling_setup_map) {
+ if (phys_proc_id[cpu] == phys_proc_id[i]) {
+ cpu_set(i, cpu_core_map[cpu]);
+ cpu_set(cpu, cpu_core_map[i]);
+ /*
+ * Does this new cpu bringup a new core?
+ */
+ if (cpus_weight(cpu_sibling_map[cpu]) == 1) {
+ /*
+ * for each core in package, increment
+ * the booted_cores for this new cpu
+ */
+ if (first_cpu(cpu_sibling_map[i]) == i)
+ c[cpu].booted_cores++;
+ /*
+ * increment the core count for all
+ * the other cpus in this package
+ */
+ if (i != cpu)
+ c[i].booted_cores++;
+ } else if (i != cpu && !c[cpu].booted_cores)
+ c[cpu].booted_cores = c[i].booted_cores;
+ }
}
}
@@ -1095,11 +1122,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
current_thread_info()->cpu = 0;
smp_tune_scheduling();
- cpus_clear(cpu_sibling_map[0]);
- cpu_set(0, cpu_sibling_map[0]);
- cpus_clear(cpu_core_map[0]);
- cpu_set(0, cpu_core_map[0]);
+ set_cpu_sibling_map(0);
/*
* If we couldn't find an SMP configuration at boot time,
@@ -1278,15 +1302,24 @@ static void
remove_siblinginfo(int cpu)
{
int sibling;
+ struct cpuinfo_x86 *c = cpu_data;
+ for_each_cpu_mask(sibling, cpu_core_map[cpu]) {
+ cpu_clear(cpu, cpu_core_map[sibling]);
+ /*
+ * last thread sibling in this cpu core going down
+ */
+ if (cpus_weight(cpu_sibling_map[cpu]) == 1)
+ c[sibling].booted_cores--;
+ }
+
for_each_cpu_mask(sibling, cpu_sibling_map[cpu])
cpu_clear(cpu, cpu_sibling_map[sibling]);
- for_each_cpu_mask(sibling, cpu_core_map[cpu])
- cpu_clear(cpu, cpu_core_map[sibling]);
cpus_clear(cpu_sibling_map[cpu]);
cpus_clear(cpu_core_map[cpu]);
phys_proc_id[cpu] = BAD_APICID;
cpu_core_id[cpu] = BAD_APICID;
+ cpu_clear(cpu, cpu_sibling_setup_map);
}
int __cpu_disable(void)
diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c
index 8de658db814..52b3ed5d2cb 100644
--- a/arch/i386/kernel/srat.c
+++ b/arch/i386/kernel/srat.c
@@ -137,8 +137,8 @@ static void __init parse_memory_affinity_structure (char *sratp)
"enabled and removable" : "enabled" ) );
}
-#if MAX_NR_ZONES != 3
-#error "MAX_NR_ZONES != 3, chunk_to_zone requires review"
+#if MAX_NR_ZONES != 4
+#error "MAX_NR_ZONES != 4, chunk_to_zone requires review"
#endif
/* Take a chunk of pages from page frame cstart to cend and count the number
* of pages in each zone, returned via zones[].
diff --git a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c
index e42e46d3515..b9b6bd56b9b 100644
--- a/arch/i386/kernel/timers/timer_pit.c
+++ b/arch/i386/kernel/timers/timer_pit.c
@@ -25,8 +25,9 @@ static int __init init_pit(char* override)
{
/* check clock override */
if (override[0] && strncmp(override,"pit",3))
- printk(KERN_ERR "Warning: clock= override failed. Defaulting to PIT\n");
-
+ printk(KERN_ERR "Warning: clock= override failed. Defaulting "
+ "to PIT\n");
+ init_cpu_khz();
count_p = LATCH;
return 0;
}
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 542d9298da5..06e26f00623 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -28,6 +28,7 @@
#include <linux/proc_fs.h>
#include <linux/efi.h>
#include <linux/memory_hotplug.h>
+#include <linux/initrd.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -267,7 +268,7 @@ static void __init permanent_kmaps_init(pgd_t *pgd_base)
pkmap_page_table = pte;
}
-void __devinit free_new_highpage(struct page *page)
+static void __devinit free_new_highpage(struct page *page)
{
set_page_count(page, 1);
__free_page(page);
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 8796e12c56f..b76ce1fe2e7 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -58,6 +58,10 @@ config IA64_UNCACHED_ALLOCATOR
bool
select GENERIC_ALLOCATOR
+config ZONE_DMA_IS_DMA32
+ bool
+ default y
+
choice
prompt "System type"
default IA64_GENERIC
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index e92ea64d804..4305d2ba76f 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -202,12 +202,9 @@ default_idle (void)
{
local_irq_enable();
while (!need_resched()) {
- if (can_do_pal_halt) {
- local_irq_disable();
- if (!need_resched())
- safe_halt();
- local_irq_enable();
- } else
+ if (can_do_pal_halt)
+ safe_halt();
+ else
cpu_relax();
}
}
@@ -272,10 +269,14 @@ cpu_idle (void)
{
void (*mark_idle)(int) = ia64_mark_idle;
int cpu = smp_processor_id();
- set_thread_flag(TIF_POLLING_NRFLAG);
/* endless idle loop with no priority at all */
while (1) {
+ if (can_do_pal_halt)
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ else
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
if (!need_resched()) {
void (*idle)(void);
#ifdef CONFIG_SMP
diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S
index 9571a21d6ad..a1629194e3f 100644
--- a/arch/m68k/fpsp040/skeleton.S
+++ b/arch/m68k/fpsp040/skeleton.S
@@ -381,10 +381,8 @@ fpsp_done:
.Lnotkern:
SAVE_ALL_INT
GET_CURRENT(%d0)
- tstb %curptr@(TASK_NEEDRESCHED)
- jne ret_from_exception | deliver signals,
- | reschedule etc..
- RESTORE_ALL
+ | deliver signals, reschedule etc..
+ jra ret_from_exception
|
| mem_write --- write to user or supervisor address space
diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S
index 4ba2c74da93..b2dbdf5ee30 100644
--- a/arch/m68k/ifpsp060/iskeleton.S
+++ b/arch/m68k/ifpsp060/iskeleton.S
@@ -75,10 +75,8 @@ _060_isp_done:
.Lnotkern:
SAVE_ALL_INT
GET_CURRENT(%d0)
- tstb %curptr@(TASK_NEEDRESCHED)
- jne ret_from_exception | deliver signals,
- | reschedule etc..
- RESTORE_ALL
+ | deliver signals, reschedule etc..
+ jra ret_from_exception
|
| _060_real_chk():
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index cee3317b866..c787c5ba951 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -25,12 +25,8 @@ int main(void)
DEFINE(TASK_STATE, offsetof(struct task_struct, state));
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
- DEFINE(TASK_WORK, offsetof(struct task_struct, thread.work));
- DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, thread.work.need_resched));
- DEFINE(TASK_SYSCALL_TRACE, offsetof(struct task_struct, thread.work.syscall_trace));
- DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, thread.work.sigpending));
- DEFINE(TASK_NOTIFY_RESUME, offsetof(struct task_struct, thread.work.notify_resume));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+ DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
@@ -45,6 +41,10 @@ int main(void)
DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
+ /* offsets into the thread_info struct */
+ DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
+ DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
+
/* offsets into the pt_regs */
DEFINE(PT_D0, offsetof(struct pt_regs, d0));
DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 23ca60a4555..320fde05dc6 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -44,9 +44,7 @@
#include <asm/asm-offsets.h>
-.globl system_call, buserr, trap
-.globl resume, ret_from_exception
-.globl ret_from_signal
+.globl system_call, buserr, trap, resume
.globl inthandler, sys_call_table
.globl sys_fork, sys_clone, sys_vfork
.globl ret_from_interrupt, bad_interrupt
@@ -58,7 +56,7 @@ ENTRY(buserr)
movel %sp,%sp@- | stack frame pointer argument
bsrl buserr_c
addql #4,%sp
- jra ret_from_exception
+ jra .Lret_from_exception
ENTRY(trap)
SAVE_ALL_INT
@@ -66,7 +64,7 @@ ENTRY(trap)
movel %sp,%sp@- | stack frame pointer argument
bsrl trap_c
addql #4,%sp
- jra ret_from_exception
+ jra .Lret_from_exception
| After a fork we jump here directly from resume,
| so that %d1 contains the previous task
@@ -75,30 +73,31 @@ ENTRY(ret_from_fork)
movel %d1,%sp@-
jsr schedule_tail
addql #4,%sp
- jra ret_from_exception
+ jra .Lret_from_exception
-badsys:
- movel #-ENOSYS,%sp@(PT_D0)
- jra ret_from_exception
-
-do_trace:
+do_trace_entry:
movel #-ENOSYS,%sp@(PT_D0) | needed for strace
subql #4,%sp
SAVE_SWITCH_STACK
jbsr syscall_trace
RESTORE_SWITCH_STACK
addql #4,%sp
- movel %sp@(PT_ORIG_D0),%d1
- movel #-ENOSYS,%d0
- cmpl #NR_syscalls,%d1
- jcc 1f
- jbsr @(sys_call_table,%d1:l:4)@(0)
-1: movel %d0,%sp@(PT_D0) | save the return value
- subql #4,%sp | dummy return address
+ movel %sp@(PT_ORIG_D0),%d0
+ cmpl #NR_syscalls,%d0
+ jcs syscall
+badsys:
+ movel #-ENOSYS,%sp@(PT_D0)
+ jra ret_from_syscall
+
+do_trace_exit:
+ subql #4,%sp
SAVE_SWITCH_STACK
jbsr syscall_trace
+ RESTORE_SWITCH_STACK
+ addql #4,%sp
+ jra .Lret_from_exception
-ret_from_signal:
+ENTRY(ret_from_signal)
RESTORE_SWITCH_STACK
addql #4,%sp
/* on 68040 complete pending writebacks if any */
@@ -111,7 +110,7 @@ ret_from_signal:
addql #4,%sp
1:
#endif
- jra ret_from_exception
+ jra .Lret_from_exception
ENTRY(system_call)
SAVE_ALL_SYS
@@ -120,30 +119,34 @@ ENTRY(system_call)
| save top of frame
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
- tstb %curptr@(TASK_SYSCALL_TRACE)
- jne do_trace
+ | syscall trace?
+ tstb %curptr@(TASK_INFO+TINFO_FLAGS+2)
+ jmi do_trace_entry
cmpl #NR_syscalls,%d0
jcc badsys
+syscall:
jbsr @(sys_call_table,%d0:l:4)@(0)
movel %d0,%sp@(PT_D0) | save the return value
-
+ret_from_syscall:
|oriw #0x0700,%sr
- movel %curptr@(TASK_WORK),%d0
+ movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0
jne syscall_exit_work
1: RESTORE_ALL
syscall_exit_work:
btst #5,%sp@(PT_SR) | check if returning to kernel
bnes 1b | if so, skip resched, signals
- tstw %d0
- jeq do_signal_return
- tstb %d0
- jne do_delayed_trace
-
+ lslw #1,%d0
+ jcs do_trace_exit
+ jmi do_delayed_trace
+ lslw #8,%d0
+ jmi do_signal_return
pea resume_userspace
- jmp schedule
+ jra schedule
+
-ret_from_exception:
+ENTRY(ret_from_exception)
+.Lret_from_exception:
btst #5,%sp@(PT_SR) | check if returning to kernel
bnes 1f | if so, skip resched, signals
| only allow interrupts when we are really the last one on the
@@ -152,19 +155,18 @@ ret_from_exception:
andw #ALLOWINT,%sr
resume_userspace:
- movel %curptr@(TASK_WORK),%d0
- lsrl #8,%d0
+ moveb %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0
jne exit_work
1: RESTORE_ALL
exit_work:
| save top of frame
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
- tstb %d0
- jeq do_signal_return
-
+ lslb #1,%d0
+ jmi do_signal_return
pea resume_userspace
- jmp schedule
+ jra schedule
+
do_signal_return:
|andw #ALLOWINT,%sr
@@ -254,7 +256,7 @@ ret_from_interrupt:
/* check if we need to do software interrupts */
tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING
- jeq ret_from_exception
+ jeq .Lret_from_exception
pea ret_from_exception
jra do_softirq
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 7e54422685c..540638ca81f 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -109,7 +109,7 @@ static inline void singlestep_disable(struct task_struct *child)
{
unsigned long tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
put_reg(child, PT_SR, tmp);
- child->thread.work.delayed_trace = 0;
+ clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
}
/*
@@ -118,7 +118,7 @@ static inline void singlestep_disable(struct task_struct *child)
void ptrace_disable(struct task_struct *child)
{
singlestep_disable(child);
- child->thread.work.syscall_trace = 0;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
@@ -198,9 +198,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
goto out_eio;
if (request == PTRACE_SYSCALL)
- child->thread.work.syscall_trace = ~0;
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
else
- child->thread.work.syscall_trace = 0;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
singlestep_disable(child);
wake_up_process(child);
@@ -223,10 +223,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
if (!valid_signal(data))
goto out_eio;
- child->thread.work.syscall_trace = 0;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16);
put_reg(child, PT_SR, tmp);
- child->thread.work.delayed_trace = 1;
+ set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
child->exit_code = data;
/* give it a chance to run. */
@@ -288,9 +288,6 @@ out_eio:
asmlinkage void syscall_trace(void)
{
- if (!current->thread.work.delayed_trace &&
- !current->thread.work.syscall_trace)
- return;
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0));
/*
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index f85093b8d54..f4926315fb6 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -32,6 +32,7 @@
#include <linux/config.h>
#include <linux/init.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/jiffies.h>
diff --git a/arch/mips/au1000/common/usbdev.c b/arch/mips/au1000/common/usbdev.c
index 0b21bed7ee5..2cab7629702 100644
--- a/arch/mips/au1000/common/usbdev.c
+++ b/arch/mips/au1000/common/usbdev.c
@@ -348,7 +348,7 @@ endpoint_stall(endpoint_t * ep)
{
u32 cs;
- warn(__FUNCTION__);
+ warn("%s", __FUNCTION__);
cs = au_readl(ep->reg->ctrl_stat) | USBDEV_CS_STALL;
au_writel(cs, ep->reg->ctrl_stat);
@@ -360,7 +360,7 @@ endpoint_unstall(endpoint_t * ep)
{
u32 cs;
- warn(__FUNCTION__);
+ warn("%s", __FUNCTION__);
cs = au_readl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL;
au_writel(cs, ep->reg->ctrl_stat);
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index c523029674e..94df74bcc0e 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -261,7 +261,7 @@ config PPC_ISERIES
config EMBEDDED6xx
bool "Embedded 6xx/7xx/7xxx-based board"
- depends on PPC32
+ depends on PPC32 && BROKEN
config APUS
bool "Amiga-APUS"
@@ -305,7 +305,7 @@ config PPC_PMAC64
config PPC_PREP
bool " PowerPC Reference Platform (PReP) based machines"
- depends on PPC_MULTIPLATFORM && PPC32
+ depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
select PPC_I8259
select PPC_INDIRECT_PCI
default y
@@ -932,6 +932,7 @@ source "arch/powerpc/oprofile/Kconfig"
config KPROBES
bool "Kprobes (EXPERIMENTAL)"
+ depends on PPC64
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 5bc11bd36c1..d41ad2e675d 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -187,7 +187,7 @@ archprepare: checkbin
# Temporary hack until we have migrated to asm-powerpc
include/asm: arch/$(ARCH)/include/asm
-arch/$(ARCH)/include/asm:
+arch/$(ARCH)/include/asm: FORCE
$(Q)if [ ! -d arch/$(ARCH)/include ]; then mkdir -p arch/$(ARCH)/include; fi
$(Q)ln -fsn $(srctree)/include/asm-$(OLDARCH) arch/$(ARCH)/include/asm
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index 9f09dff9e11..913962c1dae 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -1,18 +1,33 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc4
-# Thu Oct 20 08:32:17 2005
+# Linux kernel version: 2.6.15-rc1
+# Mon Nov 14 15:27:00 2005
#
+CONFIG_PPC64=y
CONFIG_64BIT=y
+CONFIG_PPC_MERGE=y
CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC=y
CONFIG_EARLY_PRINTK=y
CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
-CONFIG_FORCE_MAX_ZONEORDER=13
+
+#
+# Processor support
+#
+# CONFIG_POWER4_ONLY is not set
+CONFIG_POWER3=y
+CONFIG_POWER4=y
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=128
#
# Code maturity level options
@@ -68,75 +83,103 @@ CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_KMOD=y
CONFIG_STOP_MACHINE=y
-CONFIG_SYSVIPC_COMPAT=y
+
+#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# Platform support
#
-# CONFIG_PPC_ISERIES is not set
CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_PPC_ISERIES is not set
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_APUS is not set
CONFIG_PPC_PSERIES=y
-# CONFIG_PPC_BPA is not set
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
-CONFIG_PPC=y
-CONFIG_PPC64=y
+# CONFIG_PPC_CELL is not set
CONFIG_PPC_OF=y
CONFIG_XICS=y
+# CONFIG_U3_DART is not set
CONFIG_MPIC=y
-CONFIG_ALTIVEC=y
-CONFIG_PPC_SPLPAR=y
-CONFIG_KEXEC=y
+CONFIG_PPC_RTAS=y
+CONFIG_RTAS_ERROR_LOGGING=y
+CONFIG_RTAS_PROC=y
+CONFIG_RTAS_FLASH=m
+# CONFIG_MMIO_NVRAM is not set
CONFIG_IBMVIO=y
-# CONFIG_U3_DART is not set
-# CONFIG_BOOTX_TEXT is not set
-# CONFIG_POWER4_ONLY is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Kernel options
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_BKL is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_IOMMU_VMERGE=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=128
+CONFIG_HOTPLUG_CPU=y
+CONFIG_KEXEC=y
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_PPC_SPLPAR=y
+CONFIG_EEH=y
+CONFIG_SCANLOG=m
+CONFIG_LPARCFG=y
+CONFIG_NUMA=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_FLATMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM_MANUAL=y
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_HAVE_MEMORY_PRESENT=y
# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_EXTREME=y
+# CONFIG_MEMORY_HOTPLUG is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
CONFIG_NODES_SPAN_OTHER_NODES=y
-CONFIG_NUMA=y
+# CONFIG_PPC_64K_PAGES is not set
CONFIG_SCHED_SMT=y
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-# CONFIG_PREEMPT_BKL is not set
-# CONFIG_HZ_100 is not set
-CONFIG_HZ_250=y
-# CONFIG_HZ_1000 is not set
-CONFIG_HZ=250
-CONFIG_EEH=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_PPC_RTAS=y
-CONFIG_RTAS_PROC=y
-CONFIG_RTAS_FLASH=m
-CONFIG_SCANLOG=m
-CONFIG_LPARCFG=y
-CONFIG_SECCOMP=y
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_HOTPLUG_CPU=y
CONFIG_PROC_DEVICETREE=y
# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
CONFIG_ISA_DMA_API=y
#
-# Bus Options
+# Bus options
#
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_I8259=y
+# CONFIG_PPC_INDIRECT_PCI is not set
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_LEGACY_PROC=y
@@ -156,6 +199,7 @@ CONFIG_HOTPLUG_PCI=m
# CONFIG_HOTPLUG_PCI_SHPC is not set
CONFIG_HOTPLUG_PCI_RPA=m
CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
+CONFIG_KERNEL_START=0xc000000000000000
#
# Networking
@@ -197,6 +241,10 @@ CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
CONFIG_NETFILTER_NETLINK=y
CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NETFILTER_NETLINK_LOG=m
@@ -299,6 +347,10 @@ CONFIG_LLC=y
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
CONFIG_NET_CLS_ROUTE=y
@@ -368,14 +420,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=65536
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -473,6 +517,7 @@ CONFIG_SCSI_ISCSI_ATTRS=m
#
# SCSI low-level drivers
#
+# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -559,6 +604,7 @@ CONFIG_DM_MULTIPATH_EMC=m
#
# Macintosh device drivers
#
+# CONFIG_WINDFARM is not set
#
# Network device support
@@ -645,7 +691,6 @@ CONFIG_IXGB=m
# CONFIG_IXGB_NAPI is not set
CONFIG_S2IO=m
# CONFIG_S2IO_NAPI is not set
-# CONFIG_2BUFF_MODE is not set
#
# Token Ring devices
@@ -674,6 +719,7 @@ CONFIG_PPP_ASYNC=m
CONFIG_PPP_SYNC_TTY=m
CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
CONFIG_PPPOE=m
# CONFIG_SLIP is not set
# CONFIG_NET_FC is not set
@@ -784,6 +830,8 @@ CONFIG_HVCS=m
#
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -801,6 +849,7 @@ CONFIG_MAX_RAW_DEVS=1024
# TPM devices
#
# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -852,6 +901,7 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -893,7 +943,6 @@ CONFIG_FB=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
CONFIG_FB_MACMODES=y
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
@@ -905,6 +954,7 @@ CONFIG_FB_OF=y
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
CONFIG_FB_MATROX=y
@@ -927,7 +977,6 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_CYBLA is not set
# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -936,6 +985,7 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
@@ -990,12 +1040,15 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
#
# USB Device Class drivers
#
-# CONFIG_USB_BLUETOOTH_TTY is not set
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
#
CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_DEBUG is not set
@@ -1106,6 +1159,7 @@ CONFIG_INFINIBAND_MTHCA=m
# CONFIG_INFINIBAND_MTHCA_DEBUG is not set
CONFIG_INFINIBAND_IPOIB=m
# CONFIG_INFINIBAND_IPOIB_DEBUG is not set
+# CONFIG_INFINIBAND_SRP is not set
#
# SN Devices
@@ -1288,10 +1342,25 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_UTF8 is not set
#
-# Profiling support
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+
+#
+# Instrumentation Support
#
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
+# CONFIG_KPROBES is not set
#
# Kernel hacking
@@ -1308,14 +1377,15 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUG_STACKOVERFLOW=y
-# CONFIG_KPROBES is not set
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
-# CONFIG_PPCDBG is not set
CONFIG_IRQSTACKS=y
+# CONFIG_BOOTX_TEXT is not set
#
# Security options
@@ -1355,17 +1425,3 @@ CONFIG_CRYPTO_TEST=m
#
# Hardware crypto devices
#
-
-#
-# Library routines
-#
-CONFIG_CRC_CCITT=m
-# CONFIG_CRC16 is not set
-CONFIG_CRC32=y
-CONFIG_LIBCRC32C=m
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=m
-CONFIG_TEXTSEARCH=y
-CONFIG_TEXTSEARCH_KMP=m
-CONFIG_TEXTSEARCH_BM=m
-CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 9a74b7ab03a..4970e3721a8 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -25,7 +25,7 @@ obj-$(CONFIG_PPC_OF) += of_device.o
procfs-$(CONFIG_PPC64) := proc_ppc64.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
rtaspci-$(CONFIG_PPC64) := rtas_pci.o
-obj-$(CONFIG_PPC_RTAS) += rtas.o $(rtaspci-y)
+obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y)
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
obj-$(CONFIG_LPARCFG) += lparcfg.o
@@ -49,12 +49,23 @@ extra-y += vmlinux.lds
obj-y += process.o init_task.o time.o \
prom.o traps.o setup-common.o
obj-$(CONFIG_PPC32) += entry_32.o setup_32.o misc_32.o systbl.o
-obj-$(CONFIG_PPC64) += misc_64.o
+obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o
obj-$(CONFIG_PPC_OF) += prom_init.o
obj-$(CONFIG_MODULES) += ppc_ksyms.o
obj-$(CONFIG_BOOTX_TEXT) += btext.o
obj-$(CONFIG_6xx) += idle_6xx.o
obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_KPROBES) += kprobes.o
+
+module-$(CONFIG_PPC64) += module_64.o
+obj-$(CONFIG_MODULES) += $(module-y)
+
+pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o pci_iommu.o \
+ pci_direct_iommu.o iomap.o
+obj-$(CONFIG_PCI) += $(pci64-y)
+
+kexec64-$(CONFIG_PPC64) += machine_kexec_64.o
+obj-$(CONFIG_KEXEC) += $(kexec64-y)
ifeq ($(CONFIG_PPC_ISERIES),y)
$(obj)/head_64.o: $(obj)/lparmap.s
@@ -62,11 +73,8 @@ AFLAGS_head_64.o += -I$(obj)
endif
else
-# stuff used from here for ARCH=ppc or ARCH=ppc64
+# stuff used from here for ARCH=ppc
smpobj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_PPC64) += traps.o process.o init_task.o time.o \
- setup-common.o $(smpobj-y)
-
endif
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 4550eb4f4fb..91538d2445b 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -270,13 +270,15 @@ int main(void)
DEFINE(TVAL64_TV_USEC, offsetof(struct timeval, tv_usec));
DEFINE(TVAL32_TV_SEC, offsetof(struct compat_timeval, tv_sec));
DEFINE(TVAL32_TV_USEC, offsetof(struct compat_timeval, tv_usec));
+ DEFINE(TSPC64_TV_SEC, offsetof(struct timespec, tv_sec));
+ DEFINE(TSPC64_TV_NSEC, offsetof(struct timespec, tv_nsec));
DEFINE(TSPC32_TV_SEC, offsetof(struct compat_timespec, tv_sec));
DEFINE(TSPC32_TV_NSEC, offsetof(struct compat_timespec, tv_nsec));
#else
DEFINE(TVAL32_TV_SEC, offsetof(struct timeval, tv_sec));
DEFINE(TVAL32_TV_USEC, offsetof(struct timeval, tv_usec));
- DEFINE(TSPEC32_TV_SEC, offsetof(struct timespec, tv_sec));
- DEFINE(TSPEC32_TV_NSEC, offsetof(struct timespec, tv_nsec));
+ DEFINE(TSPC32_TV_SEC, offsetof(struct timespec, tv_sec));
+ DEFINE(TSPC32_TV_NSEC, offsetof(struct timespec, tv_nsec));
#endif
/* timeval/timezone offsets for use by vdso */
DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest));
diff --git a/arch/ppc64/kernel/dma.c b/arch/powerpc/kernel/dma_64.c
index 7c3419656cc..7c3419656cc 100644
--- a/arch/ppc64/kernel/dma.c
+++ b/arch/powerpc/kernel/dma_64.c
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 5063c603fad..8d60fa99fc4 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -24,7 +24,7 @@
* Copyright 2002-2004 MontaVista Software, Inc.
* PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
* Copyright 2004 Freescale Semiconductor, Inc
- * PowerPC e500 modifications, Kumar Gala <kumar.gala@freescale.com>
+ * PowerPC e500 modifications, Kumar Gala <galak@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
diff --git a/arch/ppc64/kernel/iomap.c b/arch/powerpc/kernel/iomap.c
index 6160c8dbb7c..6160c8dbb7c 100644
--- a/arch/ppc64/kernel/iomap.c
+++ b/arch/powerpc/kernel/iomap.c
diff --git a/arch/ppc64/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 4d9b4388918..4d9b4388918 100644
--- a/arch/ppc64/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 4b7940693f3..5a71ed9612f 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -71,6 +71,11 @@
#include <asm/paca.h>
#endif
+int __irq_offset_value;
+#ifdef CONFIG_PPC32
+EXPORT_SYMBOL(__irq_offset_value);
+#endif
+
static int ppc_spurious_interrupts;
#if defined(CONFIG_PPC_ISERIES) && defined(CONFIG_SMP)
@@ -98,7 +103,6 @@ extern atomic_t ipi_sent;
EXPORT_SYMBOL(irq_desc);
int distribute_irqs = 1;
-int __irq_offset_value;
u64 ppc64_interrupt_controller;
#endif /* CONFIG_PPC64 */
@@ -311,7 +315,6 @@ void __init init_IRQ(void)
}
#ifdef CONFIG_PPC64
-#ifndef CONFIG_PPC_ISERIES
/*
* Virtual IRQ mapping code, used on systems with XICS interrupt controllers.
*/
@@ -420,8 +423,6 @@ unsigned int real_irq_to_virt_slowpath(unsigned int real_irq)
}
-#endif /* CONFIG_PPC_ISERIES */
-
#ifdef CONFIG_IRQSTACKS
struct thread_info *softirq_ctx[NR_CPUS];
struct thread_info *hardirq_ctx[NR_CPUS];
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 511af54e623..511af54e623 100644
--- a/arch/ppc64/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 1b3ba8a440a..9dda16ccde7 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -42,32 +42,6 @@
/* #define LPARCFG_DEBUG */
-/* find a better place for this function... */
-static void log_plpar_hcall_return(unsigned long rc, char *tag)
-{
- if (rc == 0) /* success, return */
- return;
-/* check for null tag ? */
- if (rc == H_Hardware)
- printk(KERN_INFO
- "plpar-hcall (%s) failed with hardware fault\n", tag);
- else if (rc == H_Function)
- printk(KERN_INFO
- "plpar-hcall (%s) failed; function not allowed\n", tag);
- else if (rc == H_Authority)
- printk(KERN_INFO
- "plpar-hcall (%s) failed; not authorized to this function\n",
- tag);
- else if (rc == H_Parameter)
- printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n",
- tag);
- else
- printk(KERN_INFO
- "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n",
- tag, rc);
-
-}
-
static struct proc_dir_entry *proc_ppc64_lparcfg;
#define LPARCFG_BUFF_SIZE 4096
@@ -172,6 +146,31 @@ static int lparcfg_data(struct seq_file *m, void *v)
/*
* Methods used to fetch LPAR data when running on a pSeries platform.
*/
+/* find a better place for this function... */
+static void log_plpar_hcall_return(unsigned long rc, char *tag)
+{
+ if (rc == 0) /* success, return */
+ return;
+/* check for null tag ? */
+ if (rc == H_Hardware)
+ printk(KERN_INFO
+ "plpar-hcall (%s) failed with hardware fault\n", tag);
+ else if (rc == H_Function)
+ printk(KERN_INFO
+ "plpar-hcall (%s) failed; function not allowed\n", tag);
+ else if (rc == H_Authority)
+ printk(KERN_INFO
+ "plpar-hcall (%s) failed; not authorized to this function\n",
+ tag);
+ else if (rc == H_Parameter)
+ printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n",
+ tag);
+ else
+ printk(KERN_INFO
+ "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n",
+ tag, rc);
+
+}
/*
* H_GET_PPP hcall returns info in 4 parms.
diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec_64.c
index 07ea03598c0..97c51e452be 100644
--- a/arch/ppc64/kernel/machine_kexec.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -185,8 +185,8 @@ void kexec_copy_flush(struct kimage *image)
*/
void kexec_smp_down(void *arg)
{
- if (ppc_md.cpu_irq_down)
- ppc_md.cpu_irq_down(1);
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(0, 1);
local_irq_disable();
kexec_smp_wait();
@@ -233,8 +233,8 @@ static void kexec_prepare_cpus(void)
}
/* after we tell the others to go down */
- if (ppc_md.cpu_irq_down)
- ppc_md.cpu_irq_down(0);
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(0, 0);
put_cpu();
@@ -255,8 +255,8 @@ static void kexec_prepare_cpus(void)
* UP to an SMP kernel.
*/
smp_release_cpus();
- if (ppc_md.cpu_irq_down)
- ppc_md.cpu_irq_down(0);
+ if (ppc_md.kexec_cpu_down)
+ ppc_md.kexec_cpu_down(0, 0);
local_irq_disable();
}
@@ -305,3 +305,54 @@ void machine_kexec(struct kimage *image)
ppc_md.hpte_clear_all);
/* NOTREACHED */
}
+
+/* Values we need to export to the second kernel via the device tree. */
+static unsigned long htab_base, htab_size, kernel_end;
+
+static struct property htab_base_prop = {
+ .name = "linux,htab-base",
+ .length = sizeof(unsigned long),
+ .value = (unsigned char *)&htab_base,
+};
+
+static struct property htab_size_prop = {
+ .name = "linux,htab-size",
+ .length = sizeof(unsigned long),
+ .value = (unsigned char *)&htab_size,
+};
+
+static struct property kernel_end_prop = {
+ .name = "linux,kernel-end",
+ .length = sizeof(unsigned long),
+ .value = (unsigned char *)&kernel_end,
+};
+
+static void __init export_htab_values(void)
+{
+ struct device_node *node;
+
+ node = of_find_node_by_path("/chosen");
+ if (!node)
+ return;
+
+ kernel_end = __pa(_end);
+ prom_add_property(node, &kernel_end_prop);
+
+ /* On machines with no htab htab_address is NULL */
+ if (NULL == htab_address)
+ goto out;
+
+ htab_base = __pa(htab_address);
+ prom_add_property(node, &htab_base_prop);
+
+ htab_size = 1UL << ppc64_pft_size;
+ prom_add_property(node, &htab_size_prop);
+
+ out:
+ of_node_put(node);
+}
+
+void __init kexec_setup(void)
+{
+ export_htab_values();
+}
diff --git a/arch/ppc64/kernel/module.c b/arch/powerpc/kernel/module_64.c
index 928b8581fcb..928b8581fcb 100644
--- a/arch/ppc64/kernel/module.c
+++ b/arch/powerpc/kernel/module_64.c
diff --git a/arch/ppc64/kernel/pci.c b/arch/powerpc/kernel/pci_64.c
index 3cef1b8f57f..3cef1b8f57f 100644
--- a/arch/ppc64/kernel/pci.c
+++ b/arch/powerpc/kernel/pci_64.c
diff --git a/arch/ppc64/kernel/pci_direct_iommu.c b/arch/powerpc/kernel/pci_direct_iommu.c
index e1a32f802c0..e1a32f802c0 100644
--- a/arch/ppc64/kernel/pci_direct_iommu.c
+++ b/arch/powerpc/kernel/pci_direct_iommu.c
diff --git a/arch/ppc64/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index 12c4c9e9bbc..12c4c9e9bbc 100644
--- a/arch/ppc64/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
diff --git a/arch/ppc64/kernel/pci_iommu.c b/arch/powerpc/kernel/pci_iommu.c
index bdf15dbbf4f..bdf15dbbf4f 100644
--- a/arch/ppc64/kernel/pci_iommu.c
+++ b/arch/powerpc/kernel/pci_iommu.c
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 5dcf4ba05ee..59846b40d52 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -105,6 +105,13 @@ EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__strnlen_user);
+#ifndef __powerpc64__
+EXPORT_SYMBOL(__ide_mm_insl);
+EXPORT_SYMBOL(__ide_mm_outsw);
+EXPORT_SYMBOL(__ide_mm_insw);
+EXPORT_SYMBOL(__ide_mm_outsl);
+#endif
+
EXPORT_SYMBOL(_insb);
EXPORT_SYMBOL(_outsb);
EXPORT_SYMBOL(_insw);
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 6a5b468edb4..3bf968e7409 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1368,6 +1368,7 @@ prom_n_addr_cells(struct device_node* np)
/* No #address-cells property for the root node, default to 1 */
return 1;
}
+EXPORT_SYMBOL(prom_n_addr_cells);
int
prom_n_size_cells(struct device_node* np)
@@ -1383,6 +1384,7 @@ prom_n_size_cells(struct device_node* np)
/* No #size-cells property for the root node, default to 1 */
return 1;
}
+EXPORT_SYMBOL(prom_n_size_cells);
/**
* Work out the sense (active-low level / active-high edge)
diff --git a/arch/powerpc/kernel/rtas-rtc.c b/arch/powerpc/kernel/rtas-rtc.c
new file mode 100644
index 00000000000..7b948662704
--- /dev/null
+++ b/arch/powerpc/kernel/rtas-rtc.c
@@ -0,0 +1,105 @@
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+#include <asm/time.h>
+
+
+#define MAX_RTC_WAIT 5000 /* 5 sec */
+#define RTAS_CLOCK_BUSY (-2)
+unsigned long __init rtas_get_boot_time(void)
+{
+ int ret[8];
+ int error, wait_time;
+ unsigned long max_wait_tb;
+
+ max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
+ do {
+ error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
+ if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+ wait_time = rtas_extended_busy_delay_time(error);
+ /* This is boot time so we spin. */
+ udelay(wait_time*1000);
+ error = RTAS_CLOCK_BUSY;
+ }
+ } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+
+ if (error != 0 && printk_ratelimit()) {
+ printk(KERN_WARNING "error: reading the clock failed (%d)\n",
+ error);
+ return 0;
+ }
+
+ return mktime(ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
+}
+
+/* NOTE: get_rtc_time will get an error if executed in interrupt context
+ * and if a delay is needed to read the clock. In this case we just
+ * silently return without updating rtc_tm.
+ */
+void rtas_get_rtc_time(struct rtc_time *rtc_tm)
+{
+ int ret[8];
+ int error, wait_time;
+ unsigned long max_wait_tb;
+
+ max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
+ do {
+ error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
+ if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+ if (in_interrupt() && printk_ratelimit()) {
+ memset(&rtc_tm, 0, sizeof(struct rtc_time));
+ printk(KERN_WARNING "error: reading clock"
+ " would delay interrupt\n");
+ return; /* delay not allowed */
+ }
+ wait_time = rtas_extended_busy_delay_time(error);
+ msleep(wait_time);
+ error = RTAS_CLOCK_BUSY;
+ }
+ } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+
+ if (error != 0 && printk_ratelimit()) {
+ printk(KERN_WARNING "error: reading the clock failed (%d)\n",
+ error);
+ return;
+ }
+
+ rtc_tm->tm_sec = ret[5];
+ rtc_tm->tm_min = ret[4];
+ rtc_tm->tm_hour = ret[3];
+ rtc_tm->tm_mday = ret[2];
+ rtc_tm->tm_mon = ret[1] - 1;
+ rtc_tm->tm_year = ret[0] - 1900;
+}
+
+int rtas_set_rtc_time(struct rtc_time *tm)
+{
+ int error, wait_time;
+ unsigned long max_wait_tb;
+
+ max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
+ do {
+ error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL,
+ tm->tm_year + 1900, tm->tm_mon + 1,
+ tm->tm_mday, tm->tm_hour, tm->tm_min,
+ tm->tm_sec, 0);
+ if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
+ if (in_interrupt())
+ return 1; /* probably decrementer */
+ wait_time = rtas_extended_busy_delay_time(error);
+ msleep(wait_time);
+ error = RTAS_CLOCK_BUSY;
+ }
+ } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb));
+
+ if (error != 0 && printk_ratelimit())
+ printk(KERN_WARNING "error: setting the clock failed (%d)\n",
+ error);
+
+ return 0;
+}
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index c98cfcc9cd9..e5694335bf1 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -57,10 +57,6 @@ extern void power4_idle(void);
boot_infos_t *boot_infos;
struct ide_machdep_calls ppc_ide_md;
-/* XXX should go elsewhere */
-int __irq_offset_value;
-EXPORT_SYMBOL(__irq_offset_value);
-
int boot_cpuid;
EXPORT_SYMBOL_GPL(boot_cpuid);
int boot_cpuid_phys;
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index fdbd9f9122f..608fee7c7e2 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -59,6 +59,7 @@
#include <asm/firmware.h>
#include <asm/xmon.h>
#include <asm/udbg.h>
+#include <asm/kexec.h>
#include "setup.h"
@@ -415,6 +416,10 @@ void __init setup_system(void)
*/
unflatten_device_tree();
+#ifdef CONFIG_KEXEC
+ kexec_setup(); /* requires unflattened device tree. */
+#endif
+
/*
* Fill the ppc64_caches & systemcfg structures with informations
* retreived from the device-tree. Need to be called before
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 8bdf95b7e42..5a2eba60dd3 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -403,8 +403,6 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
ELF_NFPREG * sizeof(double)))
return 1;
- current->thread.fpscr.val = 0; /* turn off all fp exceptions */
-
#ifdef CONFIG_ALTIVEC
/* save altivec registers */
if (current->thread.used_vr) {
@@ -818,6 +816,9 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
goto badframe;
regs->link = (unsigned long) frame->tramp;
}
+
+ current->thread.fpscr.val = 0; /* turn off all fp exceptions */
+
if (put_user(regs->gpr[1], (u32 __user *)newsp))
goto badframe;
regs->gpr[1] = newsp;
@@ -1097,6 +1098,8 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
regs->link = (unsigned long) frame->mctx.tramp;
}
+ current->thread.fpscr.val = 0; /* turn off all fp exceptions */
+
if (put_user(regs->gpr[1], (u32 __user *)newsp))
goto badframe;
regs->gpr[1] = newsp;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 58194e15071..1decf278553 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -131,9 +131,6 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
flush_fp_to_thread(current);
- /* Make sure signal doesn't get spurrious FP exceptions */
- current->thread.fpscr.val = 0;
-
#ifdef CONFIG_ALTIVEC
err |= __put_user(v_regs, &sc->v_regs);
@@ -423,6 +420,9 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
if (err)
goto badframe;
+ /* Make sure signal handler doesn't get spurious FP exceptions */
+ current->thread.fpscr.val = 0;
+
/* Set up to return from userspace. */
if (vdso64_rt_sigtramp && current->thread.vdso_base) {
regs->link = current->thread.vdso_base + vdso64_rt_sigtramp;
diff --git a/arch/powerpc/kernel/vdso32/datapage.S b/arch/powerpc/kernel/vdso32/datapage.S
index a08c26e8783..f6b38472318 100644
--- a/arch/powerpc/kernel/vdso32/datapage.S
+++ b/arch/powerpc/kernel/vdso32/datapage.S
@@ -77,8 +77,9 @@ V_FUNCTION_BEGIN(__kernel_get_tbfreq)
mflr r12
.cfi_register lr,r12
bl __get_datapage@local
- lwz r3,CFG_TB_TICKS_PER_SEC(r3)
lwz r4,(CFG_TB_TICKS_PER_SEC + 4)(r3)
+ lwz r3,CFG_TB_TICKS_PER_SEC(r3)
mtlr r12
+ blr
.cfi_endproc
V_FUNCTION_END(__kernel_get_tbfreq)
diff --git a/arch/powerpc/kernel/vdso32/gettimeofday.S b/arch/powerpc/kernel/vdso32/gettimeofday.S
index aeb5fc9b87b..0a32a41d50b 100644
--- a/arch/powerpc/kernel/vdso32/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso32/gettimeofday.S
@@ -83,7 +83,7 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
/* Check for supported clock IDs */
cmpli cr0,r3,CLOCK_REALTIME
cmpli cr1,r3,CLOCK_MONOTONIC
- cror cr0,cr0,cr1
+ cror cr0*4+eq,cr0*4+eq,cr1*4+eq
bne cr0,99f
mflr r12 /* r12 saves lr */
@@ -91,7 +91,7 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
mr r10,r3 /* r10 saves id */
mr r11,r4 /* r11 saves tp */
bl __get_datapage@local /* get data page */
- mr r9, r3 /* datapage ptr in r9 */
+ mr r9,r3 /* datapage ptr in r9 */
beq cr1,50f /* if monotonic -> jump there */
/*
@@ -173,10 +173,14 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
add r4,r4,r7
lis r5,NSEC_PER_SEC@h
ori r5,r5,NSEC_PER_SEC@l
- cmpli cr0,r4,r5
+ cmpl cr0,r4,r5
+ cmpli cr1,r4,0
blt 1f
subf r4,r5,r4
addi r3,r3,1
+1: bge cr1,1f
+ addi r3,r3,-1
+ add r4,r4,r5
1: stw r3,TSPC32_TV_SEC(r11)
stw r4,TSPC32_TV_NSEC(r11)
@@ -210,7 +214,7 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
/* Check for supported clock IDs */
cmpwi cr0,r3,CLOCK_REALTIME
cmpwi cr1,r3,CLOCK_MONOTONIC
- cror cr0,cr0,cr1
+ cror cr0*4+eq,cr0*4+eq,cr1*4+eq
bne cr0,99f
li r3,0
diff --git a/arch/powerpc/kernel/vdso64/datapage.S b/arch/powerpc/kernel/vdso64/datapage.S
index e67eda0f8cd..6393e4137bc 100644
--- a/arch/powerpc/kernel/vdso64/datapage.S
+++ b/arch/powerpc/kernel/vdso64/datapage.S
@@ -80,5 +80,6 @@ V_FUNCTION_BEGIN(__kernel_get_tbfreq)
bl V_LOCAL_FUNC(__get_datapage)
ld r3,CFG_TB_TICKS_PER_SEC(r3)
mtlr r12
+ blr
.cfi_endproc
V_FUNCTION_END(__kernel_get_tbfreq)
diff --git a/arch/powerpc/kernel/vdso64/gettimeofday.S b/arch/powerpc/kernel/vdso64/gettimeofday.S
index d371c02a8c0..1a89094715c 100644
--- a/arch/powerpc/kernel/vdso64/gettimeofday.S
+++ b/arch/powerpc/kernel/vdso64/gettimeofday.S
@@ -1,4 +1,5 @@
-/*
+
+ /*
* Userland implementation of gettimeofday() for 64 bits processes in a
* ppc64 kernel for use in the vDSO
*
@@ -68,7 +69,7 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
/* Check for supported clock IDs */
cmpwi cr0,r3,CLOCK_REALTIME
cmpwi cr1,r3,CLOCK_MONOTONIC
- cror cr0,cr0,cr1
+ cror cr0*4+eq,cr0*4+eq,cr1*4+eq
bne cr0,99f
mflr r12 /* r12 saves lr */
@@ -84,16 +85,17 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */
- lis r7,0x3b9a /* r7 = 1000000000 = NSEC_PER_SEC */
- ori r7,r7,0xca00
+ lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */
+ ori r7,r7,16960
rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */
rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */
std r5,TSPC64_TV_SEC(r11) /* store sec in tv */
subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */
- mulld r0,r0,r7 /* nsec = (xsec * NSEC_PER_SEC) /
+ mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) /
* XSEC_PER_SEC
*/
rldicl r0,r0,44,20
+ mulli r0,r0,1000 /* nsec = usec * 1000 */
std r0,TSPC64_TV_NSEC(r11) /* store nsec in tp */
mtlr r12
@@ -106,15 +108,16 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
50: bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */
- lis r7,0x3b9a /* r7 = 1000000000 = NSEC_PER_SEC */
- ori r7,r7,0xca00
+ lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */
+ ori r7,r7,16960
rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */
rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */
subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */
- mulld r0,r0,r7 /* nsec = (xsec * NSEC_PER_SEC) /
+ mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) /
* XSEC_PER_SEC
*/
rldicl r6,r0,44,20
+ mulli r6,r6,1000 /* nsec = usec * 1000 */
/* now we must fixup using wall to monotonic. We need to snapshot
* that value and do the counter trick again. Fortunately, we still
@@ -123,8 +126,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
* can be used
*/
- lwz r4,WTOM_CLOCK_SEC(r9)
- lwz r7,WTOM_CLOCK_NSEC(r9)
+ lwa r4,WTOM_CLOCK_SEC(r3)
+ lwa r7,WTOM_CLOCK_NSEC(r3)
/* We now have our result in r4,r7. We create a fake dependency
* on that result and re-check the counter
@@ -144,10 +147,14 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
add r7,r7,r6
lis r9,NSEC_PER_SEC@h
ori r9,r9,NSEC_PER_SEC@l
- cmpli cr0,r7,r9
+ cmpl cr0,r7,r9
+ cmpli cr1,r7,0
blt 1f
subf r7,r9,r7
addi r4,r4,1
+1: bge cr1,1f
+ addi r4,r4,-1
+ add r7,r7,r9
1: std r4,TSPC64_TV_SEC(r11)
std r7,TSPC64_TV_NSEC(r11)
@@ -181,7 +188,7 @@ V_FUNCTION_BEGIN(__kernel_clock_getres)
/* Check for supported clock IDs */
cmpwi cr0,r3,CLOCK_REALTIME
cmpwi cr1,r3,CLOCK_MONOTONIC
- cror cr0,cr0,cr1
+ cror cr0*4+eq,cr0*4+eq,cr1*4+eq
bne cr0,99f
li r3,0
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index af9ca0eb6d5..5d581bb3aa1 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -1,5 +1,5 @@
/*
- * Modifications by Kumar Gala (kumar.gala@freescale.com) to support
+ * Modifications by Kumar Gala (galak@kernel.crashing.org) to support
* E500 Book E processors.
*
* Copyright 2004 Freescale Semiconductor, Inc
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index e2c95fcb805..4bd7b0a7099 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -200,6 +200,8 @@ void show_mem(void)
unsigned long flags;
pgdat_resize_lock(pgdat, &flags);
for (i = 0; i < pgdat->node_spanned_pages; i++) {
+ if (!pfn_valid(pgdat->node_start_pfn + i))
+ continue;
page = pgdat_page_nr(pgdat, i);
total++;
if (PageHighMem(page))
@@ -336,7 +338,7 @@ void __init mem_init(void)
struct page *page;
unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
- num_physpages = max_pfn; /* RAM is assumed contiguous */
+ num_physpages = lmb.memory.size >> PAGE_SHIFT;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
#ifdef CONFIG_NEED_MULTIPLE_NODES
@@ -348,11 +350,13 @@ void __init mem_init(void)
}
}
#else
- max_mapnr = num_physpages;
+ max_mapnr = max_pfn;
totalram_pages += free_all_bootmem();
#endif
for_each_pgdat(pgdat) {
for (i = 0; i < pgdat->node_spanned_pages; i++) {
+ if (!pfn_valid(pgdat->node_start_pfn + i))
+ continue;
page = pgdat_page_nr(pgdat, i);
if (PageReserved(page))
reservedpages++;
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index bd2cf133688..f72cf87364c 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -483,6 +483,7 @@ static void __init setup_nonnuma(void)
{
unsigned long top_of_ram = lmb_end_of_DRAM();
unsigned long total_ram = lmb_phys_mem_size();
+ unsigned int i;
printk(KERN_INFO "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
top_of_ram, total_ram);
@@ -490,7 +491,9 @@ static void __init setup_nonnuma(void)
(top_of_ram - total_ram) >> 20);
map_cpu_to_node(boot_cpuid, 0);
- add_region(0, 0, lmb_end_of_DRAM() >> PAGE_SHIFT);
+ for (i = 0; i < lmb.memory.cnt; ++i)
+ add_region(0, lmb.memory.region[i].base >> PAGE_SHIFT,
+ lmb_size_pages(&lmb.memory, i));
node_set_online(0);
}
diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c
index 86124a94c9a..26539cda602 100644
--- a/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ b/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -7,7 +7,7 @@
* Copyright (c) 2004 Freescale Semiconductor, Inc
*
* Author: Andy Fleming
- * Maintainer: Kumar Gala <Kumar.Gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@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
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 01090e9ce0c..a58daa15368 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -42,13 +42,6 @@
#include "irq.h"
#include "call_pci.h"
-/* This maps virtual irq numbers to real irqs */
-unsigned int virt_irq_to_real_map[NR_IRQS];
-
-/* The next available virtual irq number */
-/* Note: the pcnet32 driver assumes irq numbers < 2 aren't valid. :( */
-static int next_virtual_irq = 2;
-
static long Pci_Interrupt_Count;
static long Pci_Event_Count;
@@ -350,26 +343,14 @@ static hw_irq_controller iSeries_IRQ_handler = {
int __init iSeries_allocate_IRQ(HvBusNumber busNumber,
HvSubBusNumber subBusNumber, HvAgentId deviceId)
{
- unsigned int realirq, virtirq;
+ int virtirq;
+ unsigned int realirq;
u8 idsel = (deviceId >> 4);
u8 function = deviceId & 7;
- virtirq = next_virtual_irq++;
realirq = ((busNumber - 1) << 6) + ((idsel - 1) << 3) + function;
- virt_irq_to_real_map[virtirq] = realirq;
+ virtirq = virt_irq_create_mapping(realirq);
irq_desc[virtirq].handler = &iSeries_IRQ_handler;
return virtirq;
}
-
-int virt_irq_create_mapping(unsigned int real_irq)
-{
- BUG(); /* Don't call this on iSeries, yet */
-
- return 0;
-}
-
-void virt_irq_init(void)
-{
- return;
-}
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 6a29f301436..da26639190d 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -39,7 +39,6 @@
#include <asm/sections.h>
#include <asm/iommu.h>
#include <asm/firmware.h>
-#include <asm/systemcfg.h>
#include <asm/system.h>
#include <asm/time.h>
#include <asm/paca.h>
@@ -548,8 +547,6 @@ static unsigned long __init build_iSeries_Memory_Map(void)
*/
static void __init iSeries_setup_arch(void)
{
- unsigned procIx = get_paca()->lppaca.dyn_hv_phys_proc_index;
-
if (get_paca()->lppaca.shared_proc) {
ppc_md.idle_loop = iseries_shared_idle;
printk(KERN_INFO "Using shared processor idle loop\n");
@@ -565,9 +562,6 @@ static void __init iSeries_setup_arch(void)
itVpdAreas.xSlicMaxLogicalProcs);
printk("Max physical processors = %d\n",
itVpdAreas.xSlicMaxPhysicalProcs);
-
- _systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR;
- printk("Processor version = %x\n", _systemcfg->processor);
}
static void iSeries_show_cpuinfo(struct seq_file *m)
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index 5947b21a858..feb0a94e781 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -102,7 +102,7 @@ static unsigned long from_rtc_time(struct rtc_time *tm)
static unsigned long cuda_get_time(void)
{
struct adb_request req;
- unsigned long now;
+ unsigned int now;
if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
return 0;
@@ -113,7 +113,7 @@ static unsigned long cuda_get_time(void)
req.reply_len);
now = (req.reply[3] << 24) + (req.reply[4] << 16)
+ (req.reply[5] << 8) + req.reply[6];
- return now - RTC_OFFSET;
+ return ((unsigned long)now) - RTC_OFFSET;
}
#define cuda_get_rtc_time(tm) to_rtc_time(cuda_get_time(), (tm))
@@ -146,7 +146,7 @@ static int cuda_set_rtc_time(struct rtc_time *tm)
static unsigned long pmu_get_time(void)
{
struct adb_request req;
- unsigned long now;
+ unsigned int now;
if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
return 0;
@@ -156,7 +156,7 @@ static unsigned long pmu_get_time(void)
req.reply_len);
now = (req.reply[0] << 24) + (req.reply[1] << 16)
+ (req.reply[2] << 8) + req.reply[3];
- return now - RTC_OFFSET;
+ return ((unsigned long)now) - RTC_OFFSET;
}
#define pmu_get_rtc_time(tm) to_rtc_time(pmu_get_time(), (tm))
@@ -199,6 +199,7 @@ static unsigned long smu_get_time(void)
#define smu_set_rtc_time(tm, spin) 0
#endif
+/* Can't be __init, it's called when suspending and resuming */
unsigned long pmac_get_boot_time(void)
{
/* Get the time from the RTC, used only at boot time */
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index e7ca5b1f591..06d5ef50121 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -4,4 +4,7 @@ obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_SCANLOG) += scanlog.o
-obj-$(CONFIG_EEH) += eeh.o eeh_event.o
+obj-$(CONFIG_EEH) += eeh.o eeh_event.o
+
+obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
+obj-$(CONFIG_HVCS) += hvcserver.o
diff --git a/arch/ppc64/kernel/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index 138e128a388..138e128a388 100644
--- a/arch/ppc64/kernel/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
diff --git a/arch/ppc64/kernel/hvcserver.c b/arch/powerpc/platforms/pseries/hvcserver.c
index 4d584172055..4d584172055 100644
--- a/arch/ppc64/kernel/hvcserver.c
+++ b/arch/powerpc/platforms/pseries/hvcserver.c
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 31990829310..b9d9732b2e0 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -200,14 +200,12 @@ static void __init pSeries_setup_arch(void)
if (ppc64_interrupt_controller == IC_OPEN_PIC) {
ppc_md.init_IRQ = pSeries_init_mpic;
ppc_md.get_irq = mpic_get_irq;
- ppc_md.cpu_irq_down = mpic_teardown_this_cpu;
/* Allocate the mpic now, so that find_and_init_phbs() can
* fill the ISUs */
pSeries_setup_mpic();
} else {
ppc_md.init_IRQ = xics_init_IRQ;
ppc_md.get_irq = xics_get_irq;
- ppc_md.cpu_irq_down = xics_teardown_cpu;
}
#ifdef CONFIG_SMP
@@ -595,6 +593,27 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus)
return PCI_PROBE_NORMAL;
}
+#ifdef CONFIG_KEXEC
+static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
+{
+ /* Don't risk a hypervisor call if we're crashing */
+ if (!crash_shutdown) {
+ unsigned long vpa = __pa(&get_paca()->lppaca);
+
+ if (unregister_vpa(hard_smp_processor_id(), vpa)) {
+ printk("VPA deregistration of cpu %u (hw_cpu_id %d) "
+ "failed\n", smp_processor_id(),
+ hard_smp_processor_id());
+ }
+ }
+
+ if (ppc64_interrupt_controller == IC_OPEN_PIC)
+ mpic_teardown_this_cpu(secondary);
+ else
+ xics_teardown_cpu(secondary);
+}
+#endif
+
struct machdep_calls __initdata pSeries_md = {
.probe = pSeries_probe,
.setup_arch = pSeries_setup_arch,
@@ -617,4 +636,7 @@ struct machdep_calls __initdata pSeries_md = {
.check_legacy_ioport = pSeries_check_legacy_ioport,
.system_reset_exception = pSeries_system_reset_exception,
.machine_check_exception = pSeries_machine_check_exception,
+#ifdef CONFIG_KEXEC
+ .kexec_cpu_down = pseries_kexec_cpu_down,
+#endif
};
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index ef4356b29a9..c45a6ad5f3b 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -19,6 +19,7 @@
#include <linux/cpumask.h>
#include <linux/module.h>
#include <linux/sysrq.h>
+#include <linux/interrupt.h>
#include <asm/ptrace.h>
#include <asm/string.h>
diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S
index 5063c603fad..8d60fa99fc4 100644
--- a/arch/ppc/kernel/head_fsl_booke.S
+++ b/arch/ppc/kernel/head_fsl_booke.S
@@ -24,7 +24,7 @@
* Copyright 2002-2004 MontaVista Software, Inc.
* PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
* Copyright 2004 Freescale Semiconductor, Inc
- * PowerPC e500 modifications, Kumar Gala <kumar.gala@freescale.com>
+ * PowerPC e500 modifications, Kumar Gala <galak@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
diff --git a/arch/ppc/mm/fsl_booke_mmu.c b/arch/ppc/mm/fsl_booke_mmu.c
index af9ca0eb6d5..5d581bb3aa1 100644
--- a/arch/ppc/mm/fsl_booke_mmu.c
+++ b/arch/ppc/mm/fsl_booke_mmu.c
@@ -1,5 +1,5 @@
/*
- * Modifications by Kumar Gala (kumar.gala@freescale.com) to support
+ * Modifications by Kumar Gala (galak@kernel.crashing.org) to support
* E500 Book E processors.
*
* Copyright 2004 Freescale Semiconductor, Inc
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
index 98edc75f410..04bdc39bf47 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.c
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -3,7 +3,7 @@
*
* MPC834x SYS board specific routines
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor Inc.
*
@@ -73,12 +73,19 @@ mpc83xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
* A B C D
*/
{
- {PIRQA, PIRQB, PIRQC, PIRQD}, /* idsel 0x11 */
- {PIRQC, PIRQD, PIRQA, PIRQB}, /* idsel 0x12 */
- {PIRQD, PIRQA, PIRQB, PIRQC} /* idsel 0x13 */
+ {PIRQA, PIRQB, PIRQC, PIRQD}, /* idsel 0x11 */
+ {PIRQC, PIRQD, PIRQA, PIRQB}, /* idsel 0x12 */
+ {PIRQD, PIRQA, PIRQB, PIRQC}, /* idsel 0x13 */
+ {0, 0, 0, 0},
+ {PIRQA, PIRQB, PIRQC, PIRQD}, /* idsel 0x15 */
+ {PIRQD, PIRQA, PIRQB, PIRQC}, /* idsel 0x16 */
+ {PIRQC, PIRQD, PIRQA, PIRQB}, /* idsel 0x17 */
+ {PIRQB, PIRQC, PIRQD, PIRQA}, /* idsel 0x18 */
+ {0, 0, 0, 0}, /* idsel 0x19 */
+ {0, 0, 0, 0}, /* idsel 0x20 */
};
- const long min_idsel = 0x11, max_idsel = 0x13, irqs_per_slot = 4;
+ const long min_idsel = 0x11, max_idsel = 0x20, irqs_per_slot = 4;
return PCI_IRQ_TABLE_LOOKUP;
}
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h
index 58e44c04253..2e514d316fb 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.h
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.h
@@ -3,7 +3,7 @@
*
* MPC834X SYS common board definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor, Inc.
*
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c
index 7e952c1228c..c5cde97c6ef 100644
--- a/arch/ppc/platforms/85xx/mpc8540_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.c
@@ -3,7 +3,7 @@
*
* MPC8540ADS board specific routines
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.h b/arch/ppc/platforms/85xx/mpc8540_ads.h
index 3d05d7c4a93..e48ca3a9739 100644
--- a/arch/ppc/platforms/85xx/mpc8540_ads.h
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.h
@@ -3,7 +3,7 @@
*
* MPC8540ADS board definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/platforms/85xx/mpc8555_cds.h b/arch/ppc/platforms/85xx/mpc8555_cds.h
index e0e75568bc5..1a8e6c67355 100644
--- a/arch/ppc/platforms/85xx/mpc8555_cds.h
+++ b/arch/ppc/platforms/85xx/mpc8555_cds.h
@@ -3,7 +3,7 @@
*
* MPC8555CDS board definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
index 208433f1e93..8e39a551709 100644
--- a/arch/ppc/platforms/85xx/mpc8560_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -3,7 +3,7 @@
*
* MPC8560ADS board specific routines
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.h b/arch/ppc/platforms/85xx/mpc8560_ads.h
index 7df885d73e9..143ae7eefa7 100644
--- a/arch/ppc/platforms/85xx/mpc8560_ads.h
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.h
@@ -3,7 +3,7 @@
*
* MPC8540ADS board definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
index 16ad092d8a0..17ce48fe350 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.c
@@ -3,7 +3,7 @@
*
* MPC85xx ADS board common routines
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
index 84acf6e8d45..7b26bcc5d10 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
+++ b/arch/ppc/platforms/85xx/mpc85xx_ads_common.h
@@ -3,7 +3,7 @@
*
* MPC85XX ADS common board definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
index a21156967a5..d8991b88dc9 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -3,7 +3,7 @@
*
* MPC85xx CDS board specific routines
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor, Inc
*
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
index 12b292c6ae3..5b588cfd0e4 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h
@@ -3,7 +3,7 @@
*
* MPC85xx CDS board definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor, Inc
*
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c
index b4ee1707a83..45a5b81b4ed 100644
--- a/arch/ppc/platforms/85xx/sbc8560.c
+++ b/arch/ppc/platforms/85xx/sbc8560.c
@@ -3,7 +3,7 @@
*
* Wind River SBC8560 board specific routines
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
index 58884a63ebd..1e69b059316 100644
--- a/arch/ppc/platforms/pmac_feature.c
+++ b/arch/ppc/platforms/pmac_feature.c
@@ -2317,6 +2317,14 @@ static struct pmac_mb_def pmac_mb_defs[] = {
PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
},
+ { "PowerBook5,8", "PowerBook G4 15\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
+ { "PowerBook5,9", "PowerBook G4 17\"",
+ PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
+ PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+ },
{ "PowerBook6,1", "PowerBook G4 12\"",
PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,
PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
diff --git a/arch/ppc/platforms/pq2ads.c b/arch/ppc/platforms/pq2ads.c
index 6a1475c1e12..71c9fca1fe9 100644
--- a/arch/ppc/platforms/pq2ads.c
+++ b/arch/ppc/platforms/pq2ads.c
@@ -3,7 +3,7 @@
*
* PQ2ADS platform support
*
- * Author: Kumar Gala <kumar.gala@freescale.com>
+ * Author: Kumar Gala <galak@kernel.crashing.org>
* Derived from: est8260_setup.c by Allen Curtis
*
* Copyright 2004 Freescale Semiconductor, Inc.
diff --git a/arch/ppc/syslib/ipic.h b/arch/ppc/syslib/ipic.h
index 2b56a4fcf37..a7ce7da8785 100644
--- a/arch/ppc/syslib/ipic.h
+++ b/arch/ppc/syslib/ipic.h
@@ -3,7 +3,7 @@
*
* IPIC private definitions and structure.
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor, Inc
*
diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c
index f43fbf9a938..847df440998 100644
--- a/arch/ppc/syslib/mpc83xx_devices.c
+++ b/arch/ppc/syslib/mpc83xx_devices.c
@@ -3,7 +3,7 @@
*
* MPC83xx Device descriptions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/mpc83xx_sys.c b/arch/ppc/syslib/mpc83xx_sys.c
index da743446789..a1523989aff 100644
--- a/arch/ppc/syslib/mpc83xx_sys.c
+++ b/arch/ppc/syslib/mpc83xx_sys.c
@@ -3,7 +3,7 @@
*
* MPC83xx System descriptions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c
index 2ede677a0a5..69949d25565 100644
--- a/arch/ppc/syslib/mpc85xx_devices.c
+++ b/arch/ppc/syslib/mpc85xx_devices.c
@@ -3,7 +3,7 @@
*
* MPC85xx Device descriptions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/mpc85xx_sys.c b/arch/ppc/syslib/mpc85xx_sys.c
index cb68d8c5834..397cfbcce5e 100644
--- a/arch/ppc/syslib/mpc85xx_sys.c
+++ b/arch/ppc/syslib/mpc85xx_sys.c
@@ -3,7 +3,7 @@
*
* MPC85xx System descriptions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/mpc8xx_devices.c b/arch/ppc/syslib/mpc8xx_devices.c
index 2b5f0e70168..92dc98b36bd 100644
--- a/arch/ppc/syslib/mpc8xx_devices.c
+++ b/arch/ppc/syslib/mpc8xx_devices.c
@@ -3,7 +3,7 @@
*
* MPC8xx Device descriptions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug<vbordug@ru.mvista.com>
*
diff --git a/arch/ppc/syslib/mpc8xx_sys.c b/arch/ppc/syslib/mpc8xx_sys.c
index 3cc27d29e3a..d3c61752160 100644
--- a/arch/ppc/syslib/mpc8xx_sys.c
+++ b/arch/ppc/syslib/mpc8xx_sys.c
@@ -3,7 +3,7 @@
*
* MPC8xx System descriptions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug <vbordug@ru.mvista.com>
*
diff --git a/arch/ppc/syslib/ppc83xx_setup.c b/arch/ppc/syslib/ppc83xx_setup.c
index 4da168a6ad0..1b5fe9e398d 100644
--- a/arch/ppc/syslib/ppc83xx_setup.c
+++ b/arch/ppc/syslib/ppc83xx_setup.c
@@ -3,7 +3,7 @@
*
* MPC83XX common board code
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/ppc83xx_setup.h b/arch/ppc/syslib/ppc83xx_setup.h
index c766c1a5f78..a122a7322e5 100644
--- a/arch/ppc/syslib/ppc83xx_setup.h
+++ b/arch/ppc/syslib/ppc83xx_setup.h
@@ -3,7 +3,7 @@
*
* MPC83XX common board definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/ppc85xx_common.c b/arch/ppc/syslib/ppc85xx_common.c
index da841dacdc1..19ad537225e 100644
--- a/arch/ppc/syslib/ppc85xx_common.c
+++ b/arch/ppc/syslib/ppc85xx_common.c
@@ -3,7 +3,7 @@
*
* MPC85xx support routines
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/ppc85xx_common.h b/arch/ppc/syslib/ppc85xx_common.h
index 2c8f304441b..94edf32151d 100644
--- a/arch/ppc/syslib/ppc85xx_common.h
+++ b/arch/ppc/syslib/ppc85xx_common.h
@@ -3,7 +3,7 @@
*
* MPC85xx support routines
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c
index de2f9057657..1a47ff4b831 100644
--- a/arch/ppc/syslib/ppc85xx_setup.c
+++ b/arch/ppc/syslib/ppc85xx_setup.c
@@ -3,7 +3,7 @@
*
* MPC85XX common board code
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/ppc85xx_setup.h b/arch/ppc/syslib/ppc85xx_setup.h
index 6e6cfe162fa..e340b0545fb 100644
--- a/arch/ppc/syslib/ppc85xx_setup.h
+++ b/arch/ppc/syslib/ppc85xx_setup.h
@@ -3,7 +3,7 @@
*
* MPC85XX common board definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor Inc.
*
diff --git a/arch/ppc/syslib/ppc_sys.c b/arch/ppc/syslib/ppc_sys.c
index 603f0119081..c0b93c4191e 100644
--- a/arch/ppc/syslib/ppc_sys.c
+++ b/arch/ppc/syslib/ppc_sys.c
@@ -3,7 +3,7 @@
*
* PPC System library functions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor Inc.
* Copyright 2005 MontaVista, Inc. by Vitaly Bordug <vbordug@ru.mvista.com>
diff --git a/arch/ppc/syslib/pq2_devices.c b/arch/ppc/syslib/pq2_devices.c
index e960fe93532..6ff3aab82fc 100644
--- a/arch/ppc/syslib/pq2_devices.c
+++ b/arch/ppc/syslib/pq2_devices.c
@@ -3,7 +3,7 @@
*
* PQ2 Device descriptions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
diff --git a/arch/ppc/syslib/pq2_sys.c b/arch/ppc/syslib/pq2_sys.c
index 7b6c9ebdb9e..36d6e217994 100644
--- a/arch/ppc/syslib/pq2_sys.c
+++ b/arch/ppc/syslib/pq2_sys.c
@@ -3,7 +3,7 @@
*
* PQ2 System descriptions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
deleted file mode 100644
index 9d10c12e87f..00000000000
--- a/arch/ppc64/Kconfig
+++ /dev/null
@@ -1,520 +0,0 @@
-#
-# For a description of the syntax of this configuration file,
-# see Documentation/kbuild/kconfig-language.txt.
-#
-
-config 64BIT
- def_bool y
-
-config MMU
- bool
- default y
-
-config PPC_STD_MMU
- def_bool y
-
-config UID16
- bool
-
-config RWSEM_GENERIC_SPINLOCK
- bool
-
-config RWSEM_XCHGADD_ALGORITHM
- bool
- default y
-
-config GENERIC_CALIBRATE_DELAY
- bool
- default y
-
-config GENERIC_ISA_DMA
- bool
- default y
-
-config EARLY_PRINTK
- bool
- default y
-
-config COMPAT
- bool
- default y
-
-config SCHED_NO_NO_OMIT_FRAME_POINTER
- bool
- default y
-
-config ARCH_MAY_HAVE_PC_FDC
- bool
- default y
-
-config PPC_STD_MMU
- bool
- default y
-
-# We optimistically allocate largepages from the VM, so make the limit
-# large enough (16MB). This badly named config option is actually
-# max order + 1
-config FORCE_MAX_ZONEORDER
- int
- default "9" if PPC_64K_PAGES
- default "13"
-
-source "init/Kconfig"
-
-config SYSVIPC_COMPAT
- bool
- depends on COMPAT && SYSVIPC
- default y
-
-menu "Platform support"
-
-choice
- prompt "Platform Type"
- default PPC_MULTIPLATFORM
-
-config PPC_ISERIES
- bool "IBM Legacy iSeries"
-
-config PPC_MULTIPLATFORM
- bool "Generic"
-
-endchoice
-
-config PPC_PSERIES
- depends on PPC_MULTIPLATFORM
- bool " IBM pSeries & new iSeries"
- default y
-
-config PPC_BPA
- bool " Broadband Processor Architecture"
- depends on PPC_MULTIPLATFORM
-
-config PPC_PMAC
- depends on PPC_MULTIPLATFORM
- bool " Apple G5 based machines"
- default y
- select U3_DART
- select GENERIC_TBSYNC
-
-config PPC_MAPLE
- depends on PPC_MULTIPLATFORM
- bool " Maple 970FX Evaluation Board"
- select U3_DART
- select MPIC_BROKEN_U3
- select GENERIC_TBSYNC
- default n
- help
- This option enables support for the Maple 970FX Evaluation Board.
- For more informations, refer to <http://www.970eval.com>
-
-config PPC
- bool
- default y
-
-config PPC64
- bool
- default y
-
-config PPC_OF
- depends on PPC_MULTIPLATFORM
- bool
- default y
-
-config XICS
- depends on PPC_PSERIES
- bool
- default y
-
-config MPIC
- depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE
- bool
- default y
-
-config PPC_I8259
- depends on PPC_PSERIES
- bool
- default y
-
-config BPA_IIC
- depends on PPC_BPA
- bool
- default y
-
-# VMX is pSeries only for now until somebody writes the iSeries
-# exception vectors for it
-config ALTIVEC
- bool "Support for VMX (Altivec) vector unit"
- depends on PPC_MULTIPLATFORM
- default y
-
-config PPC_SPLPAR
- depends on PPC_PSERIES
- bool "Support for shared-processor logical partitions"
- default n
- help
- Enabling this option will make the kernel run more efficiently
- on logically-partitioned pSeries systems which use shared
- processors, that is, which share physical processors between
- two or more partitions.
-
-config KEXEC
- bool "kexec system call (EXPERIMENTAL)"
- depends on PPC_MULTIPLATFORM && EXPERIMENTAL
- help
- kexec is a system call that implements the ability to shutdown your
- current kernel, and to start another kernel. It is like a reboot
- but it is indepedent of the system firmware. And like a reboot
- you can start any kernel with it, not just Linux.
-
- The name comes from the similiarity to the exec system call.
-
- It is an ongoing process to be certain the hardware in a machine
- is properly shutdown, so do not be surprised if this code does not
- initially work for you. It may help to enable device hotplugging
- support. As of this writing the exact hardware interface is
- strongly in flux, so no good recommendation can be made.
-
-source "drivers/cpufreq/Kconfig"
-
-config CPU_FREQ_PMAC64
- bool "Support for some Apple G5s"
- depends on CPU_FREQ && PMAC_SMU && PPC64
- select CPU_FREQ_TABLE
- help
- This adds support for frequency switching on Apple iMac G5,
- and some of the more recent desktop G5 machines as well.
-
-config IBMVIO
- depends on PPC_PSERIES || PPC_ISERIES
- bool
- default y
-
-config U3_DART
- bool
- depends on PPC_MULTIPLATFORM
- default n
-
-config MPIC_BROKEN_U3
- bool
- depends on PPC_MAPLE
- default y
-
-config GENERIC_TBSYNC
- def_bool n
-
-config PPC_PMAC64
- bool
- depends on PPC_PMAC
- default y
-
-config BOOTX_TEXT
- bool "Support for early boot text console"
- depends PPC_OF
- help
- Say Y here to see progress messages from the boot firmware in text
- mode. Requires an Open Firmware compatible video card.
-
-config POWER4
- def_bool y
-
-config PPC_FPU
- def_bool y
-
-config POWER4_ONLY
- bool "Optimize for POWER4"
- default n
- ---help---
- Cause the compiler to optimize for POWER4 processors. The resulting
- binary will not work on POWER3 or RS64 processors when compiled with
- binutils 2.15 or later.
-
-config IOMMU_VMERGE
- bool "Enable IOMMU virtual merging (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- default n
- help
- Cause IO segments sent to a device for DMA to be merged virtually
- by the IOMMU when they happen to have been allocated contiguously.
- This doesn't add pressure to the IOMMU allocator. However, some
- drivers don't support getting large merged segments coming back
- from *_map_sg(). Say Y if you know the drivers you are using are
- properly handling this case.
-
-config SMP
- bool "Symmetric multi-processing support"
- ---help---
- This enables support for systems with more than one CPU. If you have
- a system with only one CPU, say N. If you have a system with more
- than one CPU, say Y.
-
- If you say N here, the kernel will run on single and multiprocessor
- machines, but will use only one CPU of a multiprocessor machine. If
- you say Y here, the kernel will run on single-processor machines.
- On a single-processor machine, the kernel will run faster if you say
- N here.
-
- If you don't know what to do here, say Y.
-
-config NR_CPUS
- int "Maximum number of CPUs (2-128)"
- range 2 128
- depends on SMP
- default "32"
-
-config HMT
- bool "Hardware multithreading"
- depends on SMP && PPC_PSERIES && BROKEN
- help
- This option enables hardware multithreading on RS64 cpus.
- pSeries systems p620 and p660 have such a cpu type.
-
-config NUMA
- bool "NUMA support"
- default y if SMP && PPC_PSERIES
-
-config ARCH_SELECT_MEMORY_MODEL
- def_bool y
-
-config ARCH_FLATMEM_ENABLE
- def_bool y
- depends on !NUMA
-
-config ARCH_SPARSEMEM_ENABLE
- def_bool y
-
-config ARCH_SPARSEMEM_DEFAULT
- def_bool y
- depends on NUMA
-
-source "mm/Kconfig"
-
-config HAVE_ARCH_EARLY_PFN_TO_NID
- def_bool y
- depends on NEED_MULTIPLE_NODES
-
-config ARCH_MEMORY_PROBE
- def_bool y
- depends on MEMORY_HOTPLUG
-
-# Some NUMA nodes have memory ranges that span
-# other nodes. Even though a pfn is valid and
-# between a node's start and end pfns, it may not
-# reside on that node.
-#
-# This is a relatively temporary hack that should
-# be able to go away when sparsemem is fully in
-# place
-config NODES_SPAN_OTHER_NODES
- def_bool y
- depends on NEED_MULTIPLE_NODES
-
-config PPC_64K_PAGES
- bool "64k page size"
- help
- This option changes the kernel logical page size to 64k. On machines
- without processor support for 64k pages, the kernel will simulate
- them by loading each individual 4k page on demand transparently,
- while on hardware with such support, it will be used to map
- normal application pages.
-
-config SCHED_SMT
- bool "SMT (Hyperthreading) scheduler support"
- depends on SMP
- default off
- help
- SMT scheduler support improves the CPU scheduler's decision making
- when dealing with POWER5 cpus at a cost of slightly increased
- overhead in some places. If unsure say N here.
-
-source "kernel/Kconfig.preempt"
-source kernel/Kconfig.hz
-
-config EEH
- bool "PCI Extended Error Handling (EEH)" if EMBEDDED
- depends on PPC_PSERIES
- default y if !EMBEDDED
-
-#
-# Use the generic interrupt handling code in kernel/irq/:
-#
-config GENERIC_HARDIRQS
- bool
- default y
-
-config PPC_RTAS
- bool
- depends on PPC_PSERIES || PPC_BPA
- default y
-
-config RTAS_ERROR_LOGGING
- bool
- depends on PPC_RTAS
- default y
-
-config RTAS_PROC
- bool "Proc interface to RTAS"
- depends on PPC_RTAS
- default y
-
-config RTAS_FLASH
- tristate "Firmware flash interface"
- depends on RTAS_PROC
-
-config SCANLOG
- tristate "Scanlog dump interface"
- depends on RTAS_PROC && PPC_PSERIES
-
-config LPARCFG
- tristate "LPAR Configuration Data"
- depends on PPC_PSERIES || PPC_ISERIES
- help
- Provide system capacity information via human readable
- <key word>=<value> pairs through a /proc/ppc64/lparcfg interface.
-
-config SECCOMP
- bool "Enable seccomp to safely compute untrusted bytecode"
- depends on PROC_FS
- default y
- help
- This kernel feature is useful for number crunching applications
- that may need to compute untrusted bytecode during their
- execution. By using pipes or other transports made available to
- the process as file descriptors supporting the read/write
- syscalls, it's possible to isolate those applications in
- their own address space using seccomp. Once seccomp is
- enabled via /proc/<pid>/seccomp, it cannot be disabled
- and the task is only allowed to execute a few safe syscalls
- defined by each seccomp mode.
-
- If unsure, say Y. Only embedded should say N here.
-
-source "fs/Kconfig.binfmt"
-
-config HOTPLUG_CPU
- bool "Support for hot-pluggable CPUs"
- depends on SMP && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC)
- select HOTPLUG
- ---help---
- Say Y here to be able to turn CPUs off and on.
-
- Say N if you are unsure.
-
-config PROC_DEVICETREE
- bool "Support for Open Firmware device tree in /proc"
- help
- This option adds a device-tree directory under /proc which contains
- an image of the device tree that the kernel copies from Open
- Firmware. If unsure, say Y here.
-
-config CMDLINE_BOOL
- bool "Default bootloader kernel arguments"
- depends on !PPC_ISERIES
-
-config CMDLINE
- string "Initial kernel command string"
- depends on CMDLINE_BOOL
- default "console=ttyS0,9600 console=tty0 root=/dev/sda2"
- help
- On some platforms, there is currently no way for the boot loader to
- pass arguments to the kernel. For these platforms, you can supply
- some command-line options at build time by entering them here. In
- most cases you will need to specify the root device here.
-
-endmenu
-
-config ISA_DMA_API
- bool
- default y
-
-menu "Bus Options"
-
-config ISA
- bool
- help
- Find out whether you have ISA slots on your motherboard. ISA is the
- name of a bus system, i.e. the way the CPU talks to the other stuff
- inside your box. If you have an Apple machine, say N here; if you
- have an IBM RS/6000 or pSeries machine or a PReP machine, say Y. If
- you have an embedded board, consult your board documentation.
-
-config SBUS
- bool
-
-config MCA
- bool
-
-config EISA
- bool
-
-config PCI
- bool "support for PCI devices" if (EMBEDDED && PPC_ISERIES)
- default y
- help
- Find out whether your system includes a PCI bus. PCI is the name of
- a bus system, i.e. the way the CPU talks to the other stuff inside
- your box. If you say Y here, the kernel will include drivers and
- infrastructure code to support PCI bus devices.
-
-config PCI_DOMAINS
- bool
- default PCI
-
-source "drivers/pci/Kconfig"
-
-source "drivers/pcmcia/Kconfig"
-
-source "drivers/pci/hotplug/Kconfig"
-
-endmenu
-
-source "net/Kconfig"
-
-source "drivers/Kconfig"
-
-source "fs/Kconfig"
-
-menu "iSeries device drivers"
- depends on PPC_ISERIES
-
-config VIOCONS
- tristate "iSeries Virtual Console Support"
-
-config VIODASD
- tristate "iSeries Virtual I/O disk support"
- help
- If you are running on an iSeries system and you want to use
- virtual disks created and managed by OS/400, say Y.
-
-config VIOCD
- tristate "iSeries Virtual I/O CD support"
- help
- If you are running Linux on an IBM iSeries system and you want to
- read a CD drive owned by OS/400, say Y here.
-
-config VIOTAPE
- tristate "iSeries Virtual Tape Support"
- help
- If you are running Linux on an iSeries system and you want Linux
- to read and/or write a tape drive owned by OS/400, say Y here.
-
-endmenu
-
-config VIOPATH
- bool
- depends on VIOCONS || VIODASD || VIOCD || VIOTAPE || VETH
- default y
-
-source "arch/powerpc/oprofile/Kconfig"
-
-source "arch/ppc64/Kconfig.debug"
-
-source "security/Kconfig"
-
-config KEYS_COMPAT
- bool
- depends on COMPAT && KEYS
- default y
-
-source "crypto/Kconfig"
-
-source "lib/Kconfig"
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
index dac4cc20fa9..e876c213f5c 100644
--- a/arch/ppc64/kernel/Makefile
+++ b/arch/ppc64/kernel/Makefile
@@ -2,45 +2,6 @@
# Makefile for the linux ppc64 kernel.
#
-ifneq ($(CONFIG_PPC_MERGE),y)
-
-EXTRA_CFLAGS += -mno-minimal-toc
-extra-y := head.o vmlinux.lds
-
-obj-y := misc.o prom.o
-
-endif
-
-obj-y += idle.o dma.o \
- align.o \
- rtc.o \
- iommu.o
-
-pci-obj-$(CONFIG_PPC_MULTIPLATFORM) += pci_dn.o pci_direct_iommu.o
-
-obj-$(CONFIG_PCI) += pci.o pci_iommu.o iomap.o $(pci-obj-y)
+obj-y += idle.o align.o
obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o
-ifneq ($(CONFIG_PPC_MERGE),y)
-obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o
-endif
-
-obj-$(CONFIG_KEXEC) += machine_kexec.o
-obj-$(CONFIG_MODULES) += module.o
-ifneq ($(CONFIG_PPC_MERGE),y)
-obj-$(CONFIG_MODULES) += ppc_ksyms.o
-endif
-obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
-ifneq ($(CONFIG_PPC_MERGE),y)
-obj-$(CONFIG_BOOTX_TEXT) += btext.o
-endif
-obj-$(CONFIG_HVCS) += hvcserver.o
-
-obj-$(CONFIG_KPROBES) += kprobes.o
-
-ifneq ($(CONFIG_PPC_MERGE),y)
-ifeq ($(CONFIG_PPC_ISERIES),y)
-arch/ppc64/kernel/head.o: arch/powerpc/kernel/lparmap.s
-AFLAGS_head.o += -Iarch/powerpc/kernel
-endif
-endif
diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c
deleted file mode 100644
index 84ab5c18ef5..00000000000
--- a/arch/ppc64/kernel/asm-offsets.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- *
- * This program is free software; you can redistribute 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/config.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/time.h>
-#include <linux/hardirq.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-
-#include <asm/paca.h>
-#include <asm/lppaca.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/rtas.h>
-#include <asm/cputable.h>
-#include <asm/cache.h>
-#include <asm/systemcfg.h>
-#include <asm/compat.h>
-
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
-int main(void)
-{
- /* thread struct on stack */
- DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
- DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
- DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
-
- /* task_struct->thread */
- DEFINE(THREAD, offsetof(struct task_struct, thread));
- DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
- DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
- DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
- DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
- DEFINE(KSP, offsetof(struct thread_struct, ksp));
- DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid));
-
-#ifdef CONFIG_ALTIVEC
- DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0]));
- DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave));
- DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
- DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr));
-#endif /* CONFIG_ALTIVEC */
- DEFINE(MM, offsetof(struct task_struct, mm));
- DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context));
-
- DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size));
- DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_dline_size));
- DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, dlines_per_page));
- DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size));
- DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size));
- DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page));
- DEFINE(PLATFORM_LPAR, PLATFORM_LPAR);
-
- /* paca */
- DEFINE(PACA_SIZE, sizeof(struct paca_struct));
- DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index));
- DEFINE(PACAPROCSTART, offsetof(struct paca_struct, cpu_start));
- DEFINE(PACAKSAVE, offsetof(struct paca_struct, kstack));
- DEFINE(PACACURRENT, offsetof(struct paca_struct, __current));
- DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, saved_msr));
- DEFINE(PACASTABREAL, offsetof(struct paca_struct, stab_real));
- DEFINE(PACASTABVIRT, offsetof(struct paca_struct, stab_addr));
- DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr));
- DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1));
- DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc));
- DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, proc_enabled));
- DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
- DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
- DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
-#ifdef CONFIG_PPC_64K_PAGES
- DEFINE(PACAPGDIR, offsetof(struct paca_struct, pgdir));
-#endif
-#ifdef CONFIG_HUGETLB_PAGE
- DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
- DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
-#endif /* CONFIG_HUGETLB_PAGE */
- DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
- DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
- DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
- DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
- DEFINE(PACA_EXDSI, offsetof(struct paca_struct, exdsi));
- DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
- DEFINE(PACALPPACA, offsetof(struct paca_struct, lppaca));
- DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
- DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
- DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1));
- DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int));
- DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int));
-
- /* RTAS */
- DEFINE(RTASBASE, offsetof(struct rtas_t, base));
- DEFINE(RTASENTRY, offsetof(struct rtas_t, entry));
-
- /* Interrupt register frame */
- DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
-
- DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
-
- /* 288 = # of volatile regs, int & fp, for leaf routines */
- /* which do not stack a frame. See the PPC64 ABI. */
- DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
- /* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
- DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
- DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
- DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
- DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
- DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
- DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
- DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
- DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
- DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
- DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
- DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
- DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
- DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10]));
- DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11]));
- DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12]));
- DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13]));
- /*
- * Note: these symbols include _ because they overlap with special
- * register names
- */
- DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
- DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
- DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
- DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
- DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
- DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
- DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
- DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
- DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
- DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
- DEFINE(_TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
- DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe));
-
- /* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */
- DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs));
- DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
-
- DEFINE(CLONE_VM, CLONE_VM);
- DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
-
- /* About the CPU features table */
- DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec));
- DEFINE(CPU_SPEC_PVR_MASK, offsetof(struct cpu_spec, pvr_mask));
- DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value));
- DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
- DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
-
- /* systemcfg offsets for use by vdso */
- DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct systemcfg, tb_orig_stamp));
- DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct systemcfg, tb_ticks_per_sec));
- DEFINE(CFG_TB_TO_XS, offsetof(struct systemcfg, tb_to_xs));
- DEFINE(CFG_STAMP_XSEC, offsetof(struct systemcfg, stamp_xsec));
- DEFINE(CFG_TB_UPDATE_COUNT, offsetof(struct systemcfg, tb_update_count));
- DEFINE(CFG_TZ_MINUTEWEST, offsetof(struct systemcfg, tz_minuteswest));
- DEFINE(CFG_TZ_DSTTIME, offsetof(struct systemcfg, tz_dsttime));
- DEFINE(CFG_SYSCALL_MAP32, offsetof(struct systemcfg, syscall_map_32));
- DEFINE(CFG_SYSCALL_MAP64, offsetof(struct systemcfg, syscall_map_64));
-
- /* timeval/timezone offsets for use by vdso */
- DEFINE(TVAL64_TV_SEC, offsetof(struct timeval, tv_sec));
- DEFINE(TVAL64_TV_USEC, offsetof(struct timeval, tv_usec));
- DEFINE(TVAL32_TV_SEC, offsetof(struct compat_timeval, tv_sec));
- DEFINE(TVAL32_TV_USEC, offsetof(struct compat_timeval, tv_usec));
- DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest));
- DEFINE(TZONE_TZ_DSTTIME, offsetof(struct timezone, tz_dsttime));
-
- return 0;
-}
diff --git a/arch/ppc64/kernel/btext.c b/arch/ppc64/kernel/btext.c
deleted file mode 100644
index 506a37885c5..00000000000
--- a/arch/ppc64/kernel/btext.c
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * Procedures for drawing on the screen early on in the boot process.
- *
- * Benjamin Herrenschmidt <benh@kernel.crashing.org>
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/btext.h>
-#include <asm/prom.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/lmb.h>
-#include <asm/processor.h>
-#include <asm/udbg.h>
-
-#undef NO_SCROLL
-
-#ifndef NO_SCROLL
-static void scrollscreen(void);
-#endif
-
-static void draw_byte(unsigned char c, long locX, long locY);
-static void draw_byte_32(unsigned char *bits, unsigned int *base, int rb);
-static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
-static void draw_byte_8(unsigned char *bits, unsigned int *base, int rb);
-
-static int g_loc_X;
-static int g_loc_Y;
-static int g_max_loc_X;
-static int g_max_loc_Y;
-
-static int dispDeviceRowBytes;
-static int dispDeviceDepth;
-static int dispDeviceRect[4];
-static unsigned char *dispDeviceBase, *logicalDisplayBase;
-
-unsigned long disp_BAT[2] __initdata = {0, 0};
-
-#define cmapsz (16*256)
-
-static unsigned char vga_font[cmapsz];
-
-int boot_text_mapped;
-int force_printk_to_btext = 0;
-
-
-/* Here's a small text engine to use during early boot
- * or for debugging purposes
- *
- * todo:
- *
- * - build some kind of vgacon with it to enable early printk
- * - move to a separate file
- * - add a few video driver hooks to keep in sync with display
- * changes.
- */
-
-void map_boot_text(void)
-{
- unsigned long base, offset, size;
- unsigned char *vbase;
-
- /* By default, we are no longer mapped */
- boot_text_mapped = 0;
- if (dispDeviceBase == 0)
- return;
- base = ((unsigned long) dispDeviceBase) & 0xFFFFF000UL;
- offset = ((unsigned long) dispDeviceBase) - base;
- size = dispDeviceRowBytes * dispDeviceRect[3] + offset
- + dispDeviceRect[0];
- vbase = __ioremap(base, size, _PAGE_NO_CACHE);
- if (vbase == 0)
- return;
- logicalDisplayBase = vbase + offset;
- boot_text_mapped = 1;
-}
-
-int btext_initialize(struct device_node *np)
-{
- unsigned int width, height, depth, pitch;
- unsigned long address = 0;
- u32 *prop;
-
- prop = (u32 *)get_property(np, "width", NULL);
- if (prop == NULL)
- return -EINVAL;
- width = *prop;
- prop = (u32 *)get_property(np, "height", NULL);
- if (prop == NULL)
- return -EINVAL;
- height = *prop;
- prop = (u32 *)get_property(np, "depth", NULL);
- if (prop == NULL)
- return -EINVAL;
- depth = *prop;
- pitch = width * ((depth + 7) / 8);
- prop = (u32 *)get_property(np, "linebytes", NULL);
- if (prop)
- pitch = *prop;
- if (pitch == 1)
- pitch = 0x1000;
- prop = (u32 *)get_property(np, "address", NULL);
- if (prop)
- address = *prop;
-
- /* FIXME: Add support for PCI reg properties */
-
- if (address == 0)
- return -EINVAL;
-
- g_loc_X = 0;
- g_loc_Y = 0;
- g_max_loc_X = width / 8;
- g_max_loc_Y = height / 16;
- logicalDisplayBase = (unsigned char *)address;
- dispDeviceBase = (unsigned char *)address;
- dispDeviceRowBytes = pitch;
- dispDeviceDepth = depth;
- dispDeviceRect[0] = dispDeviceRect[1] = 0;
- dispDeviceRect[2] = width;
- dispDeviceRect[3] = height;
-
- map_boot_text();
-
- return 0;
-}
-
-static void btext_putc(unsigned char c)
-{
- btext_drawchar(c);
-}
-
-void __init init_boot_display(void)
-{
- char *name;
- struct device_node *np = NULL;
- int rc = -ENODEV;
-
- printk("trying to initialize btext ...\n");
-
- name = (char *)get_property(of_chosen, "linux,stdout-path", NULL);
- if (name != NULL) {
- np = of_find_node_by_path(name);
- if (np != NULL) {
- if (strcmp(np->type, "display") != 0) {
- printk("boot stdout isn't a display !\n");
- of_node_put(np);
- np = NULL;
- }
- }
- }
- if (np)
- rc = btext_initialize(np);
- if (rc) {
- for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
- if (get_property(np, "linux,opened", NULL)) {
- printk("trying %s ...\n", np->full_name);
- rc = btext_initialize(np);
- printk("result: %d\n", rc);
- }
- if (rc == 0)
- break;
- }
- }
- if (rc == 0 && udbg_putc == NULL)
- udbg_putc = btext_putc;
-}
-
-
-/* Calc the base address of a given point (x,y) */
-static unsigned char * calc_base(int x, int y)
-{
- unsigned char *base;
-
- base = logicalDisplayBase;
- if (base == 0)
- base = dispDeviceBase;
- base += (x + dispDeviceRect[0]) * (dispDeviceDepth >> 3);
- base += (y + dispDeviceRect[1]) * dispDeviceRowBytes;
- return base;
-}
-
-/* Adjust the display to a new resolution */
-void btext_update_display(unsigned long phys, int width, int height,
- int depth, int pitch)
-{
- if (dispDeviceBase == 0)
- return;
-
- /* check it's the same frame buffer (within 256MB) */
- if ((phys ^ (unsigned long)dispDeviceBase) & 0xf0000000)
- return;
-
- dispDeviceBase = (__u8 *) phys;
- dispDeviceRect[0] = 0;
- dispDeviceRect[1] = 0;
- dispDeviceRect[2] = width;
- dispDeviceRect[3] = height;
- dispDeviceDepth = depth;
- dispDeviceRowBytes = pitch;
- if (boot_text_mapped) {
- iounmap(logicalDisplayBase);
- boot_text_mapped = 0;
- }
- map_boot_text();
- g_loc_X = 0;
- g_loc_Y = 0;
- g_max_loc_X = width / 8;
- g_max_loc_Y = height / 16;
-}
-
-void btext_clearscreen(void)
-{
- unsigned long *base = (unsigned long *)calc_base(0, 0);
- unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
- (dispDeviceDepth >> 3)) >> 3;
- int i,j;
-
- for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1]); i++)
- {
- unsigned long *ptr = base;
- for(j=width; j; --j)
- *(ptr++) = 0;
- base += (dispDeviceRowBytes >> 3);
- }
-}
-
-#ifndef NO_SCROLL
-static void scrollscreen(void)
-{
- unsigned long *src = (unsigned long *)calc_base(0,16);
- unsigned long *dst = (unsigned long *)calc_base(0,0);
- unsigned long width = ((dispDeviceRect[2] - dispDeviceRect[0]) *
- (dispDeviceDepth >> 3)) >> 3;
- int i,j;
-
- for (i=0; i<(dispDeviceRect[3] - dispDeviceRect[1] - 16); i++)
- {
- unsigned long *src_ptr = src;
- unsigned long *dst_ptr = dst;
- for(j=width; j; --j)
- *(dst_ptr++) = *(src_ptr++);
- src += (dispDeviceRowBytes >> 3);
- dst += (dispDeviceRowBytes >> 3);
- }
- for (i=0; i<16; i++)
- {
- unsigned long *dst_ptr = dst;
- for(j=width; j; --j)
- *(dst_ptr++) = 0;
- dst += (dispDeviceRowBytes >> 3);
- }
-}
-#endif /* ndef NO_SCROLL */
-
-void btext_drawchar(char c)
-{
- int cline = 0;
-#ifdef NO_SCROLL
- int x;
-#endif
- if (!boot_text_mapped)
- return;
-
- switch (c) {
- case '\b':
- if (g_loc_X > 0)
- --g_loc_X;
- break;
- case '\t':
- g_loc_X = (g_loc_X & -8) + 8;
- break;
- case '\r':
- g_loc_X = 0;
- break;
- case '\n':
- g_loc_X = 0;
- g_loc_Y++;
- cline = 1;
- break;
- default:
- draw_byte(c, g_loc_X++, g_loc_Y);
- }
- if (g_loc_X >= g_max_loc_X) {
- g_loc_X = 0;
- g_loc_Y++;
- cline = 1;
- }
-#ifndef NO_SCROLL
- while (g_loc_Y >= g_max_loc_Y) {
- scrollscreen();
- g_loc_Y--;
- }
-#else
- /* wrap around from bottom to top of screen so we don't
- waste time scrolling each line. -- paulus. */
- if (g_loc_Y >= g_max_loc_Y)
- g_loc_Y = 0;
- if (cline) {
- for (x = 0; x < g_max_loc_X; ++x)
- draw_byte(' ', x, g_loc_Y);
- }
-#endif
-}
-
-void btext_drawstring(const char *c)
-{
- if (!boot_text_mapped)
- return;
- while (*c)
- btext_drawchar(*c++);
-}
-
-void btext_drawhex(unsigned long v)
-{
- char *hex_table = "0123456789abcdef";
-
- if (!boot_text_mapped)
- return;
- btext_drawchar(hex_table[(v >> 60) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 56) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 52) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 48) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 44) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 40) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 36) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 32) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 8) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 4) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 0) & 0x0000000FUL]);
- btext_drawchar(' ');
-}
-
-static void draw_byte(unsigned char c, long locX, long locY)
-{
- unsigned char *base = calc_base(locX << 3, locY << 4);
- unsigned char *font = &vga_font[((unsigned int)c) * 16];
- int rb = dispDeviceRowBytes;
-
- switch(dispDeviceDepth) {
- case 24:
- case 32:
- draw_byte_32(font, (unsigned int *)base, rb);
- break;
- case 15:
- case 16:
- draw_byte_16(font, (unsigned int *)base, rb);
- break;
- case 8:
- draw_byte_8(font, (unsigned int *)base, rb);
- break;
- }
-}
-
-static unsigned int expand_bits_8[16] = {
- 0x00000000,
- 0x000000ff,
- 0x0000ff00,
- 0x0000ffff,
- 0x00ff0000,
- 0x00ff00ff,
- 0x00ffff00,
- 0x00ffffff,
- 0xff000000,
- 0xff0000ff,
- 0xff00ff00,
- 0xff00ffff,
- 0xffff0000,
- 0xffff00ff,
- 0xffffff00,
- 0xffffffff
-};
-
-static unsigned int expand_bits_16[4] = {
- 0x00000000,
- 0x0000ffff,
- 0xffff0000,
- 0xffffffff
-};
-
-
-static void draw_byte_32(unsigned char *font, unsigned int *base, int rb)
-{
- int l, bits;
- int fg = 0xFFFFFFFFUL;
- int bg = 0x00000000UL;
-
- for (l = 0; l < 16; ++l)
- {
- bits = *font++;
- base[0] = (-(bits >> 7) & fg) ^ bg;
- base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
- base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
- base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
- base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
- base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
- base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
- base[7] = (-(bits & 1) & fg) ^ bg;
- base = (unsigned int *) ((char *)base + rb);
- }
-}
-
-static void draw_byte_16(unsigned char *font, unsigned int *base, int rb)
-{
- int l, bits;
- int fg = 0xFFFFFFFFUL;
- int bg = 0x00000000UL;
- unsigned int *eb = (int *)expand_bits_16;
-
- for (l = 0; l < 16; ++l)
- {
- bits = *font++;
- base[0] = (eb[bits >> 6] & fg) ^ bg;
- base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
- base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
- base[3] = (eb[bits & 3] & fg) ^ bg;
- base = (unsigned int *) ((char *)base + rb);
- }
-}
-
-static void draw_byte_8(unsigned char *font, unsigned int *base, int rb)
-{
- int l, bits;
- int fg = 0x0F0F0F0FUL;
- int bg = 0x00000000UL;
- unsigned int *eb = (int *)expand_bits_8;
-
- for (l = 0; l < 16; ++l)
- {
- bits = *font++;
- base[0] = (eb[bits >> 4] & fg) ^ bg;
- base[1] = (eb[bits & 0xf] & fg) ^ bg;
- base = (unsigned int *) ((char *)base + rb);
- }
-}
-
-static unsigned char vga_font[cmapsz] = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd,
-0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
-0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe,
-0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
-0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
-0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e,
-0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
-0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
-0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8,
-0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e,
-0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
-0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
-0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6,
-0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
-0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
-0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
-0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c,
-0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c,
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18,
-0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
-0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
-0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
-0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
-0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
-0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
-0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
-0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
-0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
-0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c,
-0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
-0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
-0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
-0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
-0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
-0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
-0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c,
-0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
-0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
-0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
-0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18,
-0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
-0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
-0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
-0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60,
-0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
-0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60,
-0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06,
-0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60,
-0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb,
-0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
-0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
-0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
-0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
-0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
-0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6,
-0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
-0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
-0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe,
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06,
-0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe,
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66,
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
-0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
-0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b,
-0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c,
-0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
-0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
-0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
-0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
-0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
-0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66,
-0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18,
-0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc,
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc,
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
-0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
-0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
-0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06,
-0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
-0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
-0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
-0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
-0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
-0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
-0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
-0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
-0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
-0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
-0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
-0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
-0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8,
-0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66,
-0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
-0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60,
-0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
-0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
-0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
-0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
-0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
-0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
-0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00,
-};
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
deleted file mode 100644
index 1c869ea72d2..00000000000
--- a/arch/ppc64/kernel/head.S
+++ /dev/null
@@ -1,2007 +0,0 @@
-/*
- * arch/ppc64/kernel/head.S
- *
- * PowerPC version
- * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
- * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu>
- * Adapted for Power Macintosh by Paul Mackerras.
- * Low-level exception handlers and MMU support
- * rewritten by Paul Mackerras.
- * Copyright (C) 1996 Paul Mackerras.
- *
- * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and
- * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com
- *
- * This file contains the low-level support and setup for the
- * PowerPC-64 platform, including trap and interrupt dispatch.
- *
- * This program is free software; you can redistribute 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/config.h>
-#include <linux/threads.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/bug.h>
-#include <asm/cputable.h>
-#include <asm/setup.h>
-#include <asm/hvcall.h>
-#include <asm/iseries/lpar_map.h>
-#include <asm/thread_info.h>
-
-#ifdef CONFIG_PPC_ISERIES
-#define DO_SOFT_DISABLE
-#endif
-
-/*
- * We layout physical memory as follows:
- * 0x0000 - 0x00ff : Secondary processor spin code
- * 0x0100 - 0x2fff : pSeries Interrupt prologs
- * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs
- * 0x6000 - 0x6fff : Initial (CPU0) segment table
- * 0x7000 - 0x7fff : FWNMI data area
- * 0x8000 - : Early init and support code
- */
-
-/*
- * SPRG Usage
- *
- * Register Definition
- *
- * SPRG0 reserved for hypervisor
- * SPRG1 temp - used to save gpr
- * SPRG2 temp - used to save gpr
- * SPRG3 virt addr of paca
- */
-
-/*
- * Entering into this code we make the following assumptions:
- * For pSeries:
- * 1. The MMU is off & open firmware is running in real mode.
- * 2. The kernel is entered at __start
- *
- * For iSeries:
- * 1. The MMU is on (as it always is for iSeries)
- * 2. The kernel is entered at system_reset_iSeries
- */
-
- .text
- .globl _stext
-_stext:
-#ifdef CONFIG_PPC_MULTIPLATFORM
-_GLOBAL(__start)
- /* NOP this out unconditionally */
-BEGIN_FTR_SECTION
- b .__start_initialization_multiplatform
-END_FTR_SECTION(0, 1)
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
- /* Catch branch to 0 in real mode */
- trap
-
-#ifdef CONFIG_PPC_ISERIES
- /*
- * At offset 0x20, there is a pointer to iSeries LPAR data.
- * This is required by the hypervisor
- */
- . = 0x20
- .llong hvReleaseData-KERNELBASE
-
- /*
- * At offset 0x28 and 0x30 are offsets to the mschunks_map
- * array (used by the iSeries LPAR debugger to do translation
- * between physical addresses and absolute addresses) and
- * to the pidhash table (also used by the debugger)
- */
- .llong mschunks_map-KERNELBASE
- .llong 0 /* pidhash-KERNELBASE SFRXXX */
-
- /* Offset 0x38 - Pointer to start of embedded System.map */
- .globl embedded_sysmap_start
-embedded_sysmap_start:
- .llong 0
- /* Offset 0x40 - Pointer to end of embedded System.map */
- .globl embedded_sysmap_end
-embedded_sysmap_end:
- .llong 0
-
-#endif /* CONFIG_PPC_ISERIES */
-
- /* Secondary processors spin on this value until it goes to 1. */
- .globl __secondary_hold_spinloop
-__secondary_hold_spinloop:
- .llong 0x0
-
- /* Secondary processors write this value with their cpu # */
- /* after they enter the spin loop immediately below. */
- .globl __secondary_hold_acknowledge
-__secondary_hold_acknowledge:
- .llong 0x0
-
- . = 0x60
-/*
- * The following code is used on pSeries to hold secondary processors
- * in a spin loop after they have been freed from OpenFirmware, but
- * before the bulk of the kernel has been relocated. This code
- * is relocated to physical address 0x60 before prom_init is run.
- * All of it must fit below the first exception vector at 0x100.
- */
-_GLOBAL(__secondary_hold)
- mfmsr r24
- ori r24,r24,MSR_RI
- mtmsrd r24 /* RI on */
-
- /* Grab our linux cpu number */
- mr r24,r3
-
- /* Tell the master cpu we're here */
- /* Relocation is off & we are located at an address less */
- /* than 0x100, so only need to grab low order offset. */
- std r24,__secondary_hold_acknowledge@l(0)
- sync
-
- /* All secondary cpus wait here until told to start. */
-100: ld r4,__secondary_hold_spinloop@l(0)
- cmpdi 0,r4,1
- bne 100b
-
-#ifdef CONFIG_HMT
- b .hmt_init
-#else
-#ifdef CONFIG_SMP
- mr r3,r24
- b .pSeries_secondary_smp_init
-#else
- BUG_OPCODE
-#endif
-#endif
-
-/* This value is used to mark exception frames on the stack. */
- .section ".toc","aw"
-exception_marker:
- .tc ID_72656773_68657265[TC],0x7265677368657265
- .text
-
-/*
- * The following macros define the code that appears as
- * the prologue to each of the exception handlers. They
- * are split into two parts to allow a single kernel binary
- * to be used for pSeries and iSeries.
- * LOL. One day... - paulus
- */
-
-/*
- * We make as much of the exception code common between native
- * exception handlers (including pSeries LPAR) and iSeries LPAR
- * implementations as possible.
- */
-
-/*
- * This is the start of the interrupt handlers for pSeries
- * This code runs with relocation off.
- */
-#define EX_R9 0
-#define EX_R10 8
-#define EX_R11 16
-#define EX_R12 24
-#define EX_R13 32
-#define EX_SRR0 40
-#define EX_DAR 48
-#define EX_DSISR 56
-#define EX_CCR 60
-#define EX_R3 64
-#define EX_LR 72
-
-#define EXCEPTION_PROLOG_PSERIES(area, label) \
- mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \
- std r9,area+EX_R9(r13); /* save r9 - r12 */ \
- std r10,area+EX_R10(r13); \
- std r11,area+EX_R11(r13); \
- std r12,area+EX_R12(r13); \
- mfspr r9,SPRN_SPRG1; \
- std r9,area+EX_R13(r13); \
- mfcr r9; \
- clrrdi r12,r13,32; /* get high part of &label */ \
- mfmsr r10; \
- mfspr r11,SPRN_SRR0; /* save SRR0 */ \
- ori r12,r12,(label)@l; /* virt addr of handler */ \
- ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \
- mtspr SPRN_SRR0,r12; \
- mfspr r12,SPRN_SRR1; /* and SRR1 */ \
- mtspr SPRN_SRR1,r10; \
- rfid; \
- b . /* prevent speculative execution */
-
-/*
- * This is the start of the interrupt handlers for iSeries
- * This code runs with relocation on.
- */
-#define EXCEPTION_PROLOG_ISERIES_1(area) \
- mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \
- std r9,area+EX_R9(r13); /* save r9 - r12 */ \
- std r10,area+EX_R10(r13); \
- std r11,area+EX_R11(r13); \
- std r12,area+EX_R12(r13); \
- mfspr r9,SPRN_SPRG1; \
- std r9,area+EX_R13(r13); \
- mfcr r9
-
-#define EXCEPTION_PROLOG_ISERIES_2 \
- mfmsr r10; \
- ld r11,PACALPPACA+LPPACASRR0(r13); \
- ld r12,PACALPPACA+LPPACASRR1(r13); \
- ori r10,r10,MSR_RI; \
- mtmsrd r10,1
-
-/*
- * The common exception prolog is used for all except a few exceptions
- * such as a segment miss on a kernel address. We have to be prepared
- * to take another exception from the point where we first touch the
- * kernel stack onwards.
- *
- * On entry r13 points to the paca, r9-r13 are saved in the paca,
- * r9 contains the saved CR, r11 and r12 contain the saved SRR0 and
- * SRR1, and relocation is on.
- */
-#define EXCEPTION_PROLOG_COMMON(n, area) \
- andi. r10,r12,MSR_PR; /* See if coming from user */ \
- mr r10,r1; /* Save r1 */ \
- subi r1,r1,INT_FRAME_SIZE; /* alloc frame on kernel stack */ \
- beq- 1f; \
- ld r1,PACAKSAVE(r13); /* kernel stack to use */ \
-1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \
- bge- cr1,bad_stack; /* abort if it is */ \
- std r9,_CCR(r1); /* save CR in stackframe */ \
- std r11,_NIP(r1); /* save SRR0 in stackframe */ \
- std r12,_MSR(r1); /* save SRR1 in stackframe */ \
- std r10,0(r1); /* make stack chain pointer */ \
- std r0,GPR0(r1); /* save r0 in stackframe */ \
- std r10,GPR1(r1); /* save r1 in stackframe */ \
- std r2,GPR2(r1); /* save r2 in stackframe */ \
- SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \
- SAVE_2GPRS(7, r1); /* save r7, r8 in stackframe */ \
- ld r9,area+EX_R9(r13); /* move r9, r10 to stackframe */ \
- ld r10,area+EX_R10(r13); \
- std r9,GPR9(r1); \
- std r10,GPR10(r1); \
- ld r9,area+EX_R11(r13); /* move r11 - r13 to stackframe */ \
- ld r10,area+EX_R12(r13); \
- ld r11,area+EX_R13(r13); \
- std r9,GPR11(r1); \
- std r10,GPR12(r1); \
- std r11,GPR13(r1); \
- ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \
- mflr r9; /* save LR in stackframe */ \
- std r9,_LINK(r1); \
- mfctr r10; /* save CTR in stackframe */ \
- std r10,_CTR(r1); \
- mfspr r11,SPRN_XER; /* save XER in stackframe */ \
- std r11,_XER(r1); \
- li r9,(n)+1; \
- std r9,_TRAP(r1); /* set trap number */ \
- li r10,0; \
- ld r11,exception_marker@toc(r2); \
- std r10,RESULT(r1); /* clear regs->result */ \
- std r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame */
-
-/*
- * Exception vectors.
- */
-#define STD_EXCEPTION_PSERIES(n, label) \
- . = n; \
- .globl label##_pSeries; \
-label##_pSeries: \
- HMT_MEDIUM; \
- mtspr SPRN_SPRG1,r13; /* save r13 */ \
- RUNLATCH_ON(r13); \
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
-
-#define STD_EXCEPTION_ISERIES(n, label, area) \
- .globl label##_iSeries; \
-label##_iSeries: \
- HMT_MEDIUM; \
- mtspr SPRN_SPRG1,r13; /* save r13 */ \
- RUNLATCH_ON(r13); \
- EXCEPTION_PROLOG_ISERIES_1(area); \
- EXCEPTION_PROLOG_ISERIES_2; \
- b label##_common
-
-#define MASKABLE_EXCEPTION_ISERIES(n, label) \
- .globl label##_iSeries; \
-label##_iSeries: \
- HMT_MEDIUM; \
- mtspr SPRN_SPRG1,r13; /* save r13 */ \
- RUNLATCH_ON(r13); \
- EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \
- lbz r10,PACAPROCENABLED(r13); \
- cmpwi 0,r10,0; \
- beq- label##_iSeries_masked; \
- EXCEPTION_PROLOG_ISERIES_2; \
- b label##_common; \
-
-#ifdef DO_SOFT_DISABLE
-#define DISABLE_INTS \
- lbz r10,PACAPROCENABLED(r13); \
- li r11,0; \
- std r10,SOFTE(r1); \
- mfmsr r10; \
- stb r11,PACAPROCENABLED(r13); \
- ori r10,r10,MSR_EE; \
- mtmsrd r10,1
-
-#define ENABLE_INTS \
- lbz r10,PACAPROCENABLED(r13); \
- mfmsr r11; \
- std r10,SOFTE(r1); \
- ori r11,r11,MSR_EE; \
- mtmsrd r11,1
-
-#else /* hard enable/disable interrupts */
-#define DISABLE_INTS
-
-#define ENABLE_INTS \
- ld r12,_MSR(r1); \
- mfmsr r11; \
- rlwimi r11,r12,0,MSR_EE; \
- mtmsrd r11,1
-
-#endif
-
-#define STD_EXCEPTION_COMMON(trap, label, hdlr) \
- .align 7; \
- .globl label##_common; \
-label##_common: \
- EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \
- DISABLE_INTS; \
- bl .save_nvgprs; \
- addi r3,r1,STACK_FRAME_OVERHEAD; \
- bl hdlr; \
- b .ret_from_except
-
-#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \
- .align 7; \
- .globl label##_common; \
-label##_common: \
- EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \
- DISABLE_INTS; \
- addi r3,r1,STACK_FRAME_OVERHEAD; \
- bl hdlr; \
- b .ret_from_except_lite
-
-/*
- * Start of pSeries system interrupt routines
- */
- . = 0x100
- .globl __start_interrupts
-__start_interrupts:
-
- STD_EXCEPTION_PSERIES(0x100, system_reset)
-
- . = 0x200
-_machine_check_pSeries:
- HMT_MEDIUM
- mtspr SPRN_SPRG1,r13 /* save r13 */
- RUNLATCH_ON(r13)
- EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
-
- . = 0x300
- .globl data_access_pSeries
-data_access_pSeries:
- HMT_MEDIUM
- mtspr SPRN_SPRG1,r13
-BEGIN_FTR_SECTION
- mtspr SPRN_SPRG2,r12
- mfspr r13,SPRN_DAR
- mfspr r12,SPRN_DSISR
- srdi r13,r13,60
- rlwimi r13,r12,16,0x20
- mfcr r12
- cmpwi r13,0x2c
- beq .do_stab_bolted_pSeries
- mtcrf 0x80,r12
- mfspr r12,SPRN_SPRG2
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common)
-
- . = 0x380
- .globl data_access_slb_pSeries
-data_access_slb_pSeries:
- HMT_MEDIUM
- mtspr SPRN_SPRG1,r13
- RUNLATCH_ON(r13)
- mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
- std r3,PACA_EXSLB+EX_R3(r13)
- mfspr r3,SPRN_DAR
- std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
- mfcr r9
-#ifdef __DISABLED__
- /* Keep that around for when we re-implement dynamic VSIDs */
- cmpdi r3,0
- bge slb_miss_user_pseries
-#endif /* __DISABLED__ */
- std r10,PACA_EXSLB+EX_R10(r13)
- std r11,PACA_EXSLB+EX_R11(r13)
- std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG1
- std r10,PACA_EXSLB+EX_R13(r13)
- mfspr r12,SPRN_SRR1 /* and SRR1 */
- b .slb_miss_realmode /* Rel. branch works in real mode */
-
- STD_EXCEPTION_PSERIES(0x400, instruction_access)
-
- . = 0x480
- .globl instruction_access_slb_pSeries
-instruction_access_slb_pSeries:
- HMT_MEDIUM
- mtspr SPRN_SPRG1,r13
- RUNLATCH_ON(r13)
- mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
- std r3,PACA_EXSLB+EX_R3(r13)
- mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
- std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
- mfcr r9
-#ifdef __DISABLED__
- /* Keep that around for when we re-implement dynamic VSIDs */
- cmpdi r3,0
- bge slb_miss_user_pseries
-#endif /* __DISABLED__ */
- std r10,PACA_EXSLB+EX_R10(r13)
- std r11,PACA_EXSLB+EX_R11(r13)
- std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG1
- std r10,PACA_EXSLB+EX_R13(r13)
- mfspr r12,SPRN_SRR1 /* and SRR1 */
- b .slb_miss_realmode /* Rel. branch works in real mode */
-
- STD_EXCEPTION_PSERIES(0x500, hardware_interrupt)
- STD_EXCEPTION_PSERIES(0x600, alignment)
- STD_EXCEPTION_PSERIES(0x700, program_check)
- STD_EXCEPTION_PSERIES(0x800, fp_unavailable)
- STD_EXCEPTION_PSERIES(0x900, decrementer)
- STD_EXCEPTION_PSERIES(0xa00, trap_0a)
- STD_EXCEPTION_PSERIES(0xb00, trap_0b)
-
- . = 0xc00
- .globl system_call_pSeries
-system_call_pSeries:
- HMT_MEDIUM
- RUNLATCH_ON(r9)
- mr r9,r13
- mfmsr r10
- mfspr r13,SPRN_SPRG3
- mfspr r11,SPRN_SRR0
- clrrdi r12,r13,32
- oris r12,r12,system_call_common@h
- ori r12,r12,system_call_common@l
- mtspr SPRN_SRR0,r12
- ori r10,r10,MSR_IR|MSR_DR|MSR_RI
- mfspr r12,SPRN_SRR1
- mtspr SPRN_SRR1,r10
- rfid
- b . /* prevent speculative execution */
-
- STD_EXCEPTION_PSERIES(0xd00, single_step)
- STD_EXCEPTION_PSERIES(0xe00, trap_0e)
-
- /* We need to deal with the Altivec unavailable exception
- * here which is at 0xf20, thus in the middle of the
- * prolog code of the PerformanceMonitor one. A little
- * trickery is thus necessary
- */
- . = 0xf00
- b performance_monitor_pSeries
-
- STD_EXCEPTION_PSERIES(0xf20, altivec_unavailable)
-
- STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)
- STD_EXCEPTION_PSERIES(0x1700, altivec_assist)
-
- . = 0x3000
-
-/*** pSeries interrupt support ***/
-
- /* moved from 0xf00 */
- STD_EXCEPTION_PSERIES(., performance_monitor)
-
- .align 7
-_GLOBAL(do_stab_bolted_pSeries)
- mtcrf 0x80,r12
- mfspr r12,SPRN_SPRG2
- EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)
-
-/*
- * We have some room here we use that to put
- * the peries slb miss user trampoline code so it's reasonably
- * away from slb_miss_user_common to avoid problems with rfid
- *
- * This is used for when the SLB miss handler has to go virtual,
- * which doesn't happen for now anymore but will once we re-implement
- * dynamic VSIDs for shared page tables
- */
-#ifdef __DISABLED__
-slb_miss_user_pseries:
- std r10,PACA_EXGEN+EX_R10(r13)
- std r11,PACA_EXGEN+EX_R11(r13)
- std r12,PACA_EXGEN+EX_R12(r13)
- mfspr r10,SPRG1
- ld r11,PACA_EXSLB+EX_R9(r13)
- ld r12,PACA_EXSLB+EX_R3(r13)
- std r10,PACA_EXGEN+EX_R13(r13)
- std r11,PACA_EXGEN+EX_R9(r13)
- std r12,PACA_EXGEN+EX_R3(r13)
- clrrdi r12,r13,32
- mfmsr r10
- mfspr r11,SRR0 /* save SRR0 */
- ori r12,r12,slb_miss_user_common@l /* virt addr of handler */
- ori r10,r10,MSR_IR|MSR_DR|MSR_RI
- mtspr SRR0,r12
- mfspr r12,SRR1 /* and SRR1 */
- mtspr SRR1,r10
- rfid
- b . /* prevent spec. execution */
-#endif /* __DISABLED__ */
-
-/*
- * Vectors for the FWNMI option. Share common code.
- */
- .globl system_reset_fwnmi
-system_reset_fwnmi:
- HMT_MEDIUM
- mtspr SPRN_SPRG1,r13 /* save r13 */
- RUNLATCH_ON(r13)
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
-
- .globl machine_check_fwnmi
-machine_check_fwnmi:
- HMT_MEDIUM
- mtspr SPRN_SPRG1,r13 /* save r13 */
- RUNLATCH_ON(r13)
- EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
-
-#ifdef CONFIG_PPC_ISERIES
-/*** ISeries-LPAR interrupt handlers ***/
-
- STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC)
-
- .globl data_access_iSeries
-data_access_iSeries:
- mtspr SPRN_SPRG1,r13
-BEGIN_FTR_SECTION
- mtspr SPRN_SPRG2,r12
- mfspr r13,SPRN_DAR
- mfspr r12,SPRN_DSISR
- srdi r13,r13,60
- rlwimi r13,r12,16,0x20
- mfcr r12
- cmpwi r13,0x2c
- beq .do_stab_bolted_iSeries
- mtcrf 0x80,r12
- mfspr r12,SPRN_SPRG2
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
- EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN)
- EXCEPTION_PROLOG_ISERIES_2
- b data_access_common
-
-.do_stab_bolted_iSeries:
- mtcrf 0x80,r12
- mfspr r12,SPRN_SPRG2
- EXCEPTION_PROLOG_ISERIES_1(PACA_EXSLB)
- EXCEPTION_PROLOG_ISERIES_2
- b .do_stab_bolted
-
- .globl data_access_slb_iSeries
-data_access_slb_iSeries:
- mtspr SPRN_SPRG1,r13 /* save r13 */
- mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
- std r3,PACA_EXSLB+EX_R3(r13)
- mfspr r3,SPRN_DAR
- std r9,PACA_EXSLB+EX_R9(r13)
- mfcr r9
-#ifdef __DISABLED__
- cmpdi r3,0
- bge slb_miss_user_iseries
-#endif
- std r10,PACA_EXSLB+EX_R10(r13)
- std r11,PACA_EXSLB+EX_R11(r13)
- std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG1
- std r10,PACA_EXSLB+EX_R13(r13)
- ld r12,PACALPPACA+LPPACASRR1(r13);
- b .slb_miss_realmode
-
- STD_EXCEPTION_ISERIES(0x400, instruction_access, PACA_EXGEN)
-
- .globl instruction_access_slb_iSeries
-instruction_access_slb_iSeries:
- mtspr SPRN_SPRG1,r13 /* save r13 */
- mfspr r13,SPRN_SPRG3 /* get paca address into r13 */
- std r3,PACA_EXSLB+EX_R3(r13)
- ld r3,PACALPPACA+LPPACASRR0(r13) /* get SRR0 value */
- std r9,PACA_EXSLB+EX_R9(r13)
- mfcr r9
-#ifdef __DISABLED__
- cmpdi r3,0
- bge .slb_miss_user_iseries
-#endif
- std r10,PACA_EXSLB+EX_R10(r13)
- std r11,PACA_EXSLB+EX_R11(r13)
- std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG1
- std r10,PACA_EXSLB+EX_R13(r13)
- ld r12,PACALPPACA+LPPACASRR1(r13);
- b .slb_miss_realmode
-
-#ifdef __DISABLED__
-slb_miss_user_iseries:
- std r10,PACA_EXGEN+EX_R10(r13)
- std r11,PACA_EXGEN+EX_R11(r13)
- std r12,PACA_EXGEN+EX_R12(r13)
- mfspr r10,SPRG1
- ld r11,PACA_EXSLB+EX_R9(r13)
- ld r12,PACA_EXSLB+EX_R3(r13)
- std r10,PACA_EXGEN+EX_R13(r13)
- std r11,PACA_EXGEN+EX_R9(r13)
- std r12,PACA_EXGEN+EX_R3(r13)
- EXCEPTION_PROLOG_ISERIES_2
- b slb_miss_user_common
-#endif
-
- MASKABLE_EXCEPTION_ISERIES(0x500, hardware_interrupt)
- STD_EXCEPTION_ISERIES(0x600, alignment, PACA_EXGEN)
- STD_EXCEPTION_ISERIES(0x700, program_check, PACA_EXGEN)
- STD_EXCEPTION_ISERIES(0x800, fp_unavailable, PACA_EXGEN)
- MASKABLE_EXCEPTION_ISERIES(0x900, decrementer)
- STD_EXCEPTION_ISERIES(0xa00, trap_0a, PACA_EXGEN)
- STD_EXCEPTION_ISERIES(0xb00, trap_0b, PACA_EXGEN)
-
- .globl system_call_iSeries
-system_call_iSeries:
- mr r9,r13
- mfspr r13,SPRN_SPRG3
- EXCEPTION_PROLOG_ISERIES_2
- b system_call_common
-
- STD_EXCEPTION_ISERIES( 0xd00, single_step, PACA_EXGEN)
- STD_EXCEPTION_ISERIES( 0xe00, trap_0e, PACA_EXGEN)
- STD_EXCEPTION_ISERIES( 0xf00, performance_monitor, PACA_EXGEN)
-
- .globl system_reset_iSeries
-system_reset_iSeries:
- mfspr r13,SPRN_SPRG3 /* Get paca address */
- mfmsr r24
- ori r24,r24,MSR_RI
- mtmsrd r24 /* RI on */
- lhz r24,PACAPACAINDEX(r13) /* Get processor # */
- cmpwi 0,r24,0 /* Are we processor 0? */
- beq .__start_initialization_iSeries /* Start up the first processor */
- mfspr r4,SPRN_CTRLF
- li r5,CTRL_RUNLATCH /* Turn off the run light */
- andc r4,r4,r5
- mtspr SPRN_CTRLT,r4
-
-1:
- HMT_LOW
-#ifdef CONFIG_SMP
- lbz r23,PACAPROCSTART(r13) /* Test if this processor
- * should start */
- sync
- LOADADDR(r3,current_set)
- sldi r28,r24,3 /* get current_set[cpu#] */
- ldx r3,r3,r28
- addi r1,r3,THREAD_SIZE
- subi r1,r1,STACK_FRAME_OVERHEAD
-
- cmpwi 0,r23,0
- beq iSeries_secondary_smp_loop /* Loop until told to go */
- bne .__secondary_start /* Loop until told to go */
-iSeries_secondary_smp_loop:
- /* Let the Hypervisor know we are alive */
- /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
- lis r3,0x8002
- rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */
-#else /* CONFIG_SMP */
- /* Yield the processor. This is required for non-SMP kernels
- which are running on multi-threaded machines. */
- lis r3,0x8000
- rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */
- addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */
- li r4,0 /* "yield timed" */
- li r5,-1 /* "yield forever" */
-#endif /* CONFIG_SMP */
- li r0,-1 /* r0=-1 indicates a Hypervisor call */
- sc /* Invoke the hypervisor via a system call */
- mfspr r13,SPRN_SPRG3 /* Put r13 back ???? */
- b 1b /* If SMP not configured, secondaries
- * loop forever */
-
- .globl decrementer_iSeries_masked
-decrementer_iSeries_masked:
- li r11,1
- stb r11,PACALPPACA+LPPACADECRINT(r13)
- lwz r12,PACADEFAULTDECR(r13)
- mtspr SPRN_DEC,r12
- /* fall through */
-
- .globl hardware_interrupt_iSeries_masked
-hardware_interrupt_iSeries_masked:
- mtcrf 0x80,r9 /* Restore regs */
- ld r11,PACALPPACA+LPPACASRR0(r13)
- ld r12,PACALPPACA+LPPACASRR1(r13)
- mtspr SPRN_SRR0,r11
- mtspr SPRN_SRR1,r12
- ld r9,PACA_EXGEN+EX_R9(r13)
- ld r10,PACA_EXGEN+EX_R10(r13)
- ld r11,PACA_EXGEN+EX_R11(r13)
- ld r12,PACA_EXGEN+EX_R12(r13)
- ld r13,PACA_EXGEN+EX_R13(r13)
- rfid
- b . /* prevent speculative execution */
-#endif /* CONFIG_PPC_ISERIES */
-
-/*** Common interrupt handlers ***/
-
- STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception)
-
- /*
- * Machine check is different because we use a different
- * save area: PACA_EXMC instead of PACA_EXGEN.
- */
- .align 7
- .globl machine_check_common
-machine_check_common:
- EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC)
- DISABLE_INTS
- bl .save_nvgprs
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl .machine_check_exception
- b .ret_from_except
-
- STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt)
- STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception)
- STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception)
- STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception)
- STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception)
- STD_EXCEPTION_COMMON(0xf00, performance_monitor, .performance_monitor_exception)
- STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception)
-#ifdef CONFIG_ALTIVEC
- STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception)
-#else
- STD_EXCEPTION_COMMON(0x1700, altivec_assist, .unknown_exception)
-#endif
-
-/*
- * Here we have detected that the kernel stack pointer is bad.
- * R9 contains the saved CR, r13 points to the paca,
- * r10 contains the (bad) kernel stack pointer,
- * r11 and r12 contain the saved SRR0 and SRR1.
- * We switch to using an emergency stack, save the registers there,
- * and call kernel_bad_stack(), which panics.
- */
-bad_stack:
- ld r1,PACAEMERGSP(r13)
- subi r1,r1,64+INT_FRAME_SIZE
- std r9,_CCR(r1)
- std r10,GPR1(r1)
- std r11,_NIP(r1)
- std r12,_MSR(r1)
- mfspr r11,SPRN_DAR
- mfspr r12,SPRN_DSISR
- std r11,_DAR(r1)
- std r12,_DSISR(r1)
- mflr r10
- mfctr r11
- mfxer r12
- std r10,_LINK(r1)
- std r11,_CTR(r1)
- std r12,_XER(r1)
- SAVE_GPR(0,r1)
- SAVE_GPR(2,r1)
- SAVE_4GPRS(3,r1)
- SAVE_2GPRS(7,r1)
- SAVE_10GPRS(12,r1)
- SAVE_10GPRS(22,r1)
- addi r11,r1,INT_FRAME_SIZE
- std r11,0(r1)
- li r12,0
- std r12,0(r11)
- ld r2,PACATOC(r13)
-1: addi r3,r1,STACK_FRAME_OVERHEAD
- bl .kernel_bad_stack
- b 1b
-
-/*
- * Return from an exception with minimal checks.
- * The caller is assumed to have done EXCEPTION_PROLOG_COMMON.
- * If interrupts have been enabled, or anything has been
- * done that might have changed the scheduling status of
- * any task or sent any task a signal, you should use
- * ret_from_except or ret_from_except_lite instead of this.
- */
- .globl fast_exception_return
-fast_exception_return:
- ld r12,_MSR(r1)
- ld r11,_NIP(r1)
- andi. r3,r12,MSR_RI /* check if RI is set */
- beq- unrecov_fer
- ld r3,_CCR(r1)
- ld r4,_LINK(r1)
- ld r5,_CTR(r1)
- ld r6,_XER(r1)
- mtcr r3
- mtlr r4
- mtctr r5
- mtxer r6
- REST_GPR(0, r1)
- REST_8GPRS(2, r1)
-
- mfmsr r10
- clrrdi r10,r10,2 /* clear RI (LE is 0 already) */
- mtmsrd r10,1
-
- mtspr SPRN_SRR1,r12
- mtspr SPRN_SRR0,r11
- REST_4GPRS(10, r1)
- ld r1,GPR1(r1)
- rfid
- b . /* prevent speculative execution */
-
-unrecov_fer:
- bl .save_nvgprs
-1: addi r3,r1,STACK_FRAME_OVERHEAD
- bl .unrecoverable_exception
- b 1b
-
-/*
- * Here r13 points to the paca, r9 contains the saved CR,
- * SRR0 and SRR1 are saved in r11 and r12,
- * r9 - r13 are saved in paca->exgen.
- */
- .align 7
- .globl data_access_common
-data_access_common:
- RUNLATCH_ON(r10) /* It wont fit in the 0x300 handler */
- mfspr r10,SPRN_DAR
- std r10,PACA_EXGEN+EX_DAR(r13)
- mfspr r10,SPRN_DSISR
- stw r10,PACA_EXGEN+EX_DSISR(r13)
- EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN)
- ld r3,PACA_EXGEN+EX_DAR(r13)
- lwz r4,PACA_EXGEN+EX_DSISR(r13)
- li r5,0x300
- b .do_hash_page /* Try to handle as hpte fault */
-
- .align 7
- .globl instruction_access_common
-instruction_access_common:
- EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN)
- ld r3,_NIP(r1)
- andis. r4,r12,0x5820
- li r5,0x400
- b .do_hash_page /* Try to handle as hpte fault */
-
-/*
- * Here is the common SLB miss user that is used when going to virtual
- * mode for SLB misses, that is currently not used
- */
-#ifdef __DISABLED__
- .align 7
- .globl slb_miss_user_common
-slb_miss_user_common:
- mflr r10
- std r3,PACA_EXGEN+EX_DAR(r13)
- stw r9,PACA_EXGEN+EX_CCR(r13)
- std r10,PACA_EXGEN+EX_LR(r13)
- std r11,PACA_EXGEN+EX_SRR0(r13)
- bl .slb_allocate_user
-
- ld r10,PACA_EXGEN+EX_LR(r13)
- ld r3,PACA_EXGEN+EX_R3(r13)
- lwz r9,PACA_EXGEN+EX_CCR(r13)
- ld r11,PACA_EXGEN+EX_SRR0(r13)
- mtlr r10
- beq- slb_miss_fault
-
- andi. r10,r12,MSR_RI /* check for unrecoverable exception */
- beq- unrecov_user_slb
- mfmsr r10
-
-.machine push
-.machine "power4"
- mtcrf 0x80,r9
-.machine pop
-
- clrrdi r10,r10,2 /* clear RI before setting SRR0/1 */
- mtmsrd r10,1
-
- mtspr SRR0,r11
- mtspr SRR1,r12
-
- ld r9,PACA_EXGEN+EX_R9(r13)
- ld r10,PACA_EXGEN+EX_R10(r13)
- ld r11,PACA_EXGEN+EX_R11(r13)
- ld r12,PACA_EXGEN+EX_R12(r13)
- ld r13,PACA_EXGEN+EX_R13(r13)
- rfid
- b .
-
-slb_miss_fault:
- EXCEPTION_PROLOG_COMMON(0x380, PACA_EXGEN)
- ld r4,PACA_EXGEN+EX_DAR(r13)
- li r5,0
- std r4,_DAR(r1)
- std r5,_DSISR(r1)
- b .handle_page_fault
-
-unrecov_user_slb:
- EXCEPTION_PROLOG_COMMON(0x4200, PACA_EXGEN)
- DISABLE_INTS
- bl .save_nvgprs
-1: addi r3,r1,STACK_FRAME_OVERHEAD
- bl .unrecoverable_exception
- b 1b
-
-#endif /* __DISABLED__ */
-
-
-/*
- * r13 points to the PACA, r9 contains the saved CR,
- * r12 contain the saved SRR1, SRR0 is still ready for return
- * r3 has the faulting address
- * r9 - r13 are saved in paca->exslb.
- * r3 is saved in paca->slb_r3
- * We assume we aren't going to take any exceptions during this procedure.
- */
-_GLOBAL(slb_miss_realmode)
- mflr r10
-
- stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */
- std r10,PACA_EXSLB+EX_LR(r13) /* save LR */
-
- bl .slb_allocate_realmode
-
- /* All done -- return from exception. */
-
- ld r10,PACA_EXSLB+EX_LR(r13)
- ld r3,PACA_EXSLB+EX_R3(r13)
- lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */
-#ifdef CONFIG_PPC_ISERIES
- ld r11,PACALPPACA+LPPACASRR0(r13) /* get SRR0 value */
-#endif /* CONFIG_PPC_ISERIES */
-
- mtlr r10
-
- andi. r10,r12,MSR_RI /* check for unrecoverable exception */
- beq- unrecov_slb
-
-.machine push
-.machine "power4"
- mtcrf 0x80,r9
- mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */
-.machine pop
-
-#ifdef CONFIG_PPC_ISERIES
- mtspr SPRN_SRR0,r11
- mtspr SPRN_SRR1,r12
-#endif /* CONFIG_PPC_ISERIES */
- ld r9,PACA_EXSLB+EX_R9(r13)
- ld r10,PACA_EXSLB+EX_R10(r13)
- ld r11,PACA_EXSLB+EX_R11(r13)
- ld r12,PACA_EXSLB+EX_R12(r13)
- ld r13,PACA_EXSLB+EX_R13(r13)
- rfid
- b . /* prevent speculative execution */
-
-unrecov_slb:
- EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB)
- DISABLE_INTS
- bl .save_nvgprs
-1: addi r3,r1,STACK_FRAME_OVERHEAD
- bl .unrecoverable_exception
- b 1b
-
- .align 7
- .globl hardware_interrupt_common
- .globl hardware_interrupt_entry
-hardware_interrupt_common:
- EXCEPTION_PROLOG_COMMON(0x500, PACA_EXGEN)
-hardware_interrupt_entry:
- DISABLE_INTS
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl .do_IRQ
- b .ret_from_except_lite
-
- .align 7
- .globl alignment_common
-alignment_common:
- mfspr r10,SPRN_DAR
- std r10,PACA_EXGEN+EX_DAR(r13)
- mfspr r10,SPRN_DSISR
- stw r10,PACA_EXGEN+EX_DSISR(r13)
- EXCEPTION_PROLOG_COMMON(0x600, PACA_EXGEN)
- ld r3,PACA_EXGEN+EX_DAR(r13)
- lwz r4,PACA_EXGEN+EX_DSISR(r13)
- std r3,_DAR(r1)
- std r4,_DSISR(r1)
- bl .save_nvgprs
- addi r3,r1,STACK_FRAME_OVERHEAD
- ENABLE_INTS
- bl .alignment_exception
- b .ret_from_except
-
- .align 7
- .globl program_check_common
-program_check_common:
- EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN)
- bl .save_nvgprs
- addi r3,r1,STACK_FRAME_OVERHEAD
- ENABLE_INTS
- bl .program_check_exception
- b .ret_from_except
-
- .align 7
- .globl fp_unavailable_common
-fp_unavailable_common:
- EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN)
- bne .load_up_fpu /* if from user, just load it up */
- bl .save_nvgprs
- addi r3,r1,STACK_FRAME_OVERHEAD
- ENABLE_INTS
- bl .kernel_fp_unavailable_exception
- BUG_OPCODE
-
- .align 7
- .globl altivec_unavailable_common
-altivec_unavailable_common:
- EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN)
-#ifdef CONFIG_ALTIVEC
-BEGIN_FTR_SECTION
- bne .load_up_altivec /* if from user, just load it up */
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-#endif
- bl .save_nvgprs
- addi r3,r1,STACK_FRAME_OVERHEAD
- ENABLE_INTS
- bl .altivec_unavailable_exception
- b .ret_from_except
-
-#ifdef CONFIG_ALTIVEC
-/*
- * load_up_altivec(unused, unused, tsk)
- * Disable VMX for the task which had it previously,
- * and save its vector registers in its thread_struct.
- * Enables the VMX for use in the kernel on return.
- * On SMP we know the VMX is free, since we give it up every
- * switch (ie, no lazy save of the vector registers).
- * On entry: r13 == 'current' && last_task_used_altivec != 'current'
- */
-_STATIC(load_up_altivec)
- mfmsr r5 /* grab the current MSR */
- oris r5,r5,MSR_VEC@h
- mtmsrd r5 /* enable use of VMX now */
- isync
-
-/*
- * For SMP, we don't do lazy VMX switching because it just gets too
- * horrendously complex, especially when a task switches from one CPU
- * to another. Instead we call giveup_altvec in switch_to.
- * VRSAVE isn't dealt with here, that is done in the normal context
- * switch code. Note that we could rely on vrsave value to eventually
- * avoid saving all of the VREGs here...
- */
-#ifndef CONFIG_SMP
- ld r3,last_task_used_altivec@got(r2)
- ld r4,0(r3)
- cmpdi 0,r4,0
- beq 1f
- /* Save VMX state to last_task_used_altivec's THREAD struct */
- addi r4,r4,THREAD
- SAVE_32VRS(0,r5,r4)
- mfvscr vr0
- li r10,THREAD_VSCR
- stvx vr0,r10,r4
- /* Disable VMX for last_task_used_altivec */
- ld r5,PT_REGS(r4)
- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- lis r6,MSR_VEC@h
- andc r4,r4,r6
- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#endif /* CONFIG_SMP */
- /* Hack: if we get an altivec unavailable trap with VRSAVE
- * set to all zeros, we assume this is a broken application
- * that fails to set it properly, and thus we switch it to
- * all 1's
- */
- mfspr r4,SPRN_VRSAVE
- cmpdi 0,r4,0
- bne+ 1f
- li r4,-1
- mtspr SPRN_VRSAVE,r4
-1:
- /* enable use of VMX after return */
- ld r4,PACACURRENT(r13)
- addi r5,r4,THREAD /* Get THREAD */
- oris r12,r12,MSR_VEC@h
- std r12,_MSR(r1)
- li r4,1
- li r10,THREAD_VSCR
- stw r4,THREAD_USED_VR(r5)
- lvx vr0,r10,r5
- mtvscr vr0
- REST_32VRS(0,r4,r5)
-#ifndef CONFIG_SMP
- /* Update last_task_used_math to 'current' */
- subi r4,r5,THREAD /* Back to 'current' */
- std r4,0(r3)
-#endif /* CONFIG_SMP */
- /* restore registers and return */
- b fast_exception_return
-#endif /* CONFIG_ALTIVEC */
-
-/*
- * Hash table stuff
- */
- .align 7
-_GLOBAL(do_hash_page)
- std r3,_DAR(r1)
- std r4,_DSISR(r1)
-
- andis. r0,r4,0xa450 /* weird error? */
- bne- .handle_page_fault /* if not, try to insert a HPTE */
-BEGIN_FTR_SECTION
- andis. r0,r4,0x0020 /* Is it a segment table fault? */
- bne- .do_ste_alloc /* If so handle it */
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
-
- /*
- * We need to set the _PAGE_USER bit if MSR_PR is set or if we are
- * accessing a userspace segment (even from the kernel). We assume
- * kernel addresses always have the high bit set.
- */
- rlwinm r4,r4,32-25+9,31-9,31-9 /* DSISR_STORE -> _PAGE_RW */
- rotldi r0,r3,15 /* Move high bit into MSR_PR posn */
- orc r0,r12,r0 /* MSR_PR | ~high_bit */
- rlwimi r4,r0,32-13,30,30 /* becomes _PAGE_USER access bit */
- ori r4,r4,1 /* add _PAGE_PRESENT */
- rlwimi r4,r5,22+2,31-2,31-2 /* Set _PAGE_EXEC if trap is 0x400 */
-
- /*
- * On iSeries, we soft-disable interrupts here, then
- * hard-enable interrupts so that the hash_page code can spin on
- * the hash_table_lock without problems on a shared processor.
- */
- DISABLE_INTS
-
- /*
- * r3 contains the faulting address
- * r4 contains the required access permissions
- * r5 contains the trap number
- *
- * at return r3 = 0 for success
- */
- bl .hash_page /* build HPTE if possible */
- cmpdi r3,0 /* see if hash_page succeeded */
-
-#ifdef DO_SOFT_DISABLE
- /*
- * If we had interrupts soft-enabled at the point where the
- * DSI/ISI occurred, and an interrupt came in during hash_page,
- * handle it now.
- * We jump to ret_from_except_lite rather than fast_exception_return
- * because ret_from_except_lite will check for and handle pending
- * interrupts if necessary.
- */
- beq .ret_from_except_lite
- /* For a hash failure, we don't bother re-enabling interrupts */
- ble- 12f
-
- /*
- * hash_page couldn't handle it, set soft interrupt enable back
- * to what it was before the trap. Note that .local_irq_restore
- * handles any interrupts pending at this point.
- */
- ld r3,SOFTE(r1)
- bl .local_irq_restore
- b 11f
-#else
- beq fast_exception_return /* Return from exception on success */
- ble- 12f /* Failure return from hash_page */
-
- /* fall through */
-#endif
-
-/* Here we have a page fault that hash_page can't handle. */
-_GLOBAL(handle_page_fault)
- ENABLE_INTS
-11: ld r4,_DAR(r1)
- ld r5,_DSISR(r1)
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl .do_page_fault
- cmpdi r3,0
- beq+ .ret_from_except_lite
- bl .save_nvgprs
- mr r5,r3
- addi r3,r1,STACK_FRAME_OVERHEAD
- lwz r4,_DAR(r1)
- bl .bad_page_fault
- b .ret_from_except
-
-/* We have a page fault that hash_page could handle but HV refused
- * the PTE insertion
- */
-12: bl .save_nvgprs
- addi r3,r1,STACK_FRAME_OVERHEAD
- lwz r4,_DAR(r1)
- bl .low_hash_fault
- b .ret_from_except
-
- /* here we have a segment miss */
-_GLOBAL(do_ste_alloc)
- bl .ste_allocate /* try to insert stab entry */
- cmpdi r3,0
- beq+ fast_exception_return
- b .handle_page_fault
-
-/*
- * r13 points to the PACA, r9 contains the saved CR,
- * r11 and r12 contain the saved SRR0 and SRR1.
- * r9 - r13 are saved in paca->exslb.
- * We assume we aren't going to take any exceptions during this procedure.
- * We assume (DAR >> 60) == 0xc.
- */
- .align 7
-_GLOBAL(do_stab_bolted)
- stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */
- std r11,PACA_EXSLB+EX_SRR0(r13) /* save SRR0 in exc. frame */
-
- /* Hash to the primary group */
- ld r10,PACASTABVIRT(r13)
- mfspr r11,SPRN_DAR
- srdi r11,r11,28
- rldimi r10,r11,7,52 /* r10 = first ste of the group */
-
- /* Calculate VSID */
- /* This is a kernel address, so protovsid = ESID */
- ASM_VSID_SCRAMBLE(r11, r9)
- rldic r9,r11,12,16 /* r9 = vsid << 12 */
-
- /* Search the primary group for a free entry */
-1: ld r11,0(r10) /* Test valid bit of the current ste */
- andi. r11,r11,0x80
- beq 2f
- addi r10,r10,16
- andi. r11,r10,0x70
- bne 1b
-
- /* Stick for only searching the primary group for now. */
- /* At least for now, we use a very simple random castout scheme */
- /* Use the TB as a random number ; OR in 1 to avoid entry 0 */
- mftb r11
- rldic r11,r11,4,57 /* r11 = (r11 << 4) & 0x70 */
- ori r11,r11,0x10
-
- /* r10 currently points to an ste one past the group of interest */
- /* make it point to the randomly selected entry */
- subi r10,r10,128
- or r10,r10,r11 /* r10 is the entry to invalidate */
-
- isync /* mark the entry invalid */
- ld r11,0(r10)
- rldicl r11,r11,56,1 /* clear the valid bit */
- rotldi r11,r11,8
- std r11,0(r10)
- sync
-
- clrrdi r11,r11,28 /* Get the esid part of the ste */
- slbie r11
-
-2: std r9,8(r10) /* Store the vsid part of the ste */
- eieio
-
- mfspr r11,SPRN_DAR /* Get the new esid */
- clrrdi r11,r11,28 /* Permits a full 32b of ESID */
- ori r11,r11,0x90 /* Turn on valid and kp */
- std r11,0(r10) /* Put new entry back into the stab */
-
- sync
-
- /* All done -- return from exception. */
- lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */
- ld r11,PACA_EXSLB+EX_SRR0(r13) /* get saved SRR0 */
-
- andi. r10,r12,MSR_RI
- beq- unrecov_slb
-
- mtcrf 0x80,r9 /* restore CR */
-
- mfmsr r10
- clrrdi r10,r10,2
- mtmsrd r10,1
-
- mtspr SPRN_SRR0,r11
- mtspr SPRN_SRR1,r12
- ld r9,PACA_EXSLB+EX_R9(r13)
- ld r10,PACA_EXSLB+EX_R10(r13)
- ld r11,PACA_EXSLB+EX_R11(r13)
- ld r12,PACA_EXSLB+EX_R12(r13)
- ld r13,PACA_EXSLB+EX_R13(r13)
- rfid
- b . /* prevent speculative execution */
-
-/*
- * Space for CPU0's segment table.
- *
- * On iSeries, the hypervisor must fill in at least one entry before
- * we get control (with relocate on). The address is give to the hv
- * as a page number (see xLparMap in lpardata.c), so this must be at a
- * fixed address (the linker can't compute (u64)&initial_stab >>
- * PAGE_SHIFT).
- */
- . = STAB0_PHYS_ADDR /* 0x6000 */
- .globl initial_stab
-initial_stab:
- .space 4096
-
-/*
- * Data area reserved for FWNMI option.
- * This address (0x7000) is fixed by the RPA.
- */
- .= 0x7000
- .globl fwnmi_data_area
-fwnmi_data_area:
-
- /* iSeries does not use the FWNMI stuff, so it is safe to put
- * this here, even if we later allow kernels that will boot on
- * both pSeries and iSeries */
-#ifdef CONFIG_PPC_ISERIES
- . = LPARMAP_PHYS
-#include "lparmap.s"
-/*
- * This ".text" is here for old compilers that generate a trailing
- * .note section when compiling .c files to .s
- */
- .text
-#endif /* CONFIG_PPC_ISERIES */
-
- . = 0x8000
-
-/*
- * On pSeries, secondary processors spin in the following code.
- * At entry, r3 = this processor's number (physical cpu id)
- */
-_GLOBAL(pSeries_secondary_smp_init)
- mr r24,r3
-
- /* turn on 64-bit mode */
- bl .enable_64b_mode
- isync
-
- /* Copy some CPU settings from CPU 0 */
- bl .__restore_cpu_setup
-
- /* Set up a paca value for this processor. Since we have the
- * physical cpu id in r24, we need to search the pacas to find
- * which logical id maps to our physical one.
- */
- LOADADDR(r13, paca) /* Get base vaddr of paca array */
- li r5,0 /* logical cpu id */
-1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */
- cmpw r6,r24 /* Compare to our id */
- beq 2f
- addi r13,r13,PACA_SIZE /* Loop to next PACA on miss */
- addi r5,r5,1
- cmpwi r5,NR_CPUS
- blt 1b
-
- mr r3,r24 /* not found, copy phys to r3 */
- b .kexec_wait /* next kernel might do better */
-
-2: mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */
- /* From now on, r24 is expected to be logical cpuid */
- mr r24,r5
-3: HMT_LOW
- lbz r23,PACAPROCSTART(r13) /* Test if this processor should */
- /* start. */
- sync
-
- /* Create a temp kernel stack for use before relocation is on. */
- ld r1,PACAEMERGSP(r13)
- subi r1,r1,STACK_FRAME_OVERHEAD
-
- cmpwi 0,r23,0
-#ifdef CONFIG_SMP
- bne .__secondary_start
-#endif
- b 3b /* Loop until told to go */
-
-#ifdef CONFIG_PPC_ISERIES
-_STATIC(__start_initialization_iSeries)
- /* Clear out the BSS */
- LOADADDR(r11,__bss_stop)
- LOADADDR(r8,__bss_start)
- sub r11,r11,r8 /* bss size */
- addi r11,r11,7 /* round up to an even double word */
- rldicl. r11,r11,61,3 /* shift right by 3 */
- beq 4f
- addi r8,r8,-8
- li r0,0
- mtctr r11 /* zero this many doublewords */
-3: stdu r0,8(r8)
- bdnz 3b
-4:
- LOADADDR(r1,init_thread_union)
- addi r1,r1,THREAD_SIZE
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
-
- LOADADDR(r3,cpu_specs)
- LOADADDR(r4,cur_cpu_spec)
- li r5,0
- bl .identify_cpu
-
- LOADADDR(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
-
- bl .iSeries_early_setup
- bl .early_setup
-
- /* relocation is on at this point */
-
- b .start_here_common
-#endif /* CONFIG_PPC_ISERIES */
-
-#ifdef CONFIG_PPC_MULTIPLATFORM
-
-_STATIC(__mmu_off)
- mfmsr r3
- andi. r0,r3,MSR_IR|MSR_DR
- beqlr
- andc r3,r3,r0
- mtspr SPRN_SRR0,r4
- mtspr SPRN_SRR1,r3
- sync
- rfid
- b . /* prevent speculative execution */
-
-
-/*
- * Here is our main kernel entry point. We support currently 2 kind of entries
- * depending on the value of r5.
- *
- * r5 != NULL -> OF entry, we go to prom_init, "legacy" parameter content
- * in r3...r7
- *
- * r5 == NULL -> kexec style entry. r3 is a physical pointer to the
- * DT block, r4 is a physical pointer to the kernel itself
- *
- */
-_GLOBAL(__start_initialization_multiplatform)
- /*
- * Are we booted from a PROM Of-type client-interface ?
- */
- cmpldi cr0,r5,0
- bne .__boot_from_prom /* yes -> prom */
-
- /* Save parameters */
- mr r31,r3
- mr r30,r4
-
- /* Make sure we are running in 64 bits mode */
- bl .enable_64b_mode
-
- /* Setup some critical 970 SPRs before switching MMU off */
- bl .__970_cpu_preinit
-
- /* cpu # */
- li r24,0
-
- /* Switch off MMU if not already */
- LOADADDR(r4, .__after_prom_start - KERNELBASE)
- add r4,r4,r30
- bl .__mmu_off
- b .__after_prom_start
-
-_STATIC(__boot_from_prom)
- /* Save parameters */
- mr r31,r3
- mr r30,r4
- mr r29,r5
- mr r28,r6
- mr r27,r7
-
- /* Make sure we are running in 64 bits mode */
- bl .enable_64b_mode
-
- /* put a relocation offset into r3 */
- bl .reloc_offset
-
- LOADADDR(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
-
- /* Relocate the TOC from a virt addr to a real addr */
- sub r2,r2,r3
-
- /* Restore parameters */
- mr r3,r31
- mr r4,r30
- mr r5,r29
- mr r6,r28
- mr r7,r27
-
- /* Do all of the interaction with OF client interface */
- bl .prom_init
- /* We never return */
- trap
-
-/*
- * At this point, r3 contains the physical address we are running at,
- * returned by prom_init()
- */
-_STATIC(__after_prom_start)
-
-/*
- * We need to run with __start at physical address 0.
- * This will leave some code in the first 256B of
- * real memory, which are reserved for software use.
- * The remainder of the first page is loaded with the fixed
- * interrupt vectors. The next two pages are filled with
- * unknown exception placeholders.
- *
- * Note: This process overwrites the OF exception vectors.
- * r26 == relocation offset
- * r27 == KERNELBASE
- */
- bl .reloc_offset
- mr r26,r3
- SET_REG_TO_CONST(r27,KERNELBASE)
-
- li r3,0 /* target addr */
-
- // XXX FIXME: Use phys returned by OF (r30)
- sub r4,r27,r26 /* source addr */
- /* current address of _start */
- /* i.e. where we are running */
- /* the source addr */
-
- LOADADDR(r5,copy_to_here) /* # bytes of memory to copy */
- sub r5,r5,r27
-
- li r6,0x100 /* Start offset, the first 0x100 */
- /* bytes were copied earlier. */
-
- bl .copy_and_flush /* copy the first n bytes */
- /* this includes the code being */
- /* executed here. */
-
- LOADADDR(r0, 4f) /* Jump to the copy of this code */
- mtctr r0 /* that we just made/relocated */
- bctr
-
-4: LOADADDR(r5,klimit)
- sub r5,r5,r26
- ld r5,0(r5) /* get the value of klimit */
- sub r5,r5,r27
- bl .copy_and_flush /* copy the rest */
- b .start_here_multiplatform
-
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
-/*
- * Copy routine used to copy the kernel to start at physical address 0
- * and flush and invalidate the caches as needed.
- * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
- * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
- *
- * Note: this routine *only* clobbers r0, r6 and lr
- */
-_GLOBAL(copy_and_flush)
- addi r5,r5,-8
- addi r6,r6,-8
-4: li r0,16 /* Use the least common */
- /* denominator cache line */
- /* size. This results in */
- /* extra cache line flushes */
- /* but operation is correct. */
- /* Can't get cache line size */
- /* from NACA as it is being */
- /* moved too. */
-
- mtctr r0 /* put # words/line in ctr */
-3: addi r6,r6,8 /* copy a cache line */
- ldx r0,r6,r4
- stdx r0,r6,r3
- bdnz 3b
- dcbst r6,r3 /* write it to memory */
- sync
- icbi r6,r3 /* flush the icache line */
- cmpld 0,r6,r5
- blt 4b
- sync
- addi r5,r5,8
- addi r6,r6,8
- blr
-
-.align 8
-copy_to_here:
-
-#ifdef CONFIG_SMP
-#ifdef CONFIG_PPC_PMAC
-/*
- * On PowerMac, secondary processors starts from the reset vector, which
- * is temporarily turned into a call to one of the functions below.
- */
- .section ".text";
- .align 2 ;
-
- .globl __secondary_start_pmac_0
-__secondary_start_pmac_0:
- /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */
- li r24,0
- b 1f
- li r24,1
- b 1f
- li r24,2
- b 1f
- li r24,3
-1:
-
-_GLOBAL(pmac_secondary_start)
- /* turn on 64-bit mode */
- bl .enable_64b_mode
- isync
-
- /* Copy some CPU settings from CPU 0 */
- bl .__restore_cpu_setup
-
- /* pSeries do that early though I don't think we really need it */
- mfmsr r3
- ori r3,r3,MSR_RI
- mtmsrd r3 /* RI on */
-
- /* Set up a paca value for this processor. */
- LOADADDR(r4, paca) /* Get base vaddr of paca array */
- mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */
- add r13,r13,r4 /* for this processor. */
- mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */
-
- /* Create a temp kernel stack for use before relocation is on. */
- ld r1,PACAEMERGSP(r13)
- subi r1,r1,STACK_FRAME_OVERHEAD
-
- b .__secondary_start
-
-#endif /* CONFIG_PPC_PMAC */
-
-/*
- * This function is called after the master CPU has released the
- * secondary processors. The execution environment is relocation off.
- * The paca for this processor has the following fields initialized at
- * this point:
- * 1. Processor number
- * 2. Segment table pointer (virtual address)
- * On entry the following are set:
- * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries
- * r24 = cpu# (in Linux terms)
- * r13 = paca virtual address
- * SPRG3 = paca virtual address
- */
-_GLOBAL(__secondary_start)
-
- HMT_MEDIUM /* Set thread priority to MEDIUM */
-
- ld r2,PACATOC(r13)
-
- /* Do early setup for that CPU */
- bl .early_setup_secondary
-
- /* Initialize the kernel stack. Just a repeat for iSeries. */
- LOADADDR(r3,current_set)
- sldi r28,r24,3 /* get current_set[cpu#] */
- ldx r1,r3,r28
- addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
- std r1,PACAKSAVE(r13)
-
- li r7,0
- mtlr r7
-
- /* enable MMU and jump to start_secondary */
- LOADADDR(r3,.start_secondary_prolog)
- SET_REG_TO_CONST(r4, MSR_KERNEL)
-#ifdef DO_SOFT_DISABLE
- ori r4,r4,MSR_EE
-#endif
- mtspr SPRN_SRR0,r3
- mtspr SPRN_SRR1,r4
- rfid
- b . /* prevent speculative execution */
-
-/*
- * Running with relocation on at this point. All we want to do is
- * zero the stack back-chain pointer before going into C code.
- */
-_GLOBAL(start_secondary_prolog)
- li r3,0
- std r3,0(r1) /* Zero the stack frame pointer */
- bl .start_secondary
-#endif
-
-/*
- * This subroutine clobbers r11 and r12
- */
-_GLOBAL(enable_64b_mode)
- mfmsr r11 /* grab the current MSR */
- li r12,1
- rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
- or r11,r11,r12
- li r12,1
- rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
- or r11,r11,r12
- mtmsrd r11
- isync
- blr
-
-#ifdef CONFIG_PPC_MULTIPLATFORM
-/*
- * This is where the main kernel code starts.
- */
-_STATIC(start_here_multiplatform)
- /* get a new offset, now that the kernel has moved. */
- bl .reloc_offset
- mr r26,r3
-
- /* Clear out the BSS. It may have been done in prom_init,
- * already but that's irrelevant since prom_init will soon
- * be detached from the kernel completely. Besides, we need
- * to clear it now for kexec-style entry.
- */
- LOADADDR(r11,__bss_stop)
- LOADADDR(r8,__bss_start)
- sub r11,r11,r8 /* bss size */
- addi r11,r11,7 /* round up to an even double word */
- rldicl. r11,r11,61,3 /* shift right by 3 */
- beq 4f
- addi r8,r8,-8
- li r0,0
- mtctr r11 /* zero this many doublewords */
-3: stdu r0,8(r8)
- bdnz 3b
-4:
-
- mfmsr r6
- ori r6,r6,MSR_RI
- mtmsrd r6 /* RI on */
-
-#ifdef CONFIG_HMT
- /* Start up the second thread on cpu 0 */
- mfspr r3,SPRN_PVR
- srwi r3,r3,16
- cmpwi r3,0x34 /* Pulsar */
- beq 90f
- cmpwi r3,0x36 /* Icestar */
- beq 90f
- cmpwi r3,0x37 /* SStar */
- beq 90f
- b 91f /* HMT not supported */
-90: li r3,0
- bl .hmt_start_secondary
-91:
-#endif
-
- /* The following gets the stack and TOC set up with the regs */
- /* pointing to the real addr of the kernel stack. This is */
- /* all done to support the C function call below which sets */
- /* up the htab. This is done because we have relocated the */
- /* kernel but are still running in real mode. */
-
- LOADADDR(r3,init_thread_union)
- sub r3,r3,r26
-
- /* set up a stack pointer (physical address) */
- addi r1,r3,THREAD_SIZE
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
-
- /* set up the TOC (physical address) */
- LOADADDR(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
- sub r2,r2,r26
-
- LOADADDR(r3,cpu_specs)
- sub r3,r3,r26
- LOADADDR(r4,cur_cpu_spec)
- sub r4,r4,r26
- mr r5,r26
- bl .identify_cpu
-
- /* Save some low level config HIDs of CPU0 to be copied to
- * other CPUs later on, or used for suspend/resume
- */
- bl .__save_cpu_setup
- sync
-
- /* Setup a valid physical PACA pointer in SPRG3 for early_setup
- * note that boot_cpuid can always be 0 nowadays since there is
- * nowhere it can be initialized differently before we reach this
- * code
- */
- LOADADDR(r27, boot_cpuid)
- sub r27,r27,r26
- lwz r27,0(r27)
-
- LOADADDR(r24, paca) /* Get base vaddr of paca array */
- mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */
- add r13,r13,r24 /* for this processor. */
- sub r13,r13,r26 /* convert to physical addr */
- mtspr SPRN_SPRG3,r13 /* PPPBBB: Temp... -Peter */
-
- /* Do very early kernel initializations, including initial hash table,
- * stab and slb setup before we turn on relocation. */
-
- /* Restore parameters passed from prom_init/kexec */
- mr r3,r31
- bl .early_setup
-
- LOADADDR(r3,.start_here_common)
- SET_REG_TO_CONST(r4, MSR_KERNEL)
- mtspr SPRN_SRR0,r3
- mtspr SPRN_SRR1,r4
- rfid
- b . /* prevent speculative execution */
-#endif /* CONFIG_PPC_MULTIPLATFORM */
-
- /* This is where all platforms converge execution */
-_STATIC(start_here_common)
- /* relocation is on at this point */
-
- /* The following code sets up the SP and TOC now that we are */
- /* running with translation enabled. */
-
- LOADADDR(r3,init_thread_union)
-
- /* set up the stack */
- addi r1,r3,THREAD_SIZE
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
-
- /* Apply the CPUs-specific fixups (nop out sections not relevant
- * to this CPU
- */
- li r3,0
- bl .do_cpu_ftr_fixups
-
- LOADADDR(r26, boot_cpuid)
- lwz r26,0(r26)
-
- LOADADDR(r24, paca) /* Get base vaddr of paca array */
- mulli r13,r26,PACA_SIZE /* Calculate vaddr of right paca */
- add r13,r13,r24 /* for this processor. */
- mtspr SPRN_SPRG3,r13
-
- /* ptr to current */
- LOADADDR(r4,init_task)
- std r4,PACACURRENT(r13)
-
- /* Load the TOC */
- ld r2,PACATOC(r13)
- std r1,PACAKSAVE(r13)
-
- bl .setup_system
-
- /* Load up the kernel context */
-5:
-#ifdef DO_SOFT_DISABLE
- li r5,0
- stb r5,PACAPROCENABLED(r13) /* Soft Disabled */
- mfmsr r5
- ori r5,r5,MSR_EE /* Hard Enabled */
- mtmsrd r5
-#endif
-
- bl .start_kernel
-
-_GLOBAL(hmt_init)
-#ifdef CONFIG_HMT
- LOADADDR(r5, hmt_thread_data)
- mfspr r7,SPRN_PVR
- srwi r7,r7,16
- cmpwi r7,0x34 /* Pulsar */
- beq 90f
- cmpwi r7,0x36 /* Icestar */
- beq 91f
- cmpwi r7,0x37 /* SStar */
- beq 91f
- b 101f
-90: mfspr r6,SPRN_PIR
- andi. r6,r6,0x1f
- b 92f
-91: mfspr r6,SPRN_PIR
- andi. r6,r6,0x3ff
-92: sldi r4,r24,3
- stwx r6,r5,r4
- bl .hmt_start_secondary
- b 101f
-
-__hmt_secondary_hold:
- LOADADDR(r5, hmt_thread_data)
- clrldi r5,r5,4
- li r7,0
- mfspr r6,SPRN_PIR
- mfspr r8,SPRN_PVR
- srwi r8,r8,16
- cmpwi r8,0x34
- bne 93f
- andi. r6,r6,0x1f
- b 103f
-93: andi. r6,r6,0x3f
-
-103: lwzx r8,r5,r7
- cmpw r8,r6
- beq 104f
- addi r7,r7,8
- b 103b
-
-104: addi r7,r7,4
- lwzx r9,r5,r7
- mr r24,r9
-101:
-#endif
- mr r3,r24
- b .pSeries_secondary_smp_init
-
-#ifdef CONFIG_HMT
-_GLOBAL(hmt_start_secondary)
- LOADADDR(r4,__hmt_secondary_hold)
- clrldi r4,r4,4
- mtspr SPRN_NIADORM, r4
- mfspr r4, SPRN_MSRDORM
- li r5, -65
- and r4, r4, r5
- mtspr SPRN_MSRDORM, r4
- lis r4,0xffef
- ori r4,r4,0x7403
- mtspr SPRN_TSC, r4
- li r4,0x1f4
- mtspr SPRN_TST, r4
- mfspr r4, SPRN_HID0
- ori r4, r4, 0x1
- mtspr SPRN_HID0, r4
- mfspr r4, SPRN_CTRLF
- oris r4, r4, 0x40
- mtspr SPRN_CTRLT, r4
- blr
-#endif
-
-/*
- * We put a few things here that have to be page-aligned.
- * This stuff goes at the beginning of the bss, which is page-aligned.
- */
- .section ".bss"
-
- .align PAGE_SHIFT
-
- .globl empty_zero_page
-empty_zero_page:
- .space PAGE_SIZE
-
- .globl swapper_pg_dir
-swapper_pg_dir:
- .space PAGE_SIZE
-
-/*
- * This space gets a copy of optional info passed to us by the bootstrap
- * Used to pass parameters into the kernel like root=/dev/sda1, etc.
- */
- .globl cmd_line
-cmd_line:
- .space COMMAND_LINE_SIZE
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
deleted file mode 100644
index 5e089deb0a2..00000000000
--- a/arch/ppc64/kernel/misc.S
+++ /dev/null
@@ -1,940 +0,0 @@
-/*
- * arch/ppc/kernel/misc.S
- *
- *
- *
- * This file contains miscellaneous low-level functions.
- * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
- *
- * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
- * and Paul Mackerras.
- * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
- * PPC64 updates by Dave Engebretsen (engebret@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/config.h>
-#include <linux/sys.h>
-#include <asm/unistd.h>
-#include <asm/errno.h>
-#include <asm/processor.h>
-#include <asm/page.h>
-#include <asm/cache.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/cputable.h>
-#include <asm/thread_info.h>
-
- .text
-
-/*
- * Returns (address we were linked at) - (address we are running at)
- * for use before the text and data are mapped to KERNELBASE.
- */
-
-_GLOBAL(reloc_offset)
- mflr r0
- bl 1f
-1: mflr r3
- LOADADDR(r4,1b)
- sub r3,r4,r3
- mtlr r0
- blr
-
-_GLOBAL(get_msr)
- mfmsr r3
- blr
-
-_GLOBAL(get_dar)
- mfdar r3
- blr
-
-_GLOBAL(get_srr0)
- mfsrr0 r3
- blr
-
-_GLOBAL(get_srr1)
- mfsrr1 r3
- blr
-
-_GLOBAL(get_sp)
- mr r3,r1
- blr
-
-#ifdef CONFIG_IRQSTACKS
-_GLOBAL(call_do_softirq)
- mflr r0
- std r0,16(r1)
- stdu r1,THREAD_SIZE-112(r3)
- mr r1,r3
- bl .__do_softirq
- ld r1,0(r1)
- ld r0,16(r1)
- mtlr r0
- blr
-
-_GLOBAL(call___do_IRQ)
- mflr r0
- std r0,16(r1)
- stdu r1,THREAD_SIZE-112(r5)
- mr r1,r5
- bl .__do_IRQ
- ld r1,0(r1)
- ld r0,16(r1)
- mtlr r0
- blr
-#endif /* CONFIG_IRQSTACKS */
-
- /*
- * To be called by C code which needs to do some operations with MMU
- * disabled. Note that interrupts have to be disabled by the caller
- * prior to calling us. The code called _MUST_ be in the RMO of course
- * and part of the linear mapping as we don't attempt to translate the
- * stack pointer at all. The function is called with the stack switched
- * to this CPU emergency stack
- *
- * prototype is void *call_with_mmu_off(void *func, void *data);
- *
- * the called function is expected to be of the form
- *
- * void *called(void *data);
- */
-_GLOBAL(call_with_mmu_off)
- mflr r0 /* get link, save it on stackframe */
- std r0,16(r1)
- mr r1,r5 /* save old stack ptr */
- ld r1,PACAEMERGSP(r13) /* get emerg. stack */
- subi r1,r1,STACK_FRAME_OVERHEAD
- std r0,16(r1) /* save link on emerg. stack */
- std r5,0(r1) /* save old stack ptr in backchain */
- ld r3,0(r3) /* get to real function ptr (assume same TOC) */
- bl 2f /* we need LR to return, continue at label 2 */
-
- ld r0,16(r1) /* we return here from the call, get LR and */
- ld r1,0(r1) /* .. old stack ptr */
- mtspr SPRN_SRR0,r0 /* and get back to virtual mode with these */
- mfmsr r4
- ori r4,r4,MSR_IR|MSR_DR
- mtspr SPRN_SRR1,r4
- rfid
-
-2: mtspr SPRN_SRR0,r3 /* coming from above, enter real mode */
- mr r3,r4 /* get parameter */
- mfmsr r0
- ori r0,r0,MSR_IR|MSR_DR
- xori r0,r0,MSR_IR|MSR_DR
- mtspr SPRN_SRR1,r0
- rfid
-
-
- .section ".toc","aw"
-PPC64_CACHES:
- .tc ppc64_caches[TC],ppc64_caches
- .section ".text"
-
-/*
- * Write any modified data cache blocks out to memory
- * and invalidate the corresponding instruction cache blocks.
- *
- * flush_icache_range(unsigned long start, unsigned long stop)
- *
- * flush all bytes from start through stop-1 inclusive
- */
-
-_KPROBE(__flush_icache_range)
-
-/*
- * Flush the data cache to memory
- *
- * Different systems have different cache line sizes
- * and in some cases i-cache and d-cache line sizes differ from
- * each other.
- */
- ld r10,PPC64_CACHES@toc(r2)
- lwz r7,DCACHEL1LINESIZE(r10)/* Get cache line size */
- addi r5,r7,-1
- andc r6,r3,r5 /* round low to line bdy */
- subf r8,r6,r4 /* compute length */
- add r8,r8,r5 /* ensure we get enough */
- lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of cache line size */
- srw. r8,r8,r9 /* compute line count */
- beqlr /* nothing to do? */
- mtctr r8
-1: dcbst 0,r6
- add r6,r6,r7
- bdnz 1b
- sync
-
-/* Now invalidate the instruction cache */
-
- lwz r7,ICACHEL1LINESIZE(r10) /* Get Icache line size */
- addi r5,r7,-1
- andc r6,r3,r5 /* round low to line bdy */
- subf r8,r6,r4 /* compute length */
- add r8,r8,r5
- lwz r9,ICACHEL1LOGLINESIZE(r10) /* Get log-2 of Icache line size */
- srw. r8,r8,r9 /* compute line count */
- beqlr /* nothing to do? */
- mtctr r8
-2: icbi 0,r6
- add r6,r6,r7
- bdnz 2b
- isync
- blr
-
- .text
-/*
- * Like above, but only do the D-cache.
- *
- * flush_dcache_range(unsigned long start, unsigned long stop)
- *
- * flush all bytes from start to stop-1 inclusive
- */
-_GLOBAL(flush_dcache_range)
-
-/*
- * Flush the data cache to memory
- *
- * Different systems have different cache line sizes
- */
- ld r10,PPC64_CACHES@toc(r2)
- lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */
- addi r5,r7,-1
- andc r6,r3,r5 /* round low to line bdy */
- subf r8,r6,r4 /* compute length */
- add r8,r8,r5 /* ensure we get enough */
- lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */
- srw. r8,r8,r9 /* compute line count */
- beqlr /* nothing to do? */
- mtctr r8
-0: dcbst 0,r6
- add r6,r6,r7
- bdnz 0b
- sync
- blr
-
-/*
- * Like above, but works on non-mapped physical addresses.
- * Use only for non-LPAR setups ! It also assumes real mode
- * is cacheable. Used for flushing out the DART before using
- * it as uncacheable memory
- *
- * flush_dcache_phys_range(unsigned long start, unsigned long stop)
- *
- * flush all bytes from start to stop-1 inclusive
- */
-_GLOBAL(flush_dcache_phys_range)
- ld r10,PPC64_CACHES@toc(r2)
- lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */
- addi r5,r7,-1
- andc r6,r3,r5 /* round low to line bdy */
- subf r8,r6,r4 /* compute length */
- add r8,r8,r5 /* ensure we get enough */
- lwz r9,DCACHEL1LOGLINESIZE(r10) /* Get log-2 of dcache line size */
- srw. r8,r8,r9 /* compute line count */
- beqlr /* nothing to do? */
- mfmsr r5 /* Disable MMU Data Relocation */
- ori r0,r5,MSR_DR
- xori r0,r0,MSR_DR
- sync
- mtmsr r0
- sync
- isync
- mtctr r8
-0: dcbst 0,r6
- add r6,r6,r7
- bdnz 0b
- sync
- isync
- mtmsr r5 /* Re-enable MMU Data Relocation */
- sync
- isync
- blr
-
-_GLOBAL(flush_inval_dcache_range)
- ld r10,PPC64_CACHES@toc(r2)
- lwz r7,DCACHEL1LINESIZE(r10) /* Get dcache line size */
- addi r5,r7,-1
- andc r6,r3,r5 /* round low to line bdy */
- subf r8,r6,r4 /* compute length */
- add r8,r8,r5 /* ensure we get enough */
- lwz r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */
- srw. r8,r8,r9 /* compute line count */
- beqlr /* nothing to do? */
- sync
- isync
- mtctr r8
-0: dcbf 0,r6
- add r6,r6,r7
- bdnz 0b
- sync
- isync
- blr
-
-
-/*
- * Flush a particular page from the data cache to RAM.
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- *
- * void __flush_dcache_icache(void *page)
- */
-_GLOBAL(__flush_dcache_icache)
-/*
- * Flush the data cache to memory
- *
- * Different systems have different cache line sizes
- */
-
-/* Flush the dcache */
- ld r7,PPC64_CACHES@toc(r2)
- clrrdi r3,r3,PAGE_SHIFT /* Page align */
- lwz r4,DCACHEL1LINESPERPAGE(r7) /* Get # dcache lines per page */
- lwz r5,DCACHEL1LINESIZE(r7) /* Get dcache line size */
- mr r6,r3
- mtctr r4
-0: dcbst 0,r6
- add r6,r6,r5
- bdnz 0b
- sync
-
-/* Now invalidate the icache */
-
- lwz r4,ICACHEL1LINESPERPAGE(r7) /* Get # icache lines per page */
- lwz r5,ICACHEL1LINESIZE(r7) /* Get icache line size */
- mtctr r4
-1: icbi 0,r3
- add r3,r3,r5
- bdnz 1b
- isync
- blr
-
-/*
- * I/O string operations
- *
- * insb(port, buf, len)
- * outsb(port, buf, len)
- * insw(port, buf, len)
- * outsw(port, buf, len)
- * insl(port, buf, len)
- * outsl(port, buf, len)
- * insw_ns(port, buf, len)
- * outsw_ns(port, buf, len)
- * insl_ns(port, buf, len)
- * outsl_ns(port, buf, len)
- *
- * The *_ns versions don't do byte-swapping.
- */
-_GLOBAL(_insb)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,1
- blelr-
-00: lbz r5,0(r3)
- eieio
- stbu r5,1(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-_GLOBAL(_outsb)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,1
- blelr-
-00: lbzu r5,1(r4)
- stb r5,0(r3)
- bdnz 00b
- sync
- blr
-
-_GLOBAL(_insw)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhbrx r5,0,r3
- eieio
- sthu r5,2(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-_GLOBAL(_outsw)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhzu r5,2(r4)
- sthbrx r5,0,r3
- bdnz 00b
- sync
- blr
-
-_GLOBAL(_insl)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwbrx r5,0,r3
- eieio
- stwu r5,4(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-_GLOBAL(_outsl)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwzu r5,4(r4)
- stwbrx r5,0,r3
- bdnz 00b
- sync
- blr
-
-/* _GLOBAL(ide_insw) now in drivers/ide/ide-iops.c */
-_GLOBAL(_insw_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhz r5,0(r3)
- eieio
- sthu r5,2(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-/* _GLOBAL(ide_outsw) now in drivers/ide/ide-iops.c */
-_GLOBAL(_outsw_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,2
- blelr-
-00: lhzu r5,2(r4)
- sth r5,0(r3)
- bdnz 00b
- sync
- blr
-
-_GLOBAL(_insl_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwz r5,0(r3)
- eieio
- stwu r5,4(r4)
- bdnz 00b
- twi 0,r5,0
- isync
- blr
-
-_GLOBAL(_outsl_ns)
- cmpwi 0,r5,0
- mtctr r5
- subi r4,r4,4
- blelr-
-00: lwzu r5,4(r4)
- stw r5,0(r3)
- bdnz 00b
- sync
- blr
-
-/*
- * identify_cpu and calls setup_cpu
- * In: r3 = base of the cpu_specs array
- * r4 = address of cur_cpu_spec
- * r5 = relocation offset
- */
-_GLOBAL(identify_cpu)
- mfpvr r7
-1:
- lwz r8,CPU_SPEC_PVR_MASK(r3)
- and r8,r8,r7
- lwz r9,CPU_SPEC_PVR_VALUE(r3)
- cmplw 0,r9,r8
- beq 1f
- addi r3,r3,CPU_SPEC_ENTRY_SIZE
- b 1b
-1:
- add r0,r3,r5
- std r0,0(r4)
- ld r4,CPU_SPEC_SETUP(r3)
- sub r4,r4,r5
- ld r4,0(r4)
- sub r4,r4,r5
- mtctr r4
- /* Calling convention for cpu setup is r3=offset, r4=cur_cpu_spec */
- mr r4,r3
- mr r3,r5
- bctr
-
-/*
- * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
- * and writes nop's over sections of code that don't apply for this cpu.
- * r3 = data offset (not changed)
- */
-_GLOBAL(do_cpu_ftr_fixups)
- /* Get CPU 0 features */
- LOADADDR(r6,cur_cpu_spec)
- sub r6,r6,r3
- ld r4,0(r6)
- sub r4,r4,r3
- ld r4,CPU_SPEC_FEATURES(r4)
- /* Get the fixup table */
- LOADADDR(r6,__start___ftr_fixup)
- sub r6,r6,r3
- LOADADDR(r7,__stop___ftr_fixup)
- sub r7,r7,r3
- /* Do the fixup */
-1: cmpld r6,r7
- bgelr
- addi r6,r6,32
- ld r8,-32(r6) /* mask */
- and r8,r8,r4
- ld r9,-24(r6) /* value */
- cmpld r8,r9
- beq 1b
- ld r8,-16(r6) /* section begin */
- ld r9,-8(r6) /* section end */
- subf. r9,r8,r9
- beq 1b
- /* write nops over the section of code */
- /* todo: if large section, add a branch at the start of it */
- srwi r9,r9,2
- mtctr r9
- sub r8,r8,r3
- lis r0,0x60000000@h /* nop */
-3: stw r0,0(r8)
- andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@l
- beq 2f
- dcbst 0,r8 /* suboptimal, but simpler */
- sync
- icbi 0,r8
-2: addi r8,r8,4
- bdnz 3b
- sync /* additional sync needed on g4 */
- isync
- b 1b
-
-#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
-/*
- * Do an IO access in real mode
- */
-_GLOBAL(real_readb)
- mfmsr r7
- ori r0,r7,MSR_DR
- xori r0,r0,MSR_DR
- sync
- mtmsrd r0
- sync
- isync
- mfspr r6,SPRN_HID4
- rldicl r5,r6,32,0
- ori r5,r5,0x100
- rldicl r5,r5,32,0
- sync
- mtspr SPRN_HID4,r5
- isync
- slbia
- isync
- lbz r3,0(r3)
- sync
- mtspr SPRN_HID4,r6
- isync
- slbia
- isync
- mtmsrd r7
- sync
- isync
- blr
-
-/*
- * Do an IO access in real mode
- */
-_GLOBAL(real_writeb)
- mfmsr r7
- ori r0,r7,MSR_DR
- xori r0,r0,MSR_DR
- sync
- mtmsrd r0
- sync
- isync
- mfspr r6,SPRN_HID4
- rldicl r5,r6,32,0
- ori r5,r5,0x100
- rldicl r5,r5,32,0
- sync
- mtspr SPRN_HID4,r5
- isync
- slbia
- isync
- stb r3,0(r4)
- sync
- mtspr SPRN_HID4,r6
- isync
- slbia
- isync
- mtmsrd r7
- sync
- isync
- blr
-#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
-
-/*
- * SCOM access functions for 970 (FX only for now)
- *
- * unsigned long scom970_read(unsigned int address);
- * void scom970_write(unsigned int address, unsigned long value);
- *
- * The address passed in is the 24 bits register address. This code
- * is 970 specific and will not check the status bits, so you should
- * know what you are doing.
- */
-_GLOBAL(scom970_read)
- /* interrupts off */
- mfmsr r4
- ori r0,r4,MSR_EE
- xori r0,r0,MSR_EE
- mtmsrd r0,1
-
- /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
- * (including parity). On current CPUs they must be 0'd,
- * and finally or in RW bit
- */
- rlwinm r3,r3,8,0,15
- ori r3,r3,0x8000
-
- /* do the actual scom read */
- sync
- mtspr SPRN_SCOMC,r3
- isync
- mfspr r3,SPRN_SCOMD
- isync
- mfspr r0,SPRN_SCOMC
- isync
-
- /* XXX: fixup result on some buggy 970's (ouch ! we lost a bit, bah
- * that's the best we can do). Not implemented yet as we don't use
- * the scom on any of the bogus CPUs yet, but may have to be done
- * ultimately
- */
-
- /* restore interrupts */
- mtmsrd r4,1
- blr
-
-
-_GLOBAL(scom970_write)
- /* interrupts off */
- mfmsr r5
- ori r0,r5,MSR_EE
- xori r0,r0,MSR_EE
- mtmsrd r0,1
-
- /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
- * (including parity). On current CPUs they must be 0'd.
- */
-
- rlwinm r3,r3,8,0,15
-
- sync
- mtspr SPRN_SCOMD,r4 /* write data */
- isync
- mtspr SPRN_SCOMC,r3 /* write command */
- isync
- mfspr 3,SPRN_SCOMC
- isync
-
- /* restore interrupts */
- mtmsrd r5,1
- blr
-
-
-/*
- * Create a kernel thread
- * kernel_thread(fn, arg, flags)
- */
-_GLOBAL(kernel_thread)
- std r29,-24(r1)
- std r30,-16(r1)
- stdu r1,-STACK_FRAME_OVERHEAD(r1)
- mr r29,r3
- mr r30,r4
- ori r3,r5,CLONE_VM /* flags */
- oris r3,r3,(CLONE_UNTRACED>>16)
- li r4,0 /* new sp (unused) */
- li r0,__NR_clone
- sc
- cmpdi 0,r3,0 /* parent or child? */
- bne 1f /* return if parent */
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
- ld r2,8(r29)
- ld r29,0(r29)
- mtlr r29 /* fn addr in lr */
- mr r3,r30 /* load arg and call fn */
- blrl
- li r0,__NR_exit /* exit after child exits */
- li r3,0
- sc
-1: addi r1,r1,STACK_FRAME_OVERHEAD
- ld r29,-24(r1)
- ld r30,-16(r1)
- blr
-
-/*
- * disable_kernel_fp()
- * Disable the FPU.
- */
-_GLOBAL(disable_kernel_fp)
- mfmsr r3
- rldicl r0,r3,(63-MSR_FP_LG),1
- rldicl r3,r0,(MSR_FP_LG+1),0
- mtmsrd r3 /* disable use of fpu now */
- isync
- blr
-
-#ifdef CONFIG_ALTIVEC
-
-#if 0 /* this has no callers for now */
-/*
- * disable_kernel_altivec()
- * Disable the VMX.
- */
-_GLOBAL(disable_kernel_altivec)
- mfmsr r3
- rldicl r0,r3,(63-MSR_VEC_LG),1
- rldicl r3,r0,(MSR_VEC_LG+1),0
- mtmsrd r3 /* disable use of VMX now */
- isync
- blr
-#endif /* 0 */
-
-/*
- * giveup_altivec(tsk)
- * Disable VMX for the task given as the argument,
- * and save the vector registers in its thread_struct.
- * Enables the VMX for use in the kernel on return.
- */
-_GLOBAL(giveup_altivec)
- mfmsr r5
- oris r5,r5,MSR_VEC@h
- mtmsrd r5 /* enable use of VMX now */
- isync
- cmpdi 0,r3,0
- beqlr- /* if no previous owner, done */
- addi r3,r3,THREAD /* want THREAD of task */
- ld r5,PT_REGS(r3)
- cmpdi 0,r5,0
- SAVE_32VRS(0,r4,r3)
- mfvscr vr0
- li r4,THREAD_VSCR
- stvx vr0,r4,r3
- beq 1f
- ld r4,_MSR-STACK_FRAME_OVERHEAD(r5)
- lis r3,MSR_VEC@h
- andc r4,r4,r3 /* disable FP for previous task */
- std r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
-#ifndef CONFIG_SMP
- li r5,0
- ld r4,last_task_used_altivec@got(r2)
- std r5,0(r4)
-#endif /* CONFIG_SMP */
- blr
-
-#endif /* CONFIG_ALTIVEC */
-
-_GLOBAL(__setup_cpu_power3)
- blr
-
-_GLOBAL(execve)
- li r0,__NR_execve
- sc
- bnslr
- neg r3,r3
- blr
-
-/* kexec_wait(phys_cpu)
- *
- * wait for the flag to change, indicating this kernel is going away but
- * the slave code for the next one is at addresses 0 to 100.
- *
- * This is used by all slaves.
- *
- * Physical (hardware) cpu id should be in r3.
- */
-_GLOBAL(kexec_wait)
- bl 1f
-1: mflr r5
- addi r5,r5,kexec_flag-1b
-
-99: HMT_LOW
-#ifdef CONFIG_KEXEC /* use no memory without kexec */
- lwz r4,0(r5)
- cmpwi 0,r4,0
- bnea 0x60
-#endif
- b 99b
-
-/* this can be in text because we won't change it until we are
- * running in real anyways
- */
-kexec_flag:
- .long 0
-
-
-#ifdef CONFIG_KEXEC
-
-/* kexec_smp_wait(void)
- *
- * call with interrupts off
- * note: this is a terminal routine, it does not save lr
- *
- * get phys id from paca
- * set paca id to -1 to say we got here
- * switch to real mode
- * join other cpus in kexec_wait(phys_id)
- */
-_GLOBAL(kexec_smp_wait)
- lhz r3,PACAHWCPUID(r13)
- li r4,-1
- sth r4,PACAHWCPUID(r13) /* let others know we left */
- bl real_mode
- b .kexec_wait
-
-/*
- * switch to real mode (turn mmu off)
- * we use the early kernel trick that the hardware ignores bits
- * 0 and 1 (big endian) of the effective address in real mode
- *
- * don't overwrite r3 here, it is live for kexec_wait above.
- */
-real_mode: /* assume normal blr return */
-1: li r9,MSR_RI
- li r10,MSR_DR|MSR_IR
- mflr r11 /* return address to SRR0 */
- mfmsr r12
- andc r9,r12,r9
- andc r10,r12,r10
-
- mtmsrd r9,1
- mtspr SPRN_SRR1,r10
- mtspr SPRN_SRR0,r11
- rfid
-
-
-/*
- * kexec_sequence(newstack, start, image, control, clear_all())
- *
- * does the grungy work with stack switching and real mode switches
- * also does simple calls to other code
- */
-
-_GLOBAL(kexec_sequence)
- mflr r0
- std r0,16(r1)
-
- /* switch stacks to newstack -- &kexec_stack.stack */
- stdu r1,THREAD_SIZE-112(r3)
- mr r1,r3
-
- li r0,0
- std r0,16(r1)
-
- /* save regs for local vars on new stack.
- * yes, we won't go back, but ...
- */
- std r31,-8(r1)
- std r30,-16(r1)
- std r29,-24(r1)
- std r28,-32(r1)
- std r27,-40(r1)
- std r26,-48(r1)
- std r25,-56(r1)
-
- stdu r1,-112-64(r1)
-
- /* save args into preserved regs */
- mr r31,r3 /* newstack (both) */
- mr r30,r4 /* start (real) */
- mr r29,r5 /* image (virt) */
- mr r28,r6 /* control, unused */
- mr r27,r7 /* clear_all() fn desc */
- mr r26,r8 /* spare */
- lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */
-
- /* disable interrupts, we are overwriting kernel data next */
- mfmsr r3
- rlwinm r3,r3,0,17,15
- mtmsrd r3,1
-
- /* copy dest pages, flush whole dest image */
- mr r3,r29
- bl .kexec_copy_flush /* (image) */
-
- /* turn off mmu */
- bl real_mode
-
- /* clear out hardware hash page table and tlb */
- ld r5,0(r27) /* deref function descriptor */
- mtctr r5
- bctrl /* ppc_md.hash_clear_all(void); */
-
-/*
- * kexec image calling is:
- * the first 0x100 bytes of the entry point are copied to 0
- *
- * all slaves branch to slave = 0x60 (absolute)
- * slave(phys_cpu_id);
- *
- * master goes to start = entry point
- * start(phys_cpu_id, start, 0);
- *
- *
- * a wrapper is needed to call existing kernels, here is an approximate
- * description of one method:
- *
- * v2: (2.6.10)
- * start will be near the boot_block (maybe 0x100 bytes before it?)
- * it will have a 0x60, which will b to boot_block, where it will wait
- * and 0 will store phys into struct boot-block and load r3 from there,
- * copy kernel 0-0x100 and tell slaves to back down to 0x60 again
- *
- * v1: (2.6.9)
- * boot block will have all cpus scanning device tree to see if they
- * are the boot cpu ?????
- * other device tree differences (prop sizes, va vs pa, etc)...
- */
-
- /* copy 0x100 bytes starting at start to 0 */
- li r3,0
- mr r4,r30
- li r5,0x100
- li r6,0
- bl .copy_and_flush /* (dest, src, copy limit, start offset) */
-1: /* assume normal blr return */
-
- /* release other cpus to the new kernel secondary start at 0x60 */
- mflr r5
- li r6,1
- stw r6,kexec_flag-1b(5)
- mr r3,r25 # my phys cpu
- mr r4,r30 # start, aka phys mem offset
- mtlr 4
- li r5,0
- blr /* image->start(physid, image->start, 0); */
-#endif /* CONFIG_KEXEC */
diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c
deleted file mode 100644
index 84006e26342..00000000000
--- a/arch/ppc64/kernel/ppc_ksyms.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * c 2001 PPC 64 Team, 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/config.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/console.h>
-#include <net/checksum.h>
-
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/hw_irq.h>
-#include <asm/abs_addr.h>
-#include <asm/cacheflush.h>
-
-EXPORT_SYMBOL(strcpy);
-EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strncat);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
-
-EXPORT_SYMBOL(csum_partial);
-EXPORT_SYMBOL(csum_partial_copy_generic);
-EXPORT_SYMBOL(ip_fast_csum);
-EXPORT_SYMBOL(csum_tcpudp_magic);
-
-EXPORT_SYMBOL(__copy_tofrom_user);
-EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(__strncpy_from_user);
-EXPORT_SYMBOL(__strnlen_user);
-
-EXPORT_SYMBOL(reloc_offset);
-
-EXPORT_SYMBOL(_insb);
-EXPORT_SYMBOL(_outsb);
-EXPORT_SYMBOL(_insw);
-EXPORT_SYMBOL(_outsw);
-EXPORT_SYMBOL(_insl);
-EXPORT_SYMBOL(_outsl);
-EXPORT_SYMBOL(_insw_ns);
-EXPORT_SYMBOL(_outsw_ns);
-EXPORT_SYMBOL(_insl_ns);
-EXPORT_SYMBOL(_outsl_ns);
-
-EXPORT_SYMBOL(kernel_thread);
-
-EXPORT_SYMBOL(giveup_fpu);
-#ifdef CONFIG_ALTIVEC
-EXPORT_SYMBOL(giveup_altivec);
-#endif
-EXPORT_SYMBOL(__flush_icache_range);
-EXPORT_SYMBOL(flush_dcache_range);
-
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(memscan);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memchr);
-
-EXPORT_SYMBOL(timer_interrupt);
-EXPORT_SYMBOL(console_drivers);
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
deleted file mode 100644
index fbad2c36078..00000000000
--- a/arch/ppc64/kernel/prom.c
+++ /dev/null
@@ -1,1954 +0,0 @@
-/*
- *
- *
- * Procedures for interfacing to Open Firmware.
- *
- * Paul Mackerras August 1996.
- * Copyright (C) 1996 Paul Mackerras.
- *
- * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
- * {engebret|bergner}@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.
- */
-
-#undef DEBUG
-
-#include <stdarg.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/initrd.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/module.h>
-
-#include <asm/prom.h>
-#include <asm/rtas.h>
-#include <asm/lmb.h>
-#include <asm/abs_addr.h>
-#include <asm/page.h>
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/system.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/pci.h>
-#include <asm/iommu.h>
-#include <asm/btext.h>
-#include <asm/sections.h>
-#include <asm/machdep.h>
-#include <asm/pSeries_reconfig.h>
-
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-struct pci_reg_property {
- struct pci_address addr;
- u32 size_hi;
- u32 size_lo;
-};
-
-struct isa_reg_property {
- u32 space;
- u32 address;
- u32 size;
-};
-
-
-typedef int interpret_func(struct device_node *, unsigned long *,
- int, int, int);
-
-extern struct rtas_t rtas;
-extern struct lmb lmb;
-extern unsigned long klimit;
-extern unsigned long memory_limit;
-
-static int __initdata dt_root_addr_cells;
-static int __initdata dt_root_size_cells;
-static int __initdata iommu_is_off;
-int __initdata iommu_force_on;
-unsigned long tce_alloc_start, tce_alloc_end;
-
-typedef u32 cell_t;
-
-#if 0
-static struct boot_param_header *initial_boot_params __initdata;
-#else
-struct boot_param_header *initial_boot_params;
-#endif
-
-static struct device_node *allnodes = NULL;
-
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-/* export that to outside world */
-struct device_node *of_chosen;
-
-/*
- * Wrapper for allocating memory for various data that needs to be
- * attached to device nodes as they are processed at boot or when
- * added to the device tree later (e.g. DLPAR). At boot there is
- * already a region reserved so we just increment *mem_start by size;
- * otherwise we call kmalloc.
- */
-static void * prom_alloc(unsigned long size, unsigned long *mem_start)
-{
- unsigned long tmp;
-
- if (!mem_start)
- return kmalloc(size, GFP_KERNEL);
-
- tmp = *mem_start;
- *mem_start += size;
- return (void *)tmp;
-}
-
-/*
- * Find the device_node with a given phandle.
- */
-static struct device_node * find_phandle(phandle ph)
-{
- struct device_node *np;
-
- for (np = allnodes; np != 0; np = np->allnext)
- if (np->linux_phandle == ph)
- return np;
- return NULL;
-}
-
-/*
- * Find the interrupt parent of a node.
- */
-static struct device_node * __devinit intr_parent(struct device_node *p)
-{
- phandle *parp;
-
- parp = (phandle *) get_property(p, "interrupt-parent", NULL);
- if (parp == NULL)
- return p->parent;
- return find_phandle(*parp);
-}
-
-/*
- * Find out the size of each entry of the interrupts property
- * for a node.
- */
-int __devinit prom_n_intr_cells(struct device_node *np)
-{
- struct device_node *p;
- unsigned int *icp;
-
- for (p = np; (p = intr_parent(p)) != NULL; ) {
- icp = (unsigned int *)
- get_property(p, "#interrupt-cells", NULL);
- if (icp != NULL)
- return *icp;
- if (get_property(p, "interrupt-controller", NULL) != NULL
- || get_property(p, "interrupt-map", NULL) != NULL) {
- printk("oops, node %s doesn't have #interrupt-cells\n",
- p->full_name);
- return 1;
- }
- }
-#ifdef DEBUG_IRQ
- printk("prom_n_intr_cells failed for %s\n", np->full_name);
-#endif
- return 1;
-}
-
-/*
- * Map an interrupt from a device up to the platform interrupt
- * descriptor.
- */
-static int __devinit map_interrupt(unsigned int **irq, struct device_node **ictrler,
- struct device_node *np, unsigned int *ints,
- int nintrc)
-{
- struct device_node *p, *ipar;
- unsigned int *imap, *imask, *ip;
- int i, imaplen, match;
- int newintrc = 0, newaddrc = 0;
- unsigned int *reg;
- int naddrc;
-
- reg = (unsigned int *) get_property(np, "reg", NULL);
- naddrc = prom_n_addr_cells(np);
- p = intr_parent(np);
- while (p != NULL) {
- if (get_property(p, "interrupt-controller", NULL) != NULL)
- /* this node is an interrupt controller, stop here */
- break;
- imap = (unsigned int *)
- get_property(p, "interrupt-map", &imaplen);
- if (imap == NULL) {
- p = intr_parent(p);
- continue;
- }
- imask = (unsigned int *)
- get_property(p, "interrupt-map-mask", NULL);
- if (imask == NULL) {
- printk("oops, %s has interrupt-map but no mask\n",
- p->full_name);
- return 0;
- }
- imaplen /= sizeof(unsigned int);
- match = 0;
- ipar = NULL;
- while (imaplen > 0 && !match) {
- /* check the child-interrupt field */
- match = 1;
- for (i = 0; i < naddrc && match; ++i)
- match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
- for (; i < naddrc + nintrc && match; ++i)
- match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
- imap += naddrc + nintrc;
- imaplen -= naddrc + nintrc;
- /* grab the interrupt parent */
- ipar = find_phandle((phandle) *imap++);
- --imaplen;
- if (ipar == NULL) {
- printk("oops, no int parent %x in map of %s\n",
- imap[-1], p->full_name);
- return 0;
- }
- /* find the parent's # addr and intr cells */
- ip = (unsigned int *)
- get_property(ipar, "#interrupt-cells", NULL);
- if (ip == NULL) {
- printk("oops, no #interrupt-cells on %s\n",
- ipar->full_name);
- return 0;
- }
- newintrc = *ip;
- ip = (unsigned int *)
- get_property(ipar, "#address-cells", NULL);
- newaddrc = (ip == NULL)? 0: *ip;
- imap += newaddrc + newintrc;
- imaplen -= newaddrc + newintrc;
- }
- if (imaplen < 0) {
- printk("oops, error decoding int-map on %s, len=%d\n",
- p->full_name, imaplen);
- return 0;
- }
- if (!match) {
-#ifdef DEBUG_IRQ
- printk("oops, no match in %s int-map for %s\n",
- p->full_name, np->full_name);
-#endif
- return 0;
- }
- p = ipar;
- naddrc = newaddrc;
- nintrc = newintrc;
- ints = imap - nintrc;
- reg = ints - naddrc;
- }
- if (p == NULL) {
-#ifdef DEBUG_IRQ
- printk("hmmm, int tree for %s doesn't have ctrler\n",
- np->full_name);
-#endif
- return 0;
- }
- *irq = ints;
- *ictrler = p;
- return nintrc;
-}
-
-static int __devinit finish_node_interrupts(struct device_node *np,
- unsigned long *mem_start,
- int measure_only)
-{
- unsigned int *ints;
- int intlen, intrcells, intrcount;
- int i, j, n;
- unsigned int *irq, virq;
- struct device_node *ic;
-
- ints = (unsigned int *) get_property(np, "interrupts", &intlen);
- if (ints == NULL)
- return 0;
- intrcells = prom_n_intr_cells(np);
- intlen /= intrcells * sizeof(unsigned int);
-
- np->intrs = prom_alloc(intlen * sizeof(*(np->intrs)), mem_start);
- if (!np->intrs)
- return -ENOMEM;
-
- if (measure_only)
- return 0;
-
- intrcount = 0;
- for (i = 0; i < intlen; ++i, ints += intrcells) {
- n = map_interrupt(&irq, &ic, np, ints, intrcells);
- if (n <= 0)
- continue;
-
- /* don't map IRQ numbers under a cascaded 8259 controller */
- if (ic && device_is_compatible(ic, "chrp,iic")) {
- np->intrs[intrcount].line = irq[0];
- } else {
- virq = virt_irq_create_mapping(irq[0]);
- if (virq == NO_IRQ) {
- printk(KERN_CRIT "Could not allocate interrupt"
- " number for %s\n", np->full_name);
- continue;
- }
- np->intrs[intrcount].line = irq_offset_up(virq);
- }
-
- /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
- if (_machine == PLATFORM_POWERMAC && ic && ic->parent) {
- char *name = get_property(ic->parent, "name", NULL);
- if (name && !strcmp(name, "u3"))
- np->intrs[intrcount].line += 128;
- else if (!(name && !strcmp(name, "mac-io")))
- /* ignore other cascaded controllers, such as
- the k2-sata-root */
- break;
- }
- np->intrs[intrcount].sense = 1;
- if (n > 1)
- np->intrs[intrcount].sense = irq[1];
- if (n > 2) {
- printk("hmmm, got %d intr cells for %s:", n,
- np->full_name);
- for (j = 0; j < n; ++j)
- printk(" %d", irq[j]);
- printk("\n");
- }
- ++intrcount;
- }
- np->n_intrs = intrcount;
-
- return 0;
-}
-
-static int __devinit interpret_pci_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct address_range *adr;
- struct pci_reg_property *pci_addrs;
- int i, l, n_addrs;
-
- pci_addrs = (struct pci_reg_property *)
- get_property(np, "assigned-addresses", &l);
- if (!pci_addrs)
- return 0;
-
- n_addrs = l / sizeof(*pci_addrs);
-
- adr = prom_alloc(n_addrs * sizeof(*adr), mem_start);
- if (!adr)
- return -ENOMEM;
-
- if (measure_only)
- return 0;
-
- np->addrs = adr;
- np->n_addrs = n_addrs;
-
- for (i = 0; i < n_addrs; i++) {
- adr[i].space = pci_addrs[i].addr.a_hi;
- adr[i].address = pci_addrs[i].addr.a_lo |
- ((u64)pci_addrs[i].addr.a_mid << 32);
- adr[i].size = pci_addrs[i].size_lo;
- }
-
- return 0;
-}
-
-static int __init interpret_dbdma_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct reg_property32 *rp;
- struct address_range *adr;
- unsigned long base_address;
- int i, l;
- struct device_node *db;
-
- base_address = 0;
- if (!measure_only) {
- for (db = np->parent; db != NULL; db = db->parent) {
- if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
- base_address = db->addrs[0].address;
- break;
- }
- }
- }
-
- rp = (struct reg_property32 *) get_property(np, "reg", &l);
- if (rp != 0 && l >= sizeof(struct reg_property32)) {
- i = 0;
- adr = (struct address_range *) (*mem_start);
- while ((l -= sizeof(struct reg_property32)) >= 0) {
- if (!measure_only) {
- adr[i].space = 2;
- adr[i].address = rp[i].address + base_address;
- adr[i].size = rp[i].size;
- }
- ++i;
- }
- np->addrs = adr;
- np->n_addrs = i;
- (*mem_start) += i * sizeof(struct address_range);
- }
-
- return 0;
-}
-
-static int __init interpret_macio_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct reg_property32 *rp;
- struct address_range *adr;
- unsigned long base_address;
- int i, l;
- struct device_node *db;
-
- base_address = 0;
- if (!measure_only) {
- for (db = np->parent; db != NULL; db = db->parent) {
- if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
- base_address = db->addrs[0].address;
- break;
- }
- }
- }
-
- rp = (struct reg_property32 *) get_property(np, "reg", &l);
- if (rp != 0 && l >= sizeof(struct reg_property32)) {
- i = 0;
- adr = (struct address_range *) (*mem_start);
- while ((l -= sizeof(struct reg_property32)) >= 0) {
- if (!measure_only) {
- adr[i].space = 2;
- adr[i].address = rp[i].address + base_address;
- adr[i].size = rp[i].size;
- }
- ++i;
- }
- np->addrs = adr;
- np->n_addrs = i;
- (*mem_start) += i * sizeof(struct address_range);
- }
-
- return 0;
-}
-
-static int __init interpret_isa_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct isa_reg_property *rp;
- struct address_range *adr;
- int i, l;
-
- rp = (struct isa_reg_property *) get_property(np, "reg", &l);
- if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
- i = 0;
- adr = (struct address_range *) (*mem_start);
- while ((l -= sizeof(struct isa_reg_property)) >= 0) {
- if (!measure_only) {
- adr[i].space = rp[i].space;
- adr[i].address = rp[i].address;
- adr[i].size = rp[i].size;
- }
- ++i;
- }
- np->addrs = adr;
- np->n_addrs = i;
- (*mem_start) += i * sizeof(struct address_range);
- }
-
- return 0;
-}
-
-static int __init interpret_root_props(struct device_node *np,
- unsigned long *mem_start,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct address_range *adr;
- int i, l;
- unsigned int *rp;
- int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
-
- rp = (unsigned int *) get_property(np, "reg", &l);
- if (rp != 0 && l >= rpsize) {
- i = 0;
- adr = (struct address_range *) (*mem_start);
- while ((l -= rpsize) >= 0) {
- if (!measure_only) {
- adr[i].space = 0;
- adr[i].address = rp[naddrc - 1];
- adr[i].size = rp[naddrc + nsizec - 1];
- }
- ++i;
- rp += naddrc + nsizec;
- }
- np->addrs = adr;
- np->n_addrs = i;
- (*mem_start) += i * sizeof(struct address_range);
- }
-
- return 0;
-}
-
-static int __devinit finish_node(struct device_node *np,
- unsigned long *mem_start,
- interpret_func *ifunc,
- int naddrc, int nsizec,
- int measure_only)
-{
- struct device_node *child;
- int *ip, rc = 0;
-
- /* get the device addresses and interrupts */
- if (ifunc != NULL)
- rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);
- if (rc)
- goto out;
-
- rc = finish_node_interrupts(np, mem_start, measure_only);
- if (rc)
- goto out;
-
- /* Look for #address-cells and #size-cells properties. */
- ip = (int *) get_property(np, "#address-cells", NULL);
- if (ip != NULL)
- naddrc = *ip;
- ip = (int *) get_property(np, "#size-cells", NULL);
- if (ip != NULL)
- nsizec = *ip;
-
- if (!strcmp(np->name, "device-tree") || np->parent == NULL)
- ifunc = interpret_root_props;
- else if (np->type == 0)
- ifunc = NULL;
- else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
- ifunc = interpret_pci_props;
- else if (!strcmp(np->type, "dbdma"))
- ifunc = interpret_dbdma_props;
- else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)
- ifunc = interpret_macio_props;
- else if (!strcmp(np->type, "isa"))
- ifunc = interpret_isa_props;
- else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
- ifunc = interpret_root_props;
- else if (!((ifunc == interpret_dbdma_props
- || ifunc == interpret_macio_props)
- && (!strcmp(np->type, "escc")
- || !strcmp(np->type, "media-bay"))))
- ifunc = NULL;
-
- for (child = np->child; child != NULL; child = child->sibling) {
- rc = finish_node(child, mem_start, ifunc,
- naddrc, nsizec, measure_only);
- if (rc)
- goto out;
- }
-out:
- return rc;
-}
-
-/**
- * finish_device_tree is called once things are running normally
- * (i.e. with text and data mapped to the address they were linked at).
- * It traverses the device tree and fills in some of the additional,
- * fields in each node like {n_}addrs and {n_}intrs, the virt interrupt
- * mapping is also initialized at this point.
- */
-void __init finish_device_tree(void)
-{
- unsigned long start, end, size = 0;
-
- DBG(" -> finish_device_tree\n");
-
- if (ppc64_interrupt_controller == IC_INVALID) {
- DBG("failed to configure interrupt controller type\n");
- panic("failed to configure interrupt controller type\n");
- }
-
- /* Initialize virtual IRQ map */
- virt_irq_init();
-
- /*
- * Finish device-tree (pre-parsing some properties etc...)
- * We do this in 2 passes. One with "measure_only" set, which
- * will only measure the amount of memory needed, then we can
- * allocate that memory, and call finish_node again. However,
- * we must be careful as most routines will fail nowadays when
- * prom_alloc() returns 0, so we must make sure our first pass
- * doesn't start at 0. We pre-initialize size to 16 for that
- * reason and then remove those additional 16 bytes
- */
- size = 16;
- finish_node(allnodes, &size, NULL, 0, 0, 1);
- size -= 16;
- end = start = (unsigned long)abs_to_virt(lmb_alloc(size, 128));
- finish_node(allnodes, &end, NULL, 0, 0, 0);
- BUG_ON(end != start + size);
-
- DBG(" <- finish_device_tree\n");
-}
-
-#ifdef DEBUG
-#define printk udbg_printf
-#endif
-
-static inline char *find_flat_dt_string(u32 offset)
-{
- return ((char *)initial_boot_params) +
- initial_boot_params->off_dt_strings + offset;
-}
-
-/**
- * This function is used to scan the flattened device-tree, it is
- * used to extract the memory informations at boot before we can
- * unflatten the tree
- */
-int __init of_scan_flat_dt(int (*it)(unsigned long node,
- const char *uname, int depth,
- void *data),
- void *data)
-{
- unsigned long p = ((unsigned long)initial_boot_params) +
- initial_boot_params->off_dt_struct;
- int rc = 0;
- int depth = -1;
-
- do {
- u32 tag = *((u32 *)p);
- char *pathp;
-
- p += 4;
- if (tag == OF_DT_END_NODE) {
- depth --;
- continue;
- }
- if (tag == OF_DT_NOP)
- continue;
- if (tag == OF_DT_END)
- break;
- if (tag == OF_DT_PROP) {
- u32 sz = *((u32 *)p);
- p += 8;
- if (initial_boot_params->version < 0x10)
- p = _ALIGN(p, sz >= 8 ? 8 : 4);
- p += sz;
- p = _ALIGN(p, 4);
- continue;
- }
- if (tag != OF_DT_BEGIN_NODE) {
- printk(KERN_WARNING "Invalid tag %x scanning flattened"
- " device tree !\n", tag);
- return -EINVAL;
- }
- depth++;
- pathp = (char *)p;
- p = _ALIGN(p + strlen(pathp) + 1, 4);
- if ((*pathp) == '/') {
- char *lp, *np;
- for (lp = NULL, np = pathp; *np; np++)
- if ((*np) == '/')
- lp = np+1;
- if (lp != NULL)
- pathp = lp;
- }
- rc = it(p, pathp, depth, data);
- if (rc != 0)
- break;
- } while(1);
-
- return rc;
-}
-
-/**
- * This function can be used within scan_flattened_dt callback to get
- * access to properties
- */
-void* __init of_get_flat_dt_prop(unsigned long node, const char *name,
- unsigned long *size)
-{
- unsigned long p = node;
-
- do {
- u32 tag = *((u32 *)p);
- u32 sz, noff;
- const char *nstr;
-
- p += 4;
- if (tag == OF_DT_NOP)
- continue;
- if (tag != OF_DT_PROP)
- return NULL;
-
- sz = *((u32 *)p);
- noff = *((u32 *)(p + 4));
- p += 8;
- if (initial_boot_params->version < 0x10)
- p = _ALIGN(p, sz >= 8 ? 8 : 4);
-
- nstr = find_flat_dt_string(noff);
- if (nstr == NULL) {
- printk(KERN_WARNING "Can't find property index"
- " name !\n");
- return NULL;
- }
- if (strcmp(name, nstr) == 0) {
- if (size)
- *size = sz;
- return (void *)p;
- }
- p += sz;
- p = _ALIGN(p, 4);
- } while(1);
-}
-
-static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
- unsigned long align)
-{
- void *res;
-
- *mem = _ALIGN(*mem, align);
- res = (void *)*mem;
- *mem += size;
-
- return res;
-}
-
-static unsigned long __init unflatten_dt_node(unsigned long mem,
- unsigned long *p,
- struct device_node *dad,
- struct device_node ***allnextpp,
- unsigned long fpsize)
-{
- struct device_node *np;
- struct property *pp, **prev_pp = NULL;
- char *pathp;
- u32 tag;
- unsigned int l, allocl;
- int has_name = 0;
- int new_format = 0;
-
- tag = *((u32 *)(*p));
- if (tag != OF_DT_BEGIN_NODE) {
- printk("Weird tag at start of node: %x\n", tag);
- return mem;
- }
- *p += 4;
- pathp = (char *)*p;
- l = allocl = strlen(pathp) + 1;
- *p = _ALIGN(*p + l, 4);
-
- /* version 0x10 has a more compact unit name here instead of the full
- * path. we accumulate the full path size using "fpsize", we'll rebuild
- * it later. We detect this because the first character of the name is
- * not '/'.
- */
- if ((*pathp) != '/') {
- new_format = 1;
- if (fpsize == 0) {
- /* root node: special case. fpsize accounts for path
- * plus terminating zero. root node only has '/', so
- * fpsize should be 2, but we want to avoid the first
- * level nodes to have two '/' so we use fpsize 1 here
- */
- fpsize = 1;
- allocl = 2;
- } else {
- /* account for '/' and path size minus terminal 0
- * already in 'l'
- */
- fpsize += l;
- allocl = fpsize;
- }
- }
-
-
- np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
- __alignof__(struct device_node));
- if (allnextpp) {
- memset(np, 0, sizeof(*np));
- np->full_name = ((char*)np) + sizeof(struct device_node);
- if (new_format) {
- char *p = np->full_name;
- /* rebuild full path for new format */
- if (dad && dad->parent) {
- strcpy(p, dad->full_name);
-#ifdef DEBUG
- if ((strlen(p) + l + 1) != allocl) {
- DBG("%s: p: %d, l: %d, a: %d\n",
- pathp, strlen(p), l, allocl);
- }
-#endif
- p += strlen(p);
- }
- *(p++) = '/';
- memcpy(p, pathp, l);
- } else
- memcpy(np->full_name, pathp, l);
- prev_pp = &np->properties;
- **allnextpp = np;
- *allnextpp = &np->allnext;
- if (dad != NULL) {
- np->parent = dad;
- /* we temporarily use the next field as `last_child'*/
- if (dad->next == 0)
- dad->child = np;
- else
- dad->next->sibling = np;
- dad->next = np;
- }
- kref_init(&np->kref);
- }
- while(1) {
- u32 sz, noff;
- char *pname;
-
- tag = *((u32 *)(*p));
- if (tag == OF_DT_NOP) {
- *p += 4;
- continue;
- }
- if (tag != OF_DT_PROP)
- break;
- *p += 4;
- sz = *((u32 *)(*p));
- noff = *((u32 *)((*p) + 4));
- *p += 8;
- if (initial_boot_params->version < 0x10)
- *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
-
- pname = find_flat_dt_string(noff);
- if (pname == NULL) {
- printk("Can't find property name in list !\n");
- break;
- }
- if (strcmp(pname, "name") == 0)
- has_name = 1;
- l = strlen(pname) + 1;
- pp = unflatten_dt_alloc(&mem, sizeof(struct property),
- __alignof__(struct property));
- if (allnextpp) {
- if (strcmp(pname, "linux,phandle") == 0) {
- np->node = *((u32 *)*p);
- if (np->linux_phandle == 0)
- np->linux_phandle = np->node;
- }
- if (strcmp(pname, "ibm,phandle") == 0)
- np->linux_phandle = *((u32 *)*p);
- pp->name = pname;
- pp->length = sz;
- pp->value = (void *)*p;
- *prev_pp = pp;
- prev_pp = &pp->next;
- }
- *p = _ALIGN((*p) + sz, 4);
- }
- /* with version 0x10 we may not have the name property, recreate
- * it here from the unit name if absent
- */
- if (!has_name) {
- char *p = pathp, *ps = pathp, *pa = NULL;
- int sz;
-
- while (*p) {
- if ((*p) == '@')
- pa = p;
- if ((*p) == '/')
- ps = p + 1;
- p++;
- }
- if (pa < ps)
- pa = p;
- sz = (pa - ps) + 1;
- pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
- __alignof__(struct property));
- if (allnextpp) {
- pp->name = "name";
- pp->length = sz;
- pp->value = (unsigned char *)(pp + 1);
- *prev_pp = pp;
- prev_pp = &pp->next;
- memcpy(pp->value, ps, sz - 1);
- ((char *)pp->value)[sz - 1] = 0;
- DBG("fixed up name for %s -> %s\n", pathp, pp->value);
- }
- }
- if (allnextpp) {
- *prev_pp = NULL;
- np->name = get_property(np, "name", NULL);
- np->type = get_property(np, "device_type", NULL);
-
- if (!np->name)
- np->name = "<NULL>";
- if (!np->type)
- np->type = "<NULL>";
- }
- while (tag == OF_DT_BEGIN_NODE) {
- mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
- tag = *((u32 *)(*p));
- }
- if (tag != OF_DT_END_NODE) {
- printk("Weird tag at end of node: %x\n", tag);
- return mem;
- }
- *p += 4;
- return mem;
-}
-
-
-/**
- * unflattens the device-tree passed by the firmware, creating the
- * tree of struct device_node. It also fills the "name" and "type"
- * pointers of the nodes so the normal device-tree walking functions
- * can be used (this used to be done by finish_device_tree)
- */
-void __init unflatten_device_tree(void)
-{
- unsigned long start, mem, size;
- struct device_node **allnextp = &allnodes;
- char *p = NULL;
- int l = 0;
-
- DBG(" -> unflatten_device_tree()\n");
-
- /* First pass, scan for size */
- start = ((unsigned long)initial_boot_params) +
- initial_boot_params->off_dt_struct;
- size = unflatten_dt_node(0, &start, NULL, NULL, 0);
- size = (size | 3) + 1;
-
- DBG(" size is %lx, allocating...\n", size);
-
- /* Allocate memory for the expanded device tree */
- mem = lmb_alloc(size + 4, __alignof__(struct device_node));
- if (!mem) {
- DBG("Couldn't allocate memory with lmb_alloc()!\n");
- panic("Couldn't allocate memory with lmb_alloc()!\n");
- }
- mem = (unsigned long)abs_to_virt(mem);
-
- ((u32 *)mem)[size / 4] = 0xdeadbeef;
-
- DBG(" unflattening...\n", mem);
-
- /* Second pass, do actual unflattening */
- start = ((unsigned long)initial_boot_params) +
- initial_boot_params->off_dt_struct;
- unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
- if (*((u32 *)start) != OF_DT_END)
- printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));
- if (((u32 *)mem)[size / 4] != 0xdeadbeef)
- printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
- ((u32 *)mem)[size / 4] );
- *allnextp = NULL;
-
- /* Get pointer to OF "/chosen" node for use everywhere */
- of_chosen = of_find_node_by_path("/chosen");
-
- /* Retreive command line */
- if (of_chosen != NULL) {
- p = (char *)get_property(of_chosen, "bootargs", &l);
- if (p != NULL && l > 0)
- strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE));
- }
-#ifdef CONFIG_CMDLINE
- if (l == 0 || (l == 1 && (*p) == 0))
- strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#endif /* CONFIG_CMDLINE */
-
- DBG("Command line is: %s\n", cmd_line);
-
- DBG(" <- unflatten_device_tree()\n");
-}
-
-
-static int __init early_init_dt_scan_cpus(unsigned long node,
- const char *uname, int depth, void *data)
-{
- char *type = of_get_flat_dt_prop(node, "device_type", NULL);
- u32 *prop;
- unsigned long size;
-
- /* We are scanning "cpu" nodes only */
- if (type == NULL || strcmp(type, "cpu") != 0)
- return 0;
-
- if (initial_boot_params && initial_boot_params->version >= 2) {
- /* version 2 of the kexec param format adds the phys cpuid
- * of booted proc.
- */
- boot_cpuid_phys = initial_boot_params->boot_cpuid_phys;
- boot_cpuid = 0;
- } else {
- /* Check if it's the boot-cpu, set it's hw index in paca now */
- if (of_get_flat_dt_prop(node, "linux,boot-cpu", NULL)
- != NULL) {
- u32 *prop = of_get_flat_dt_prop(node, "reg", NULL);
- set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop);
- boot_cpuid_phys = get_hard_smp_processor_id(0);
- }
- }
-
-#ifdef CONFIG_ALTIVEC
- /* Check if we have a VMX and eventually update CPU features */
- prop = (u32 *)of_get_flat_dt_prop(node, "ibm,vmx", NULL);
- if (prop && (*prop) > 0) {
- cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
- cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
- }
-
- /* Same goes for Apple's "altivec" property */
- prop = (u32 *)of_get_flat_dt_prop(node, "altivec", NULL);
- if (prop) {
- cur_cpu_spec->cpu_features |= CPU_FTR_ALTIVEC;
- cur_cpu_spec->cpu_user_features |= PPC_FEATURE_HAS_ALTIVEC;
- }
-#endif /* CONFIG_ALTIVEC */
-
- /*
- * Check for an SMT capable CPU and set the CPU feature. We do
- * this by looking at the size of the ibm,ppc-interrupt-server#s
- * property
- */
- prop = (u32 *)of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s",
- &size);
- cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
- if (prop && ((size / sizeof(u32)) > 1))
- cur_cpu_spec->cpu_features |= CPU_FTR_SMT;
-
- return 0;
-}
-
-static int __init early_init_dt_scan_chosen(unsigned long node,
- const char *uname, int depth, void *data)
-{
- u32 *prop;
- u64 *prop64;
-
- DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
-
- if (depth != 1 || strcmp(uname, "chosen") != 0)
- return 0;
-
- /* get platform type */
- prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL);
- if (prop == NULL)
- return 0;
- _machine = *prop;
-
- /* check if iommu is forced on or off */
- if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
- iommu_is_off = 1;
- if (of_get_flat_dt_prop(node, "linux,iommu-force-on", NULL) != NULL)
- iommu_force_on = 1;
-
- prop64 = (u64*)of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
- if (prop64)
- memory_limit = *prop64;
-
- prop64 = (u64*)of_get_flat_dt_prop(node, "linux,tce-alloc-start",NULL);
- if (prop64)
- tce_alloc_start = *prop64;
-
- prop64 = (u64*)of_get_flat_dt_prop(node, "linux,tce-alloc-end", NULL);
- if (prop64)
- tce_alloc_end = *prop64;
-
-#ifdef CONFIG_PPC_RTAS
- /* To help early debugging via the front panel, we retreive a minimal
- * set of RTAS infos now if available
- */
- {
- u64 *basep, *entryp;
-
- basep = (u64*)of_get_flat_dt_prop(node,
- "linux,rtas-base", NULL);
- entryp = (u64*)of_get_flat_dt_prop(node,
- "linux,rtas-entry", NULL);
- prop = (u32*)of_get_flat_dt_prop(node,
- "linux,rtas-size", NULL);
- if (basep && entryp && prop) {
- rtas.base = *basep;
- rtas.entry = *entryp;
- rtas.size = *prop;
- }
- }
-#endif /* CONFIG_PPC_RTAS */
-
- /* break now */
- return 1;
-}
-
-static int __init early_init_dt_scan_root(unsigned long node,
- const char *uname, int depth, void *data)
-{
- u32 *prop;
-
- if (depth != 0)
- return 0;
-
- prop = (u32 *)of_get_flat_dt_prop(node, "#size-cells", NULL);
- dt_root_size_cells = (prop == NULL) ? 1 : *prop;
- DBG("dt_root_size_cells = %x\n", dt_root_size_cells);
-
- prop = (u32 *)of_get_flat_dt_prop(node, "#address-cells", NULL);
- dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
- DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
-
- /* break now */
- return 1;
-}
-
-static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp)
-{
- cell_t *p = *cellp;
- unsigned long r = 0;
-
- /* Ignore more than 2 cells */
- while (s > 2) {
- p++;
- s--;
- }
- while (s) {
- r <<= 32;
- r |= *(p++);
- s--;
- }
-
- *cellp = p;
- return r;
-}
-
-
-static int __init early_init_dt_scan_memory(unsigned long node,
- const char *uname, int depth, void *data)
-{
- char *type = of_get_flat_dt_prop(node, "device_type", NULL);
- cell_t *reg, *endp;
- unsigned long l;
-
- /* We are scanning "memory" nodes only */
- if (type == NULL || strcmp(type, "memory") != 0)
- return 0;
-
- reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
- if (reg == NULL)
- return 0;
-
- endp = reg + (l / sizeof(cell_t));
-
- DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n",
- uname, l, reg[0], reg[1], reg[2], reg[3]);
-
- while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
- unsigned long base, size;
-
- base = dt_mem_next_cell(dt_root_addr_cells, &reg);
- size = dt_mem_next_cell(dt_root_size_cells, &reg);
-
- if (size == 0)
- continue;
- DBG(" - %lx , %lx\n", base, size);
- if (iommu_is_off) {
- if (base >= 0x80000000ul)
- continue;
- if ((base + size) > 0x80000000ul)
- size = 0x80000000ul - base;
- }
- lmb_add(base, size);
- }
- return 0;
-}
-
-static void __init early_reserve_mem(void)
-{
- u64 base, size;
- u64 *reserve_map = (u64 *)(((unsigned long)initial_boot_params) +
- initial_boot_params->off_mem_rsvmap);
- while (1) {
- base = *(reserve_map++);
- size = *(reserve_map++);
- if (size == 0)
- break;
- DBG("reserving: %lx -> %lx\n", base, size);
- lmb_reserve(base, size);
- }
-
-#if 0
- DBG("memory reserved, lmbs :\n");
- lmb_dump_all();
-#endif
-}
-
-void __init early_init_devtree(void *params)
-{
- DBG(" -> early_init_devtree()\n");
-
- /* Setup flat device-tree pointer */
- initial_boot_params = params;
-
- /* Retreive various informations from the /chosen node of the
- * device-tree, including the platform type, initrd location and
- * size, TCE reserve, and more ...
- */
- of_scan_flat_dt(early_init_dt_scan_chosen, NULL);
-
- /* Scan memory nodes and rebuild LMBs */
- lmb_init();
- of_scan_flat_dt(early_init_dt_scan_root, NULL);
- of_scan_flat_dt(early_init_dt_scan_memory, NULL);
- lmb_enforce_memory_limit(memory_limit);
- lmb_analyze();
- lmb_reserve(0, __pa(klimit));
-
- /* Reserve LMB regions used by kernel, initrd, dt, etc... */
- early_reserve_mem();
-
- DBG("Scanning CPUs ...\n");
-
- /* Retreive hash table size from flattened tree plus other
- * CPU related informations (altivec support, boot CPU ID, ...)
- */
- of_scan_flat_dt(early_init_dt_scan_cpus, NULL);
-
- DBG(" <- early_init_devtree()\n");
-}
-
-#undef printk
-
-int
-prom_n_addr_cells(struct device_node* np)
-{
- int* ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = (int *) 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;
-}
-
-int
-prom_n_size_cells(struct device_node* np)
-{
- int* ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = (int *) 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;
-}
-
-/**
- * Work out the sense (active-low level / active-high edge)
- * of each interrupt from the device tree.
- */
-void __init prom_get_irq_senses(unsigned char *senses, int off, int max)
-{
- struct device_node *np;
- int i, j;
-
- /* default to level-triggered */
- memset(senses, 1, max - off);
-
- for (np = allnodes; np != 0; np = np->allnext) {
- for (j = 0; j < np->n_intrs; j++) {
- i = np->intrs[j].line;
- if (i >= off && i < max)
- senses[i-off] = np->intrs[j].sense ?
- IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE :
- IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE;
- }
- }
-}
-
-/**
- * Construct and return a list of the device_nodes with a given name.
- */
-struct device_node *
-find_devices(const char *name)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- if (np->name != 0 && strcasecmp(np->name, name) == 0) {
- *prevp = np;
- prevp = &np->next;
- }
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_devices);
-
-/**
- * Construct and return a list of the device_nodes with a given type.
- */
-struct device_node *
-find_type_devices(const char *type)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- if (np->type != 0 && strcasecmp(np->type, type) == 0) {
- *prevp = np;
- prevp = &np->next;
- }
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_type_devices);
-
-/**
- * Returns all nodes linked together
- */
-struct device_node *
-find_all_nodes(void)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- *prevp = np;
- prevp = &np->next;
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_all_nodes);
-
-/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
- */
-int
-device_is_compatible(struct device_node *device, const char *compat)
-{
- const char* cp;
- int cplen, l;
-
- cp = (char *) 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(device_is_compatible);
-
-
-/**
- * Indicates whether the root node has a given value in its
- * compatible property.
- */
-int
-machine_is_compatible(const char *compat)
-{
- struct device_node *root;
- int rc = 0;
-
- root = of_find_node_by_path("/");
- if (root) {
- rc = device_is_compatible(root, compat);
- of_node_put(root);
- }
- return rc;
-}
-EXPORT_SYMBOL(machine_is_compatible);
-
-/**
- * Construct and return a list of the device_nodes with a given type
- * and compatible property.
- */
-struct device_node *
-find_compatible_devices(const char *type, const char *compat)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- if (type != NULL
- && !(np->type != 0 && strcasecmp(np->type, type) == 0))
- continue;
- if (device_is_compatible(np, compat)) {
- *prevp = np;
- prevp = &np->next;
- }
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_compatible_devices);
-
-/**
- * Find the device_node with a given full_name.
- */
-struct device_node *
-find_path_device(const char *path)
-{
- struct device_node *np;
-
- for (np = allnodes; np != 0; np = np->allnext)
- if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
- return np;
- return NULL;
-}
-EXPORT_SYMBOL(find_path_device);
-
-/*******
- *
- * New implementation of the OF "find" APIs, return a refcounted
- * object, call of_node_put() when done. The device tree and list
- * are protected by a rw_lock.
- *
- * Note that property management will need some locking as well,
- * this isn't dealt with yet.
- *
- *******/
-
-/**
- * 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 != 0; np = np->allnext)
- if (np->name != 0 && strcasecmp(np->name, name) == 0
- && of_node_get(np))
- break;
- if (from)
- 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, 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 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;
- if (from)
- 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 (device_is_compatible(np, compatible) && of_node_get(np))
- break;
- }
- if (from)
- 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
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_phandle(phandle handle)
-{
- struct device_node *np;
-
- read_lock(&devtree_lock);
- for (np = allnodes; np != 0; np = np->allnext)
- if (np->linux_phandle == handle)
- break;
- if (np)
- of_node_get(np);
- read_unlock(&devtree_lock);
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_phandle);
-
-/**
- * of_find_all_nodes - Get next node in global list
- * @prev: Previous node or NULL to start iteration
- * of_node_put() will be called on it
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_find_all_nodes(struct device_node *prev)
-{
- struct device_node *np;
-
- read_lock(&devtree_lock);
- np = prev ? prev->allnext : allnodes;
- for (; np != 0; np = np->allnext)
- if (of_node_get(np))
- break;
- if (prev)
- of_node_put(prev);
- read_unlock(&devtree_lock);
- return np;
-}
-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;
- if (prev)
- 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
- * simplify writing of callers
- *
- * Returns node.
- */
-struct device_node *of_node_get(struct device_node *node)
-{
- if (node)
- kref_get(&node->kref);
- return node;
-}
-EXPORT_SYMBOL(of_node_get);
-
-static inline struct device_node * kref_to_device_node(struct kref *kref)
-{
- return container_of(kref, struct device_node, kref);
-}
-
-/**
- * of_node_release - release a dynamically allocated node
- * @kref: kref element of the node to be released
- *
- * In of_node_put() this function is passed to kref_put()
- * as the destructor.
- */
-static void of_node_release(struct kref *kref)
-{
- struct device_node *node = kref_to_device_node(kref);
- struct property *prop = node->properties;
-
- if (!OF_IS_DYNAMIC(node))
- return;
- while (prop) {
- struct property *next = prop->next;
- kfree(prop->name);
- kfree(prop->value);
- kfree(prop);
- prop = next;
- }
- kfree(node->intrs);
- kfree(node->addrs);
- kfree(node->full_name);
- kfree(node->data);
- kfree(node);
-}
-
-/**
- * of_node_put - Decrement refcount of a node
- * @node: Node to dec refcount, NULL is supported to
- * simplify writing of callers
- *
- */
-void of_node_put(struct device_node *node)
-{
- if (node)
- kref_put(&node->kref, of_node_release);
-}
-EXPORT_SYMBOL(of_node_put);
-
-/*
- * Fix up the uninitialized fields in a new device node:
- * name, type, n_addrs, addrs, n_intrs, intrs, and pci-specific fields
- *
- * A lot of boot-time code is duplicated here, because functions such
- * as finish_node_interrupts, interpret_pci_props, etc. cannot use the
- * slab allocator.
- *
- * This should probably be split up into smaller chunks.
- */
-
-static int of_finish_dynamic_node(struct device_node *node,
- unsigned long *unused1, int unused2,
- int unused3, int unused4)
-{
- struct device_node *parent = of_get_parent(node);
- int err = 0;
- phandle *ibm_phandle;
-
- node->name = get_property(node, "name", NULL);
- node->type = get_property(node, "device_type", NULL);
-
- if (!parent) {
- err = -ENODEV;
- goto out;
- }
-
- /* We don't support that function on PowerMac, at least
- * not yet
- */
- if (_machine == PLATFORM_POWERMAC)
- return -ENODEV;
-
- /* fix up new node's linux_phandle field */
- if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL)))
- node->linux_phandle = *ibm_phandle;
-
-out:
- of_node_put(parent);
- return err;
-}
-
-/*
- * Plug a device node into the tree and global list.
- */
-void of_attach_node(struct device_node *np)
-{
- write_lock(&devtree_lock);
- np->sibling = np->parent->child;
- np->allnext = allnodes;
- np->parent->child = np;
- allnodes = np;
- write_unlock(&devtree_lock);
-}
-
-/*
- * "Unplug" a node from the device tree. The caller must hold
- * a reference to the node. The memory associated with the node
- * is not freed until its refcount goes to zero.
- */
-void of_detach_node(const struct device_node *np)
-{
- struct device_node *parent;
-
- write_lock(&devtree_lock);
-
- parent = np->parent;
-
- if (allnodes == np)
- allnodes = np->allnext;
- else {
- struct device_node *prev;
- for (prev = allnodes;
- prev->allnext != np;
- prev = prev->allnext)
- ;
- prev->allnext = np->allnext;
- }
-
- if (parent->child == np)
- parent->child = np->sibling;
- else {
- struct device_node *prevsib;
- for (prevsib = np->parent->child;
- prevsib->sibling != np;
- prevsib = prevsib->sibling)
- ;
- prevsib->sibling = np->sibling;
- }
-
- write_unlock(&devtree_lock);
-}
-
-static int prom_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
-{
- int err;
-
- switch (action) {
- case PSERIES_RECONFIG_ADD:
- err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0);
- if (err < 0) {
- printk(KERN_ERR "finish_node returned %d\n", err);
- err = NOTIFY_BAD;
- }
- break;
- default:
- err = NOTIFY_DONE;
- break;
- }
- return err;
-}
-
-static struct notifier_block prom_reconfig_nb = {
- .notifier_call = prom_reconfig_notifier,
- .priority = 10, /* This one needs to run first */
-};
-
-static int __init prom_reconfig_setup(void)
-{
- return pSeries_reconfig_notifier_register(&prom_reconfig_nb);
-}
-__initcall(prom_reconfig_setup);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-unsigned char *
-get_property(struct device_node *np, const char *name, int *lenp)
-{
- struct property *pp;
-
- for (pp = np->properties; pp != 0; pp = pp->next)
- if (strcmp(pp->name, name) == 0) {
- if (lenp != 0)
- *lenp = pp->length;
- return pp->value;
- }
- return NULL;
-}
-EXPORT_SYMBOL(get_property);
-
-/*
- * Add a property to a node.
- */
-int
-prom_add_property(struct device_node* np, struct property* prop)
-{
- struct property **next;
-
- prop->next = NULL;
- write_lock(&devtree_lock);
- next = &np->properties;
- while (*next) {
- if (strcmp(prop->name, (*next)->name) == 0) {
- /* duplicate ! don't insert it */
- write_unlock(&devtree_lock);
- return -1;
- }
- next = &(*next)->next;
- }
- *next = prop;
- write_unlock(&devtree_lock);
-
- /* try to add to proc as well if it was initialized */
- if (np->pde)
- proc_device_tree_add_prop(np->pde, prop);
-
- return 0;
-}
-
-#if 0
-void
-print_properties(struct device_node *np)
-{
- struct property *pp;
- char *cp;
- int i, n;
-
- for (pp = np->properties; pp != 0; pp = pp->next) {
- printk(KERN_INFO "%s", pp->name);
- for (i = strlen(pp->name); i < 16; ++i)
- printk(" ");
- cp = (char *) pp->value;
- for (i = pp->length; i > 0; --i, ++cp)
- if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
- || (i == 1 && *cp != 0))
- break;
- if (i == 0 && pp->length > 1) {
- /* looks like a string */
- printk(" %s\n", (char *) pp->value);
- } else {
- /* dump it in hex */
- n = pp->length;
- if (n > 64)
- n = 64;
- if (pp->length % 4 == 0) {
- unsigned int *p = (unsigned int *) pp->value;
-
- n /= 4;
- for (i = 0; i < n; ++i) {
- if (i != 0 && (i % 4) == 0)
- printk("\n ");
- printk(" %08x", *p++);
- }
- } else {
- unsigned char *bp = pp->value;
-
- for (i = 0; i < n; ++i) {
- if (i != 0 && (i % 16) == 0)
- printk("\n ");
- printk(" %02x", *bp++);
- }
- }
- printk("\n");
- if (pp->length > 64)
- printk(" ... (length = %d)\n",
- pp->length);
- }
- }
-}
-#endif
-
-
-
-
-
-
-
-
-
-
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c
deleted file mode 100644
index 6375f40b23d..00000000000
--- a/arch/ppc64/kernel/prom_init.c
+++ /dev/null
@@ -1,2051 +0,0 @@
-/*
- *
- *
- * Procedures for interfacing to Open Firmware.
- *
- * Paul Mackerras August 1996.
- * Copyright (C) 1996 Paul Mackerras.
- *
- * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
- * {engebret|bergner}@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.
- */
-
-#undef DEBUG_PROM
-
-#include <stdarg.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/stringify.h>
-#include <linux/delay.h>
-#include <linux/initrd.h>
-#include <linux/bitops.h>
-#include <asm/prom.h>
-#include <asm/rtas.h>
-#include <asm/abs_addr.h>
-#include <asm/page.h>
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/system.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/pci.h>
-#include <asm/iommu.h>
-#include <asm/btext.h>
-#include <asm/sections.h>
-#include <asm/machdep.h>
-
-#ifdef CONFIG_LOGO_LINUX_CLUT224
-#include <linux/linux_logo.h>
-extern const struct linux_logo logo_linux_clut224;
-#endif
-
-/*
- * Properties whose value is longer than this get excluded from our
- * copy of the device tree. This value does need to be big enough to
- * ensure that we don't lose things like the interrupt-map property
- * on a PCI-PCI bridge.
- */
-#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024)
-
-/*
- * Eventually bump that one up
- */
-#define DEVTREE_CHUNK_SIZE 0x100000
-
-/*
- * This is the size of the local memory reserve map that gets copied
- * into the boot params passed to the kernel. That size is totally
- * flexible as the kernel just reads the list until it encounters an
- * entry with size 0, so it can be changed without breaking binary
- * compatibility
- */
-#define MEM_RESERVE_MAP_SIZE 8
-
-/*
- * prom_init() is called very early on, before the kernel text
- * and data have been mapped to KERNELBASE. At this point the code
- * is running at whatever address it has been loaded at, so
- * references to extern and static variables must be relocated
- * explicitly. The procedure reloc_offset() returns the address
- * we're currently running at minus the address we were linked at.
- * (Note that strings count as static variables.)
- *
- * Because OF may have mapped I/O devices into the area starting at
- * KERNELBASE, particularly on CHRP machines, we can't safely call
- * OF once the kernel has been mapped to KERNELBASE. Therefore all
- * OF calls should be done within prom_init(), and prom_init()
- * and all routines called within it must be careful to relocate
- * references as necessary.
- *
- * Note that the bss is cleared *after* prom_init runs, so we have
- * to make sure that any static or extern variables it accesses
- * are put in the data segment.
- */
-
-
-#define PROM_BUG() do { \
- prom_printf("kernel BUG at %s line 0x%x!\n", \
- RELOC(__FILE__), __LINE__); \
- __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR); \
-} while (0)
-
-#ifdef DEBUG_PROM
-#define prom_debug(x...) prom_printf(x)
-#else
-#define prom_debug(x...)
-#endif
-
-
-typedef u32 prom_arg_t;
-
-struct prom_args {
- u32 service;
- u32 nargs;
- u32 nret;
- prom_arg_t args[10];
- prom_arg_t *rets; /* Pointer to return values in args[16]. */
-};
-
-struct prom_t {
- unsigned long entry;
- ihandle root;
- ihandle chosen;
- int cpu;
- ihandle stdout;
- ihandle disp_node;
- struct prom_args args;
- unsigned long version;
- unsigned long root_size_cells;
- unsigned long root_addr_cells;
-};
-
-struct pci_reg_property {
- struct pci_address addr;
- u32 size_hi;
- u32 size_lo;
-};
-
-struct mem_map_entry {
- u64 base;
- u64 size;
-};
-
-typedef u32 cell_t;
-
-extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
-
-extern void enter_prom(struct prom_args *args, unsigned long entry);
-extern void copy_and_flush(unsigned long dest, unsigned long src,
- unsigned long size, unsigned long offset);
-
-extern unsigned long klimit;
-
-/* prom structure */
-static struct prom_t __initdata prom;
-
-#define PROM_SCRATCH_SIZE 256
-
-static char __initdata of_stdout_device[256];
-static char __initdata prom_scratch[PROM_SCRATCH_SIZE];
-
-static unsigned long __initdata dt_header_start;
-static unsigned long __initdata dt_struct_start, dt_struct_end;
-static unsigned long __initdata dt_string_start, dt_string_end;
-
-static unsigned long __initdata prom_initrd_start, prom_initrd_end;
-
-static int __initdata iommu_force_on;
-static int __initdata ppc64_iommu_off;
-static int __initdata of_platform;
-
-static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
-
-static unsigned long __initdata prom_memory_limit;
-static unsigned long __initdata prom_tce_alloc_start;
-static unsigned long __initdata prom_tce_alloc_end;
-
-static unsigned long __initdata alloc_top;
-static unsigned long __initdata alloc_top_high;
-static unsigned long __initdata alloc_bottom;
-static unsigned long __initdata rmo_top;
-static unsigned long __initdata ram_top;
-
-static struct mem_map_entry __initdata mem_reserve_map[MEM_RESERVE_MAP_SIZE];
-static int __initdata mem_reserve_cnt;
-
-static cell_t __initdata regbuf[1024];
-
-
-#define MAX_CPU_THREADS 2
-
-/* TO GO */
-#ifdef CONFIG_HMT
-struct {
- unsigned int pir;
- unsigned int threadid;
-} hmt_thread_data[NR_CPUS];
-#endif /* CONFIG_HMT */
-
-/*
- * This are used in calls to call_prom. The 4th and following
- * arguments to call_prom should be 32-bit values. 64 bit values
- * are truncated to 32 bits (and fortunately don't get interpreted
- * as two arguments).
- */
-#define ADDR(x) (u32) ((unsigned long)(x) - offset)
-
-/*
- * Error results ... some OF calls will return "-1" on error, some
- * will return 0, some will return either. To simplify, here are
- * macros to use with any ihandle or phandle return value to check if
- * it is valid
- */
-
-#define PROM_ERROR (-1u)
-#define PHANDLE_VALID(p) ((p) != 0 && (p) != PROM_ERROR)
-#define IHANDLE_VALID(i) ((i) != 0 && (i) != PROM_ERROR)
-
-
-/* This is the one and *ONLY* place where we actually call open
- * firmware from, since we need to make sure we're running in 32b
- * mode when we do. We switch back to 64b mode upon return.
- */
-
-static int __init call_prom(const char *service, int nargs, int nret, ...)
-{
- int i;
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- va_list list;
-
- _prom->args.service = ADDR(service);
- _prom->args.nargs = nargs;
- _prom->args.nret = nret;
- _prom->args.rets = (prom_arg_t *)&(_prom->args.args[nargs]);
-
- va_start(list, nret);
- for (i=0; i < nargs; i++)
- _prom->args.args[i] = va_arg(list, prom_arg_t);
- va_end(list);
-
- for (i=0; i < nret ;i++)
- _prom->args.rets[i] = 0;
-
- enter_prom(&_prom->args, _prom->entry);
-
- return (nret > 0) ? _prom->args.rets[0] : 0;
-}
-
-
-static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
- unsigned long align)
-{
- return (unsigned int)call_prom("claim", 3, 1,
- (prom_arg_t)virt, (prom_arg_t)size,
- (prom_arg_t)align);
-}
-
-static void __init prom_print(const char *msg)
-{
- const char *p, *q;
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
-
- if (_prom->stdout == 0)
- return;
-
- for (p = msg; *p != 0; p = q) {
- for (q = p; *q != 0 && *q != '\n'; ++q)
- ;
- if (q > p)
- call_prom("write", 3, 1, _prom->stdout, p, q - p);
- if (*q == 0)
- break;
- ++q;
- call_prom("write", 3, 1, _prom->stdout, ADDR("\r\n"), 2);
- }
-}
-
-
-static void __init prom_print_hex(unsigned long val)
-{
- unsigned long offset = reloc_offset();
- int i, nibbles = sizeof(val)*2;
- char buf[sizeof(val)*2+1];
- struct prom_t *_prom = PTRRELOC(&prom);
-
- for (i = nibbles-1; i >= 0; i--) {
- buf[i] = (val & 0xf) + '0';
- if (buf[i] > '9')
- buf[i] += ('a'-'0'-10);
- val >>= 4;
- }
- buf[nibbles] = '\0';
- call_prom("write", 3, 1, _prom->stdout, buf, nibbles);
-}
-
-
-static void __init prom_printf(const char *format, ...)
-{
- unsigned long offset = reloc_offset();
- const char *p, *q, *s;
- va_list args;
- unsigned long v;
- struct prom_t *_prom = PTRRELOC(&prom);
-
- va_start(args, format);
- for (p = PTRRELOC(format); *p != 0; p = q) {
- for (q = p; *q != 0 && *q != '\n' && *q != '%'; ++q)
- ;
- if (q > p)
- call_prom("write", 3, 1, _prom->stdout, p, q - p);
- if (*q == 0)
- break;
- if (*q == '\n') {
- ++q;
- call_prom("write", 3, 1, _prom->stdout,
- ADDR("\r\n"), 2);
- continue;
- }
- ++q;
- if (*q == 0)
- break;
- switch (*q) {
- case 's':
- ++q;
- s = va_arg(args, const char *);
- prom_print(s);
- break;
- case 'x':
- ++q;
- v = va_arg(args, unsigned long);
- prom_print_hex(v);
- break;
- }
- }
-}
-
-
-static void __init __attribute__((noreturn)) prom_panic(const char *reason)
-{
- unsigned long offset = reloc_offset();
-
- prom_print(PTRRELOC(reason));
- /* ToDo: should put up an SRC here */
- call_prom("exit", 0, 0);
-
- for (;;) /* should never get here */
- ;
-}
-
-
-static int __init prom_next_node(phandle *nodep)
-{
- phandle node;
-
- if ((node = *nodep) != 0
- && (*nodep = call_prom("child", 1, 1, node)) != 0)
- return 1;
- if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
- return 1;
- for (;;) {
- if ((node = call_prom("parent", 1, 1, node)) == 0)
- return 0;
- if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
- return 1;
- }
-}
-
-static int __init prom_getprop(phandle node, const char *pname,
- void *value, size_t valuelen)
-{
- unsigned long offset = reloc_offset();
-
- return call_prom("getprop", 4, 1, node, ADDR(pname),
- (u32)(unsigned long) value, (u32) valuelen);
-}
-
-static int __init prom_getproplen(phandle node, const char *pname)
-{
- unsigned long offset = reloc_offset();
-
- return call_prom("getproplen", 2, 1, node, ADDR(pname));
-}
-
-static int __init prom_setprop(phandle node, const char *pname,
- void *value, size_t valuelen)
-{
- unsigned long offset = reloc_offset();
-
- return call_prom("setprop", 4, 1, node, ADDR(pname),
- (u32)(unsigned long) value, (u32) valuelen);
-}
-
-/* We can't use the standard versions because of RELOC headaches. */
-#define isxdigit(c) (('0' <= (c) && (c) <= '9') \
- || ('a' <= (c) && (c) <= 'f') \
- || ('A' <= (c) && (c) <= 'F'))
-
-#define isdigit(c) ('0' <= (c) && (c) <= '9')
-#define islower(c) ('a' <= (c) && (c) <= 'z')
-#define toupper(c) (islower(c) ? ((c) - 'a' + 'A') : (c))
-
-unsigned long prom_strtoul(const char *cp, const char **endp)
-{
- unsigned long result = 0, base = 10, value;
-
- if (*cp == '0') {
- base = 8;
- cp++;
- if (toupper(*cp) == 'X') {
- cp++;
- base = 16;
- }
- }
-
- while (isxdigit(*cp) &&
- (value = isdigit(*cp) ? *cp - '0' : toupper(*cp) - 'A' + 10) < base) {
- result = result * base + value;
- cp++;
- }
-
- if (endp)
- *endp = cp;
-
- return result;
-}
-
-unsigned long prom_memparse(const char *ptr, const char **retptr)
-{
- unsigned long ret = prom_strtoul(ptr, retptr);
- int shift = 0;
-
- /*
- * We can't use a switch here because GCC *may* generate a
- * jump table which won't work, because we're not running at
- * the address we're linked at.
- */
- if ('G' == **retptr || 'g' == **retptr)
- shift = 30;
-
- if ('M' == **retptr || 'm' == **retptr)
- shift = 20;
-
- if ('K' == **retptr || 'k' == **retptr)
- shift = 10;
-
- if (shift) {
- ret <<= shift;
- (*retptr)++;
- }
-
- return ret;
-}
-
-/*
- * Early parsing of the command line passed to the kernel, used for
- * "mem=x" and the options that affect the iommu
- */
-static void __init early_cmdline_parse(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- char *opt, *p;
- int l = 0;
-
- RELOC(prom_cmd_line[0]) = 0;
- p = RELOC(prom_cmd_line);
- if ((long)_prom->chosen > 0)
- l = prom_getprop(_prom->chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
-#ifdef CONFIG_CMDLINE
- if (l == 0) /* dbl check */
- strlcpy(RELOC(prom_cmd_line),
- RELOC(CONFIG_CMDLINE), sizeof(prom_cmd_line));
-#endif /* CONFIG_CMDLINE */
- prom_printf("command line: %s\n", RELOC(prom_cmd_line));
-
- opt = strstr(RELOC(prom_cmd_line), RELOC("iommu="));
- if (opt) {
- prom_printf("iommu opt is: %s\n", opt);
- opt += 6;
- while (*opt && *opt == ' ')
- opt++;
- if (!strncmp(opt, RELOC("off"), 3))
- RELOC(ppc64_iommu_off) = 1;
- else if (!strncmp(opt, RELOC("force"), 5))
- RELOC(iommu_force_on) = 1;
- }
-
- opt = strstr(RELOC(prom_cmd_line), RELOC("mem="));
- if (opt) {
- opt += 4;
- RELOC(prom_memory_limit) = prom_memparse(opt, (const char **)&opt);
- /* Align to 16 MB == size of large page */
- RELOC(prom_memory_limit) = ALIGN(RELOC(prom_memory_limit), 0x1000000);
- }
-}
-
-/*
- * To tell the firmware what our capabilities are, we have to pass
- * it a fake 32-bit ELF header containing a couple of PT_NOTE sections
- * that contain structures that contain the actual values.
- */
-static struct fake_elf {
- Elf32_Ehdr elfhdr;
- Elf32_Phdr phdr[2];
- struct chrpnote {
- u32 namesz;
- u32 descsz;
- u32 type;
- char name[8]; /* "PowerPC" */
- struct chrpdesc {
- u32 real_mode;
- u32 real_base;
- u32 real_size;
- u32 virt_base;
- u32 virt_size;
- u32 load_base;
- } chrpdesc;
- } chrpnote;
- struct rpanote {
- u32 namesz;
- u32 descsz;
- u32 type;
- char name[24]; /* "IBM,RPA-Client-Config" */
- struct rpadesc {
- u32 lpar_affinity;
- u32 min_rmo_size;
- u32 min_rmo_percent;
- u32 max_pft_size;
- u32 splpar;
- u32 min_load;
- u32 new_mem_def;
- u32 ignore_me;
- } rpadesc;
- } rpanote;
-} fake_elf = {
- .elfhdr = {
- .e_ident = { 0x7f, 'E', 'L', 'F',
- ELFCLASS32, ELFDATA2MSB, EV_CURRENT },
- .e_type = ET_EXEC, /* yeah right */
- .e_machine = EM_PPC,
- .e_version = EV_CURRENT,
- .e_phoff = offsetof(struct fake_elf, phdr),
- .e_phentsize = sizeof(Elf32_Phdr),
- .e_phnum = 2
- },
- .phdr = {
- [0] = {
- .p_type = PT_NOTE,
- .p_offset = offsetof(struct fake_elf, chrpnote),
- .p_filesz = sizeof(struct chrpnote)
- }, [1] = {
- .p_type = PT_NOTE,
- .p_offset = offsetof(struct fake_elf, rpanote),
- .p_filesz = sizeof(struct rpanote)
- }
- },
- .chrpnote = {
- .namesz = sizeof("PowerPC"),
- .descsz = sizeof(struct chrpdesc),
- .type = 0x1275,
- .name = "PowerPC",
- .chrpdesc = {
- .real_mode = ~0U, /* ~0 means "don't care" */
- .real_base = ~0U,
- .real_size = ~0U,
- .virt_base = ~0U,
- .virt_size = ~0U,
- .load_base = ~0U
- },
- },
- .rpanote = {
- .namesz = sizeof("IBM,RPA-Client-Config"),
- .descsz = sizeof(struct rpadesc),
- .type = 0x12759999,
- .name = "IBM,RPA-Client-Config",
- .rpadesc = {
- .lpar_affinity = 0,
- .min_rmo_size = 64, /* in megabytes */
- .min_rmo_percent = 0,
- .max_pft_size = 48, /* 2^48 bytes max PFT size */
- .splpar = 1,
- .min_load = ~0U,
- .new_mem_def = 0
- }
- }
-};
-
-static void __init prom_send_capabilities(void)
-{
- unsigned long offset = reloc_offset();
- ihandle elfloader;
-
- elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader"));
- if (elfloader == 0) {
- prom_printf("couldn't open /packages/elf-loader\n");
- return;
- }
- call_prom("call-method", 3, 1, ADDR("process-elf-header"),
- elfloader, ADDR(&fake_elf));
- call_prom("close", 1, 0, elfloader);
-}
-
-/*
- * Memory allocation strategy... our layout is normally:
- *
- * at 14Mb or more we vmlinux, then a gap and initrd. In some rare cases, initrd
- * might end up beeing before the kernel though. We assume this won't override
- * the final kernel at 0, we have no provision to handle that in this version,
- * but it should hopefully never happen.
- *
- * alloc_top is set to the top of RMO, eventually shrink down if the TCEs overlap
- * alloc_bottom is set to the top of kernel/initrd
- *
- * from there, allocations are done that way : rtas is allocated topmost, and
- * the device-tree is allocated from the bottom. We try to grow the device-tree
- * allocation as we progress. If we can't, then we fail, we don't currently have
- * a facility to restart elsewhere, but that shouldn't be necessary neither
- *
- * Note that calls to reserve_mem have to be done explicitely, memory allocated
- * with either alloc_up or alloc_down isn't automatically reserved.
- */
-
-
-/*
- * Allocates memory in the RMO upward from the kernel/initrd
- *
- * When align is 0, this is a special case, it means to allocate in place
- * at the current location of alloc_bottom or fail (that is basically
- * extending the previous allocation). Used for the device-tree flattening
- */
-static unsigned long __init alloc_up(unsigned long size, unsigned long align)
-{
- unsigned long offset = reloc_offset();
- unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align);
- unsigned long addr = 0;
-
- prom_debug("alloc_up(%x, %x)\n", size, align);
- if (RELOC(ram_top) == 0)
- prom_panic("alloc_up() called with mem not initialized\n");
-
- if (align)
- base = _ALIGN_UP(RELOC(alloc_bottom), align);
- else
- base = RELOC(alloc_bottom);
-
- for(; (base + size) <= RELOC(alloc_top);
- base = _ALIGN_UP(base + 0x100000, align)) {
- prom_debug(" trying: 0x%x\n\r", base);
- addr = (unsigned long)prom_claim(base, size, 0);
- if (addr != PROM_ERROR)
- break;
- addr = 0;
- if (align == 0)
- break;
- }
- if (addr == 0)
- return 0;
- RELOC(alloc_bottom) = addr;
-
- prom_debug(" -> %x\n", addr);
- prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom));
- prom_debug(" alloc_top : %x\n", RELOC(alloc_top));
- prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
- prom_debug(" rmo_top : %x\n", RELOC(rmo_top));
- prom_debug(" ram_top : %x\n", RELOC(ram_top));
-
- return addr;
-}
-
-/*
- * Allocates memory downard, either from top of RMO, or if highmem
- * is set, from the top of RAM. Note that this one doesn't handle
- * failures. In does claim memory if highmem is not set.
- */
-static unsigned long __init alloc_down(unsigned long size, unsigned long align,
- int highmem)
-{
- unsigned long offset = reloc_offset();
- unsigned long base, addr = 0;
-
- prom_debug("alloc_down(%x, %x, %s)\n", size, align,
- highmem ? RELOC("(high)") : RELOC("(low)"));
- if (RELOC(ram_top) == 0)
- prom_panic("alloc_down() called with mem not initialized\n");
-
- if (highmem) {
- /* Carve out storage for the TCE table. */
- addr = _ALIGN_DOWN(RELOC(alloc_top_high) - size, align);
- if (addr <= RELOC(alloc_bottom))
- return 0;
- else {
- /* Will we bump into the RMO ? If yes, check out that we
- * didn't overlap existing allocations there, if we did,
- * we are dead, we must be the first in town !
- */
- if (addr < RELOC(rmo_top)) {
- /* Good, we are first */
- if (RELOC(alloc_top) == RELOC(rmo_top))
- RELOC(alloc_top) = RELOC(rmo_top) = addr;
- else
- return 0;
- }
- RELOC(alloc_top_high) = addr;
- }
- goto bail;
- }
-
- base = _ALIGN_DOWN(RELOC(alloc_top) - size, align);
- for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) {
- prom_debug(" trying: 0x%x\n\r", base);
- addr = (unsigned long)prom_claim(base, size, 0);
- if (addr != PROM_ERROR)
- break;
- addr = 0;
- }
- if (addr == 0)
- return 0;
- RELOC(alloc_top) = addr;
-
- bail:
- prom_debug(" -> %x\n", addr);
- prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom));
- prom_debug(" alloc_top : %x\n", RELOC(alloc_top));
- prom_debug(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
- prom_debug(" rmo_top : %x\n", RELOC(rmo_top));
- prom_debug(" ram_top : %x\n", RELOC(ram_top));
-
- return addr;
-}
-
-/*
- * Parse a "reg" cell
- */
-static unsigned long __init prom_next_cell(int s, cell_t **cellp)
-{
- cell_t *p = *cellp;
- unsigned long r = 0;
-
- /* Ignore more than 2 cells */
- while (s > 2) {
- p++;
- s--;
- }
- while (s) {
- r <<= 32;
- r |= *(p++);
- s--;
- }
-
- *cellp = p;
- return r;
-}
-
-/*
- * Very dumb function for adding to the memory reserve list, but
- * we don't need anything smarter at this point
- *
- * XXX Eventually check for collisions. They should NEVER happen
- * if problems seem to show up, it would be a good start to track
- * them down.
- */
-static void reserve_mem(unsigned long base, unsigned long size)
-{
- unsigned long offset = reloc_offset();
- unsigned long top = base + size;
- unsigned long cnt = RELOC(mem_reserve_cnt);
-
- if (size == 0)
- return;
-
- /* We need to always keep one empty entry so that we
- * have our terminator with "size" set to 0 since we are
- * dumb and just copy this entire array to the boot params
- */
- base = _ALIGN_DOWN(base, PAGE_SIZE);
- top = _ALIGN_UP(top, PAGE_SIZE);
- size = top - base;
-
- if (cnt >= (MEM_RESERVE_MAP_SIZE - 1))
- prom_panic("Memory reserve map exhausted !\n");
- RELOC(mem_reserve_map)[cnt].base = base;
- RELOC(mem_reserve_map)[cnt].size = size;
- RELOC(mem_reserve_cnt) = cnt + 1;
-}
-
-/*
- * Initialize memory allocation mecanism, parse "memory" nodes and
- * obtain that way the top of memory and RMO to setup out local allocator
- */
-static void __init prom_init_mem(void)
-{
- phandle node;
- char *path, type[64];
- unsigned int plen;
- cell_t *p, *endp;
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
-
- /*
- * We iterate the memory nodes to find
- * 1) top of RMO (first node)
- * 2) top of memory
- */
- prom_debug("root_addr_cells: %x\n", (long)_prom->root_addr_cells);
- prom_debug("root_size_cells: %x\n", (long)_prom->root_size_cells);
-
- prom_debug("scanning memory:\n");
- path = RELOC(prom_scratch);
-
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- prom_getprop(node, "device_type", type, sizeof(type));
-
- if (strcmp(type, RELOC("memory")))
- continue;
-
- plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf));
- if (plen > sizeof(regbuf)) {
- prom_printf("memory node too large for buffer !\n");
- plen = sizeof(regbuf);
- }
- p = RELOC(regbuf);
- endp = p + (plen / sizeof(cell_t));
-
-#ifdef DEBUG_PROM
- memset(path, 0, PROM_SCRATCH_SIZE);
- call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
- prom_debug(" node %s :\n", path);
-#endif /* DEBUG_PROM */
-
- while ((endp - p) >= (_prom->root_addr_cells + _prom->root_size_cells)) {
- unsigned long base, size;
-
- base = prom_next_cell(_prom->root_addr_cells, &p);
- size = prom_next_cell(_prom->root_size_cells, &p);
-
- if (size == 0)
- continue;
- prom_debug(" %x %x\n", base, size);
- if (base == 0)
- RELOC(rmo_top) = size;
- if ((base + size) > RELOC(ram_top))
- RELOC(ram_top) = base + size;
- }
- }
-
- RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(klimit) - offset + 0x4000);
-
- /* Check if we have an initrd after the kernel, if we do move our bottom
- * point to after it
- */
- if (RELOC(prom_initrd_start)) {
- if (RELOC(prom_initrd_end) > RELOC(alloc_bottom))
- RELOC(alloc_bottom) = PAGE_ALIGN(RELOC(prom_initrd_end));
- }
-
- /*
- * If prom_memory_limit is set we reduce the upper limits *except* for
- * alloc_top_high. This must be the real top of RAM so we can put
- * TCE's up there.
- */
-
- RELOC(alloc_top_high) = RELOC(ram_top);
-
- if (RELOC(prom_memory_limit)) {
- if (RELOC(prom_memory_limit) <= RELOC(alloc_bottom)) {
- prom_printf("Ignoring mem=%x <= alloc_bottom.\n",
- RELOC(prom_memory_limit));
- RELOC(prom_memory_limit) = 0;
- } else if (RELOC(prom_memory_limit) >= RELOC(ram_top)) {
- prom_printf("Ignoring mem=%x >= ram_top.\n",
- RELOC(prom_memory_limit));
- RELOC(prom_memory_limit) = 0;
- } else {
- RELOC(ram_top) = RELOC(prom_memory_limit);
- RELOC(rmo_top) = min(RELOC(rmo_top), RELOC(prom_memory_limit));
- }
- }
-
- /*
- * Setup our top alloc point, that is top of RMO or top of
- * segment 0 when running non-LPAR.
- */
- if ( RELOC(of_platform) == PLATFORM_PSERIES_LPAR )
- RELOC(alloc_top) = RELOC(rmo_top);
- else
- /* Some RS64 machines have buggy firmware where claims up at 1GB
- * fails. Cap at 768MB as a workaround. Still plenty of room.
- */
- RELOC(alloc_top) = RELOC(rmo_top) = min(0x30000000ul, RELOC(ram_top));
-
- prom_printf("memory layout at init:\n");
- prom_printf(" memory_limit : %x (16 MB aligned)\n", RELOC(prom_memory_limit));
- prom_printf(" alloc_bottom : %x\n", RELOC(alloc_bottom));
- prom_printf(" alloc_top : %x\n", RELOC(alloc_top));
- prom_printf(" alloc_top_hi : %x\n", RELOC(alloc_top_high));
- prom_printf(" rmo_top : %x\n", RELOC(rmo_top));
- prom_printf(" ram_top : %x\n", RELOC(ram_top));
-}
-
-
-/*
- * Allocate room for and instanciate RTAS
- */
-static void __init prom_instantiate_rtas(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- phandle rtas_node;
- ihandle rtas_inst;
- u32 base, entry = 0;
- u32 size = 0;
-
- prom_debug("prom_instantiate_rtas: start...\n");
-
- rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas"));
- prom_debug("rtas_node: %x\n", rtas_node);
- if (!PHANDLE_VALID(rtas_node))
- return;
-
- prom_getprop(rtas_node, "rtas-size", &size, sizeof(size));
- if (size == 0)
- return;
-
- base = alloc_down(size, PAGE_SIZE, 0);
- if (base == 0) {
- prom_printf("RTAS allocation failed !\n");
- return;
- }
-
- rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
- if (!IHANDLE_VALID(rtas_inst)) {
- prom_printf("opening rtas package failed");
- return;
- }
-
- prom_printf("instantiating rtas at 0x%x ...", base);
-
- if (call_prom("call-method", 3, 2,
- ADDR("instantiate-rtas"),
- rtas_inst, base) != PROM_ERROR) {
- entry = (long)_prom->args.rets[1];
- }
- if (entry == 0) {
- prom_printf(" failed\n");
- return;
- }
- prom_printf(" done\n");
-
- reserve_mem(base, size);
-
- prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base));
- prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry));
-
- prom_debug("rtas base = 0x%x\n", base);
- prom_debug("rtas entry = 0x%x\n", entry);
- prom_debug("rtas size = 0x%x\n", (long)size);
-
- prom_debug("prom_instantiate_rtas: end...\n");
-}
-
-
-/*
- * Allocate room for and initialize TCE tables
- */
-static void __init prom_initialize_tce_table(void)
-{
- phandle node;
- ihandle phb_node;
- unsigned long offset = reloc_offset();
- char compatible[64], type[64], model[64];
- char *path = RELOC(prom_scratch);
- u64 base, align;
- u32 minalign, minsize;
- u64 tce_entry, *tce_entryp;
- u64 local_alloc_top, local_alloc_bottom;
- u64 i;
-
- if (RELOC(ppc64_iommu_off))
- return;
-
- prom_debug("starting prom_initialize_tce_table\n");
-
- /* Cache current top of allocs so we reserve a single block */
- local_alloc_top = RELOC(alloc_top_high);
- local_alloc_bottom = local_alloc_top;
-
- /* Search all nodes looking for PHBs. */
- for (node = 0; prom_next_node(&node); ) {
- compatible[0] = 0;
- type[0] = 0;
- model[0] = 0;
- prom_getprop(node, "compatible",
- compatible, sizeof(compatible));
- prom_getprop(node, "device_type", type, sizeof(type));
- prom_getprop(node, "model", model, sizeof(model));
-
- if ((type[0] == 0) || (strstr(type, RELOC("pci")) == NULL))
- continue;
-
- /* Keep the old logic in tack to avoid regression. */
- if (compatible[0] != 0) {
- if ((strstr(compatible, RELOC("python")) == NULL) &&
- (strstr(compatible, RELOC("Speedwagon")) == NULL) &&
- (strstr(compatible, RELOC("Winnipeg")) == NULL))
- continue;
- } else if (model[0] != 0) {
- if ((strstr(model, RELOC("ython")) == NULL) &&
- (strstr(model, RELOC("peedwagon")) == NULL) &&
- (strstr(model, RELOC("innipeg")) == NULL))
- continue;
- }
-
- if (prom_getprop(node, "tce-table-minalign", &minalign,
- sizeof(minalign)) == PROM_ERROR)
- minalign = 0;
- if (prom_getprop(node, "tce-table-minsize", &minsize,
- sizeof(minsize)) == PROM_ERROR)
- minsize = 4UL << 20;
-
- /*
- * Even though we read what OF wants, we just set the table
- * size to 4 MB. This is enough to map 2GB of PCI DMA space.
- * By doing this, we avoid the pitfalls of trying to DMA to
- * MMIO space and the DMA alias hole.
- *
- * On POWER4, firmware sets the TCE region by assuming
- * each TCE table is 8MB. Using this memory for anything
- * else will impact performance, so we always allocate 8MB.
- * Anton
- */
- if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
- minsize = 8UL << 20;
- else
- minsize = 4UL << 20;
-
- /* Align to the greater of the align or size */
- align = max(minalign, minsize);
- base = alloc_down(minsize, align, 1);
- if (base == 0)
- prom_panic("ERROR, cannot find space for TCE table.\n");
- if (base < local_alloc_bottom)
- local_alloc_bottom = base;
-
- /* Save away the TCE table attributes for later use. */
- prom_setprop(node, "linux,tce-base", &base, sizeof(base));
- prom_setprop(node, "linux,tce-size", &minsize, sizeof(minsize));
-
- /* It seems OF doesn't null-terminate the path :-( */
- memset(path, 0, sizeof(path));
- /* Call OF to setup the TCE hardware */
- if (call_prom("package-to-path", 3, 1, node,
- path, PROM_SCRATCH_SIZE-1) == PROM_ERROR) {
- prom_printf("package-to-path failed\n");
- }
-
- prom_debug("TCE table: %s\n", path);
- prom_debug("\tnode = 0x%x\n", node);
- prom_debug("\tbase = 0x%x\n", base);
- prom_debug("\tsize = 0x%x\n", minsize);
-
- /* Initialize the table to have a one-to-one mapping
- * over the allocated size.
- */
- tce_entryp = (unsigned long *)base;
- for (i = 0; i < (minsize >> 3) ;tce_entryp++, i++) {
- tce_entry = (i << PAGE_SHIFT);
- tce_entry |= 0x3;
- *tce_entryp = tce_entry;
- }
-
- prom_printf("opening PHB %s", path);
- phb_node = call_prom("open", 1, 1, path);
- if (phb_node == 0)
- prom_printf("... failed\n");
- else
- prom_printf("... done\n");
-
- call_prom("call-method", 6, 0, ADDR("set-64-bit-addressing"),
- phb_node, -1, minsize,
- (u32) base, (u32) (base >> 32));
- call_prom("close", 1, 0, phb_node);
- }
-
- reserve_mem(local_alloc_bottom, local_alloc_top - local_alloc_bottom);
-
- if (RELOC(prom_memory_limit)) {
- /*
- * We align the start to a 16MB boundary so we can map the TCE area
- * using large pages if possible. The end should be the top of RAM
- * so no need to align it.
- */
- RELOC(prom_tce_alloc_start) = _ALIGN_DOWN(local_alloc_bottom, 0x1000000);
- RELOC(prom_tce_alloc_end) = local_alloc_top;
- }
-
- /* Flag the first invalid entry */
- prom_debug("ending prom_initialize_tce_table\n");
-}
-
-/*
- * With CHRP SMP we need to use the OF to start the other
- * processors so we can't wait until smp_boot_cpus (the OF is
- * trashed by then) so we have to put the processors into
- * a holding pattern controlled by the kernel (not OF) before
- * we destroy the OF.
- *
- * This uses a chunk of low memory, puts some holding pattern
- * code there and sends the other processors off to there until
- * smp_boot_cpus tells them to do something. The holding pattern
- * checks that address until its cpu # is there, when it is that
- * cpu jumps to __secondary_start(). smp_boot_cpus() takes care
- * of setting those values.
- *
- * We also use physical address 0x4 here to tell when a cpu
- * is in its holding pattern code.
- *
- * Fixup comment... DRENG / PPPBBB - Peter
- *
- * -- Cort
- */
-static void __init prom_hold_cpus(void)
-{
- unsigned long i;
- unsigned int reg;
- phandle node;
- unsigned long offset = reloc_offset();
- char type[64];
- int cpuid = 0;
- unsigned int interrupt_server[MAX_CPU_THREADS];
- unsigned int cpu_threads, hw_cpu_num;
- int propsize;
- extern void __secondary_hold(void);
- extern unsigned long __secondary_hold_spinloop;
- extern unsigned long __secondary_hold_acknowledge;
- unsigned long *spinloop
- = (void *)virt_to_abs(&__secondary_hold_spinloop);
- unsigned long *acknowledge
- = (void *)virt_to_abs(&__secondary_hold_acknowledge);
- unsigned long secondary_hold
- = virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold));
- struct prom_t *_prom = PTRRELOC(&prom);
-
- prom_debug("prom_hold_cpus: start...\n");
- prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop);
- prom_debug(" 1) *spinloop = 0x%x\n", *spinloop);
- prom_debug(" 1) acknowledge = 0x%x\n",
- (unsigned long)acknowledge);
- prom_debug(" 1) *acknowledge = 0x%x\n", *acknowledge);
- prom_debug(" 1) secondary_hold = 0x%x\n", secondary_hold);
-
- /* Set the common spinloop variable, so all of the secondary cpus
- * will block when they are awakened from their OF spinloop.
- * This must occur for both SMP and non SMP kernels, since OF will
- * be trashed when we move the kernel.
- */
- *spinloop = 0;
-
-#ifdef CONFIG_HMT
- for (i=0; i < NR_CPUS; i++) {
- RELOC(hmt_thread_data)[i].pir = 0xdeadbeef;
- }
-#endif
- /* look for cpus */
- for (node = 0; prom_next_node(&node); ) {
- type[0] = 0;
- prom_getprop(node, "device_type", type, sizeof(type));
- if (strcmp(type, RELOC("cpu")) != 0)
- continue;
-
- /* Skip non-configured cpus. */
- if (prom_getprop(node, "status", type, sizeof(type)) > 0)
- if (strcmp(type, RELOC("okay")) != 0)
- continue;
-
- reg = -1;
- prom_getprop(node, "reg", &reg, sizeof(reg));
-
- prom_debug("\ncpuid = 0x%x\n", cpuid);
- prom_debug("cpu hw idx = 0x%x\n", reg);
-
- /* Init the acknowledge var which will be reset by
- * the secondary cpu when it awakens from its OF
- * spinloop.
- */
- *acknowledge = (unsigned long)-1;
-
- propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s",
- &interrupt_server,
- sizeof(interrupt_server));
- if (propsize < 0) {
- /* no property. old hardware has no SMT */
- cpu_threads = 1;
- interrupt_server[0] = reg; /* fake it with phys id */
- } else {
- /* We have a threaded processor */
- cpu_threads = propsize / sizeof(u32);
- if (cpu_threads > MAX_CPU_THREADS) {
- prom_printf("SMT: too many threads!\n"
- "SMT: found %x, max is %x\n",
- cpu_threads, MAX_CPU_THREADS);
- cpu_threads = 1; /* ToDo: panic? */
- }
- }
-
- hw_cpu_num = interrupt_server[0];
- if (hw_cpu_num != _prom->cpu) {
- /* Primary Thread of non-boot cpu */
- prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg);
- call_prom("start-cpu", 3, 0, node,
- secondary_hold, reg);
-
- for ( i = 0 ; (i < 100000000) &&
- (*acknowledge == ((unsigned long)-1)); i++ )
- mb();
-
- if (*acknowledge == reg) {
- prom_printf("done\n");
- /* We have to get every CPU out of OF,
- * even if we never start it. */
- if (cpuid >= NR_CPUS)
- goto next;
- } else {
- prom_printf("failed: %x\n", *acknowledge);
- }
- }
-#ifdef CONFIG_SMP
- else
- prom_printf("%x : boot cpu %x\n", cpuid, reg);
-#endif
-next:
-#ifdef CONFIG_SMP
- /* Init paca for secondary threads. They start later. */
- for (i=1; i < cpu_threads; i++) {
- cpuid++;
- if (cpuid >= NR_CPUS)
- continue;
- }
-#endif /* CONFIG_SMP */
- cpuid++;
- }
-#ifdef CONFIG_HMT
- /* Only enable HMT on processors that provide support. */
- if (__is_processor(PV_PULSAR) ||
- __is_processor(PV_ICESTAR) ||
- __is_processor(PV_SSTAR)) {
- prom_printf(" starting secondary threads\n");
-
- for (i = 0; i < NR_CPUS; i += 2) {
- if (!cpu_online(i))
- continue;
-
- if (i == 0) {
- unsigned long pir = mfspr(SPRN_PIR);
- if (__is_processor(PV_PULSAR)) {
- RELOC(hmt_thread_data)[i].pir =
- pir & 0x1f;
- } else {
- RELOC(hmt_thread_data)[i].pir =
- pir & 0x3ff;
- }
- }
- }
- } else {
- prom_printf("Processor is not HMT capable\n");
- }
-#endif
-
- if (cpuid > NR_CPUS)
- prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS)
- ") exceeded: ignoring extras\n");
-
- prom_debug("prom_hold_cpus: end...\n");
-}
-
-
-static void __init prom_init_client_services(unsigned long pp)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
-
- /* Get a handle to the prom entry point before anything else */
- _prom->entry = pp;
-
- /* Init default value for phys size */
- _prom->root_size_cells = 1;
- _prom->root_addr_cells = 2;
-
- /* get a handle for the stdout device */
- _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen"));
- if (!PHANDLE_VALID(_prom->chosen))
- prom_panic("cannot find chosen"); /* msg won't be printed :( */
-
- /* get device tree root */
- _prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
- if (!PHANDLE_VALID(_prom->root))
- prom_panic("cannot find device tree root"); /* msg won't be printed :( */
-}
-
-static void __init prom_init_stdout(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- char *path = RELOC(of_stdout_device);
- char type[16];
- u32 val;
-
- if (prom_getprop(_prom->chosen, "stdout", &val, sizeof(val)) <= 0)
- prom_panic("cannot find stdout");
-
- _prom->stdout = val;
-
- /* Get the full OF pathname of the stdout device */
- memset(path, 0, 256);
- call_prom("instance-to-path", 3, 1, _prom->stdout, path, 255);
- val = call_prom("instance-to-package", 1, 1, _prom->stdout);
- prom_setprop(_prom->chosen, "linux,stdout-package", &val, sizeof(val));
- prom_printf("OF stdout device is: %s\n", RELOC(of_stdout_device));
- prom_setprop(_prom->chosen, "linux,stdout-path",
- RELOC(of_stdout_device), strlen(RELOC(of_stdout_device))+1);
-
- /* If it's a display, note it */
- memset(type, 0, sizeof(type));
- prom_getprop(val, "device_type", type, sizeof(type));
- if (strcmp(type, RELOC("display")) == 0) {
- _prom->disp_node = val;
- prom_setprop(val, "linux,boot-display", NULL, 0);
- }
-}
-
-static void __init prom_close_stdin(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- ihandle val;
-
- if (prom_getprop(_prom->chosen, "stdin", &val, sizeof(val)) > 0)
- call_prom("close", 1, 0, val);
-}
-
-static int __init prom_find_machine_type(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- char compat[256];
- int len, i = 0;
- phandle rtas;
-
- len = prom_getprop(_prom->root, "compatible",
- compat, sizeof(compat)-1);
- if (len > 0) {
- compat[len] = 0;
- while (i < len) {
- char *p = &compat[i];
- int sl = strlen(p);
- if (sl == 0)
- break;
- if (strstr(p, RELOC("Power Macintosh")) ||
- strstr(p, RELOC("MacRISC4")))
- return PLATFORM_POWERMAC;
- if (strstr(p, RELOC("Momentum,Maple")))
- return PLATFORM_MAPLE;
- i += sl + 1;
- }
- }
- /* Default to pSeries. We need to know if we are running LPAR */
- rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
- if (PHANDLE_VALID(rtas)) {
- int x = prom_getproplen(rtas, "ibm,hypertas-functions");
- if (x != PROM_ERROR) {
- prom_printf("Hypertas detected, assuming LPAR !\n");
- return PLATFORM_PSERIES_LPAR;
- }
- }
- return PLATFORM_PSERIES;
-}
-
-static int __init prom_set_color(ihandle ih, int i, int r, int g, int b)
-{
- unsigned long offset = reloc_offset();
-
- return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r);
-}
-
-/*
- * If we have a display that we don't know how to drive,
- * we will want to try to execute OF's open method for it
- * later. However, OF will probably fall over if we do that
- * we've taken over the MMU.
- * So we check whether we will need to open the display,
- * and if so, open it now.
- */
-static void __init prom_check_displays(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- char type[16], *path;
- phandle node;
- ihandle ih;
- int i;
-
- static unsigned char default_colors[] = {
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xaa,
- 0x00, 0xaa, 0x00,
- 0x00, 0xaa, 0xaa,
- 0xaa, 0x00, 0x00,
- 0xaa, 0x00, 0xaa,
- 0xaa, 0xaa, 0x00,
- 0xaa, 0xaa, 0xaa,
- 0x55, 0x55, 0x55,
- 0x55, 0x55, 0xff,
- 0x55, 0xff, 0x55,
- 0x55, 0xff, 0xff,
- 0xff, 0x55, 0x55,
- 0xff, 0x55, 0xff,
- 0xff, 0xff, 0x55,
- 0xff, 0xff, 0xff
- };
- const unsigned char *clut;
-
- prom_printf("Looking for displays\n");
- for (node = 0; prom_next_node(&node); ) {
- memset(type, 0, sizeof(type));
- prom_getprop(node, "device_type", type, sizeof(type));
- if (strcmp(type, RELOC("display")) != 0)
- continue;
-
- /* It seems OF doesn't null-terminate the path :-( */
- path = RELOC(prom_scratch);
- memset(path, 0, PROM_SCRATCH_SIZE);
-
- /*
- * leave some room at the end of the path for appending extra
- * arguments
- */
- if (call_prom("package-to-path", 3, 1, node, path,
- PROM_SCRATCH_SIZE-10) == PROM_ERROR)
- continue;
- prom_printf("found display : %s, opening ... ", path);
-
- ih = call_prom("open", 1, 1, path);
- if (ih == 0) {
- prom_printf("failed\n");
- continue;
- }
-
- /* Success */
- prom_printf("done\n");
- prom_setprop(node, "linux,opened", NULL, 0);
-
- /*
- * stdout wasn't a display node, pick the first we can find
- * for btext
- */
- if (_prom->disp_node == 0)
- _prom->disp_node = node;
-
- /* Setup a useable color table when the appropriate
- * method is available. Should update this to set-colors */
- clut = RELOC(default_colors);
- for (i = 0; i < 32; i++, clut += 3)
- if (prom_set_color(ih, i, clut[0], clut[1],
- clut[2]) != 0)
- break;
-
-#ifdef CONFIG_LOGO_LINUX_CLUT224
- clut = PTRRELOC(RELOC(logo_linux_clut224.clut));
- for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3)
- if (prom_set_color(ih, i + 32, clut[0], clut[1],
- clut[2]) != 0)
- break;
-#endif /* CONFIG_LOGO_LINUX_CLUT224 */
- }
-}
-
-
-/* Return (relocated) pointer to this much memory: moves initrd if reqd. */
-static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end,
- unsigned long needed, unsigned long align)
-{
- unsigned long offset = reloc_offset();
- void *ret;
-
- *mem_start = _ALIGN(*mem_start, align);
- while ((*mem_start + needed) > *mem_end) {
- unsigned long room, chunk;
-
- prom_debug("Chunk exhausted, claiming more at %x...\n",
- RELOC(alloc_bottom));
- room = RELOC(alloc_top) - RELOC(alloc_bottom);
- if (room > DEVTREE_CHUNK_SIZE)
- room = DEVTREE_CHUNK_SIZE;
- if (room < PAGE_SIZE)
- prom_panic("No memory for flatten_device_tree (no room)");
- chunk = alloc_up(room, 0);
- if (chunk == 0)
- prom_panic("No memory for flatten_device_tree (claim failed)");
- *mem_end = RELOC(alloc_top);
- }
-
- ret = (void *)*mem_start;
- *mem_start += needed;
-
- return ret;
-}
-
-#define dt_push_token(token, mem_start, mem_end) \
- do { *((u32 *)make_room(mem_start, mem_end, 4, 4)) = token; } while(0)
-
-static unsigned long __init dt_find_string(char *str)
-{
- unsigned long offset = reloc_offset();
- char *s, *os;
-
- s = os = (char *)RELOC(dt_string_start);
- s += 4;
- while (s < (char *)RELOC(dt_string_end)) {
- if (strcmp(s, str) == 0)
- return s - os;
- s += strlen(s) + 1;
- }
- return 0;
-}
-
-/*
- * The Open Firmware 1275 specification states properties must be 31 bytes or
- * less, however not all firmwares obey this. Make it 64 bytes to be safe.
- */
-#define MAX_PROPERTY_NAME 64
-
-static void __init scan_dt_build_strings(phandle node,
- unsigned long *mem_start,
- unsigned long *mem_end)
-{
- unsigned long offset = reloc_offset();
- char *prev_name, *namep, *sstart;
- unsigned long soff;
- phandle child;
-
- sstart = (char *)RELOC(dt_string_start);
-
- /* get and store all property names */
- prev_name = RELOC("");
- for (;;) {
- /* 64 is max len of name including nul. */
- namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
- if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) {
- /* No more nodes: unwind alloc */
- *mem_start = (unsigned long)namep;
- break;
- }
-
- /* skip "name" */
- if (strcmp(namep, RELOC("name")) == 0) {
- *mem_start = (unsigned long)namep;
- prev_name = RELOC("name");
- continue;
- }
- /* get/create string entry */
- soff = dt_find_string(namep);
- if (soff != 0) {
- *mem_start = (unsigned long)namep;
- namep = sstart + soff;
- } else {
- /* Trim off some if we can */
- *mem_start = (unsigned long)namep + strlen(namep) + 1;
- RELOC(dt_string_end) = *mem_start;
- }
- prev_name = namep;
- }
-
- /* do all our children */
- child = call_prom("child", 1, 1, node);
- while (child != 0) {
- scan_dt_build_strings(child, mem_start, mem_end);
- child = call_prom("peer", 1, 1, child);
- }
-}
-
-static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
- unsigned long *mem_end)
-{
- phandle child;
- char *namep, *prev_name, *sstart, *p, *ep, *lp, *path;
- unsigned long soff;
- unsigned char *valp;
- unsigned long offset = reloc_offset();
- static char pname[MAX_PROPERTY_NAME];
- int l;
-
- dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
-
- /* get the node's full name */
- namep = (char *)*mem_start;
- l = call_prom("package-to-path", 3, 1, node,
- namep, *mem_end - *mem_start);
- if (l >= 0) {
- /* Didn't fit? Get more room. */
- if ((l+1) > (*mem_end - *mem_start)) {
- namep = make_room(mem_start, mem_end, l+1, 1);
- call_prom("package-to-path", 3, 1, node, namep, l);
- }
- namep[l] = '\0';
-
- /* Fixup an Apple bug where they have bogus \0 chars in the
- * middle of the path in some properties
- */
- for (p = namep, ep = namep + l; p < ep; p++)
- if (*p == '\0') {
- memmove(p, p+1, ep - p);
- ep--; l--; p--;
- }
-
- /* now try to extract the unit name in that mess */
- for (p = namep, lp = NULL; *p; p++)
- if (*p == '/')
- lp = p + 1;
- if (lp != NULL)
- memmove(namep, lp, strlen(lp) + 1);
- *mem_start = _ALIGN(((unsigned long) namep) +
- strlen(namep) + 1, 4);
- }
-
- /* get it again for debugging */
- path = RELOC(prom_scratch);
- memset(path, 0, PROM_SCRATCH_SIZE);
- call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1);
-
- /* get and store all properties */
- prev_name = RELOC("");
- sstart = (char *)RELOC(dt_string_start);
- for (;;) {
- if (call_prom("nextprop", 3, 1, node, prev_name,
- RELOC(pname)) != 1)
- break;
-
- /* skip "name" */
- if (strcmp(RELOC(pname), RELOC("name")) == 0) {
- prev_name = RELOC("name");
- continue;
- }
-
- /* find string offset */
- soff = dt_find_string(RELOC(pname));
- if (soff == 0) {
- prom_printf("WARNING: Can't find string index for"
- " <%s>, node %s\n", RELOC(pname), path);
- break;
- }
- prev_name = sstart + soff;
-
- /* get length */
- l = call_prom("getproplen", 2, 1, node, RELOC(pname));
-
- /* sanity checks */
- if (l == PROM_ERROR)
- continue;
- if (l > MAX_PROPERTY_LENGTH) {
- prom_printf("WARNING: ignoring large property ");
- /* It seems OF doesn't null-terminate the path :-( */
- prom_printf("[%s] ", path);
- prom_printf("%s length 0x%x\n", RELOC(pname), l);
- continue;
- }
-
- /* push property head */
- dt_push_token(OF_DT_PROP, mem_start, mem_end);
- dt_push_token(l, mem_start, mem_end);
- dt_push_token(soff, mem_start, mem_end);
-
- /* push property content */
- valp = make_room(mem_start, mem_end, l, 4);
- call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
- *mem_start = _ALIGN(*mem_start, 4);
- }
-
- /* Add a "linux,phandle" property. */
- soff = dt_find_string(RELOC("linux,phandle"));
- if (soff == 0)
- prom_printf("WARNING: Can't find string index for"
- " <linux-phandle> node %s\n", path);
- else {
- dt_push_token(OF_DT_PROP, mem_start, mem_end);
- dt_push_token(4, mem_start, mem_end);
- dt_push_token(soff, mem_start, mem_end);
- valp = make_room(mem_start, mem_end, 4, 4);
- *(u32 *)valp = node;
- }
-
- /* do all our children */
- child = call_prom("child", 1, 1, node);
- while (child != 0) {
- scan_dt_build_struct(child, mem_start, mem_end);
- child = call_prom("peer", 1, 1, child);
- }
-
- dt_push_token(OF_DT_END_NODE, mem_start, mem_end);
-}
-
-static void __init flatten_device_tree(void)
-{
- phandle root;
- unsigned long offset = reloc_offset();
- unsigned long mem_start, mem_end, room;
- struct boot_param_header *hdr;
- struct prom_t *_prom = PTRRELOC(&prom);
- char *namep;
- u64 *rsvmap;
-
- /*
- * Check how much room we have between alloc top & bottom (+/- a
- * few pages), crop to 4Mb, as this is our "chuck" size
- */
- room = RELOC(alloc_top) - RELOC(alloc_bottom) - 0x4000;
- if (room > DEVTREE_CHUNK_SIZE)
- room = DEVTREE_CHUNK_SIZE;
- prom_debug("starting device tree allocs at %x\n", RELOC(alloc_bottom));
-
- /* Now try to claim that */
- mem_start = (unsigned long)alloc_up(room, PAGE_SIZE);
- if (mem_start == 0)
- prom_panic("Can't allocate initial device-tree chunk\n");
- mem_end = RELOC(alloc_top);
-
- /* Get root of tree */
- root = call_prom("peer", 1, 1, (phandle)0);
- if (root == (phandle)0)
- prom_panic ("couldn't get device tree root\n");
-
- /* Build header and make room for mem rsv map */
- mem_start = _ALIGN(mem_start, 4);
- hdr = make_room(&mem_start, &mem_end,
- sizeof(struct boot_param_header), 4);
- RELOC(dt_header_start) = (unsigned long)hdr;
- rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8);
-
- /* Start of strings */
- mem_start = PAGE_ALIGN(mem_start);
- RELOC(dt_string_start) = mem_start;
- mem_start += 4; /* hole */
-
- /* Add "linux,phandle" in there, we'll need it */
- namep = make_room(&mem_start, &mem_end, 16, 1);
- strcpy(namep, RELOC("linux,phandle"));
- mem_start = (unsigned long)namep + strlen(namep) + 1;
-
- /* Build string array */
- prom_printf("Building dt strings...\n");
- scan_dt_build_strings(root, &mem_start, &mem_end);
- RELOC(dt_string_end) = mem_start;
-
- /* Build structure */
- mem_start = PAGE_ALIGN(mem_start);
- RELOC(dt_struct_start) = mem_start;
- prom_printf("Building dt structure...\n");
- scan_dt_build_struct(root, &mem_start, &mem_end);
- dt_push_token(OF_DT_END, &mem_start, &mem_end);
- RELOC(dt_struct_end) = PAGE_ALIGN(mem_start);
-
- /* Finish header */
- hdr->boot_cpuid_phys = _prom->cpu;
- hdr->magic = OF_DT_HEADER;
- hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start);
- hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start);
- hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start);
- hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start);
- hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start);
- hdr->version = OF_DT_VERSION;
- /* Version 16 is not backward compatible */
- hdr->last_comp_version = 0x10;
-
- /* Reserve the whole thing and copy the reserve map in, we
- * also bump mem_reserve_cnt to cause further reservations to
- * fail since it's too late.
- */
- reserve_mem(RELOC(dt_header_start), hdr->totalsize);
- memcpy(rsvmap, RELOC(mem_reserve_map), sizeof(mem_reserve_map));
-
-#ifdef DEBUG_PROM
- {
- int i;
- prom_printf("reserved memory map:\n");
- for (i = 0; i < RELOC(mem_reserve_cnt); i++)
- prom_printf(" %x - %x\n", RELOC(mem_reserve_map)[i].base,
- RELOC(mem_reserve_map)[i].size);
- }
-#endif
- RELOC(mem_reserve_cnt) = MEM_RESERVE_MAP_SIZE;
-
- prom_printf("Device tree strings 0x%x -> 0x%x\n",
- RELOC(dt_string_start), RELOC(dt_string_end));
- prom_printf("Device tree struct 0x%x -> 0x%x\n",
- RELOC(dt_struct_start), RELOC(dt_struct_end));
-
-}
-
-
-static void __init fixup_device_tree(void)
-{
- unsigned long offset = reloc_offset();
- phandle u3, i2c, mpic;
- u32 u3_rev;
- u32 interrupts[2];
- u32 parent;
-
- /* Some G5s have a missing interrupt definition, fix it up here */
- u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000"));
- if (!PHANDLE_VALID(u3))
- return;
- i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000"));
- if (!PHANDLE_VALID(i2c))
- return;
- mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000"));
- if (!PHANDLE_VALID(mpic))
- return;
-
- /* check if proper rev of u3 */
- if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
- == PROM_ERROR)
- return;
- if (u3_rev < 0x35 || u3_rev > 0x39)
- return;
- /* does it need fixup ? */
- if (prom_getproplen(i2c, "interrupts") > 0)
- return;
-
- prom_printf("fixing up bogus interrupts for u3 i2c...\n");
-
- /* interrupt on this revision of u3 is number 0 and level */
- interrupts[0] = 0;
- interrupts[1] = 1;
- prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts));
- parent = (u32)mpic;
- prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent));
-}
-
-
-static void __init prom_find_boot_cpu(void)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- u32 getprop_rval;
- ihandle prom_cpu;
- phandle cpu_pkg;
-
- if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0)
- prom_panic("cannot find boot cpu");
-
- cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
-
- prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval));
- _prom->cpu = getprop_rval;
-
- prom_debug("Booting CPU hw index = 0x%x\n", _prom->cpu);
-}
-
-static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
-{
-#ifdef CONFIG_BLK_DEV_INITRD
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
-
- if ( r3 && r4 && r4 != 0xdeadbeef) {
- u64 val;
-
- RELOC(prom_initrd_start) = (r3 >= KERNELBASE) ? __pa(r3) : r3;
- RELOC(prom_initrd_end) = RELOC(prom_initrd_start) + r4;
-
- val = (u64)RELOC(prom_initrd_start);
- prom_setprop(_prom->chosen, "linux,initrd-start", &val, sizeof(val));
- val = (u64)RELOC(prom_initrd_end);
- prom_setprop(_prom->chosen, "linux,initrd-end", &val, sizeof(val));
-
- reserve_mem(RELOC(prom_initrd_start),
- RELOC(prom_initrd_end) - RELOC(prom_initrd_start));
-
- prom_debug("initrd_start=0x%x\n", RELOC(prom_initrd_start));
- prom_debug("initrd_end=0x%x\n", RELOC(prom_initrd_end));
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
-}
-
-/*
- * We enter here early on, when the Open Firmware prom is still
- * handling exceptions and the MMU hash table for us.
- */
-
-unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long pp,
- unsigned long r6, unsigned long r7)
-{
- unsigned long offset = reloc_offset();
- struct prom_t *_prom = PTRRELOC(&prom);
- unsigned long phys = KERNELBASE - offset;
- u32 getprop_rval;
-
- /*
- * First zero the BSS
- */
- memset(PTRRELOC(&__bss_start), 0, __bss_stop - __bss_start);
-
- /*
- * Init interface to Open Firmware, get some node references,
- * like /chosen
- */
- prom_init_client_services(pp);
-
- /*
- * Init prom stdout device
- */
- prom_init_stdout();
- prom_debug("klimit=0x%x\n", RELOC(klimit));
- prom_debug("offset=0x%x\n", offset);
-
- /*
- * Check for an initrd
- */
- prom_check_initrd(r3, r4);
-
- /*
- * Get default machine type. At this point, we do not differenciate
- * between pSeries SMP and pSeries LPAR
- */
- RELOC(of_platform) = prom_find_machine_type();
- getprop_rval = RELOC(of_platform);
- prom_setprop(_prom->chosen, "linux,platform",
- &getprop_rval, sizeof(getprop_rval));
-
- /*
- * On pSeries, inform the firmware about our capabilities
- */
- if (RELOC(of_platform) == PLATFORM_PSERIES ||
- RELOC(of_platform) == PLATFORM_PSERIES_LPAR)
- prom_send_capabilities();
-
- /*
- * On pSeries and Cell, copy the CPU hold code
- */
- if (RELOC(of_platform) & (PLATFORM_PSERIES | PLATFORM_CELL))
- copy_and_flush(0, KERNELBASE - offset, 0x100, 0);
-
- /*
- * Get memory cells format
- */
- getprop_rval = 1;
- prom_getprop(_prom->root, "#size-cells",
- &getprop_rval, sizeof(getprop_rval));
- _prom->root_size_cells = getprop_rval;
- getprop_rval = 2;
- prom_getprop(_prom->root, "#address-cells",
- &getprop_rval, sizeof(getprop_rval));
- _prom->root_addr_cells = getprop_rval;
-
- /*
- * Do early parsing of command line
- */
- early_cmdline_parse();
-
- /*
- * Initialize memory management within prom_init
- */
- prom_init_mem();
-
- /*
- * Determine which cpu is actually running right _now_
- */
- prom_find_boot_cpu();
-
- /*
- * Initialize display devices
- */
- prom_check_displays();
-
- /*
- * Initialize IOMMU (TCE tables) on pSeries. Do that before anything else
- * that uses the allocator, we need to make sure we get the top of memory
- * available for us here...
- */
- if (RELOC(of_platform) == PLATFORM_PSERIES)
- prom_initialize_tce_table();
-
- /*
- * On non-powermacs, try to instantiate RTAS and puts all CPUs
- * in spin-loops. PowerMacs don't have a working RTAS and use
- * a different way to spin CPUs
- */
- if (RELOC(of_platform) != PLATFORM_POWERMAC) {
- prom_instantiate_rtas();
- prom_hold_cpus();
- }
-
- /*
- * Fill in some infos for use by the kernel later on
- */
- if (RELOC(ppc64_iommu_off))
- prom_setprop(_prom->chosen, "linux,iommu-off", NULL, 0);
-
- if (RELOC(iommu_force_on))
- prom_setprop(_prom->chosen, "linux,iommu-force-on", NULL, 0);
-
- if (RELOC(prom_memory_limit))
- prom_setprop(_prom->chosen, "linux,memory-limit",
- PTRRELOC(&prom_memory_limit), sizeof(RELOC(prom_memory_limit)));
-
- if (RELOC(prom_tce_alloc_start)) {
- prom_setprop(_prom->chosen, "linux,tce-alloc-start",
- PTRRELOC(&prom_tce_alloc_start), sizeof(RELOC(prom_tce_alloc_start)));
- prom_setprop(_prom->chosen, "linux,tce-alloc-end",
- PTRRELOC(&prom_tce_alloc_end), sizeof(RELOC(prom_tce_alloc_end)));
- }
-
- /*
- * Fixup any known bugs in the device-tree
- */
- fixup_device_tree();
-
- /*
- * Now finally create the flattened device-tree
- */
- prom_printf("copying OF device tree ...\n");
- flatten_device_tree();
-
- /* in case stdin is USB and still active on IBM machines... */
- prom_close_stdin();
-
- /*
- * Call OF "quiesce" method to shut down pending DMA's from
- * devices etc...
- */
- prom_printf("Calling quiesce ...\n");
- call_prom("quiesce", 0, 0);
-
- /*
- * And finally, call the kernel passing it the flattened device
- * tree and NULL as r5, thus triggering the new entry point which
- * is common to us and kexec
- */
- prom_printf("returning from prom_init\n");
- prom_debug("->dt_header_start=0x%x\n", RELOC(dt_header_start));
- prom_debug("->phys=0x%x\n", phys);
-
- __start(RELOC(dt_header_start), phys, 0);
-
- return 0;
-}
-
diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c
deleted file mode 100644
index 79e7ed2858d..00000000000
--- a/arch/ppc64/kernel/rtc.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Real Time Clock interface for PPC64.
- *
- * Based on rtc.c by Paul Gortmaker
- *
- * This driver allows use of the real time clock
- * from user space. It exports the /dev/rtc
- * interface supporting various ioctl() and also the
- * /proc/driver/rtc pseudo-file for status information.
- *
- * Interface does not support RTC interrupts nor an alarm.
- *
- * This program is free software; you can redistribute 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.
- *
- * 1.0 Mike Corrigan: IBM iSeries rtc support
- * 1.1 Dave Engebretsen: IBM pSeries rtc support
- */
-
-#define RTC_VERSION "1.1"
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/ioport.h>
-#include <linux/fcntl.h>
-#include <linux/mc146818rtc.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/bcd.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/time.h>
-#include <asm/rtas.h>
-
-#include <asm/machdep.h>
-
-/*
- * We sponge a minor off of the misc major. No need slurping
- * up another valuable major dev number for this. If you add
- * an ioctl, make sure you don't conflict with SPARC's RTC
- * ioctls.
- */
-
-static ssize_t rtc_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos);
-
-static int rtc_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-
-static int rtc_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-
-/*
- * If this driver ever becomes modularised, it will be really nice
- * to make the epoch retain its value across module reload...
- */
-
-static unsigned long epoch = 1900; /* year corresponding to 0x00 */
-
-static const unsigned char days_in_mo[] =
-{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
-/*
- * Now all the various file operations that we export.
- */
-
-static ssize_t rtc_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- return -EIO;
-}
-
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct rtc_time wtime;
-
- switch (cmd) {
- case RTC_RD_TIME: /* Read the time/date from RTC */
- {
- memset(&wtime, 0, sizeof(struct rtc_time));
- ppc_md.get_rtc_time(&wtime);
- break;
- }
- case RTC_SET_TIME: /* Set the RTC */
- {
- struct rtc_time rtc_tm;
- unsigned char mon, day, hrs, min, sec, leap_yr;
- unsigned int yrs;
-
- if (!capable(CAP_SYS_TIME))
- return -EACCES;
-
- if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg,
- sizeof(struct rtc_time)))
- return -EFAULT;
-
- yrs = rtc_tm.tm_year;
- mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
- day = rtc_tm.tm_mday;
- hrs = rtc_tm.tm_hour;
- min = rtc_tm.tm_min;
- sec = rtc_tm.tm_sec;
-
- if (yrs < 70)
- return -EINVAL;
-
- leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
-
- if ((mon > 12) || (day == 0))
- return -EINVAL;
-
- if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
- return -EINVAL;
-
- if ((hrs >= 24) || (min >= 60) || (sec >= 60))
- return -EINVAL;
-
- if ( yrs > 169 )
- return -EINVAL;
-
- ppc_md.set_rtc_time(&rtc_tm);
-
- return 0;
- }
- case RTC_EPOCH_READ: /* Read the epoch. */
- {
- return put_user (epoch, (unsigned long __user *)arg);
- }
- case RTC_EPOCH_SET: /* Set the epoch. */
- {
- /*
- * There were no RTC clocks before 1900.
- */
- if (arg < 1900)
- return -EINVAL;
-
- if (!capable(CAP_SYS_TIME))
- return -EACCES;
-
- epoch = arg;
- return 0;
- }
- default:
- return -EINVAL;
- }
- return copy_to_user((void __user *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
-}
-
-static int rtc_open(struct inode *inode, struct file *file)
-{
- nonseekable_open(inode, file);
- return 0;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-/*
- * The various file operations we support.
- */
-static struct file_operations rtc_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = rtc_read,
- .ioctl = rtc_ioctl,
- .open = rtc_open,
- .release = rtc_release,
-};
-
-static struct miscdevice rtc_dev = {
- .minor = RTC_MINOR,
- .name = "rtc",
- .fops = &rtc_fops
-};
-
-static int __init rtc_init(void)
-{
- int retval;
-
- retval = misc_register(&rtc_dev);
- if(retval < 0)
- return retval;
-
-#ifdef CONFIG_PROC_FS
- if (create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL)
- == NULL) {
- misc_deregister(&rtc_dev);
- return -ENOMEM;
- }
-#endif
-
- printk(KERN_INFO "i/pSeries Real Time Clock Driver v" RTC_VERSION "\n");
-
- return 0;
-}
-
-static void __exit rtc_exit (void)
-{
- remove_proc_entry ("driver/rtc", NULL);
- misc_deregister(&rtc_dev);
-}
-
-module_init(rtc_init);
-module_exit(rtc_exit);
-
-/*
- * Info exported via "/proc/driver/rtc".
- */
-
-static int rtc_proc_output (char *buf)
-{
-
- char *p;
- struct rtc_time tm;
-
- p = buf;
-
- ppc_md.get_rtc_time(&tm);
-
- /*
- * There is no way to tell if the luser has the RTC set for local
- * time or for Universal Standard Time (GMT). Probably local though.
- */
- p += sprintf(p,
- "rtc_time\t: %02d:%02d:%02d\n"
- "rtc_date\t: %04d-%02d-%02d\n"
- "rtc_epoch\t: %04lu\n",
- tm.tm_hour, tm.tm_min, tm.tm_sec,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
-
- p += sprintf(p,
- "DST_enable\t: no\n"
- "BCD\t\t: yes\n"
- "24hr\t\t: yes\n" );
-
- return p - buf;
-}
-
-static int rtc_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = rtc_proc_output (page);
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
-}
-
-#ifdef CONFIG_PPC_RTAS
-#define MAX_RTC_WAIT 5000 /* 5 sec */
-#define RTAS_CLOCK_BUSY (-2)
-unsigned long rtas_get_boot_time(void)
-{
- int ret[8];
- int error, wait_time;
- unsigned long max_wait_tb;
-
- max_wait_tb = __get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
- do {
- error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
- if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
- wait_time = rtas_extended_busy_delay_time(error);
- /* This is boot time so we spin. */
- udelay(wait_time*1000);
- error = RTAS_CLOCK_BUSY;
- }
- } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
-
- if (error != 0 && printk_ratelimit()) {
- printk(KERN_WARNING "error: reading the clock failed (%d)\n",
- error);
- return 0;
- }
-
- return mktime(ret[0], ret[1], ret[2], ret[3], ret[4], ret[5]);
-}
-
-/* NOTE: get_rtc_time will get an error if executed in interrupt context
- * and if a delay is needed to read the clock. In this case we just
- * silently return without updating rtc_tm.
- */
-void rtas_get_rtc_time(struct rtc_time *rtc_tm)
-{
- int ret[8];
- int error, wait_time;
- unsigned long max_wait_tb;
-
- max_wait_tb = __get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
- do {
- error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
- if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
- if (in_interrupt() && printk_ratelimit()) {
- printk(KERN_WARNING "error: reading clock would delay interrupt\n");
- return; /* delay not allowed */
- }
- wait_time = rtas_extended_busy_delay_time(error);
- msleep_interruptible(wait_time);
- error = RTAS_CLOCK_BUSY;
- }
- } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
-
- if (error != 0 && printk_ratelimit()) {
- printk(KERN_WARNING "error: reading the clock failed (%d)\n",
- error);
- return;
- }
-
- rtc_tm->tm_sec = ret[5];
- rtc_tm->tm_min = ret[4];
- rtc_tm->tm_hour = ret[3];
- rtc_tm->tm_mday = ret[2];
- rtc_tm->tm_mon = ret[1] - 1;
- rtc_tm->tm_year = ret[0] - 1900;
-}
-
-int rtas_set_rtc_time(struct rtc_time *tm)
-{
- int error, wait_time;
- unsigned long max_wait_tb;
-
- max_wait_tb = __get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
- do {
- error = rtas_call(rtas_token("set-time-of-day"), 7, 1, NULL,
- tm->tm_year + 1900, tm->tm_mon + 1,
- tm->tm_mday, tm->tm_hour, tm->tm_min,
- tm->tm_sec, 0);
- if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) {
- if (in_interrupt())
- return 1; /* probably decrementer */
- wait_time = rtas_extended_busy_delay_time(error);
- msleep_interruptible(wait_time);
- error = RTAS_CLOCK_BUSY;
- }
- } while (error == RTAS_CLOCK_BUSY && (__get_tb() < max_wait_tb));
-
- if (error != 0 && printk_ratelimit())
- printk(KERN_WARNING "error: setting the clock failed (%d)\n",
- error);
-
- return 0;
-}
-#endif
diff --git a/arch/ppc64/kernel/semaphore.c b/arch/ppc64/kernel/semaphore.c
deleted file mode 100644
index a1c1db573e9..00000000000
--- a/arch/ppc64/kernel/semaphore.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- *
- *
- * PowerPC-specific semaphore code.
- *
- * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
- *
- * This program is free software; you can redistribute 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.
- *
- * April 2001 - Reworked by Paul Mackerras <paulus@samba.org>
- * to eliminate the SMP races in the old version between the updates
- * of `count' and `waking'. Now we use negative `count' values to
- * indicate that some process(es) are waiting for the semaphore.
- */
-
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/atomic.h>
-#include <asm/semaphore.h>
-#include <asm/errno.h>
-
-/*
- * Atomically update sem->count.
- * This does the equivalent of the following:
- *
- * old_count = sem->count;
- * tmp = MAX(old_count, 0) + incr;
- * sem->count = tmp;
- * return old_count;
- */
-static inline int __sem_update_count(struct semaphore *sem, int incr)
-{
- int old_count, tmp;
-
- __asm__ __volatile__("\n"
-"1: lwarx %0,0,%3\n"
-" srawi %1,%0,31\n"
-" andc %1,%0,%1\n"
-" add %1,%1,%4\n"
-" stwcx. %1,0,%3\n"
-" bne 1b"
- : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
- : "r" (&sem->count), "r" (incr), "m" (sem->count)
- : "cc");
-
- return old_count;
-}
-
-void __up(struct semaphore *sem)
-{
- /*
- * Note that we incremented count in up() before we came here,
- * but that was ineffective since the result was <= 0, and
- * any negative value of count is equivalent to 0.
- * This ends up setting count to 1, unless count is now > 0
- * (i.e. because some other cpu has called up() in the meantime),
- * in which case we just increment count.
- */
- __sem_update_count(sem, 1);
- wake_up(&sem->wait);
-}
-EXPORT_SYMBOL(__up);
-
-/*
- * Note that when we come in to __down or __down_interruptible,
- * we have already decremented count, but that decrement was
- * ineffective since the result was < 0, and any negative value
- * of count is equivalent to 0.
- * Thus it is only when we decrement count from some value > 0
- * that we have actually got the semaphore.
- */
-void __sched __down(struct semaphore *sem)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- __set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- /*
- * Try to get the semaphore. If the count is > 0, then we've
- * got the semaphore; we decrement count and exit the loop.
- * If the count is 0 or negative, we set it to -1, indicating
- * that we are asleep, and then sleep.
- */
- while (__sem_update_count(sem, -1) <= 0) {
- schedule();
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- }
- remove_wait_queue(&sem->wait, &wait);
- __set_task_state(tsk, TASK_RUNNING);
-
- /*
- * If there are any more sleepers, wake one of them up so
- * that it can either get the semaphore, or set count to -1
- * indicating that there are still processes sleeping.
- */
- wake_up(&sem->wait);
-}
-EXPORT_SYMBOL(__down);
-
-int __sched __down_interruptible(struct semaphore * sem)
-{
- int retval = 0;
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- __set_task_state(tsk, TASK_INTERRUPTIBLE);
- add_wait_queue_exclusive(&sem->wait, &wait);
-
- while (__sem_update_count(sem, -1) <= 0) {
- if (signal_pending(current)) {
- /*
- * A signal is pending - give up trying.
- * Set sem->count to 0 if it is negative,
- * since we are no longer sleeping.
- */
- __sem_update_count(sem, 0);
- retval = -EINTR;
- break;
- }
- schedule();
- set_task_state(tsk, TASK_INTERRUPTIBLE);
- }
- remove_wait_queue(&sem->wait, &wait);
- __set_task_state(tsk, TASK_RUNNING);
-
- wake_up(&sem->wait);
- return retval;
-}
-EXPORT_SYMBOL(__down_interruptible);
diff --git a/arch/ppc64/kernel/vdso.c b/arch/ppc64/kernel/vdso.c
deleted file mode 100644
index 1bbacac4498..00000000000
--- a/arch/ppc64/kernel/vdso.c
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * linux/arch/ppc64/kernel/vdso.c
- *
- * Copyright (C) 2004 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/config.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/elf.h>
-#include <linux/security.h>
-#include <linux/bootmem.h>
-
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/mmu.h>
-#include <asm/mmu_context.h>
-#include <asm/machdep.h>
-#include <asm/cputable.h>
-#include <asm/sections.h>
-#include <asm/systemcfg.h>
-#include <asm/vdso.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(fmt...) printk(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-
-/*
- * The vDSOs themselves are here
- */
-extern char vdso64_start, vdso64_end;
-extern char vdso32_start, vdso32_end;
-
-static void *vdso64_kbase = &vdso64_start;
-static void *vdso32_kbase = &vdso32_start;
-
-unsigned int vdso64_pages;
-unsigned int vdso32_pages;
-
-/* Signal trampolines user addresses */
-
-unsigned long vdso64_rt_sigtramp;
-unsigned long vdso32_sigtramp;
-unsigned long vdso32_rt_sigtramp;
-
-/* Format of the patch table */
-struct vdso_patch_def
-{
- u32 pvr_mask, pvr_value;
- const char *gen_name;
- const char *fix_name;
-};
-
-/* Table of functions to patch based on the CPU type/revision
- *
- * TODO: Improve by adding whole lists for each entry
- */
-static struct vdso_patch_def vdso_patches[] = {
- {
- 0xffff0000, 0x003a0000, /* POWER5 */
- "__kernel_sync_dicache", "__kernel_sync_dicache_p5"
- },
- {
- 0xffff0000, 0x003b0000, /* POWER5 */
- "__kernel_sync_dicache", "__kernel_sync_dicache_p5"
- },
-};
-
-/*
- * Some infos carried around for each of them during parsing at
- * boot time.
- */
-struct lib32_elfinfo
-{
- Elf32_Ehdr *hdr; /* ptr to ELF */
- Elf32_Sym *dynsym; /* ptr to .dynsym section */
- unsigned long dynsymsize; /* size of .dynsym section */
- char *dynstr; /* ptr to .dynstr section */
- unsigned long text; /* offset of .text section in .so */
-};
-
-struct lib64_elfinfo
-{
- Elf64_Ehdr *hdr;
- Elf64_Sym *dynsym;
- unsigned long dynsymsize;
- char *dynstr;
- unsigned long text;
-};
-
-
-#ifdef __DEBUG
-static void dump_one_vdso_page(struct page *pg, struct page *upg)
-{
- printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT),
- page_count(pg),
- pg->flags);
- if (upg/* && pg != upg*/) {
- printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg) << PAGE_SHIFT),
- page_count(upg),
- upg->flags);
- }
- printk("\n");
-}
-
-static void dump_vdso_pages(struct vm_area_struct * vma)
-{
- int i;
-
- if (!vma || test_thread_flag(TIF_32BIT)) {
- printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase);
- for (i=0; i<vdso32_pages; i++) {
- struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
- struct page *upg = (vma && vma->vm_mm) ?
- follow_page(vma->vm_mm, vma->vm_start + i*PAGE_SIZE, 0)
- : NULL;
- dump_one_vdso_page(pg, upg);
- }
- }
- if (!vma || !test_thread_flag(TIF_32BIT)) {
- printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase);
- for (i=0; i<vdso64_pages; i++) {
- struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
- struct page *upg = (vma && vma->vm_mm) ?
- follow_page(vma->vm_mm, vma->vm_start + i*PAGE_SIZE, 0)
- : NULL;
- dump_one_vdso_page(pg, upg);
- }
- }
-}
-#endif /* DEBUG */
-
-/*
- * Keep a dummy vma_close for now, it will prevent VMA merging.
- */
-static void vdso_vma_close(struct vm_area_struct * vma)
-{
-}
-
-/*
- * Our nopage() function, maps in the actual vDSO kernel pages, they will
- * be mapped read-only by do_no_page(), and eventually COW'ed, either
- * right away for an initial write access, or by do_wp_page().
- */
-static struct page * vdso_vma_nopage(struct vm_area_struct * vma,
- unsigned long address, int *type)
-{
- unsigned long offset = address - vma->vm_start;
- struct page *pg;
- void *vbase = test_thread_flag(TIF_32BIT) ? vdso32_kbase : vdso64_kbase;
-
- DBG("vdso_vma_nopage(current: %s, address: %016lx, off: %lx)\n",
- current->comm, address, offset);
-
- if (address < vma->vm_start || address > vma->vm_end)
- return NOPAGE_SIGBUS;
-
- /*
- * Last page is systemcfg.
- */
- if ((vma->vm_end - address) <= PAGE_SIZE)
- pg = virt_to_page(_systemcfg);
- else
- pg = virt_to_page(vbase + offset);
-
- get_page(pg);
- DBG(" ->page count: %d\n", page_count(pg));
-
- return pg;
-}
-
-static struct vm_operations_struct vdso_vmops = {
- .close = vdso_vma_close,
- .nopage = vdso_vma_nopage,
-};
-
-/*
- * This is called from binfmt_elf, we create the special vma for the
- * vDSO and insert it into the mm struct tree
- */
-int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack)
-{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
- unsigned long vdso_pages;
- unsigned long vdso_base;
-
- if (test_thread_flag(TIF_32BIT)) {
- vdso_pages = vdso32_pages;
- vdso_base = VDSO32_MBASE;
- } else {
- vdso_pages = vdso64_pages;
- vdso_base = VDSO64_MBASE;
- }
-
- current->thread.vdso_base = 0;
-
- /* vDSO has a problem and was disabled, just don't "enable" it for the
- * process
- */
- if (vdso_pages == 0)
- return 0;
-
- vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
- if (vma == NULL)
- return -ENOMEM;
-
- memset(vma, 0, sizeof(*vma));
-
- /*
- * pick a base address for the vDSO in process space. We try to put it
- * at vdso_base which is the "natural" base for it, but we might fail
- * and end up putting it elsewhere.
- */
- vdso_base = get_unmapped_area(NULL, vdso_base,
- vdso_pages << PAGE_SHIFT, 0, 0);
- if (vdso_base & ~PAGE_MASK) {
- kmem_cache_free(vm_area_cachep, vma);
- return (int)vdso_base;
- }
-
- current->thread.vdso_base = vdso_base;
-
- vma->vm_mm = mm;
- vma->vm_start = current->thread.vdso_base;
-
- /*
- * the VMA size is one page more than the vDSO since systemcfg
- * is mapped in the last one
- */
- vma->vm_end = vma->vm_start + ((vdso_pages + 1) << PAGE_SHIFT);
-
- /*
- * our vma flags don't have VM_WRITE so by default, the process isn't allowed
- * to write those pages.
- * gdb can break that with ptrace interface, and thus trigger COW on those
- * pages but it's then your responsibility to never do that on the "data" page
- * of the vDSO or you'll stop getting kernel updates and your nice userland
- * gettimeofday will be totally dead. It's fine to use that for setting
- * breakpoints in the vDSO code pages though
- */
- vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC | VM_RESERVED;
- vma->vm_flags |= mm->def_flags;
- vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
- vma->vm_ops = &vdso_vmops;
-
- down_write(&mm->mmap_sem);
- if (insert_vm_struct(mm, vma)) {
- up_write(&mm->mmap_sem);
- kmem_cache_free(vm_area_cachep, vma);
- return -ENOMEM;
- }
- mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
- up_write(&mm->mmap_sem);
-
- return 0;
-}
-
-static void * __init find_section32(Elf32_Ehdr *ehdr, const char *secname,
- unsigned long *size)
-{
- Elf32_Shdr *sechdrs;
- unsigned int i;
- char *secnames;
-
- /* Grab section headers and strings so we can tell who is who */
- sechdrs = (void *)ehdr + ehdr->e_shoff;
- secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
-
- /* Find the section they want */
- for (i = 1; i < ehdr->e_shnum; i++) {
- if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) {
- if (size)
- *size = sechdrs[i].sh_size;
- return (void *)ehdr + sechdrs[i].sh_offset;
- }
- }
- *size = 0;
- return NULL;
-}
-
-static void * __init find_section64(Elf64_Ehdr *ehdr, const char *secname,
- unsigned long *size)
-{
- Elf64_Shdr *sechdrs;
- unsigned int i;
- char *secnames;
-
- /* Grab section headers and strings so we can tell who is who */
- sechdrs = (void *)ehdr + ehdr->e_shoff;
- secnames = (void *)ehdr + sechdrs[ehdr->e_shstrndx].sh_offset;
-
- /* Find the section they want */
- for (i = 1; i < ehdr->e_shnum; i++) {
- if (strcmp(secnames+sechdrs[i].sh_name, secname) == 0) {
- if (size)
- *size = sechdrs[i].sh_size;
- return (void *)ehdr + sechdrs[i].sh_offset;
- }
- }
- if (size)
- *size = 0;
- return NULL;
-}
-
-static Elf32_Sym * __init find_symbol32(struct lib32_elfinfo *lib, const char *symname)
-{
- unsigned int i;
- char name[32], *c;
-
- for (i = 0; i < (lib->dynsymsize / sizeof(Elf32_Sym)); i++) {
- if (lib->dynsym[i].st_name == 0)
- continue;
- strlcpy(name, lib->dynstr + lib->dynsym[i].st_name, 32);
- c = strchr(name, '@');
- if (c)
- *c = 0;
- if (strcmp(symname, name) == 0)
- return &lib->dynsym[i];
- }
- return NULL;
-}
-
-static Elf64_Sym * __init find_symbol64(struct lib64_elfinfo *lib, const char *symname)
-{
- unsigned int i;
- char name[32], *c;
-
- for (i = 0; i < (lib->dynsymsize / sizeof(Elf64_Sym)); i++) {
- if (lib->dynsym[i].st_name == 0)
- continue;
- strlcpy(name, lib->dynstr + lib->dynsym[i].st_name, 32);
- c = strchr(name, '@');
- if (c)
- *c = 0;
- if (strcmp(symname, name) == 0)
- return &lib->dynsym[i];
- }
- return NULL;
-}
-
-/* Note that we assume the section is .text and the symbol is relative to
- * the library base
- */
-static unsigned long __init find_function32(struct lib32_elfinfo *lib, const char *symname)
-{
- Elf32_Sym *sym = find_symbol32(lib, symname);
-
- if (sym == NULL) {
- printk(KERN_WARNING "vDSO32: function %s not found !\n", symname);
- return 0;
- }
- return sym->st_value - VDSO32_LBASE;
-}
-
-/* Note that we assume the section is .text and the symbol is relative to
- * the library base
- */
-static unsigned long __init find_function64(struct lib64_elfinfo *lib, const char *symname)
-{
- Elf64_Sym *sym = find_symbol64(lib, symname);
-
- if (sym == NULL) {
- printk(KERN_WARNING "vDSO64: function %s not found !\n", symname);
- return 0;
- }
-#ifdef VDS64_HAS_DESCRIPTORS
- return *((u64 *)(vdso64_kbase + sym->st_value - VDSO64_LBASE)) - VDSO64_LBASE;
-#else
- return sym->st_value - VDSO64_LBASE;
-#endif
-}
-
-
-static __init int vdso_do_find_sections(struct lib32_elfinfo *v32,
- struct lib64_elfinfo *v64)
-{
- void *sect;
-
- /*
- * Locate symbol tables & text section
- */
-
- v32->dynsym = find_section32(v32->hdr, ".dynsym", &v32->dynsymsize);
- v32->dynstr = find_section32(v32->hdr, ".dynstr", NULL);
- if (v32->dynsym == NULL || v32->dynstr == NULL) {
- printk(KERN_ERR "vDSO32: a required symbol section was not found\n");
- return -1;
- }
- sect = find_section32(v32->hdr, ".text", NULL);
- if (sect == NULL) {
- printk(KERN_ERR "vDSO32: the .text section was not found\n");
- return -1;
- }
- v32->text = sect - vdso32_kbase;
-
- v64->dynsym = find_section64(v64->hdr, ".dynsym", &v64->dynsymsize);
- v64->dynstr = find_section64(v64->hdr, ".dynstr", NULL);
- if (v64->dynsym == NULL || v64->dynstr == NULL) {
- printk(KERN_ERR "vDSO64: a required symbol section was not found\n");
- return -1;
- }
- sect = find_section64(v64->hdr, ".text", NULL);
- if (sect == NULL) {
- printk(KERN_ERR "vDSO64: the .text section was not found\n");
- return -1;
- }
- v64->text = sect - vdso64_kbase;
-
- return 0;
-}
-
-static __init void vdso_setup_trampolines(struct lib32_elfinfo *v32,
- struct lib64_elfinfo *v64)
-{
- /*
- * Find signal trampolines
- */
-
- vdso64_rt_sigtramp = find_function64(v64, "__kernel_sigtramp_rt64");
- vdso32_sigtramp = find_function32(v32, "__kernel_sigtramp32");
- vdso32_rt_sigtramp = find_function32(v32, "__kernel_sigtramp_rt32");
-}
-
-static __init int vdso_fixup_datapage(struct lib32_elfinfo *v32,
- struct lib64_elfinfo *v64)
-{
- Elf32_Sym *sym32;
- Elf64_Sym *sym64;
-
- sym32 = find_symbol32(v32, "__kernel_datapage_offset");
- if (sym32 == NULL) {
- printk(KERN_ERR "vDSO32: Can't find symbol __kernel_datapage_offset !\n");
- return -1;
- }
- *((int *)(vdso32_kbase + (sym32->st_value - VDSO32_LBASE))) =
- (vdso32_pages << PAGE_SHIFT) - (sym32->st_value - VDSO32_LBASE);
-
- sym64 = find_symbol64(v64, "__kernel_datapage_offset");
- if (sym64 == NULL) {
- printk(KERN_ERR "vDSO64: Can't find symbol __kernel_datapage_offset !\n");
- return -1;
- }
- *((int *)(vdso64_kbase + sym64->st_value - VDSO64_LBASE)) =
- (vdso64_pages << PAGE_SHIFT) - (sym64->st_value - VDSO64_LBASE);
-
- return 0;
-}
-
-static int vdso_do_func_patch32(struct lib32_elfinfo *v32,
- struct lib64_elfinfo *v64,
- const char *orig, const char *fix)
-{
- Elf32_Sym *sym32_gen, *sym32_fix;
-
- sym32_gen = find_symbol32(v32, orig);
- if (sym32_gen == NULL) {
- printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", orig);
- return -1;
- }
- sym32_fix = find_symbol32(v32, fix);
- if (sym32_fix == NULL) {
- printk(KERN_ERR "vDSO32: Can't find symbol %s !\n", fix);
- return -1;
- }
- sym32_gen->st_value = sym32_fix->st_value;
- sym32_gen->st_size = sym32_fix->st_size;
- sym32_gen->st_info = sym32_fix->st_info;
- sym32_gen->st_other = sym32_fix->st_other;
- sym32_gen->st_shndx = sym32_fix->st_shndx;
-
- return 0;
-}
-
-static int vdso_do_func_patch64(struct lib32_elfinfo *v32,
- struct lib64_elfinfo *v64,
- const char *orig, const char *fix)
-{
- Elf64_Sym *sym64_gen, *sym64_fix;
-
- sym64_gen = find_symbol64(v64, orig);
- if (sym64_gen == NULL) {
- printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", orig);
- return -1;
- }
- sym64_fix = find_symbol64(v64, fix);
- if (sym64_fix == NULL) {
- printk(KERN_ERR "vDSO64: Can't find symbol %s !\n", fix);
- return -1;
- }
- sym64_gen->st_value = sym64_fix->st_value;
- sym64_gen->st_size = sym64_fix->st_size;
- sym64_gen->st_info = sym64_fix->st_info;
- sym64_gen->st_other = sym64_fix->st_other;
- sym64_gen->st_shndx = sym64_fix->st_shndx;
-
- return 0;
-}
-
-static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32,
- struct lib64_elfinfo *v64)
-{
- u32 pvr;
- int i;
-
- pvr = mfspr(SPRN_PVR);
- for (i = 0; i < ARRAY_SIZE(vdso_patches); i++) {
- struct vdso_patch_def *patch = &vdso_patches[i];
- int match = (pvr & patch->pvr_mask) == patch->pvr_value;
-
- DBG("patch %d (mask: %x, pvr: %x) : %s\n",
- i, patch->pvr_mask, patch->pvr_value, match ? "match" : "skip");
-
- if (!match)
- continue;
-
- DBG("replacing %s with %s...\n", patch->gen_name, patch->fix_name);
-
- /*
- * Patch the 32 bits and 64 bits symbols. Note that we do not patch
- * the "." symbol on 64 bits. It would be easy to do, but doesn't
- * seem to be necessary, patching the OPD symbol is enough.
- */
- vdso_do_func_patch32(v32, v64, patch->gen_name, patch->fix_name);
- vdso_do_func_patch64(v32, v64, patch->gen_name, patch->fix_name);
- }
-
- return 0;
-}
-
-
-static __init int vdso_setup(void)
-{
- struct lib32_elfinfo v32;
- struct lib64_elfinfo v64;
-
- v32.hdr = vdso32_kbase;
- v64.hdr = vdso64_kbase;
-
- if (vdso_do_find_sections(&v32, &v64))
- return -1;
-
- if (vdso_fixup_datapage(&v32, &v64))
- return -1;
-
- if (vdso_fixup_alt_funcs(&v32, &v64))
- return -1;
-
- vdso_setup_trampolines(&v32, &v64);
-
- return 0;
-}
-
-void __init vdso_init(void)
-{
- int i;
-
- vdso64_pages = (&vdso64_end - &vdso64_start) >> PAGE_SHIFT;
- vdso32_pages = (&vdso32_end - &vdso32_start) >> PAGE_SHIFT;
-
- DBG("vdso64_kbase: %p, 0x%x pages, vdso32_kbase: %p, 0x%x pages\n",
- vdso64_kbase, vdso64_pages, vdso32_kbase, vdso32_pages);
-
- /*
- * Initialize the vDSO images in memory, that is do necessary
- * fixups of vDSO symbols, locate trampolines, etc...
- */
- if (vdso_setup()) {
- printk(KERN_ERR "vDSO setup failure, not enabled !\n");
- /* XXX should free pages here ? */
- vdso64_pages = vdso32_pages = 0;
- return;
- }
-
- /* Make sure pages are in the correct state */
- for (i = 0; i < vdso64_pages; i++) {
- struct page *pg = virt_to_page(vdso64_kbase + i*PAGE_SIZE);
- ClearPageReserved(pg);
- get_page(pg);
- }
- for (i = 0; i < vdso32_pages; i++) {
- struct page *pg = virt_to_page(vdso32_kbase + i*PAGE_SIZE);
- ClearPageReserved(pg);
- get_page(pg);
- }
-
- get_page(virt_to_page(_systemcfg));
-}
-
-int in_gate_area_no_task(unsigned long addr)
-{
- return 0;
-}
-
-int in_gate_area(struct task_struct *task, unsigned long addr)
-{
- return 0;
-}
-
-struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
-{
- return NULL;
-}
-
diff --git a/arch/ppc64/kernel/vmlinux.lds.S b/arch/ppc64/kernel/vmlinux.lds.S
deleted file mode 100644
index 022f220e772..00000000000
--- a/arch/ppc64/kernel/vmlinux.lds.S
+++ /dev/null
@@ -1,151 +0,0 @@
-#include <asm/page.h>
-#include <asm-generic/vmlinux.lds.h>
-
-OUTPUT_ARCH(powerpc:common64)
-jiffies = jiffies_64;
-SECTIONS
-{
- /* Sections to be discarded. */
- /DISCARD/ : {
- *(.exitcall.exit)
- }
-
-
- /* Read-only sections, merged into text segment: */
- .text : {
- *(.text .text.*)
- SCHED_TEXT
- LOCK_TEXT
- KPROBES_TEXT
- *(.fixup)
- . = ALIGN(PAGE_SIZE);
- _etext = .;
- }
-
- __ex_table : {
- __start___ex_table = .;
- *(__ex_table)
- __stop___ex_table = .;
- }
-
- __bug_table : {
- __start___bug_table = .;
- *(__bug_table)
- __stop___bug_table = .;
- }
-
- __ftr_fixup : {
- __start___ftr_fixup = .;
- *(__ftr_fixup)
- __stop___ftr_fixup = .;
- }
-
- RODATA
-
-
- /* will be freed after init */
- . = ALIGN(PAGE_SIZE);
- __init_begin = .;
-
- .init.text : {
- _sinittext = .;
- *(.init.text)
- _einittext = .;
- }
-
- .init.data : {
- *(.init.data)
- }
-
- . = ALIGN(16);
- .init.setup : {
- __setup_start = .;
- *(.init.setup)
- __setup_end = .;
- }
-
- .initcall.init : {
- __initcall_start = .;
- *(.initcall1.init)
- *(.initcall2.init)
- *(.initcall3.init)
- *(.initcall4.init)
- *(.initcall5.init)
- *(.initcall6.init)
- *(.initcall7.init)
- __initcall_end = .;
- }
-
- .con_initcall.init : {
- __con_initcall_start = .;
- *(.con_initcall.init)
- __con_initcall_end = .;
- }
-
- SECURITY_INIT
-
- . = ALIGN(PAGE_SIZE);
- .init.ramfs : {
- __initramfs_start = .;
- *(.init.ramfs)
- __initramfs_end = .;
- }
-
- .data.percpu : {
- __per_cpu_start = .;
- *(.data.percpu)
- __per_cpu_end = .;
- }
-
- . = ALIGN(PAGE_SIZE);
- . = ALIGN(16384);
- __init_end = .;
- /* freed after init ends here */
-
-
- /* Read/write sections */
- . = ALIGN(PAGE_SIZE);
- . = ALIGN(16384);
- _sdata = .;
- /* The initial task and kernel stack */
- .data.init_task : {
- *(.data.init_task)
- }
-
- . = ALIGN(PAGE_SIZE);
- .data.page_aligned : {
- *(.data.page_aligned)
- }
-
- .data.cacheline_aligned : {
- *(.data.cacheline_aligned)
- }
-
- .data : {
- *(.data .data.rel* .toc1)
- *(.branch_lt)
- }
-
- .opd : {
- *(.opd)
- }
-
- .got : {
- __toc_start = .;
- *(.got)
- *(.toc)
- . = ALIGN(PAGE_SIZE);
- _edata = .;
- }
-
-
- . = ALIGN(PAGE_SIZE);
- .bss : {
- __bss_start = .;
- *(.bss)
- __bss_stop = .;
- }
-
- . = ALIGN(PAGE_SIZE);
- _end = . ;
-}
diff --git a/arch/ppc64/xmon/privinst.h b/arch/ppc64/xmon/privinst.h
deleted file mode 100644
index 02eb40dac0b..00000000000
--- a/arch/ppc64/xmon/privinst.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 1996 Paul Mackerras.
- *
- * This program is free software; you can redistribute 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.
- */
-
-#define GETREG(reg) \
- static inline unsigned long get_ ## reg (void) \
- { unsigned long ret; asm volatile ("mf" #reg " %0" : "=r" (ret) :); return ret; }
-
-#define SETREG(reg) \
- static inline void set_ ## reg (unsigned long val) \
- { asm volatile ("mt" #reg " %0" : : "r" (val)); }
-
-GETREG(msr)
-SETREG(msrd)
-GETREG(cr)
-
-#define GSETSPR(n, name) \
- static inline long get_ ## name (void) \
- { long ret; asm volatile ("mfspr %0," #n : "=r" (ret) : ); return ret; } \
- static inline void set_ ## name (long val) \
- { asm volatile ("mtspr " #n ",%0" : : "r" (val)); }
-
-GSETSPR(0, mq)
-GSETSPR(1, xer)
-GSETSPR(4, rtcu)
-GSETSPR(5, rtcl)
-GSETSPR(8, lr)
-GSETSPR(9, ctr)
-GSETSPR(18, dsisr)
-GSETSPR(19, dar)
-GSETSPR(22, dec)
-GSETSPR(25, sdr1)
-GSETSPR(26, srr0)
-GSETSPR(27, srr1)
-GSETSPR(272, sprg0)
-GSETSPR(273, sprg1)
-GSETSPR(274, sprg2)
-GSETSPR(275, sprg3)
-GSETSPR(282, ear)
-GSETSPR(287, pvr)
-GSETSPR(1008, hid0)
-GSETSPR(1009, hid1)
-GSETSPR(1010, iabr)
-GSETSPR(1023, pir)
-
-static inline void store_inst(void *p)
-{
- asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
-}
-
-static inline void cflush(void *p)
-{
- asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
-}
-
-static inline void cinval(void *p)
-{
- asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
-}
diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c
index 2e64e8c3e8e..cb3cf0f2282 100644
--- a/arch/sparc/lib/atomic32.c
+++ b/arch/sparc/lib/atomic32.c
@@ -37,17 +37,43 @@ int __atomic_add_return(int i, atomic_t *v)
spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
return ret;
}
+EXPORT_SYMBOL(__atomic_add_return);
-void atomic_set(atomic_t *v, int i)
+int atomic_cmpxchg(atomic_t *v, int old, int new)
{
+ int ret;
unsigned long flags;
+
spin_lock_irqsave(ATOMIC_HASH(v), flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
- v->counter = i;
+ spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+ return ret;
+}
+
+int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int ret;
+ unsigned long flags;
+ spin_lock_irqsave(ATOMIC_HASH(v), flags);
+ ret = v->counter;
+ if (ret != u)
+ v->counter += a;
spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+ return ret != u;
}
-EXPORT_SYMBOL(__atomic_add_return);
-EXPORT_SYMBOL(atomic_set);
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+/* Atomic operations are already serializing */
+void atomic_set(atomic_t *v, int i)
+{
+ unsigned long flags;
+ spin_lock_irqsave(ATOMIC_HASH(v), flags);
+ v->counter = i;
+ spin_unlock_irqrestore(ATOMIC_HASH(v), flags);
+}
+EXPORT_SYMBOL(atomic_set);
diff --git a/arch/sparc/lib/bitext.c b/arch/sparc/lib/bitext.c
index 94b05e8c906..2e168d16547 100644
--- a/arch/sparc/lib/bitext.c
+++ b/arch/sparc/lib/bitext.c
@@ -10,6 +10,7 @@
*/
#include <linux/smp_lock.h>
+#include <linux/string.h>
#include <linux/bitops.h>
#include <asm/bitext.h>
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 3b5f47c4690..563301fe5df 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -7,7 +7,6 @@ config UML
bool
default y
-# XXX: does UM have a mmu/swap?
config MMU
bool
default y
@@ -36,12 +35,6 @@ config IRQ_RELEASE_METHOD
bool
default y
-menu "Host processor type and features"
-
-source "arch/i386/Kconfig.cpu"
-
-endmenu
-
menu "UML-specific options"
config MODE_TT
@@ -209,7 +202,8 @@ config MAGIC_SYSRQ
config SMP
bool "Symmetric multi-processing support (EXPERIMENTAL)"
default n
- depends on (MODE_TT && EXPERIMENTAL && !SMP_BROKEN) || (BROKEN && SMP_BROKEN)
+ #SMP_BROKEN is for x86_64.
+ depends on MODE_TT && EXPERIMENTAL && (!SMP_BROKEN || (BROKEN && SMP_BROKEN))
help
This option enables UML SMP support.
It is NOT related to having a real SMP box. Not directly, at least.
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
index 5d92cacd56c..c71b39a677a 100644
--- a/arch/um/Kconfig.i386
+++ b/arch/um/Kconfig.i386
@@ -1,3 +1,9 @@
+menu "Host processor type and features"
+
+source "arch/i386/Kconfig.cpu"
+
+endmenu
+
config UML_X86
bool
default y
@@ -42,7 +48,3 @@ config ARCH_HAS_SC_SIGNALS
config ARCH_REUSE_HOST_VSYSCALL_AREA
bool
default y
-
-config X86_CMPXCHG
- bool
- default y
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index 1f7dcb064ae..7a0e04e34bf 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -35,4 +35,3 @@ cflags-y += $(call cc-option,-mpreferred-stack-boundary=2)
CFLAGS += $(cflags-y)
USER_CFLAGS += $(cflags-y)
-
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 16e7dc89f61..5b58fad4529 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -89,8 +89,7 @@ static int not_configged_write(int fd, const char *buf, int len, void *data)
return(-EIO);
}
-static int not_configged_console_write(int fd, const char *buf, int len,
- void *data)
+static int not_configged_console_write(int fd, const char *buf, int len)
{
my_puts("Using a channel type which is configured out of "
"UML\n");
@@ -299,7 +298,7 @@ int console_write_chan(struct list_head *chans, const char *buf, int len)
chan = list_entry(ele, struct chan, list);
if(!chan->output || (chan->ops->console_write == NULL))
continue;
- n = chan->ops->console_write(chan->fd, buf, len, chan->data);
+ n = chan->ops->console_write(chan->fd, buf, len);
if(chan->primary) ret = n;
}
return(ret);
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 1c55d580248..5d50d4a44ab 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -20,7 +20,7 @@
#include "choose-mode.h"
#include "mode.h"
-int generic_console_write(int fd, const char *buf, int n, void *unused)
+int generic_console_write(int fd, const char *buf, int n)
{
struct termios save, new;
int err;
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index c1b03f7c1da..1bb085b2824 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -98,7 +98,7 @@ static int connect_to_switch(struct daemon_data *pri)
printk("daemon_open : control setup request failed, err = %d\n",
-n);
err = -ENOTCONN;
- goto out;
+ goto out_free;
}
n = os_read_file(pri->control, sun, sizeof(*sun));
@@ -106,12 +106,14 @@ static int connect_to_switch(struct daemon_data *pri)
printk("daemon_open : read of data socket failed, err = %d\n",
-n);
err = -ENOTCONN;
- goto out_close;
+ goto out_free;
}
pri->data_addr = sun;
return(fd);
+ out_free:
+ kfree(sun);
out_close:
os_close_file(fd);
out:
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index f0b888f66e0..3296e86a03a 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -76,13 +76,6 @@ static void fd_close(int fd, void *d)
}
}
-static int fd_console_write(int fd, const char *buf, int n, void *d)
-{
- struct fd_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops fd_ops = {
.type = "fd",
.init = fd_init,
@@ -90,7 +83,7 @@ struct chan_ops fd_ops = {
.close = fd_close,
.read = generic_read,
.write = generic_write,
- .console_write = fd_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 1,
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
index 5db136e2651..afe85bfa66e 100644
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -54,7 +54,7 @@ static int mcast_open(void *data)
struct mcast_data *pri = data;
struct sockaddr_in *sin = pri->mcast_addr;
struct ip_mreq mreq;
- int fd, yes = 1, err = 0;
+ int fd, yes = 1, err = -EINVAL;
if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
@@ -63,40 +63,40 @@ static int mcast_open(void *data)
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0){
+ err = -errno;
printk("mcast_open : data socket failed, errno = %d\n",
errno);
- err = -errno;
goto out;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+ err = -errno;
printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
errno);
- err = -errno;
goto out_close;
}
/* set ttl according to config */
if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
sizeof(pri->ttl)) < 0) {
+ err = -errno;
printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
errno);
- err = -errno;
goto out_close;
}
/* set LOOP, so data does get fed back to local sockets */
if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+ err = -errno;
printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
errno);
- err = -errno;
goto out_close;
}
/* bind socket to mcast address */
if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
- printk("mcast_open : data bind failed, errno = %d\n", errno);
err = -errno;
+ printk("mcast_open : data bind failed, errno = %d\n", errno);
goto out_close;
}
@@ -105,22 +105,22 @@ static int mcast_open(void *data)
mreq.imr_interface.s_addr = 0;
if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
+ err = -errno;
printk("mcast_open: IP_ADD_MEMBERSHIP failed, error = %d\n",
errno);
printk("There appears not to be a multicast-capable network "
"interface on the host.\n");
printk("eth0 should be configured in order to use the "
"multicast transport.\n");
- err = -errno;
- goto out_close;
+ goto out_close;
}
return fd;
out_close:
- os_close_file(fd);
+ os_close_file(fd);
out:
- return err;
+ return err;
}
static void mcast_close(int fd, void *data)
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index ed4a1a6c5d8..c43e8bb3250 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -100,13 +100,6 @@ static void port_close(int fd, void *d)
os_close_file(fd);
}
-static int port_console_write(int fd, const char *buf, int n, void *d)
-{
- struct port_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops port_ops = {
.type = "port",
.init = port_init,
@@ -114,7 +107,7 @@ struct chan_ops port_ops = {
.close = port_close,
.read = generic_read,
.write = generic_write,
- .console_write = port_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = port_free,
.winch = 1,
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index 0306a1b215b..1c555c38de4 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -118,13 +118,6 @@ static int pty_open(int input, int output, int primary, void *d,
return(fd);
}
-static int pty_console_write(int fd, const char *buf, int n, void *d)
-{
- struct pty_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops pty_ops = {
.type = "pty",
.init = pty_chan_init,
@@ -132,7 +125,7 @@ struct chan_ops pty_ops = {
.close = generic_close,
.read = generic_read,
.write = generic_write,
- .console_write = pty_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 0,
@@ -145,7 +138,7 @@ struct chan_ops pts_ops = {
.close = generic_close,
.read = generic_read,
.write = generic_write,
- .console_write = pty_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 0,
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index 6fbb670ee27..94c9265a4f2 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -60,13 +60,6 @@ static int tty_open(int input, int output, int primary, void *d,
return(fd);
}
-static int tty_console_write(int fd, const char *buf, int n, void *d)
-{
- struct tty_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops tty_ops = {
.type = "tty",
.init = tty_chan_init,
@@ -74,7 +67,7 @@ struct chan_ops tty_ops = {
.close = generic_close,
.read = generic_read,
.write = generic_write,
- .console_write = tty_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = generic_free,
.winch = 0,
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index b530f1a6540..aaa63666104 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -194,13 +194,6 @@ static void xterm_free(void *d)
free(d);
}
-static int xterm_console_write(int fd, const char *buf, int n, void *d)
-{
- struct xterm_chan *data = d;
-
- return(generic_console_write(fd, buf, n, &data->tt));
-}
-
struct chan_ops xterm_ops = {
.type = "xterm",
.init = xterm_init,
@@ -208,7 +201,7 @@ struct chan_ops xterm_ops = {
.close = xterm_close,
.read = generic_read,
.write = generic_write,
- .console_write = xterm_console_write,
+ .console_write = generic_console_write,
.window_size = generic_window_size,
.free = xterm_free,
.winch = 1,
diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h
index f77d9aa4c16..659bb3cac32 100644
--- a/arch/um/include/chan_user.h
+++ b/arch/um/include/chan_user.h
@@ -25,7 +25,7 @@ struct chan_ops {
void (*close)(int, void *);
int (*read)(int, char *, void *);
int (*write)(int, const char *, int, void *);
- int (*console_write)(int, const char *, int, void *);
+ int (*console_write)(int, const char *, int);
int (*window_size)(int, void *, unsigned short *, unsigned short *);
void (*free)(void *);
int winch;
@@ -37,7 +37,7 @@ extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops,
extern void generic_close(int fd, void *unused);
extern int generic_read(int fd, char *c_out, void *unused);
extern int generic_write(int fd, const char *buf, int n, void *unused);
-extern int generic_console_write(int fd, const char *buf, int n, void *state);
+extern int generic_console_write(int fd, const char *buf, int n);
extern int generic_window_size(int fd, void *unused, unsigned short *rows_out,
unsigned short *cols_out);
extern void generic_free(void *data);
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
index 84c0868cd56..f8760a3f43b 100644
--- a/arch/um/include/um_uaccess.h
+++ b/arch/um/include/um_uaccess.h
@@ -17,8 +17,25 @@
#include "uaccess-skas.h"
#endif
+#define __under_task_size(addr, size) \
+ (((unsigned long) (addr) < TASK_SIZE) && \
+ (((unsigned long) (addr) + (size)) < TASK_SIZE))
+
+#define __access_ok_vsyscall(type, addr, size) \
+ ((type == VERIFY_READ) && \
+ ((unsigned long) (addr) >= FIXADDR_USER_START) && \
+ ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
+ ((unsigned long) (addr) + (size) >= (unsigned long)(addr)))
+
+#define __addr_range_nowrap(addr, size) \
+ ((unsigned long) (addr) <= ((unsigned long) (addr) + (size)))
+
#define access_ok(type, addr, size) \
- CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)
+ (__addr_range_nowrap(addr, size) && \
+ (__under_task_size(addr, size) || \
+ __access_ok_vsyscall(type, addr, size) || \
+ segment_eq(get_fs(), KERNEL_DS) || \
+ CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size)))
static inline int copy_from_user(void *to, const void __user *from, int n)
{
diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h
index 7da0c2def0e..f611f83ad4f 100644
--- a/arch/um/kernel/skas/include/uaccess-skas.h
+++ b/arch/um/kernel/skas/include/uaccess-skas.h
@@ -9,14 +9,8 @@
#include "asm/errno.h"
#include "asm/fixmap.h"
-#define access_ok_skas(type, addr, size) \
- ((segment_eq(get_fs(), KERNEL_DS)) || \
- (((unsigned long) (addr) < TASK_SIZE) && \
- ((unsigned long) (addr) + (size) <= TASK_SIZE)) || \
- ((type == VERIFY_READ ) && \
- ((unsigned long) (addr) >= FIXADDR_USER_START) && \
- ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
- ((unsigned long) (addr) + (size) >= (unsigned long)(addr))))
+/* No SKAS-specific checking. */
+#define access_ok_skas(type, addr, size) 0
extern int copy_from_user_skas(void *to, const void __user *from, int n);
extern int copy_to_user_skas(void __user *to, const void *from, int n);
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
index 75195281081..a5a47528dec 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -143,7 +143,7 @@ int copy_from_user_skas(void *to, const void __user *from, int n)
return(0);
}
- return(access_ok_skas(VERIFY_READ, from, n) ?
+ return(access_ok(VERIFY_READ, from, n) ?
buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
n);
}
@@ -164,7 +164,7 @@ int copy_to_user_skas(void __user *to, const void *from, int n)
return(0);
}
- return(access_ok_skas(VERIFY_WRITE, to, n) ?
+ return(access_ok(VERIFY_WRITE, to, n) ?
buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
n);
}
@@ -193,7 +193,7 @@ int strncpy_from_user_skas(char *dst, const char __user *src, int count)
return(strnlen(dst, count));
}
- if(!access_ok_skas(VERIFY_READ, src, 1))
+ if(!access_ok(VERIFY_READ, src, 1))
return(-EFAULT);
n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
@@ -221,7 +221,7 @@ int clear_user_skas(void __user *mem, int len)
return(0);
}
- return(access_ok_skas(VERIFY_WRITE, mem, len) ?
+ return(access_ok(VERIFY_WRITE, mem, len) ?
buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
}
diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
index 95c8f8733ba..0d4c10a7360 100644
--- a/arch/um/kernel/trap_kern.c
+++ b/arch/um/kernel/trap_kern.c
@@ -95,7 +95,16 @@ survive:
pte = pte_offset_kernel(pmd, address);
} while(!pte_present(*pte));
err = 0;
+ /* The below warning was added in place of
+ * pte_mkyoung(); if (is_write) pte_mkdirty();
+ * If it's triggered, we'd see normally a hang here (a clean pte is
+ * marked read-only to emulate the dirty bit).
+ * However, the generic code can mark a PTE writable but clean on a
+ * concurrent read fault, triggering this harmlessly. So comment it out.
+ */
+#if 0
WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte)));
+#endif
flush_tlb_page(vma, address);
out:
up_read(&mm->mmap_sem);
diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h
index dc2ebfa8c54..b9bfe9c481c 100644
--- a/arch/um/kernel/tt/include/uaccess-tt.h
+++ b/arch/um/kernel/tt/include/uaccess-tt.h
@@ -19,19 +19,13 @@
extern unsigned long end_vm;
extern unsigned long uml_physmem;
-#define under_task_size(addr, size) \
- (((unsigned long) (addr) < TASK_SIZE) && \
- (((unsigned long) (addr) + (size)) < TASK_SIZE))
-
#define is_stack(addr, size) \
(((unsigned long) (addr) < STACK_TOP) && \
((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \
(((unsigned long) (addr) + (size)) <= STACK_TOP))
#define access_ok_tt(type, addr, size) \
- ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \
- (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \
- (under_task_size(addr, size) || is_stack(addr, size))))
+ (is_stack(addr, size))
extern unsigned long get_fault_addr(void);
diff --git a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
index a72aa632972..1cb60726567 100644
--- a/arch/um/kernel/tt/uaccess.c
+++ b/arch/um/kernel/tt/uaccess.c
@@ -8,7 +8,7 @@
int copy_from_user_tt(void *to, const void __user *from, int n)
{
- if(!access_ok_tt(VERIFY_READ, from, n))
+ if(!access_ok(VERIFY_READ, from, n))
return(n);
return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
@@ -17,7 +17,7 @@ int copy_from_user_tt(void *to, const void __user *from, int n)
int copy_to_user_tt(void __user *to, const void *from, int n)
{
- if(!access_ok_tt(VERIFY_WRITE, to, n))
+ if(!access_ok(VERIFY_WRITE, to, n))
return(n);
return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
@@ -28,7 +28,7 @@ int strncpy_from_user_tt(char *dst, const char __user *src, int count)
{
int n;
- if(!access_ok_tt(VERIFY_READ, src, 1))
+ if(!access_ok(VERIFY_READ, src, 1))
return(-EFAULT);
n = __do_strncpy_from_user(dst, src, count,
@@ -47,7 +47,7 @@ int __clear_user_tt(void __user *mem, int len)
int clear_user_tt(void __user *mem, int len)
{
- if(!access_ok_tt(VERIFY_WRITE, mem, len))
+ if(!access_ok(VERIFY_WRITE, mem, len))
return(len);
return(__do_clear_user(mem, len, &current->thread.fault_addr,
diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig
index 89c053b6c2c..31086590323 100644
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -23,6 +23,14 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
+config GENERIC_HARDIRQS
+ bool
+ default y
+
+config GENERIC_IRQ_PROBE
+ bool
+ default y
+
# Turn off some random 386 crap that can affect device config
config ISA
bool
diff --git a/arch/v850/kernel/irq.c b/arch/v850/kernel/irq.c
index 9e85969ba97..7a151c26f82 100644
--- a/arch/v850/kernel/irq.c
+++ b/arch/v850/kernel/irq.c
@@ -1,8 +1,8 @@
/*
* arch/v850/kernel/irq.c -- High-level interrupt handling
*
- * Copyright (C) 2001,02,03,04 NEC Electronics Corporation
- * Copyright (C) 2001,02,03,04 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03,04,05 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03,04,05 Miles Bader <miles@gnu.org>
* Copyright (C) 1994-2000 Ralf Baechle
* Copyright (C) 1992 Linus Torvalds
*
@@ -27,55 +27,15 @@
#include <asm/system.h>
/*
- * Controller mappings for all interrupt sources:
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesn't deserve
+ * a generic callback i think.
*/
-irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
- [0 ... NR_IRQS-1] = {
- .handler = &no_irq_type,
- .lock = SPIN_LOCK_UNLOCKED
- }
-};
-
-/*
- * Special irq handlers.
- */
-
-irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
- return IRQ_NONE;
-}
-
-/*
- * Generic no controller code
- */
-
-static void enable_none(unsigned int irq) { }
-static unsigned int startup_none(unsigned int irq) { return 0; }
-static void disable_none(unsigned int irq) { }
-static void ack_none(unsigned int irq)
+void ack_bad_irq(unsigned int irq)
{
- /*
- * 'what should we do if we get a hw irq event on an illegal vector'.
- * each architecture has to answer this themselves, it doesn't deserve
- * a generic callback i think.
- */
printk("received IRQ %d with unknown interrupt type\n", irq);
}
-/* startup is the same as "enable", shutdown is same as "disable" */
-#define shutdown_none disable_none
-#define end_none enable_none
-
-struct hw_interrupt_type no_irq_type = {
- .typename = "none",
- .startup = startup_none,
- .shutdown = shutdown_none,
- .enable = enable_none,
- .disable = disable_none,
- .ack = ack_none,
- .end = end_none
-};
-
volatile unsigned long irq_err_count, spurious_count;
/*
@@ -84,643 +44,68 @@ volatile unsigned long irq_err_count, spurious_count;
int show_interrupts(struct seq_file *p, void *v)
{
- int i = *(loff_t *) v;
- struct irqaction * action;
- unsigned long flags;
+ int irq = *(loff_t *) v;
- if (i == 0) {
+ if (irq == 0) {
+ int cpu;
seq_puts(p, " ");
- for (i=0; i < 1 /*smp_num_cpus*/; i++)
- seq_printf(p, "CPU%d ", i);
+ for (cpu=0; cpu < 1 /*smp_num_cpus*/; cpu++)
+ seq_printf(p, "CPU%d ", cpu);
seq_putc(p, '\n');
}
- if (i < NR_IRQS) {
- int j, count, num;
- const char *type_name = irq_desc[i].handler->typename;
- spin_lock_irqsave(&irq_desc[j].lock, flags);
- action = irq_desc[i].action;
- if (!action)
- goto skip;
+ if (irq < NR_IRQS) {
+ unsigned long flags;
+ struct irqaction *action;
- count = 0;
- num = -1;
- for (j = 0; j < NR_IRQS; j++)
- if (irq_desc[j].handler->typename == type_name) {
- if (i == j)
- num = count;
- count++;
- }
+ spin_lock_irqsave(&irq_desc[irq].lock, flags);
- seq_printf(p, "%3d: ",i);
- seq_printf(p, "%10u ", kstat_irqs(i));
- if (count > 1) {
- int prec = (num >= 100 ? 3 : num >= 10 ? 2 : 1);
- seq_printf(p, " %*s%d", 14 - prec, type_name, num);
- } else
- seq_printf(p, " %14s", type_name);
+ action = irq_desc[irq].action;
+ if (action) {
+ int j;
+ int count = 0;
+ int num = -1;
+ const char *type_name = irq_desc[irq].handler->typename;
+
+ for (j = 0; j < NR_IRQS; j++)
+ if (irq_desc[j].handler->typename == type_name){
+ if (irq == j)
+ num = count;
+ count++;
+ }
+
+ seq_printf(p, "%3d: ",irq);
+ seq_printf(p, "%10u ", kstat_irqs(irq));
+ if (count > 1) {
+ int prec = (num >= 100 ? 3 : num >= 10 ? 2 : 1);
+ seq_printf(p, " %*s%d", 14 - prec,
+ type_name, num);
+ } else
+ seq_printf(p, " %14s", type_name);
- seq_printf(p, " %s", action->name);
- for (action=action->next; action; action = action->next)
- seq_printf(p, ", %s", action->name);
- seq_putc(p, '\n');
-skip:
- spin_unlock_irqrestore(&irq_desc[j].lock, flags);
- } else if (i == NR_IRQS)
- seq_printf(p, "ERR: %10lu\n", irq_err_count);
- return 0;
-}
-
-/*
- * This should really return information about whether
- * we should do bottom half handling etc. Right now we
- * end up _always_ checking the bottom half, which is a
- * waste of time and is not what some drivers would
- * prefer.
- */
-int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
-{
- int status = 1; /* Force the "do bottom halves" bit */
- int ret;
-
- if (!(action->flags & SA_INTERRUPT))
- local_irq_enable();
-
- do {
- ret = action->handler(irq, action->dev_id, regs);
- if (ret == IRQ_HANDLED)
- status |= action->flags;
- action = action->next;
- } while (action);
- if (status & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- local_irq_disable();
-
- return status;
-}
-
-/*
- * Generic enable/disable code: this just calls
- * down into the PIC-specific version for the actual
- * hardware disable after having gotten the irq
- * controller lock.
- */
-
-/**
- * disable_irq_nosync - disable an irq without waiting
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Disables of an interrupt
- * stack. Unlike disable_irq(), this function does not ensure existing
- * instances of the IRQ handler have completed before returning.
- *
- * This function may be called from IRQ context.
- */
-
-void inline disable_irq_nosync(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
-
- spin_lock_irqsave(&desc->lock, flags);
- if (!desc->depth++) {
- desc->status |= IRQ_DISABLED;
- desc->handler->disable(irq);
- }
- spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/**
- * disable_irq - disable an irq and wait for completion
- * @irq: Interrupt to disable
- *
- * Disable the selected interrupt line. Disables of an interrupt
- * stack. That is for two disables you need two enables. This
- * function waits for any pending IRQ handlers for this interrupt
- * to complete before returning. If you use this function while
- * holding a resource the IRQ handler may need you will deadlock.
- *
- * This function may be called - with care - from IRQ context.
- */
-
-void disable_irq(unsigned int irq)
-{
- disable_irq_nosync(irq);
- synchronize_irq(irq);
-}
+ seq_printf(p, " %s", action->name);
+ for (action=action->next; action; action = action->next)
+ seq_printf(p, ", %s", action->name);
+ seq_putc(p, '\n');
+ }
-/**
- * enable_irq - enable interrupt handling on an irq
- * @irq: Interrupt to enable
- *
- * Re-enables the processing of interrupts on this IRQ line
- * providing no disable_irq calls are now in effect.
- *
- * This function may be called from IRQ context.
- */
-
-void enable_irq(unsigned int irq)
-{
- irq_desc_t *desc = irq_desc + irq;
- unsigned long flags;
+ spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
+ } else if (irq == NR_IRQS)
+ seq_printf(p, "ERR: %10lu\n", irq_err_count);
- spin_lock_irqsave(&desc->lock, flags);
- switch (desc->depth) {
- case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
- desc->status = status;
- if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
- desc->status = status | IRQ_REPLAY;
- hw_resend_irq(desc->handler,irq);
- }
- desc->handler->enable(irq);
- /* fall-through */
- }
- default:
- desc->depth--;
- break;
- case 0:
- printk("enable_irq(%u) unbalanced from %p\n", irq,
- __builtin_return_address(0));
- }
- spin_unlock_irqrestore(&desc->lock, flags);
+ return 0;
}
/* Handle interrupt IRQ. REGS are the registers at the time of ther
interrupt. */
unsigned int handle_irq (int irq, struct pt_regs *regs)
{
- /*
- * We ack quickly, we don't want the irq controller
- * thinking we're snobs just because some other CPU has
- * disabled global interrupts (we have already done the
- * INT_ACK cycles, it's too late to try to pretend to the
- * controller that we aren't taking the interrupt).
- *
- * 0 return value means that this irq is already being
- * handled by some other CPU. (or is disabled)
- */
- int cpu = smp_processor_id();
- irq_desc_t *desc = irq_desc + irq;
- struct irqaction * action;
- unsigned int status;
-
irq_enter();
- kstat_cpu(cpu).irqs[irq]++;
- spin_lock(&desc->lock);
- desc->handler->ack(irq);
- /*
- REPLAY is when Linux resends an IRQ that was dropped earlier
- WAITING is used by probe to mark irqs that are being tested
- */
- status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
- status |= IRQ_PENDING; /* we _want_ to handle it */
-
- /*
- * If the IRQ is disabled for whatever reason, we cannot
- * use the action we have.
- */
- action = NULL;
- if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
- action = desc->action;
- status &= ~IRQ_PENDING; /* we commit to handling */
- status |= IRQ_INPROGRESS; /* we are handling it */
- }
- desc->status = status;
-
- /*
- * If there is no IRQ handler or it was disabled, exit early.
- Since we set PENDING, if another processor is handling
- a different instance of this same irq, the other processor
- will take care of it.
- */
- if (unlikely(!action))
- goto out;
-
- /*
- * Edge triggered interrupts need to remember
- * pending events.
- * This applies to any hw interrupts that allow a second
- * instance of the same irq to arrive while we are in handle_irq
- * or in the handler. But the code here only handles the _second_
- * instance of the irq, not the third or fourth. So it is mostly
- * useful for irq hardware that does not mask cleanly in an
- * SMP environment.
- */
- for (;;) {
- spin_unlock(&desc->lock);
- handle_IRQ_event(irq, regs, action);
- spin_lock(&desc->lock);
-
- if (likely(!(desc->status & IRQ_PENDING)))
- break;
- desc->status &= ~IRQ_PENDING;
- }
- desc->status &= ~IRQ_INPROGRESS;
-
-out:
- /*
- * The ->end() handler has to deal with interrupts which got
- * disabled while the handler was running.
- */
- desc->handler->end(irq);
- spin_unlock(&desc->lock);
-
+ __do_IRQ(irq, regs);
irq_exit();
-
return 1;
}
-/**
- * request_irq - allocate an interrupt line
- * @irq: Interrupt line to allocate
- * @handler: Function to be called when the IRQ occurs
- * @irqflags: Interrupt type flags
- * @devname: An ascii name for the claiming device
- * @dev_id: A cookie passed back to the handler function
- *
- * This call allocates interrupt resources and enables the
- * interrupt line and IRQ handling. From the point this
- * call is made your handler function may be invoked. Since
- * your handler function must clear any interrupt the board
- * raises, you must take care both to initialise your hardware
- * and to set up the interrupt handler in the right order.
- *
- * Dev_id must be globally unique. Normally the address of the
- * device data structure is used as the cookie. Since the handler
- * receives this value it makes sense to use it.
- *
- * If your interrupt is shared you must pass a non NULL dev_id
- * as this is required when freeing the interrupt.
- *
- * Flags:
- *
- * SA_SHIRQ Interrupt is shared
- *
- * SA_INTERRUPT Disable local interrupts while processing
- *
- * SA_SAMPLE_RANDOM The interrupt can be used for entropy
- *
- */
-
-int request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags,
- const char * devname,
- void *dev_id)
-{
- int retval;
- struct irqaction * action;
-
-#if 1
- /*
- * Sanity-check: shared interrupts should REALLY pass in
- * a real dev-ID, otherwise we'll have trouble later trying
- * to figure out which interrupt is which (messes up the
- * interrupt freeing logic etc).
- */
- if (irqflags & SA_SHIRQ) {
- if (!dev_id)
- printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);
- }
-#endif
-
- if (irq >= NR_IRQS)
- return -EINVAL;
- if (!handler)
- return -EINVAL;
-
- action = (struct irqaction *)
- kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- if (!action)
- return -ENOMEM;
-
- action->handler = handler;
- action->flags = irqflags;
- cpus_clear(action->mask);
- action->name = devname;
- action->next = NULL;
- action->dev_id = dev_id;
-
- retval = setup_irq(irq, action);
- if (retval)
- kfree(action);
- return retval;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-/**
- * free_irq - free an interrupt
- * @irq: Interrupt line to free
- * @dev_id: Device identity to free
- *
- * Remove an interrupt handler. The handler is removed and if the
- * interrupt line is no longer in use by any driver it is disabled.
- * On a shared IRQ the caller must ensure the interrupt is disabled
- * on the card it drives before calling this function. The function
- * does not return until any executing interrupts for this IRQ
- * have completed.
- *
- * This function may be called from interrupt context.
- *
- * Bugs: Attempting to free an irq in a handler for the same irq hangs
- * the machine.
- */
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- irq_desc_t *desc;
- struct irqaction **p;
- unsigned long flags;
-
- if (irq >= NR_IRQS)
- return;
-
- desc = irq_desc + irq;
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- for (;;) {
- struct irqaction * action = *p;
- if (action) {
- struct irqaction **pp = p;
- p = &action->next;
- if (action->dev_id != dev_id)
- continue;
-
- /* Found it - now remove it from the list of entries */
- *pp = action->next;
- if (!desc->action) {
- desc->status |= IRQ_DISABLED;
- desc->handler->shutdown(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- synchronize_irq(irq);
- kfree(action);
- return;
- }
- printk("Trying to free free IRQ%d\n",irq);
- spin_unlock_irqrestore(&desc->lock,flags);
- return;
- }
-}
-
-EXPORT_SYMBOL(free_irq);
-
-/*
- * IRQ autodetection code..
- *
- * This depends on the fact that any interrupt that
- * comes in on to an unassigned handler will get stuck
- * with "IRQ_WAITING" cleared and the interrupt
- * disabled.
- */
-
-static DECLARE_MUTEX(probe_sem);
-
-/**
- * probe_irq_on - begin an interrupt autodetect
- *
- * Commence probing for an interrupt. The interrupts are scanned
- * and a mask of potential interrupt lines is returned.
- *
- */
-
-unsigned long probe_irq_on(void)
-{
- unsigned int i;
- irq_desc_t *desc;
- unsigned long val;
- unsigned long delay;
-
- down(&probe_sem);
- /*
- * something may have generated an irq long ago and we want to
- * flush such a longstanding irq before considering it as spurious.
- */
- for (i = NR_IRQS-1; i > 0; i--) {
- desc = irq_desc + i;
-
- spin_lock_irq(&desc->lock);
- if (!irq_desc[i].action)
- irq_desc[i].handler->startup(i);
- spin_unlock_irq(&desc->lock);
- }
-
- /* Wait for longstanding interrupts to trigger. */
- for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
- /* about 20ms delay */ barrier();
-
- /*
- * enable any unassigned irqs
- * (we must startup again here because if a longstanding irq
- * happened in the previous stage, it may have masked itself)
- */
- for (i = NR_IRQS-1; i > 0; i--) {
- desc = irq_desc + i;
-
- spin_lock_irq(&desc->lock);
- if (!desc->action) {
- desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
- if (desc->handler->startup(i))
- desc->status |= IRQ_PENDING;
- }
- spin_unlock_irq(&desc->lock);
- }
-
- /*
- * Wait for spurious interrupts to trigger
- */
- for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
- /* about 100ms delay */ barrier();
-
- /*
- * Now filter out any obviously spurious interrupts
- */
- val = 0;
- for (i = 0; i < NR_IRQS; i++) {
- irq_desc_t *desc = irq_desc + i;
- unsigned int status;
-
- spin_lock_irq(&desc->lock);
- status = desc->status;
-
- if (status & IRQ_AUTODETECT) {
- /* It triggered already - consider it spurious. */
- if (!(status & IRQ_WAITING)) {
- desc->status = status & ~IRQ_AUTODETECT;
- desc->handler->shutdown(i);
- } else
- if (i < 32)
- val |= 1 << i;
- }
- spin_unlock_irq(&desc->lock);
- }
-
- return val;
-}
-
-EXPORT_SYMBOL(probe_irq_on);
-
-/*
- * Return a mask of triggered interrupts (this
- * can handle only legacy ISA interrupts).
- */
-
-/**
- * probe_irq_mask - scan a bitmap of interrupt lines
- * @val: mask of interrupts to consider
- *
- * Scan the ISA bus interrupt lines and return a bitmap of
- * active interrupts. The interrupt probe logic state is then
- * returned to its previous value.
- *
- * Note: we need to scan all the irq's even though we will
- * only return ISA irq numbers - just so that we reset them
- * all to a known state.
- */
-unsigned int probe_irq_mask(unsigned long val)
-{
- int i;
- unsigned int mask;
-
- mask = 0;
- for (i = 0; i < NR_IRQS; i++) {
- irq_desc_t *desc = irq_desc + i;
- unsigned int status;
-
- spin_lock_irq(&desc->lock);
- status = desc->status;
-
- if (status & IRQ_AUTODETECT) {
- if (i < 16 && !(status & IRQ_WAITING))
- mask |= 1 << i;
-
- desc->status = status & ~IRQ_AUTODETECT;
- desc->handler->shutdown(i);
- }
- spin_unlock_irq(&desc->lock);
- }
- up(&probe_sem);
-
- return mask & val;
-}
-
-/*
- * Return the one interrupt that triggered (this can
- * handle any interrupt source).
- */
-
-/**
- * probe_irq_off - end an interrupt autodetect
- * @val: mask of potential interrupts (unused)
- *
- * Scans the unused interrupt lines and returns the line which
- * appears to have triggered the interrupt. If no interrupt was
- * found then zero is returned. If more than one interrupt is
- * found then minus the first candidate is returned to indicate
- * their is doubt.
- *
- * The interrupt probe logic state is returned to its previous
- * value.
- *
- * BUGS: When used in a module (which arguably shouldnt happen)
- * nothing prevents two IRQ probe callers from overlapping. The
- * results of this are non-optimal.
- */
-
-int probe_irq_off(unsigned long val)
-{
- int i, irq_found, nr_irqs;
-
- nr_irqs = 0;
- irq_found = 0;
- for (i = 0; i < NR_IRQS; i++) {
- irq_desc_t *desc = irq_desc + i;
- unsigned int status;
-
- spin_lock_irq(&desc->lock);
- status = desc->status;
-
- if (status & IRQ_AUTODETECT) {
- if (!(status & IRQ_WAITING)) {
- if (!nr_irqs)
- irq_found = i;
- nr_irqs++;
- }
- desc->status = status & ~IRQ_AUTODETECT;
- desc->handler->shutdown(i);
- }
- spin_unlock_irq(&desc->lock);
- }
- up(&probe_sem);
-
- if (nr_irqs > 1)
- irq_found = -irq_found;
- return irq_found;
-}
-
-EXPORT_SYMBOL(probe_irq_off);
-
-/* this was setup_x86_irq but it seems pretty generic */
-int setup_irq(unsigned int irq, struct irqaction * new)
-{
- int shared = 0;
- unsigned long flags;
- struct irqaction *old, **p;
- irq_desc_t *desc = irq_desc + irq;
-
- /*
- * Some drivers like serial.c use request_irq() heavily,
- * so we have to be careful not to interfere with a
- * running system.
- */
- if (new->flags & SA_SAMPLE_RANDOM) {
- /*
- * This function might sleep, we want to call it first,
- * outside of the atomic block.
- * Yes, this might clear the entropy pool if the wrong
- * driver is attempted to be loaded, without actually
- * installing a new handler, but is this really a problem,
- * only the sysadmin is able to do this.
- */
- rand_initialize_irq(irq);
- }
-
- /*
- * The following block of code has to be executed atomically
- */
- spin_lock_irqsave(&desc->lock,flags);
- p = &desc->action;
- if ((old = *p) != NULL) {
- /* Can't share interrupts unless both agree to */
- if (!(old->flags & new->flags & SA_SHIRQ)) {
- spin_unlock_irqrestore(&desc->lock,flags);
- return -EBUSY;
- }
-
- /* add new interrupt at end of irq queue */
- do {
- p = &old->next;
- old = *p;
- } while (old);
- shared = 1;
- }
-
- *p = new;
-
- if (!shared) {
- desc->depth = 0;
- desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
- desc->handler->startup(irq);
- }
- spin_unlock_irqrestore(&desc->lock,flags);
-
- /* register_irq_proc(irq); */
- return 0;
-}
-
/* Initialize irq handling for IRQs.
BASE_IRQ, BASE_IRQ+INTERVAL, ..., BASE_IRQ+NUM*INTERVAL
to IRQ_TYPE. An IRQ_TYPE of 0 means to use a generic interrupt type. */
@@ -736,9 +121,3 @@ init_irq_handlers (int base_irq, int num, int interval,
base_irq += interval;
}
}
-
-#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
-void init_irq_proc(void)
-{
-}
-#endif /* CONFIG_PROC_FS && CONFIG_SYSCTL */
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 4cce2f6f170..6ece645e4db 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -226,22 +226,42 @@ config SCHED_SMT
source "kernel/Kconfig.preempt"
-config K8_NUMA
- bool "K8 NUMA support"
- select NUMA
+config NUMA
+ bool "Non Uniform Memory Access (NUMA) Support"
depends on SMP
help
- Enable NUMA (Non Unified Memory Architecture) support for
- AMD Opteron Multiprocessor systems. The kernel will try to allocate
- memory used by a CPU on the local memory controller of the CPU
- and add some more NUMA awareness to the kernel.
- This code is recommended on all multiprocessor Opteron systems
- and normally doesn't hurt on others.
+ Enable NUMA (Non Uniform Memory Access) support. The kernel
+ will try to allocate memory used by a CPU on the local memory
+ controller of the CPU and add some more NUMA awareness to the kernel.
+ This code is recommended on all multiprocessor Opteron systems.
+ If the system is EM64T, you should say N unless your system is EM64T
+ NUMA.
+
+config K8_NUMA
+ bool "Old style AMD Opteron NUMA detection"
+ depends on NUMA
+ default y
+ help
+ Enable K8 NUMA node topology detection. You should say Y here if
+ you have a multi processor AMD K8 system. This uses an old
+ method to read the NUMA configurtion directly from the builtin
+ Northbridge of Opteron. It is recommended to use X86_64_ACPI_NUMA
+ instead, which also takes priority if both are compiled in.
+
+# Dummy CONFIG option to select ACPI_NUMA from drivers/acpi/Kconfig.
+
+config X86_64_ACPI_NUMA
+ bool "ACPI NUMA detection"
+ depends on NUMA
+ select ACPI
+ select ACPI_NUMA
+ default y
+ help
+ Enable ACPI SRAT based node topology detection.
config NUMA_EMU
- bool "NUMA emulation support"
- select NUMA
- depends on SMP
+ bool "NUMA emulation"
+ depends on NUMA
help
Enable NUMA emulation. A flat machine will be split
into virtual nodes when booted with "numa=fake=N", where N is the
@@ -252,9 +272,6 @@ config ARCH_DISCONTIGMEM_ENABLE
depends on NUMA
default y
-config NUMA
- bool
- default n
config ARCH_DISCONTIGMEM_ENABLE
def_bool y
@@ -374,6 +391,14 @@ config X86_MCE_INTEL
Additional support for intel specific MCE features such as
the thermal monitor.
+config X86_MCE_AMD
+ bool "AMD MCE features"
+ depends on X86_MCE && X86_LOCAL_APIC
+ default y
+ help
+ Additional support for AMD specific MCE features such as
+ the DRAM Error Threshold.
+
config PHYSICAL_START
hex "Physical address where the kernel is loaded" if EMBEDDED
default "0x100000"
@@ -502,7 +527,7 @@ config IA32_EMULATION
left.
config IA32_AOUT
- bool "IA32 a.out support"
+ tristate "IA32 a.out support"
depends on IA32_EMULATION
help
Support old a.out binaries in the 32bit emulation.
diff --git a/arch/x86_64/Kconfig.debug b/arch/x86_64/Kconfig.debug
index d584ecc27ea..e2c6e64a85e 100644
--- a/arch/x86_64/Kconfig.debug
+++ b/arch/x86_64/Kconfig.debug
@@ -2,15 +2,6 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-# !SMP for now because the context switch early causes GPF in segment reloading
-# and the GS base checking does the wrong thing then, causing a hang.
-config CHECKING
- bool "Additional run-time checks"
- depends on DEBUG_KERNEL && !SMP
- help
- Enables some internal consistency checks for kernel debugging.
- You should normally say N.
-
config INIT_DEBUG
bool "Debug __init statements"
depends on DEBUG_KERNEL
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index f8db7e500fb..5d56542fb68 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.13-git11
-# Mon Sep 12 16:16:16 2005
+# Linux kernel version: 2.6.14-git7
+# Sat Nov 5 15:55:50 2005
#
CONFIG_X86_64=y
CONFIG_64BIT=y
@@ -35,7 +35,7 @@ CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -93,10 +93,11 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
CONFIG_PREEMPT_BKL=y
+CONFIG_NUMA=y
CONFIG_K8_NUMA=y
+CONFIG_X86_64_ACPI_NUMA=y
# CONFIG_NUMA_EMU is not set
CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_NUMA=y
CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -107,9 +108,10 @@ CONFIG_DISCONTIGMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_NEED_MULTIPLE_NODES=y
# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
-CONFIG_HAVE_DEC_LOCK=y
CONFIG_NR_CPUS=32
+CONFIG_HOTPLUG_CPU=y
CONFIG_HPET_TIMER=y
CONFIG_X86_PM_TIMER=y
CONFIG_HPET_EMULATE_RTC=y
@@ -117,6 +119,7 @@ CONFIG_GART_IOMMU=y
CONFIG_SWIOTLB=y
CONFIG_X86_MCE=y
CONFIG_X86_MCE_INTEL=y
+CONFIG_X86_MCE_AMD=y
CONFIG_PHYSICAL_START=0x100000
# CONFIG_KEXEC is not set
CONFIG_SECCOMP=y
@@ -136,11 +139,15 @@ CONFIG_PM=y
# CONFIG_PM_DEBUG is not set
CONFIG_SOFTWARE_SUSPEND=y
CONFIG_PM_STD_PARTITION=""
+CONFIG_SUSPEND_SMP=y
#
# ACPI (Advanced Configuration and Power Interface) Support
#
CONFIG_ACPI=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_SLEEP_PROC_FS=y
+CONFIG_ACPI_SLEEP_PROC_SLEEP=y
CONFIG_ACPI_AC=y
CONFIG_ACPI_BATTERY=y
CONFIG_ACPI_BUTTON=y
@@ -148,6 +155,7 @@ CONFIG_ACPI_BUTTON=y
CONFIG_ACPI_HOTKEY=m
CONFIG_ACPI_FAN=y
CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_HOTPLUG_CPU=y
CONFIG_ACPI_THERMAL=y
CONFIG_ACPI_NUMA=y
# CONFIG_ACPI_ASUS is not set
@@ -158,7 +166,7 @@ CONFIG_ACPI_BLACKLIST_YEAR=2001
CONFIG_ACPI_EC=y
CONFIG_ACPI_POWER=y
CONFIG_ACPI_SYSTEM=y
-# CONFIG_ACPI_CONTAINER is not set
+CONFIG_ACPI_CONTAINER=y
#
# CPU Frequency scaling
@@ -293,7 +301,6 @@ CONFIG_IPV6=y
# Network testing
#
# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETFILTER_NETLINK is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
@@ -312,6 +319,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_DEBUG_DRIVER is not set
#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
@@ -354,6 +366,11 @@ CONFIG_IOSCHED_NOOP=y
# CONFIG_IOSCHED_AS is not set
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
# CONFIG_ATA_OVER_ETH is not set
#
@@ -450,6 +467,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
#
# SCSI low-level drivers
@@ -469,20 +487,24 @@ CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
CONFIG_SCSI_SATA=y
# CONFIG_SCSI_SATA_AHCI is not set
# CONFIG_SCSI_SATA_SVW is not set
CONFIG_SCSI_ATA_PIIX=y
# CONFIG_SCSI_SATA_MV is not set
-# CONFIG_SCSI_SATA_NV is not set
-# CONFIG_SCSI_SATA_PROMISE is not set
+CONFIG_SCSI_SATA_NV=y
+# CONFIG_SCSI_PDC_ADMA is not set
# CONFIG_SCSI_SATA_QSTOR is not set
+# CONFIG_SCSI_SATA_PROMISE is not set
# CONFIG_SCSI_SATA_SX4 is not set
# CONFIG_SCSI_SATA_SIL is not set
+# CONFIG_SCSI_SATA_SIL24 is not set
# CONFIG_SCSI_SATA_SIS is not set
# CONFIG_SCSI_SATA_ULI is not set
CONFIG_SCSI_SATA_VIA=y
# CONFIG_SCSI_SATA_VITESSE is not set
+CONFIG_SCSI_SATA_INTEL_COMBINED=y
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
@@ -525,6 +547,7 @@ CONFIG_BLK_DEV_DM=y
CONFIG_FUSION=y
CONFIG_FUSION_SPI=y
# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
CONFIG_FUSION_MAX_SGE=128
# CONFIG_FUSION_CTL is not set
@@ -564,6 +587,7 @@ CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
CONFIG_NET_VENDOR_3COM=y
CONFIG_VORTEX=y
# CONFIG_TYPHOON is not set
@@ -740,7 +764,43 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Watchdog Cards
#
-# CONFIG_WATCHDOG is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_IBMASR is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_I8XX_TCO is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SBC8360_WDT is not set
+# CONFIG_CPU5_WDT is not set
+# CONFIG_W83627HF_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_W83977F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
CONFIG_HW_RANDOM=y
# CONFIG_NVRAM is not set
CONFIG_RTC=y
@@ -767,6 +827,7 @@ CONFIG_MAX_RAW_DEVS=256
# TPM devices
#
# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -783,6 +844,7 @@ CONFIG_MAX_RAW_DEVS=256
#
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_HDAPS is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
@@ -886,12 +948,15 @@ CONFIG_USB_UHCI_HCD=y
# USB Device Class drivers
#
# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
-# CONFIG_USB_BLUETOOTH_TTY is not set
# CONFIG_USB_ACM is not set
CONFIG_USB_PRINTER=y
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
#
CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_DEBUG is not set
@@ -924,6 +989,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_XPAD is not set
# CONFIG_USB_ATI_REMOTE is not set
# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
#
# USB Imaging devices
@@ -1005,7 +1071,7 @@ CONFIG_USB_MON=y
#
# CONFIG_EDD is not set
# CONFIG_DELL_RBU is not set
-CONFIG_DCDBAS=m
+# CONFIG_DCDBAS is not set
#
# File systems
@@ -1037,7 +1103,7 @@ CONFIG_INOTIFY=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
CONFIG_AUTOFS_FS=y
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_AUTOFS4_FS=y
# CONFIG_FUSE_FS is not set
#
@@ -1068,7 +1134,7 @@ CONFIG_TMPFS=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
+CONFIG_RELAYFS_FS=y
#
# Miscellaneous filesystems
@@ -1186,7 +1252,9 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_VM is not set
# CONFIG_FRAME_POINTER is not set
+# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_INIT_DEBUG=y
# CONFIG_IOMMU_DEBUG is not set
CONFIG_KPROBES=y
diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
index 93c60f4aa47..3bf58af9893 100644
--- a/arch/x86_64/ia32/ia32_aout.c
+++ b/arch/x86_64/ia32/ia32_aout.c
@@ -36,9 +36,6 @@
#undef WARN_OLD
#undef CORE_DUMP /* probably broken */
-extern int ia32_setup_arg_pages(struct linux_binprm *bprm,
- unsigned long stack_top, int exec_stack);
-
static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout_library(struct file*);
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index d9161e39597..830feb272ec 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -335,7 +335,8 @@ static void elf32_init(struct pt_regs *regs)
me->thread.es = __USER_DS;
}
-int setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int executable_stack)
+int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top,
+ int executable_stack)
{
unsigned long stack_base;
struct vm_area_struct *mpnt;
@@ -389,6 +390,7 @@ int setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int exec
return 0;
}
+EXPORT_SYMBOL(ia32_setup_arg_pages);
static unsigned long
elf32_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index 14328cab5d3..fe4cbd1c4b2 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -11,6 +11,7 @@ obj-y := process.o signal.o entry.o traps.o irq.o \
obj-$(CONFIG_X86_MCE) += mce.o
obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o
+obj-$(CONFIG_X86_MCE_AMD) += mce_amd.o
obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/
obj-$(CONFIG_ACPI) += acpi/
obj-$(CONFIG_X86_MSR) += msr.o
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index 962ad4823b6..c7f4fdd20f0 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -196,7 +196,7 @@ static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
void __init iommu_hole_init(void)
{
int fix, num;
- u32 aper_size, aper_alloc = 0, aper_order, last_aper_order = 0;
+ u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
u64 aper_base, last_aper_base = 0;
int valid_agp = 0;
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index b6e7715d877..18691ce4c75 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -833,6 +833,16 @@ int setup_profiling_timer(unsigned int multiplier)
return 0;
}
+#ifdef CONFIG_X86_MCE_AMD
+void setup_threshold_lvt(unsigned long lvt_off)
+{
+ unsigned int v = 0;
+ unsigned long reg = (lvt_off << 4) + 0x500;
+ v |= THRESHOLD_APIC_VECTOR;
+ apic_write(reg, v);
+}
+#endif /* CONFIG_X86_MCE_AMD */
+
#undef APIC_DIVISOR
/*
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index ab3f87aaff7..17579a1a174 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -23,8 +23,7 @@
#include <asm/e820.h>
#include <asm/proto.h>
#include <asm/bootsetup.h>
-
-extern char _end[];
+#include <asm/sections.h>
/*
* PFN of last memory page.
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index 7937971d185..9ff42041bb6 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -612,6 +612,9 @@ retint_kernel:
ENTRY(thermal_interrupt)
apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
+ENTRY(threshold_interrupt)
+ apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
+
#ifdef CONFIG_SMP
ENTRY(reschedule_interrupt)
apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index b92e5f45ed4..15290968e49 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -12,6 +12,7 @@
#include <linux/linkage.h>
#include <linux/threads.h>
+#include <linux/init.h>
#include <asm/desc.h>
#include <asm/segment.h>
#include <asm/page.h>
@@ -70,7 +71,7 @@ startup_32:
movl %eax, %cr4
/* Setup early boot stage 4 level pagetables */
- movl $(init_level4_pgt - __START_KERNEL_map), %eax
+ movl $(boot_level4_pgt - __START_KERNEL_map), %eax
movl %eax, %cr3
/* Setup EFER (Extended Feature Enable Register) */
@@ -113,7 +114,7 @@ startup_64:
movq %rax, %cr4
/* Setup early boot stage 4 level pagetables. */
- movq $(init_level4_pgt - __START_KERNEL_map), %rax
+ movq $(boot_level4_pgt - __START_KERNEL_map), %rax
movq %rax, %cr3
/* Check if nx is implemented */
@@ -240,20 +241,10 @@ ljumpvector:
ENTRY(stext)
ENTRY(_stext)
- /*
- * This default setting generates an ident mapping at address 0x100000
- * and a mapping for the kernel that precisely maps virtual address
- * 0xffffffff80000000 to physical address 0x000000. (always using
- * 2Mbyte large pages provided by PAE mode)
- */
.org 0x1000
ENTRY(init_level4_pgt)
- .quad 0x0000000000002007 + __PHYSICAL_START /* -> level3_ident_pgt */
- .fill 255,8,0
- .quad 0x000000000000a007 + __PHYSICAL_START
- .fill 254,8,0
- /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
- .quad 0x0000000000003007 + __PHYSICAL_START /* -> level3_kernel_pgt */
+ /* This gets initialized in x86_64_start_kernel */
+ .fill 512,8,0
.org 0x2000
ENTRY(level3_ident_pgt)
@@ -350,6 +341,24 @@ ENTRY(wakeup_level4_pgt)
.quad 0x0000000000003007 + __PHYSICAL_START /* -> level3_kernel_pgt */
#endif
+#ifndef CONFIG_HOTPLUG_CPU
+ __INITDATA
+#endif
+ /*
+ * This default setting generates an ident mapping at address 0x100000
+ * and a mapping for the kernel that precisely maps virtual address
+ * 0xffffffff80000000 to physical address 0x000000. (always using
+ * 2Mbyte large pages provided by PAE mode)
+ */
+ .align PAGE_SIZE
+ENTRY(boot_level4_pgt)
+ .quad 0x0000000000002007 + __PHYSICAL_START /* -> level3_ident_pgt */
+ .fill 255,8,0
+ .quad 0x000000000000a007 + __PHYSICAL_START
+ .fill 254,8,0
+ /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
+ .quad 0x0000000000003007 + __PHYSICAL_START /* -> level3_kernel_pgt */
+
.data
.align 16
diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c
index cf6ab147a2a..b675c5add01 100644
--- a/arch/x86_64/kernel/head64.c
+++ b/arch/x86_64/kernel/head64.c
@@ -19,14 +19,15 @@
#include <asm/bootsetup.h>
#include <asm/setup.h>
#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
/* Don't add a printk in there. printk relies on the PDA which is not initialized
yet. */
static void __init clear_bss(void)
{
- extern char __bss_start[], __bss_end[];
memset(__bss_start, 0,
- (unsigned long) __bss_end - (unsigned long) __bss_start);
+ (unsigned long) __bss_stop - (unsigned long) __bss_start);
}
#define NEW_CL_POINTER 0x228 /* Relative to real mode data */
@@ -75,8 +76,6 @@ static void __init setup_boot_cpu_data(void)
boot_cpu_data.x86_mask = eax & 0xf;
}
-extern char _end[];
-
void __init x86_64_start_kernel(char * real_mode_data)
{
char *s;
@@ -86,6 +85,13 @@ void __init x86_64_start_kernel(char * real_mode_data)
set_intr_gate(i, early_idt_handler);
asm volatile("lidt %0" :: "m" (idt_descr));
clear_bss();
+
+ /*
+ * switch to init_level4_pgt from boot_level4_pgt
+ */
+ memcpy(init_level4_pgt, boot_level4_pgt, PTRS_PER_PGD*sizeof(pgd_t));
+ asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
+
pda_init(0);
copy_bootdata(real_mode_data);
#ifdef CONFIG_SMP
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index c6c9791d77c..6e5101ad3d1 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -492,6 +492,7 @@ void invalidate_interrupt5(void);
void invalidate_interrupt6(void);
void invalidate_interrupt7(void);
void thermal_interrupt(void);
+void threshold_interrupt(void);
void i8254_timer_resume(void);
static void setup_timer_hardware(void)
@@ -515,7 +516,7 @@ void i8254_timer_resume(void)
}
static struct sysdev_class timer_sysclass = {
- set_kset_name("timer"),
+ set_kset_name("timer_pit"),
.resume = timer_resume,
};
@@ -580,6 +581,7 @@ void __init init_IRQ(void)
set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
#endif
set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
+ set_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
#ifdef CONFIG_X86_LOCAL_APIC
/* self generated IPI for local APIC timer */
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index c8eee20cd51..97154ab058b 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -57,7 +57,7 @@ int nr_ioapic_registers[MAX_IO_APICS];
* Rough estimation of how many shared IRQs there are, can
* be changed anytime.
*/
-#define MAX_PLUS_SHARED_IRQS NR_IRQS
+#define MAX_PLUS_SHARED_IRQS NR_IRQ_VECTORS
#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
/*
@@ -85,6 +85,7 @@ int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
int pin; \
struct irq_pin_list *entry = irq_2_pin + irq; \
\
+ BUG_ON(irq >= NR_IRQS); \
for (;;) { \
unsigned int reg; \
pin = entry->pin; \
@@ -127,6 +128,8 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
}
#endif
+static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF };
+
/*
* The common case is 1:1 IRQ<->pin mappings. Sometimes there are
* shared ISA-space IRQs, so we have to support them. We are super
@@ -137,6 +140,7 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
static int first_free_entry = NR_IRQS;
struct irq_pin_list *entry = irq_2_pin + irq;
+ BUG_ON(irq >= NR_IRQS);
while (entry->next)
entry = irq_2_pin + entry->next;
@@ -144,7 +148,7 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
entry->next = first_free_entry;
entry = irq_2_pin + entry->next;
if (++first_free_entry >= PIN_MAP_SIZE)
- panic("io_apic.c: whoops");
+ panic("io_apic.c: ran out of irq_2_pin entries!");
}
entry->apic = apic;
entry->pin = pin;
@@ -420,6 +424,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
best_guess = irq;
}
}
+ BUG_ON(best_guess >= NR_IRQS);
return best_guess;
}
@@ -610,6 +615,64 @@ static inline int irq_trigger(int idx)
return MPBIOS_trigger(idx);
}
+static int next_irq = 16;
+
+/*
+ * gsi_irq_sharing -- Name overload! "irq" can be either a legacy IRQ
+ * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number
+ * from ACPI, which can reach 800 in large boxen.
+ *
+ * Compact the sparse GSI space into a sequential IRQ series and reuse
+ * vectors if possible.
+ */
+int gsi_irq_sharing(int gsi)
+{
+ int i, tries, vector;
+
+ BUG_ON(gsi >= NR_IRQ_VECTORS);
+
+ if (platform_legacy_irq(gsi))
+ return gsi;
+
+ if (gsi_2_irq[gsi] != 0xFF)
+ return (int)gsi_2_irq[gsi];
+
+ tries = NR_IRQS;
+ try_again:
+ vector = assign_irq_vector(gsi);
+
+ /*
+ * Sharing vectors means sharing IRQs, so scan irq_vectors for previous
+ * use of vector and if found, return that IRQ. However, we never want
+ * to share legacy IRQs, which usually have a different trigger mode
+ * than PCI.
+ */
+ for (i = 0; i < NR_IRQS; i++)
+ if (IO_APIC_VECTOR(i) == vector)
+ break;
+ if (platform_legacy_irq(i)) {
+ if (--tries >= 0) {
+ IO_APIC_VECTOR(i) = 0;
+ goto try_again;
+ }
+ panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi);
+ }
+ if (i < NR_IRQS) {
+ gsi_2_irq[gsi] = i;
+ printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n",
+ gsi, vector, i);
+ return i;
+ }
+
+ i = next_irq++;
+ BUG_ON(i >= NR_IRQS);
+ gsi_2_irq[gsi] = i;
+ IO_APIC_VECTOR(i) = vector;
+ printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n",
+ gsi, vector, i);
+ return i;
+}
+
static int pin_2_irq(int idx, int apic, int pin)
{
int irq, i;
@@ -639,6 +702,7 @@ static int pin_2_irq(int idx, int apic, int pin)
while (i < apic)
irq += nr_ioapic_registers[i++];
irq += pin;
+ irq = gsi_irq_sharing(irq);
break;
}
default:
@@ -648,6 +712,7 @@ static int pin_2_irq(int idx, int apic, int pin)
break;
}
}
+ BUG_ON(irq >= NR_IRQS);
/*
* PCI IRQ command line redirection. Yes, limits are hardcoded.
@@ -663,6 +728,7 @@ static int pin_2_irq(int idx, int apic, int pin)
}
}
}
+ BUG_ON(irq >= NR_IRQS);
return irq;
}
@@ -690,8 +756,8 @@ int assign_irq_vector(int irq)
{
static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
- BUG_ON(irq >= NR_IRQ_VECTORS);
- if (IO_APIC_VECTOR(irq) > 0)
+ BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+ if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
return IO_APIC_VECTOR(irq);
next:
current_vector += 8;
@@ -699,9 +765,8 @@ next:
goto next;
if (current_vector >= FIRST_SYSTEM_VECTOR) {
- offset++;
- if (!(offset%8))
- return -ENOSPC;
+ /* If we run out of vectors on large boxen, must share them. */
+ offset = (offset + 1) % 8;
current_vector = FIRST_DEVICE_VECTOR + offset;
}
@@ -1917,6 +1982,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
entry.polarity = active_high_low;
entry.mask = 1; /* Disabled (masked) */
+ irq = gsi_irq_sharing(irq);
/*
* IRQs < 16 are already in the irq_2_pin[] map
*/
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 69541db5ff2..183dc610542 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -37,7 +37,7 @@ static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
static unsigned long console_logged;
static int notify_user;
static int rip_msr;
-static int mce_bootlog;
+static int mce_bootlog = 1;
/*
* Lockless MCE logging infrastructure.
@@ -347,7 +347,11 @@ static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
/* disable GART TBL walk error reporting, which trips off
incorrectly with the IOMMU & 3ware & Cerberus. */
clear_bit(10, &bank[4]);
+ /* Lots of broken BIOS around that don't clear them
+ by default and leave crap in there. Don't log. */
+ mce_bootlog = 0;
}
+
}
static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
@@ -356,6 +360,9 @@ static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
case X86_VENDOR_INTEL:
mce_intel_feature_init(c);
break;
+ case X86_VENDOR_AMD:
+ mce_amd_feature_init(c);
+ break;
default:
break;
}
@@ -495,16 +502,16 @@ static int __init mcheck_disable(char *str)
/* mce=off disables machine check. Note you can reenable it later
using sysfs.
mce=TOLERANCELEVEL (number, see above)
- mce=bootlog Log MCEs from before booting. Disabled by default to work
- around buggy BIOS that leave bogus MCEs. */
+ mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
+ mce=nobootlog Don't log MCEs from before booting. */
static int __init mcheck_enable(char *str)
{
if (*str == '=')
str++;
if (!strcmp(str, "off"))
mce_dont_init = 1;
- else if (!strcmp(str, "bootlog"))
- mce_bootlog = 1;
+ else if (!strcmp(str, "bootlog") || !strcmp(str,"nobootlog"))
+ mce_bootlog = str[0] == 'b';
else if (isdigit(str[0]))
get_option(&str, &tolerant);
else
diff --git a/arch/x86_64/kernel/mce_amd.c b/arch/x86_64/kernel/mce_amd.c
new file mode 100644
index 00000000000..1f76175ace0
--- /dev/null
+++ b/arch/x86_64/kernel/mce_amd.c
@@ -0,0 +1,538 @@
+/*
+ * (c) 2005 Advanced Micro Devices, Inc.
+ * Your use of this code is subject to the terms and conditions of the
+ * GNU general public license version 2. See "COPYING" or
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Written by Jacob Shin - AMD, Inc.
+ *
+ * Support : jacob.shin@amd.com
+ *
+ * MC4_MISC0 DRAM ECC Error Threshold available under AMD K8 Rev F.
+ * MC4_MISC0 exists per physical processor.
+ *
+ */
+
+#include <linux/cpu.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kobject.h>
+#include <linux/notifier.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/sysdev.h>
+#include <linux/sysfs.h>
+#include <asm/apic.h>
+#include <asm/mce.h>
+#include <asm/msr.h>
+#include <asm/percpu.h>
+
+#define PFX "mce_threshold: "
+#define VERSION "version 1.00.9"
+#define NR_BANKS 5
+#define THRESHOLD_MAX 0xFFF
+#define INT_TYPE_APIC 0x00020000
+#define MASK_VALID_HI 0x80000000
+#define MASK_LVTOFF_HI 0x00F00000
+#define MASK_COUNT_EN_HI 0x00080000
+#define MASK_INT_TYPE_HI 0x00060000
+#define MASK_OVERFLOW_HI 0x00010000
+#define MASK_ERR_COUNT_HI 0x00000FFF
+#define MASK_OVERFLOW 0x0001000000000000L
+
+struct threshold_bank {
+ unsigned int cpu;
+ u8 bank;
+ u8 interrupt_enable;
+ u16 threshold_limit;
+ struct kobject kobj;
+};
+
+static struct threshold_bank threshold_defaults = {
+ .interrupt_enable = 0,
+ .threshold_limit = THRESHOLD_MAX,
+};
+
+#ifdef CONFIG_SMP
+static unsigned char shared_bank[NR_BANKS] = {
+ 0, 0, 0, 0, 1
+};
+#endif
+
+static DEFINE_PER_CPU(unsigned char, bank_map); /* see which banks are on */
+
+/*
+ * CPU Initialization
+ */
+
+/* must be called with correct cpu affinity */
+static void threshold_restart_bank(struct threshold_bank *b,
+ int reset, u16 old_limit)
+{
+ u32 mci_misc_hi, mci_misc_lo;
+
+ rdmsr(MSR_IA32_MC0_MISC + b->bank * 4, mci_misc_lo, mci_misc_hi);
+
+ if (b->threshold_limit < (mci_misc_hi & THRESHOLD_MAX))
+ reset = 1; /* limit cannot be lower than err count */
+
+ if (reset) { /* reset err count and overflow bit */
+ mci_misc_hi =
+ (mci_misc_hi & ~(MASK_ERR_COUNT_HI | MASK_OVERFLOW_HI)) |
+ (THRESHOLD_MAX - b->threshold_limit);
+ } else if (old_limit) { /* change limit w/o reset */
+ int new_count = (mci_misc_hi & THRESHOLD_MAX) +
+ (old_limit - b->threshold_limit);
+ mci_misc_hi = (mci_misc_hi & ~MASK_ERR_COUNT_HI) |
+ (new_count & THRESHOLD_MAX);
+ }
+
+ b->interrupt_enable ?
+ (mci_misc_hi = (mci_misc_hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) :
+ (mci_misc_hi &= ~MASK_INT_TYPE_HI);
+
+ mci_misc_hi |= MASK_COUNT_EN_HI;
+ wrmsr(MSR_IA32_MC0_MISC + b->bank * 4, mci_misc_lo, mci_misc_hi);
+}
+
+void __cpuinit mce_amd_feature_init(struct cpuinfo_x86 *c)
+{
+ int bank;
+ u32 mci_misc_lo, mci_misc_hi;
+ unsigned int cpu = smp_processor_id();
+
+ for (bank = 0; bank < NR_BANKS; ++bank) {
+ rdmsr(MSR_IA32_MC0_MISC + bank * 4, mci_misc_lo, mci_misc_hi);
+
+ /* !valid, !counter present, bios locked */
+ if (!(mci_misc_hi & MASK_VALID_HI) ||
+ !(mci_misc_hi & MASK_VALID_HI >> 1) ||
+ (mci_misc_hi & MASK_VALID_HI >> 2))
+ continue;
+
+ per_cpu(bank_map, cpu) |= (1 << bank);
+
+#ifdef CONFIG_SMP
+ if (shared_bank[bank] && cpu_core_id[cpu])
+ continue;
+#endif
+
+ setup_threshold_lvt((mci_misc_hi & MASK_LVTOFF_HI) >> 20);
+ threshold_defaults.cpu = cpu;
+ threshold_defaults.bank = bank;
+ threshold_restart_bank(&threshold_defaults, 0, 0);
+ }
+}
+
+/*
+ * APIC Interrupt Handler
+ */
+
+/*
+ * threshold interrupt handler will service THRESHOLD_APIC_VECTOR.
+ * the interrupt goes off when error_count reaches threshold_limit.
+ * the handler will simply log mcelog w/ software defined bank number.
+ */
+asmlinkage void mce_threshold_interrupt(void)
+{
+ int bank;
+ struct mce m;
+
+ ack_APIC_irq();
+ irq_enter();
+
+ memset(&m, 0, sizeof(m));
+ rdtscll(m.tsc);
+ m.cpu = smp_processor_id();
+
+ /* assume first bank caused it */
+ for (bank = 0; bank < NR_BANKS; ++bank) {
+ m.bank = MCE_THRESHOLD_BASE + bank;
+ rdmsrl(MSR_IA32_MC0_MISC + bank * 4, m.misc);
+
+ if (m.misc & MASK_OVERFLOW) {
+ mce_log(&m);
+ goto out;
+ }
+ }
+ out:
+ irq_exit();
+}
+
+/*
+ * Sysfs Interface
+ */
+
+static struct sysdev_class threshold_sysclass = {
+ set_kset_name("threshold"),
+};
+
+static DEFINE_PER_CPU(struct sys_device, device_threshold);
+
+struct threshold_attr {
+ struct attribute attr;
+ ssize_t(*show) (struct threshold_bank *, char *);
+ ssize_t(*store) (struct threshold_bank *, const char *, size_t count);
+};
+
+static DEFINE_PER_CPU(struct threshold_bank *, threshold_banks[NR_BANKS]);
+
+static cpumask_t affinity_set(unsigned int cpu)
+{
+ cpumask_t oldmask = current->cpus_allowed;
+ cpumask_t newmask = CPU_MASK_NONE;
+ cpu_set(cpu, newmask);
+ set_cpus_allowed(current, newmask);
+ return oldmask;
+}
+
+static void affinity_restore(cpumask_t oldmask)
+{
+ set_cpus_allowed(current, oldmask);
+}
+
+#define SHOW_FIELDS(name) \
+ static ssize_t show_ ## name(struct threshold_bank * b, char *buf) \
+ { \
+ return sprintf(buf, "%lx\n", (unsigned long) b->name); \
+ }
+SHOW_FIELDS(interrupt_enable)
+SHOW_FIELDS(threshold_limit)
+
+static ssize_t store_interrupt_enable(struct threshold_bank *b,
+ const char *buf, size_t count)
+{
+ char *end;
+ cpumask_t oldmask;
+ unsigned long new = simple_strtoul(buf, &end, 0);
+ if (end == buf)
+ return -EINVAL;
+ b->interrupt_enable = !!new;
+
+ oldmask = affinity_set(b->cpu);
+ threshold_restart_bank(b, 0, 0);
+ affinity_restore(oldmask);
+
+ return end - buf;
+}
+
+static ssize_t store_threshold_limit(struct threshold_bank *b,
+ const char *buf, size_t count)
+{
+ char *end;
+ cpumask_t oldmask;
+ u16 old;
+ unsigned long new = simple_strtoul(buf, &end, 0);
+ if (end == buf)
+ return -EINVAL;
+ if (new > THRESHOLD_MAX)
+ new = THRESHOLD_MAX;
+ if (new < 1)
+ new = 1;
+ old = b->threshold_limit;
+ b->threshold_limit = new;
+
+ oldmask = affinity_set(b->cpu);
+ threshold_restart_bank(b, 0, old);
+ affinity_restore(oldmask);
+
+ return end - buf;
+}
+
+static ssize_t show_error_count(struct threshold_bank *b, char *buf)
+{
+ u32 high, low;
+ cpumask_t oldmask;
+ oldmask = affinity_set(b->cpu);
+ rdmsr(MSR_IA32_MC0_MISC + b->bank * 4, low, high); /* ignore low 32 */
+ affinity_restore(oldmask);
+ return sprintf(buf, "%x\n",
+ (high & 0xFFF) - (THRESHOLD_MAX - b->threshold_limit));
+}
+
+static ssize_t store_error_count(struct threshold_bank *b,
+ const char *buf, size_t count)
+{
+ cpumask_t oldmask;
+ oldmask = affinity_set(b->cpu);
+ threshold_restart_bank(b, 1, 0);
+ affinity_restore(oldmask);
+ return 1;
+}
+
+#define THRESHOLD_ATTR(_name,_mode,_show,_store) { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+#define ATTR_FIELDS(name) \
+ static struct threshold_attr name = \
+ THRESHOLD_ATTR(name, 0644, show_## name, store_## name)
+
+ATTR_FIELDS(interrupt_enable);
+ATTR_FIELDS(threshold_limit);
+ATTR_FIELDS(error_count);
+
+static struct attribute *default_attrs[] = {
+ &interrupt_enable.attr,
+ &threshold_limit.attr,
+ &error_count.attr,
+ NULL
+};
+
+#define to_bank(k) container_of(k,struct threshold_bank,kobj)
+#define to_attr(a) container_of(a,struct threshold_attr,attr)
+
+static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct threshold_bank *b = to_bank(kobj);
+ struct threshold_attr *a = to_attr(attr);
+ ssize_t ret;
+ ret = a->show ? a->show(b, buf) : -EIO;
+ return ret;
+}
+
+static ssize_t store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct threshold_bank *b = to_bank(kobj);
+ struct threshold_attr *a = to_attr(attr);
+ ssize_t ret;
+ ret = a->store ? a->store(b, buf, count) : -EIO;
+ return ret;
+}
+
+static struct sysfs_ops threshold_ops = {
+ .show = show,
+ .store = store,
+};
+
+static struct kobj_type threshold_ktype = {
+ .sysfs_ops = &threshold_ops,
+ .default_attrs = default_attrs,
+};
+
+/* symlinks sibling shared banks to first core. first core owns dir/files. */
+static __cpuinit int threshold_create_bank(unsigned int cpu, int bank)
+{
+ int err = 0;
+ struct threshold_bank *b = 0;
+
+#ifdef CONFIG_SMP
+ if (cpu_core_id[cpu] && shared_bank[bank]) { /* symlink */
+ char name[16];
+ unsigned lcpu = first_cpu(cpu_core_map[cpu]);
+ if (cpu_core_id[lcpu])
+ goto out; /* first core not up yet */
+
+ b = per_cpu(threshold_banks, lcpu)[bank];
+ if (!b)
+ goto out;
+ sprintf(name, "bank%i", bank);
+ err = sysfs_create_link(&per_cpu(device_threshold, cpu).kobj,
+ &b->kobj, name);
+ if (err)
+ goto out;
+ per_cpu(threshold_banks, cpu)[bank] = b;
+ goto out;
+ }
+#endif
+
+ b = kmalloc(sizeof(struct threshold_bank), GFP_KERNEL);
+ if (!b) {
+ err = -ENOMEM;
+ goto out;
+ }
+ memset(b, 0, sizeof(struct threshold_bank));
+
+ b->cpu = cpu;
+ b->bank = bank;
+ b->interrupt_enable = 0;
+ b->threshold_limit = THRESHOLD_MAX;
+ kobject_set_name(&b->kobj, "bank%i", bank);
+ b->kobj.parent = &per_cpu(device_threshold, cpu).kobj;
+ b->kobj.ktype = &threshold_ktype;
+
+ err = kobject_register(&b->kobj);
+ if (err) {
+ kfree(b);
+ goto out;
+ }
+ per_cpu(threshold_banks, cpu)[bank] = b;
+ out:
+ return err;
+}
+
+/* create dir/files for all valid threshold banks */
+static __cpuinit int threshold_create_device(unsigned int cpu)
+{
+ int bank;
+ int err = 0;
+
+ per_cpu(device_threshold, cpu).id = cpu;
+ per_cpu(device_threshold, cpu).cls = &threshold_sysclass;
+ err = sysdev_register(&per_cpu(device_threshold, cpu));
+ if (err)
+ goto out;
+
+ for (bank = 0; bank < NR_BANKS; ++bank) {
+ if (!(per_cpu(bank_map, cpu) & 1 << bank))
+ continue;
+ err = threshold_create_bank(cpu, bank);
+ if (err)
+ goto out;
+ }
+ out:
+ return err;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * let's be hotplug friendly.
+ * in case of multiple core processors, the first core always takes ownership
+ * of shared sysfs dir/files, and rest of the cores will be symlinked to it.
+ */
+
+/* cpu hotplug call removes all symlinks before first core dies */
+static __cpuinit void threshold_remove_bank(unsigned int cpu, int bank)
+{
+ struct threshold_bank *b;
+ char name[16];
+
+ b = per_cpu(threshold_banks, cpu)[bank];
+ if (!b)
+ return;
+ if (shared_bank[bank] && atomic_read(&b->kobj.kref.refcount) > 2) {
+ sprintf(name, "bank%i", bank);
+ sysfs_remove_link(&per_cpu(device_threshold, cpu).kobj, name);
+ per_cpu(threshold_banks, cpu)[bank] = 0;
+ } else {
+ kobject_unregister(&b->kobj);
+ kfree(per_cpu(threshold_banks, cpu)[bank]);
+ }
+}
+
+static __cpuinit void threshold_remove_device(unsigned int cpu)
+{
+ int bank;
+
+ for (bank = 0; bank < NR_BANKS; ++bank) {
+ if (!(per_cpu(bank_map, cpu) & 1 << bank))
+ continue;
+ threshold_remove_bank(cpu, bank);
+ }
+ sysdev_unregister(&per_cpu(device_threshold, cpu));
+}
+
+/* link all existing siblings when first core comes up */
+static __cpuinit int threshold_create_symlinks(unsigned int cpu)
+{
+ int bank, err = 0;
+ unsigned int lcpu = 0;
+
+ if (cpu_core_id[cpu])
+ return 0;
+ for_each_cpu_mask(lcpu, cpu_core_map[cpu]) {
+ if (lcpu == cpu)
+ continue;
+ for (bank = 0; bank < NR_BANKS; ++bank) {
+ if (!(per_cpu(bank_map, cpu) & 1 << bank))
+ continue;
+ if (!shared_bank[bank])
+ continue;
+ err = threshold_create_bank(lcpu, bank);
+ }
+ }
+ return err;
+}
+
+/* remove all symlinks before first core dies. */
+static __cpuinit void threshold_remove_symlinks(unsigned int cpu)
+{
+ int bank;
+ unsigned int lcpu = 0;
+ if (cpu_core_id[cpu])
+ return;
+ for_each_cpu_mask(lcpu, cpu_core_map[cpu]) {
+ if (lcpu == cpu)
+ continue;
+ for (bank = 0; bank < NR_BANKS; ++bank) {
+ if (!(per_cpu(bank_map, cpu) & 1 << bank))
+ continue;
+ if (!shared_bank[bank])
+ continue;
+ threshold_remove_bank(lcpu, bank);
+ }
+ }
+}
+#else /* !CONFIG_HOTPLUG_CPU */
+static __cpuinit void threshold_create_symlinks(unsigned int cpu)
+{
+}
+static __cpuinit void threshold_remove_symlinks(unsigned int cpu)
+{
+}
+static void threshold_remove_device(unsigned int cpu)
+{
+}
+#endif
+
+/* get notified when a cpu comes on/off */
+static __cpuinit int threshold_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ /* cpu was unsigned int to begin with */
+ unsigned int cpu = (unsigned long)hcpu;
+
+ if (cpu >= NR_CPUS)
+ goto out;
+
+ switch (action) {
+ case CPU_ONLINE:
+ threshold_create_device(cpu);
+ threshold_create_symlinks(cpu);
+ break;
+ case CPU_DOWN_PREPARE:
+ threshold_remove_symlinks(cpu);
+ break;
+ case CPU_DOWN_FAILED:
+ threshold_create_symlinks(cpu);
+ break;
+ case CPU_DEAD:
+ threshold_remove_device(cpu);
+ break;
+ default:
+ break;
+ }
+ out:
+ return NOTIFY_OK;
+}
+
+static struct notifier_block threshold_cpu_notifier = {
+ .notifier_call = threshold_cpu_callback,
+};
+
+static __init int threshold_init_device(void)
+{
+ int err;
+ int lcpu = 0;
+
+ err = sysdev_class_register(&threshold_sysclass);
+ if (err)
+ goto out;
+
+ /* to hit CPUs online before the notifier is up */
+ for_each_online_cpu(lcpu) {
+ err = threshold_create_device(lcpu);
+ if (err)
+ goto out;
+ }
+ register_cpu_notifier(&threshold_cpu_notifier);
+
+ out:
+ return err;
+}
+
+device_initcall(threshold_init_device);
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index f16d38d09da..1105250bf02 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -42,7 +42,7 @@ int acpi_found_madt;
* Various Linux-internal data structures created from the
* MP-table.
*/
-int apic_version [MAX_APICS];
+unsigned char apic_version [MAX_APICS];
unsigned char mp_bus_id_to_type [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
@@ -65,7 +65,9 @@ unsigned long mp_lapic_addr = 0;
/* Processor that is doing the boot up */
unsigned int boot_cpu_id = -1U;
/* Internal processor count */
-static unsigned int num_processors = 0;
+unsigned int num_processors __initdata = 0;
+
+unsigned disabled_cpus __initdata;
/* Bitmask of physically existing CPUs */
physid_mask_t phys_cpu_present_map = PHYSID_MASK_NONE;
@@ -106,11 +108,14 @@ static int __init mpf_checksum(unsigned char *mp, int len)
static void __init MP_processor_info (struct mpc_config_processor *m)
{
- int ver, cpu;
+ int cpu;
+ unsigned char ver;
static int found_bsp=0;
- if (!(m->mpc_cpuflag & CPU_ENABLED))
+ if (!(m->mpc_cpuflag & CPU_ENABLED)) {
+ disabled_cpus++;
return;
+ }
printk(KERN_INFO "Processor #%d %d:%d APIC version %d\n",
m->mpc_apicid,
@@ -129,12 +134,14 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
}
cpu = num_processors++;
-
- if (m->mpc_apicid > MAX_APICS) {
+
+#if MAX_APICS < 255
+ if ((int)m->mpc_apicid > MAX_APICS) {
printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
m->mpc_apicid, MAX_APICS);
return;
}
+#endif
ver = m->mpc_apicver;
physid_set(m->mpc_apicid, phys_cpu_present_map);
@@ -218,7 +225,7 @@ static void __init MP_intsrc_info (struct mpc_config_intsrc *m)
m->mpc_irqtype, m->mpc_irqflag & 3,
(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
- if (++mp_irq_entries == MAX_IRQ_SOURCES)
+ if (++mp_irq_entries >= MAX_IRQ_SOURCES)
panic("Max # of irq sources exceeded!!\n");
}
@@ -549,7 +556,7 @@ void __init get_smp_config (void)
* Read the physical hardware table. Anything here will
* override the defaults.
*/
- if (!smp_read_mpc((void *)(unsigned long)mpf->mpf_physptr)) {
+ if (!smp_read_mpc(phys_to_virt(mpf->mpf_physptr))) {
smp_found_config = 0;
printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index 88be97c9698..2e28e855ec3 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -220,6 +220,12 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
uses the normal dma_mask for alloc_coherent. */
dma_mask &= *dev->dma_mask;
+ /* Why <=? Even when the mask is smaller than 4GB it is often larger
+ than 16MB and in this case we have a chance of finding fitting memory
+ in the next higher zone first. If not retry with true GFP_DMA. -AK */
+ if (dma_mask <= 0xffffffff)
+ gfp |= GFP_DMA32;
+
again:
memory = dma_alloc_pages(dev, gfp, get_order(size));
if (memory == NULL)
@@ -245,7 +251,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
}
if (!(gfp & GFP_DMA)) {
- gfp |= GFP_DMA;
+ gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
goto again;
}
return NULL;
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 59be85d9a4b..5afd63e8cef 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -144,7 +144,8 @@ void cpu_idle_wait(void)
do {
ssleep(1);
for_each_online_cpu(cpu) {
- if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu))
+ if (cpu_isset(cpu, map) &&
+ !per_cpu(cpu_idle_state, cpu))
cpu_clear(cpu, map);
}
cpus_and(map, map, cpu_online_map);
@@ -275,7 +276,8 @@ void __show_regs(struct pt_regs * regs)
system_utsname.version);
printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
printk_address(regs->rip);
- printk("\nRSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
+ printk("\nRSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp,
+ regs->eflags);
printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
regs->rax, regs->rbx, regs->rcx);
printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
@@ -427,15 +429,14 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp,
struct pt_regs * childregs;
struct task_struct *me = current;
- childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
-
+ childregs = ((struct pt_regs *)
+ (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
*childregs = *regs;
childregs->rax = 0;
childregs->rsp = rsp;
- if (rsp == ~0UL) {
+ if (rsp == ~0UL)
childregs->rsp = (unsigned long)childregs;
- }
p->thread.rsp = (unsigned long) childregs;
p->thread.rsp0 = (unsigned long) (childregs+1);
@@ -457,7 +458,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp,
p->thread.io_bitmap_max = 0;
return -ENOMEM;
}
- memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr, IO_BITMAP_BYTES);
+ memcpy(p->thread.io_bitmap_ptr, me->thread.io_bitmap_ptr,
+ IO_BITMAP_BYTES);
}
/*
@@ -494,7 +496,8 @@ out:
* - fold all the options into a flag word and test it with a single test.
* - could test fs/gs bitsliced
*/
-struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
+struct task_struct *
+__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{
struct thread_struct *prev = &prev_p->thread,
*next = &next_p->thread;
@@ -565,7 +568,8 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *
prev->userrsp = read_pda(oldrsp);
write_pda(oldrsp, next->userrsp);
write_pda(pcurrent, next_p);
- write_pda(kernelstack, (unsigned long)next_p->thread_info + THREAD_SIZE - PDA_STACKOFFSET);
+ write_pda(kernelstack,
+ (unsigned long)next_p->thread_info + THREAD_SIZE - PDA_STACKOFFSET);
/*
* Now maybe reload the debug registers
@@ -646,7 +650,9 @@ asmlinkage long sys_fork(struct pt_regs *regs)
return do_fork(SIGCHLD, regs->rsp, regs, 0, NULL, NULL);
}
-asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void __user *parent_tid, void __user *child_tid, struct pt_regs *regs)
+asmlinkage long
+sys_clone(unsigned long clone_flags, unsigned long newsp,
+ void __user *parent_tid, void __user *child_tid, struct pt_regs *regs)
{
if (!newsp)
newsp = regs->rsp;
@@ -682,7 +688,8 @@ unsigned long get_wchan(struct task_struct *p)
return 0;
fp = *(u64 *)(p->thread.rsp);
do {
- if (fp < (unsigned long)stack || fp > (unsigned long)stack+THREAD_SIZE)
+ if (fp < (unsigned long)stack ||
+ fp > (unsigned long)stack+THREAD_SIZE)
return 0;
rip = *(u64 *)(fp+8);
if (!in_sched_functions(rip))
@@ -717,8 +724,8 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
task->thread.gsindex = 0;
task->thread.gs = addr;
if (doit) {
- load_gs_index(0);
- ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr);
+ load_gs_index(0);
+ ret = checking_wrmsrl(MSR_KERNEL_GS_BASE, addr);
}
}
put_cpu();
@@ -735,7 +742,7 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
set_32bit_tls(task, FS_TLS, addr);
if (doit) {
load_TLS(&task->thread, cpu);
- asm volatile("movl %0,%%fs" :: "r" (FS_TLS_SEL));
+ asm volatile("movl %0,%%fs" :: "r"(FS_TLS_SEL));
}
task->thread.fsindex = FS_TLS_SEL;
task->thread.fs = 0;
@@ -745,8 +752,8 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
if (doit) {
/* set the selector to 0 to not confuse
__switch_to */
- asm volatile("movl %0,%%fs" :: "r" (0));
- ret = checking_wrmsrl(MSR_FS_BASE, addr);
+ asm volatile("movl %0,%%fs" :: "r" (0));
+ ret = checking_wrmsrl(MSR_FS_BASE, addr);
}
}
put_cpu();
@@ -755,9 +762,9 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
unsigned long base;
if (task->thread.fsindex == FS_TLS_SEL)
base = read_32bit_tls(task, FS_TLS);
- else if (doit) {
+ else if (doit)
rdmsrl(MSR_FS_BASE, base);
- } else
+ else
base = task->thread.fs;
ret = put_user(base, (unsigned long __user *)addr);
break;
@@ -766,9 +773,9 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
unsigned long base;
if (task->thread.gsindex == GS_TLS_SEL)
base = read_32bit_tls(task, GS_TLS);
- else if (doit) {
+ else if (doit)
rdmsrl(MSR_KERNEL_GS_BASE, base);
- } else
+ else
base = task->thread.gs;
ret = put_user(base, (unsigned long __user *)addr);
break;
diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
index 47f95687905..75235ed2b31 100644
--- a/arch/x86_64/kernel/reboot.c
+++ b/arch/x86_64/kernel/reboot.c
@@ -77,6 +77,7 @@ static inline void kb_wait(void)
void machine_shutdown(void)
{
+ unsigned long flags;
/* Stop the cpus and apics */
#ifdef CONFIG_SMP
int reboot_cpu_id;
@@ -98,7 +99,7 @@ void machine_shutdown(void)
smp_send_stop();
#endif
- local_irq_disable();
+ local_irq_save(flags);
#ifndef CONFIG_SMP
disable_local_APIC();
@@ -106,7 +107,7 @@ void machine_shutdown(void)
disable_IO_APIC();
- local_irq_enable();
+ local_irq_restore(flags);
}
void machine_emergency_restart(void)
@@ -120,7 +121,7 @@ void machine_emergency_restart(void)
/* Could also try the reset bit in the Hammer NB */
switch (reboot_type) {
case BOOT_KBD:
- for (i=0; i<100; i++) {
+ for (i=0; i<10; i++) {
kb_wait();
udelay(50);
outb(0xfe,0x64); /* pulse reset low */
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index da0bc3e7bdf..750e01dcbdf 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -60,6 +60,7 @@
#include <asm/setup.h>
#include <asm/mach_apic.h>
#include <asm/numa.h>
+#include <asm/sections.h>
/*
* Machine setup..
@@ -103,7 +104,6 @@ struct edid_info edid_info;
struct e820map e820;
extern int root_mountflags;
-extern char _text, _etext, _edata, _end;
char command_line[COMMAND_LINE_SIZE];
@@ -412,7 +412,6 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
{
unsigned long bootmap_size, bootmap;
- memory_present(0, start_pfn, end_pfn);
bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
if (bootmap == -1L)
@@ -571,6 +570,8 @@ void __init setup_arch(char **cmdline_p)
init_memory_mapping(0, (end_pfn_map << PAGE_SHIFT));
+ zap_low_mappings(0);
+
#ifdef CONFIG_ACPI
/*
* Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
@@ -657,8 +658,6 @@ void __init setup_arch(char **cmdline_p)
}
#endif
- sparse_init();
-
paging_init();
check_ioapic();
@@ -793,7 +792,7 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
#endif
bits = 0;
- while ((1 << bits) < c->x86_num_cores)
+ while ((1 << bits) < c->x86_max_cores)
bits++;
/* Low order bits define the core id (index of core in socket) */
@@ -823,10 +822,10 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
if (!node_online(node))
node = nearby_node(apicid);
}
- cpu_to_node[cpu] = node;
+ numa_set_node(cpu, node);
printk(KERN_INFO "CPU %d(%d) -> Node %d -> Core %d\n",
- cpu, c->x86_num_cores, node, cpu_core_id[cpu]);
+ cpu, c->x86_max_cores, node, cpu_core_id[cpu]);
#endif
#endif
}
@@ -875,9 +874,9 @@ static int __init init_amd(struct cpuinfo_x86 *c)
display_cacheinfo(c);
if (c->extended_cpuid_level >= 0x80000008) {
- c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
- if (c->x86_num_cores & (c->x86_num_cores - 1))
- c->x86_num_cores = 1;
+ c->x86_max_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
+ if (c->x86_max_cores & (c->x86_max_cores - 1))
+ c->x86_max_cores = 1;
amd_detect_cmp(c);
}
@@ -889,54 +888,44 @@ static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_SMP
u32 eax, ebx, ecx, edx;
- int index_msb, tmp;
+ int index_msb, core_bits;
int cpu = smp_processor_id();
-
+
+ cpuid(1, &eax, &ebx, &ecx, &edx);
+
+ c->apicid = phys_pkg_id(0);
+
if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY))
return;
- cpuid(1, &eax, &ebx, &ecx, &edx);
smp_num_siblings = (ebx & 0xff0000) >> 16;
-
+
if (smp_num_siblings == 1) {
printk(KERN_INFO "CPU: Hyper-Threading is disabled\n");
- } else if (smp_num_siblings > 1) {
- index_msb = 31;
- /*
- * At this point we only support two siblings per
- * processor package.
- */
+ } else if (smp_num_siblings > 1 ) {
+
if (smp_num_siblings > NR_CPUS) {
printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
smp_num_siblings = 1;
return;
}
- tmp = smp_num_siblings;
- while ((tmp & 0x80000000 ) == 0) {
- tmp <<=1 ;
- index_msb--;
- }
- if (smp_num_siblings & (smp_num_siblings - 1))
- index_msb++;
+
+ index_msb = get_count_order(smp_num_siblings);
phys_proc_id[cpu] = phys_pkg_id(index_msb);
-
+
printk(KERN_INFO "CPU: Physical Processor ID: %d\n",
phys_proc_id[cpu]);
- smp_num_siblings = smp_num_siblings / c->x86_num_cores;
+ smp_num_siblings = smp_num_siblings / c->x86_max_cores;
- tmp = smp_num_siblings;
- index_msb = 31;
- while ((tmp & 0x80000000) == 0) {
- tmp <<=1 ;
- index_msb--;
- }
- if (smp_num_siblings & (smp_num_siblings - 1))
- index_msb++;
+ index_msb = get_count_order(smp_num_siblings) ;
- cpu_core_id[cpu] = phys_pkg_id(index_msb);
+ core_bits = get_count_order(c->x86_max_cores);
- if (c->x86_num_cores > 1)
+ cpu_core_id[cpu] = phys_pkg_id(index_msb) &
+ ((1 << core_bits) - 1);
+
+ if (c->x86_max_cores > 1)
printk(KERN_INFO "CPU: Processor Core ID: %d\n",
cpu_core_id[cpu]);
}
@@ -975,7 +964,7 @@ static void srat_detect_node(void)
node = apicid_to_node[hard_smp_processor_id()];
if (node == NUMA_NO_NODE)
node = 0;
- cpu_to_node[cpu] = node;
+ numa_set_node(cpu, node);
if (acpi_numa > 0)
printk(KERN_INFO "CPU %d -> Node %d\n", cpu, node);
@@ -993,13 +982,18 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
unsigned eax = cpuid_eax(0x80000008);
c->x86_virt_bits = (eax >> 8) & 0xff;
c->x86_phys_bits = eax & 0xff;
+ /* CPUID workaround for Intel 0F34 CPU */
+ if (c->x86_vendor == X86_VENDOR_INTEL &&
+ c->x86 == 0xF && c->x86_model == 0x3 &&
+ c->x86_mask == 0x4)
+ c->x86_phys_bits = 36;
}
if (c->x86 == 15)
c->x86_cache_alignment = c->x86_clflush_size * 2;
if (c->x86 >= 15)
set_bit(X86_FEATURE_CONSTANT_TSC, &c->x86_capability);
- c->x86_num_cores = intel_num_cpu_cores(c);
+ c->x86_max_cores = intel_num_cpu_cores(c);
srat_detect_node();
}
@@ -1037,7 +1031,7 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
c->x86_model_id[0] = '\0'; /* Unset */
c->x86_clflush_size = 64;
c->x86_cache_alignment = c->x86_clflush_size;
- c->x86_num_cores = 1;
+ c->x86_max_cores = 1;
c->extended_cpuid_level = 0;
memset(&c->x86_capability, 0, sizeof c->x86_capability);
@@ -1060,10 +1054,10 @@ void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
c->x86 = (tfms >> 8) & 0xf;
c->x86_model = (tfms >> 4) & 0xf;
c->x86_mask = tfms & 0xf;
- if (c->x86 == 0xf) {
+ if (c->x86 == 0xf)
c->x86 += (tfms >> 20) & 0xff;
+ if (c->x86 >= 0x6)
c->x86_model += ((tfms >> 16) & 0xF) << 4;
- }
if (c->x86_capability[0] & (1<<19))
c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
} else {
@@ -1271,13 +1265,12 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
#ifdef CONFIG_SMP
- if (smp_num_siblings * c->x86_num_cores > 1) {
+ if (smp_num_siblings * c->x86_max_cores > 1) {
int cpu = c - cpu_data;
seq_printf(m, "physical id\t: %d\n", phys_proc_id[cpu]);
- seq_printf(m, "siblings\t: %d\n",
- c->x86_num_cores * smp_num_siblings);
+ seq_printf(m, "siblings\t: %d\n", cpus_weight(cpu_core_map[cpu]));
seq_printf(m, "core id\t\t: %d\n", cpu_core_id[cpu]);
- seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores);
+ seq_printf(m, "cpu cores\t: %d\n", c->booted_cores);
}
#endif
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index 79190891fbc..06dc354375c 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -141,7 +141,6 @@ void pda_init(int cpu)
panic("cannot allocate irqstack for cpu %d", cpu);
}
- asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
pda->irqstackptr += IRQSTACKSIZE-64;
}
@@ -197,6 +196,7 @@ void __cpuinit cpu_init (void)
/* CPU 0 is initialised in head64.c */
if (cpu != 0) {
pda_init(cpu);
+ zap_low_mappings(cpu);
} else
estacks = boot_exception_stacks;
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index d642fbf3da2..5876df116c9 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -110,6 +110,15 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, unsigned
COPY(r14);
COPY(r15);
+ /* Kernel saves and restores only the CS segment register on signals,
+ * which is the bare minimum needed to allow mixed 32/64-bit code.
+ * App's signal handler can save/restore other segments if needed. */
+ {
+ unsigned cs;
+ err |= __get_user(cs, &sc->cs);
+ regs->cs = cs | 3; /* Force into user mode */
+ }
+
{
unsigned int tmpflags;
err |= __get_user(tmpflags, &sc->eflags);
@@ -187,6 +196,7 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned lo
{
int err = 0;
+ err |= __put_user(regs->cs, &sc->cs);
err |= __put_user(0, &sc->gs);
err |= __put_user(0, &sc->fs);
@@ -318,7 +328,14 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->rsp = (unsigned long)frame;
+ /* Set up the CS register to run signal handlers in 64-bit mode,
+ even if the handler happens to be interrupting 32-bit code. */
+ regs->cs = __USER_CS;
+
+ /* This, by contrast, has nothing to do with segment registers -
+ see include/asm-x86_64/uaccess.h for details. */
set_fs(USER_DS);
+
regs->eflags &= ~TF_MASK;
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index 9db9dda161b..cfc3d9dccbd 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -28,8 +28,6 @@
#include <asm/proto.h>
#include <asm/apicdef.h>
-#define __cpuinit __init
-
/*
* Smarter SMP flushing macros.
* c/o Linus Torvalds.
@@ -452,13 +450,14 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
void smp_stop_cpu(void)
{
+ unsigned long flags;
/*
* Remove this CPU:
*/
cpu_clear(smp_processor_id(), cpu_online_map);
- local_irq_disable();
+ local_irq_save(flags);
disable_local_APIC();
- local_irq_enable();
+ local_irq_restore(flags);
}
static void smp_really_stop_cpu(void *dummy)
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index c4e59bbdc18..683c33f7b96 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -64,6 +64,7 @@
int smp_num_siblings = 1;
/* Package ID of each logical CPU */
u8 phys_proc_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
+/* core ID of each logical CPU */
u8 cpu_core_id[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
/* Bitmask of currently online CPUs */
@@ -87,7 +88,10 @@ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
/* Set when the idlers are all forked */
int smp_threads_ready;
+/* representing HT siblings of each logical CPU */
cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
+
+/* representing HT and core siblings of each logical CPU */
cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_core_map);
@@ -434,30 +438,59 @@ void __cpuinit smp_callin(void)
cpu_set(cpuid, cpu_callin_map);
}
+/* representing cpus for which sibling maps can be computed */
+static cpumask_t cpu_sibling_setup_map;
+
static inline void set_cpu_sibling_map(int cpu)
{
int i;
+ struct cpuinfo_x86 *c = cpu_data;
+
+ cpu_set(cpu, cpu_sibling_setup_map);
if (smp_num_siblings > 1) {
- for_each_cpu(i) {
- if (cpu_core_id[cpu] == cpu_core_id[i]) {
+ for_each_cpu_mask(i, cpu_sibling_setup_map) {
+ if (phys_proc_id[cpu] == phys_proc_id[i] &&
+ cpu_core_id[cpu] == cpu_core_id[i]) {
cpu_set(i, cpu_sibling_map[cpu]);
cpu_set(cpu, cpu_sibling_map[i]);
+ cpu_set(i, cpu_core_map[cpu]);
+ cpu_set(cpu, cpu_core_map[i]);
}
}
} else {
cpu_set(cpu, cpu_sibling_map[cpu]);
}
- if (current_cpu_data.x86_num_cores > 1) {
- for_each_cpu(i) {
- if (phys_proc_id[cpu] == phys_proc_id[i]) {
- cpu_set(i, cpu_core_map[cpu]);
- cpu_set(cpu, cpu_core_map[i]);
- }
- }
- } else {
+ if (current_cpu_data.x86_max_cores == 1) {
cpu_core_map[cpu] = cpu_sibling_map[cpu];
+ c[cpu].booted_cores = 1;
+ return;
+ }
+
+ for_each_cpu_mask(i, cpu_sibling_setup_map) {
+ if (phys_proc_id[cpu] == phys_proc_id[i]) {
+ cpu_set(i, cpu_core_map[cpu]);
+ cpu_set(cpu, cpu_core_map[i]);
+ /*
+ * Does this new cpu bringup a new core?
+ */
+ if (cpus_weight(cpu_sibling_map[cpu]) == 1) {
+ /*
+ * for each core in package, increment
+ * the booted_cores for this new cpu
+ */
+ if (first_cpu(cpu_sibling_map[i]) == i)
+ c[cpu].booted_cores++;
+ /*
+ * increment the core count for all
+ * the other cpus in this package
+ */
+ if (i != cpu)
+ c[i].booted_cores++;
+ } else if (i != cpu && !c[cpu].booted_cores)
+ c[cpu].booted_cores = c[i].booted_cores;
+ }
}
}
@@ -879,6 +912,9 @@ static __init void disable_smp(void)
}
#ifdef CONFIG_HOTPLUG_CPU
+
+int additional_cpus __initdata = -1;
+
/*
* cpu_possible_map should be static, it cannot change as cpu's
* are onlined, or offlined. The reason is per-cpu data-structures
@@ -887,14 +923,38 @@ static __init void disable_smp(void)
* cpu_present_map on the other hand can change dynamically.
* In case when cpu_hotplug is not compiled, then we resort to current
* behaviour, which is cpu_possible == cpu_present.
- * If cpu-hotplug is supported, then we need to preallocate for all
- * those NR_CPUS, hence cpu_possible_map represents entire NR_CPUS range.
* - Ashok Raj
+ *
+ * Three ways to find out the number of additional hotplug CPUs:
+ * - If the BIOS specified disabled CPUs in ACPI/mptables use that.
+ * - otherwise use half of the available CPUs or 2, whatever is more.
+ * - The user can overwrite it with additional_cpus=NUM
+ * We do this because additional CPUs waste a lot of memory.
+ * -AK
*/
__init void prefill_possible_map(void)
{
int i;
- for (i = 0; i < NR_CPUS; i++)
+ int possible;
+
+ if (additional_cpus == -1) {
+ if (disabled_cpus > 0) {
+ additional_cpus = disabled_cpus;
+ } else {
+ additional_cpus = num_processors / 2;
+ if (additional_cpus == 0)
+ additional_cpus = 2;
+ }
+ }
+ possible = num_processors + additional_cpus;
+ if (possible > NR_CPUS)
+ possible = NR_CPUS;
+
+ printk(KERN_INFO "SMP: Allowing %d CPUs, %d hotplug CPUs\n",
+ possible,
+ max_t(int, possible - num_processors, 0));
+
+ for (i = 0; i < possible; i++)
cpu_set(i, cpu_possible_map);
}
#endif
@@ -965,6 +1025,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
nmi_watchdog_default();
current_cpu_data = boot_cpu_data;
current_thread_info()->cpu = 0; /* needed? */
+ set_cpu_sibling_map(0);
if (smp_sanity_check(max_cpus) < 0) {
printk(KERN_INFO "SMP disabled\n");
@@ -1008,8 +1069,6 @@ void __init smp_prepare_boot_cpu(void)
int me = smp_processor_id();
cpu_set(me, cpu_online_map);
cpu_set(me, cpu_callout_map);
- cpu_set(0, cpu_sibling_map[0]);
- cpu_set(0, cpu_core_map[0]);
per_cpu(cpu_state, me) = CPU_ONLINE;
}
@@ -1062,9 +1121,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
*/
void __init smp_cpus_done(unsigned int max_cpus)
{
-#ifndef CONFIG_HOTPLUG_CPU
- zap_low_mappings();
-#endif
smp_cleanup_boot();
#ifdef CONFIG_X86_IO_APIC
@@ -1081,15 +1137,24 @@ void __init smp_cpus_done(unsigned int max_cpus)
static void remove_siblinginfo(int cpu)
{
int sibling;
+ struct cpuinfo_x86 *c = cpu_data;
+ for_each_cpu_mask(sibling, cpu_core_map[cpu]) {
+ cpu_clear(cpu, cpu_core_map[sibling]);
+ /*
+ * last thread sibling in this cpu core going down
+ */
+ if (cpus_weight(cpu_sibling_map[cpu]) == 1)
+ c[sibling].booted_cores--;
+ }
+
for_each_cpu_mask(sibling, cpu_sibling_map[cpu])
cpu_clear(cpu, cpu_sibling_map[sibling]);
- for_each_cpu_mask(sibling, cpu_core_map[cpu])
- cpu_clear(cpu, cpu_core_map[sibling]);
cpus_clear(cpu_sibling_map[cpu]);
cpus_clear(cpu_core_map[cpu]);
phys_proc_id[cpu] = BAD_APICID;
cpu_core_id[cpu] = BAD_APICID;
+ cpu_clear(cpu, cpu_sibling_setup_map);
}
void remove_cpu_from_maps(void)
@@ -1153,6 +1218,12 @@ void __cpu_die(unsigned int cpu)
printk(KERN_ERR "CPU %u didn't die...\n", cpu);
}
+static __init int setup_additional_cpus(char *s)
+{
+ return get_option(&s, &additional_cpus);
+}
+__setup("additional_cpus=", setup_additional_cpus);
+
#else /* ... !CONFIG_HOTPLUG_CPU */
int __cpu_disable(void)
diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c
index cc7821c6885..6449ea8fe75 100644
--- a/arch/x86_64/kernel/sys_x86_64.c
+++ b/arch/x86_64/kernel/sys_x86_64.c
@@ -154,17 +154,3 @@ asmlinkage long sys_uname(struct new_utsname __user * name)
err |= copy_to_user(&name->machine, "i686", 5);
return err ? -EFAULT : 0;
}
-
-asmlinkage long sys_time64(long __user * tloc)
-{
- struct timeval now;
- int i;
-
- do_gettimeofday(&now);
- i = now.tv_sec;
- if (tloc) {
- if (put_user(i,tloc))
- i = -EFAULT;
- }
- return i;
-}
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index b5e09e6b553..bf337f49318 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -428,19 +428,6 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
{
conditional_sti(regs);
-#ifdef CONFIG_CHECKING
- {
- unsigned long gs;
- struct x8664_pda *pda = cpu_pda + safe_smp_processor_id();
- rdmsrl(MSR_GS_BASE, gs);
- if (gs != (unsigned long)pda) {
- wrmsrl(MSR_GS_BASE, pda);
- printk("%s: wrong gs %lx expected %p rip %lx\n", str, gs, pda,
- regs->rip);
- }
- }
-#endif
-
if (user_mode(regs)) {
struct task_struct *tsk = current;
@@ -513,20 +500,6 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
{
conditional_sti(regs);
-#ifdef CONFIG_CHECKING
- {
- unsigned long gs;
- struct x8664_pda *pda = cpu_pda + safe_smp_processor_id();
- rdmsrl(MSR_GS_BASE, gs);
- if (gs != (unsigned long)pda) {
- wrmsrl(MSR_GS_BASE, pda);
- oops_in_progress++;
- printk("general protection handler: wrong gs %lx expected %p\n", gs, pda);
- oops_in_progress--;
- }
- }
-#endif
-
if (user_mode(regs)) {
struct task_struct *tsk = current;
@@ -665,19 +638,6 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs,
struct task_struct *tsk = current;
siginfo_t info;
-#ifdef CONFIG_CHECKING
- {
- /* RED-PEN interaction with debugger - could destroy gs */
- unsigned long gs;
- struct x8664_pda *pda = cpu_pda + safe_smp_processor_id();
- rdmsrl(MSR_GS_BASE, gs);
- if (gs != (unsigned long)pda) {
- wrmsrl(MSR_GS_BASE, pda);
- printk("debug handler: wrong gs %lx expected %p\n", gs, pda);
- }
- }
-#endif
-
get_debugreg(condition, 6);
if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
@@ -888,6 +848,10 @@ asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
{
}
+asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
+{
+}
+
/*
* 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 6dd642cad2e..58b19215b4b 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -50,7 +50,7 @@ SECTIONS
*(.bss.page_aligned)
*(.bss)
}
- __bss_end = .;
+ __bss_stop = .;
. = ALIGN(PAGE_SIZE);
. = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
index fd99ddd009b..4a54221e10b 100644
--- a/arch/x86_64/kernel/x8664_ksyms.c
+++ b/arch/x86_64/kernel/x8664_ksyms.c
@@ -203,3 +203,6 @@ EXPORT_SYMBOL(flush_tlb_page);
#endif
EXPORT_SYMBOL(cpu_khz);
+
+EXPORT_SYMBOL(load_gs_index);
+
diff --git a/arch/x86_64/lib/clear_page.S b/arch/x86_64/lib/clear_page.S
index 30a9da458c1..43d9fa13618 100644
--- a/arch/x86_64/lib/clear_page.S
+++ b/arch/x86_64/lib/clear_page.S
@@ -5,46 +5,8 @@
.globl clear_page
.p2align 4
clear_page:
- xorl %eax,%eax
- movl $4096/64,%ecx
- .p2align 4
-.Lloop:
- decl %ecx
-#define PUT(x) movq %rax,x*8(%rdi)
- movq %rax,(%rdi)
- PUT(1)
- PUT(2)
- PUT(3)
- PUT(4)
- PUT(5)
- PUT(6)
- PUT(7)
- leaq 64(%rdi),%rdi
- jnz .Lloop
- nop
- ret
-clear_page_end:
-
- /* C stepping K8 run faster using the string instructions.
- It is also a lot simpler. Use this when possible */
-
-#include <asm/cpufeature.h>
-
- .section .altinstructions,"a"
- .align 8
- .quad clear_page
- .quad clear_page_c
- .byte X86_FEATURE_K8_C
- .byte clear_page_end-clear_page
- .byte clear_page_c_end-clear_page_c
- .previous
-
- .section .altinstr_replacement,"ax"
-clear_page_c:
movl $4096/8,%ecx
xorl %eax,%eax
rep
stosq
ret
-clear_page_c_end:
- .previous
diff --git a/arch/x86_64/lib/copy_page.S b/arch/x86_64/lib/copy_page.S
index dd3aa47b6bf..621a1976940 100644
--- a/arch/x86_64/lib/copy_page.S
+++ b/arch/x86_64/lib/copy_page.S
@@ -8,94 +8,7 @@
.globl copy_page
.p2align 4
copy_page:
- subq $3*8,%rsp
- movq %rbx,(%rsp)
- movq %r12,1*8(%rsp)
- movq %r13,2*8(%rsp)
-
- movl $(4096/64)-5,%ecx
- .p2align 4
-.Loop64:
- dec %rcx
-
- movq (%rsi), %rax
- movq 8 (%rsi), %rbx
- movq 16 (%rsi), %rdx
- movq 24 (%rsi), %r8
- movq 32 (%rsi), %r9
- movq 40 (%rsi), %r10
- movq 48 (%rsi), %r11
- movq 56 (%rsi), %r12
-
- prefetcht0 5*64(%rsi)
-
- movq %rax, (%rdi)
- movq %rbx, 8 (%rdi)
- movq %rdx, 16 (%rdi)
- movq %r8, 24 (%rdi)
- movq %r9, 32 (%rdi)
- movq %r10, 40 (%rdi)
- movq %r11, 48 (%rdi)
- movq %r12, 56 (%rdi)
-
- leaq 64 (%rsi), %rsi
- leaq 64 (%rdi), %rdi
-
- jnz .Loop64
-
- movl $5,%ecx
- .p2align 4
-.Loop2:
- decl %ecx
-
- movq (%rsi), %rax
- movq 8 (%rsi), %rbx
- movq 16 (%rsi), %rdx
- movq 24 (%rsi), %r8
- movq 32 (%rsi), %r9
- movq 40 (%rsi), %r10
- movq 48 (%rsi), %r11
- movq 56 (%rsi), %r12
-
- movq %rax, (%rdi)
- movq %rbx, 8 (%rdi)
- movq %rdx, 16 (%rdi)
- movq %r8, 24 (%rdi)
- movq %r9, 32 (%rdi)
- movq %r10, 40 (%rdi)
- movq %r11, 48 (%rdi)
- movq %r12, 56 (%rdi)
-
- leaq 64(%rdi),%rdi
- leaq 64(%rsi),%rsi
-
- jnz .Loop2
-
- movq (%rsp),%rbx
- movq 1*8(%rsp),%r12
- movq 2*8(%rsp),%r13
- addq $3*8,%rsp
- ret
-
- /* C stepping K8 run faster using the string copy instructions.
- It is also a lot simpler. Use this when possible */
-
-#include <asm/cpufeature.h>
-
- .section .altinstructions,"a"
- .align 8
- .quad copy_page
- .quad copy_page_c
- .byte X86_FEATURE_K8_C
- .byte copy_page_c_end-copy_page_c
- .byte copy_page_c_end-copy_page_c
- .previous
-
- .section .altinstr_replacement,"ax"
-copy_page_c:
movl $4096/8,%ecx
rep
movsq
ret
-copy_page_c_end:
- .previous
diff --git a/arch/x86_64/lib/memcpy.S b/arch/x86_64/lib/memcpy.S
index c6c46494fef..92dd8054460 100644
--- a/arch/x86_64/lib/memcpy.S
+++ b/arch/x86_64/lib/memcpy.S
@@ -11,6 +11,8 @@
*
* Output:
* rax original destination
+ *
+ * TODO: check best memcpy for PSC
*/
.globl __memcpy
@@ -18,95 +20,6 @@
.p2align 4
__memcpy:
memcpy:
- pushq %rbx
- movq %rdi,%rax
-
- movl %edx,%ecx
- shrl $6,%ecx
- jz .Lhandle_tail
-
- .p2align 4
-.Lloop_64:
- decl %ecx
-
- movq (%rsi),%r11
- movq 8(%rsi),%r8
-
- movq %r11,(%rdi)
- movq %r8,1*8(%rdi)
-
- movq 2*8(%rsi),%r9
- movq 3*8(%rsi),%r10
-
- movq %r9,2*8(%rdi)
- movq %r10,3*8(%rdi)
-
- movq 4*8(%rsi),%r11
- movq 5*8(%rsi),%r8
-
- movq %r11,4*8(%rdi)
- movq %r8,5*8(%rdi)
-
- movq 6*8(%rsi),%r9
- movq 7*8(%rsi),%r10
-
- movq %r9,6*8(%rdi)
- movq %r10,7*8(%rdi)
-
- leaq 64(%rsi),%rsi
- leaq 64(%rdi),%rdi
- jnz .Lloop_64
-
-.Lhandle_tail:
- movl %edx,%ecx
- andl $63,%ecx
- shrl $3,%ecx
- jz .Lhandle_7
- .p2align 4
-.Lloop_8:
- decl %ecx
- movq (%rsi),%r8
- movq %r8,(%rdi)
- leaq 8(%rdi),%rdi
- leaq 8(%rsi),%rsi
- jnz .Lloop_8
-
-.Lhandle_7:
- movl %edx,%ecx
- andl $7,%ecx
- jz .Lende
- .p2align 4
-.Lloop_1:
- movb (%rsi),%r8b
- movb %r8b,(%rdi)
- incq %rdi
- incq %rsi
- decl %ecx
- jnz .Lloop_1
-
-.Lende:
- popq %rbx
- ret
-.Lfinal:
-
- /* C stepping K8 run faster using the string copy instructions.
- It is also a lot simpler. Use this when possible */
-
- .section .altinstructions,"a"
- .align 8
- .quad memcpy
- .quad memcpy_c
- .byte X86_FEATURE_K8_C
- .byte .Lfinal-memcpy
- .byte memcpy_c_end-memcpy_c
- .previous
-
- .section .altinstr_replacement,"ax"
- /* rdi destination
- * rsi source
- * rdx count
- */
-memcpy_c:
movq %rdi,%rax
movl %edx,%ecx
shrl $3,%ecx
@@ -117,5 +30,3 @@ memcpy_c:
rep
movsb
ret
-memcpy_c_end:
- .previous
diff --git a/arch/x86_64/lib/memset.S b/arch/x86_64/lib/memset.S
index 4b4c4063864..2aa48f24ed1 100644
--- a/arch/x86_64/lib/memset.S
+++ b/arch/x86_64/lib/memset.S
@@ -13,98 +13,6 @@
.p2align 4
memset:
__memset:
- movq %rdi,%r10
- movq %rdx,%r11
-
- /* expand byte value */
- movzbl %sil,%ecx
- movabs $0x0101010101010101,%rax
- mul %rcx /* with rax, clobbers rdx */
-
- /* align dst */
- movl %edi,%r9d
- andl $7,%r9d
- jnz .Lbad_alignment
-.Lafter_bad_alignment:
-
- movl %r11d,%ecx
- shrl $6,%ecx
- jz .Lhandle_tail
-
- .p2align 4
-.Lloop_64:
- decl %ecx
- movq %rax,(%rdi)
- movq %rax,8(%rdi)
- movq %rax,16(%rdi)
- movq %rax,24(%rdi)
- movq %rax,32(%rdi)
- movq %rax,40(%rdi)
- movq %rax,48(%rdi)
- movq %rax,56(%rdi)
- leaq 64(%rdi),%rdi
- jnz .Lloop_64
-
- /* Handle tail in loops. The loops should be faster than hard
- to predict jump tables. */
- .p2align 4
-.Lhandle_tail:
- movl %r11d,%ecx
- andl $63&(~7),%ecx
- jz .Lhandle_7
- shrl $3,%ecx
- .p2align 4
-.Lloop_8:
- decl %ecx
- movq %rax,(%rdi)
- leaq 8(%rdi),%rdi
- jnz .Lloop_8
-
-.Lhandle_7:
- movl %r11d,%ecx
- andl $7,%ecx
- jz .Lende
- .p2align 4
-.Lloop_1:
- decl %ecx
- movb %al,(%rdi)
- leaq 1(%rdi),%rdi
- jnz .Lloop_1
-
-.Lende:
- movq %r10,%rax
- ret
-
-.Lbad_alignment:
- cmpq $7,%r11
- jbe .Lhandle_7
- movq %rax,(%rdi) /* unaligned store */
- movq $8,%r8
- subq %r9,%r8
- addq %r8,%rdi
- subq %r8,%r11
- jmp .Lafter_bad_alignment
-
- /* C stepping K8 run faster using the string instructions.
- It is also a lot simpler. Use this when possible */
-
-#include <asm/cpufeature.h>
-
- .section .altinstructions,"a"
- .align 8
- .quad memset
- .quad memset_c
- .byte X86_FEATURE_K8_C
- .byte memset_c_end-memset_c
- .byte memset_c_end-memset_c
- .previous
-
- .section .altinstr_replacement,"ax"
- /* rdi destination
- * rsi value
- * rdx count
- */
-memset_c:
movq %rdi,%r9
movl %edx,%r8d
andl $7,%r8d
@@ -121,5 +29,3 @@ memset_c:
stosb
movq %r9,%rax
ret
-memset_c_end:
- .previous
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index b75b872ec15..3a63707a698 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -308,18 +308,6 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
unsigned long flags;
siginfo_t info;
-#ifdef CONFIG_CHECKING
- {
- unsigned long gs;
- struct x8664_pda *pda = cpu_pda + stack_smp_processor_id();
- rdmsrl(MSR_GS_BASE, gs);
- if (gs != (unsigned long)pda) {
- wrmsrl(MSR_GS_BASE, pda);
- printk("page_fault: wrong gs %lx expected %p\n", gs, pda);
- }
- }
-#endif
-
/* get the address */
__asm__("movq %%cr2,%0":"=r" (address));
if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
@@ -571,3 +559,10 @@ do_sigbus:
force_sig_info(SIGBUS, &info, tsk);
return;
}
+
+static int __init enable_pagefaulttrace(char *str)
+{
+ page_fault_trace = 1;
+ return 0;
+}
+__setup("pagefaulttrace", enable_pagefaulttrace);
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index e60a1a848de..286f6a624c3 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -22,6 +22,7 @@
#include <linux/pagemap.h>
#include <linux/bootmem.h>
#include <linux/proc_fs.h>
+#include <linux/pci.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -36,16 +37,13 @@
#include <asm/mmu_context.h>
#include <asm/proto.h>
#include <asm/smp.h>
+#include <asm/sections.h>
#ifndef Dprintk
#define Dprintk(x...)
#endif
-#ifdef CONFIG_GART_IOMMU
-extern int swiotlb;
-#endif
-
-extern char _stext[];
+static unsigned long dma_reserve __initdata;
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -86,9 +84,6 @@ void show_mem(void)
/* References to section boundaries */
-extern char _text, _etext, _edata, __bss_start, _end[];
-extern char __init_begin, __init_end;
-
int after_bootmem;
static void *spp_getpage(void)
@@ -308,42 +303,81 @@ void __init init_memory_mapping(unsigned long start, unsigned long end)
table_end<<PAGE_SHIFT);
}
-extern struct x8664_pda cpu_pda[NR_CPUS];
+void __cpuinit zap_low_mappings(int cpu)
+{
+ if (cpu == 0) {
+ pgd_t *pgd = pgd_offset_k(0UL);
+ pgd_clear(pgd);
+ } else {
+ /*
+ * For AP's, zap the low identity mappings by changing the cr3
+ * to init_level4_pgt and doing local flush tlb all
+ */
+ asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
+ }
+ __flush_tlb_all();
+}
-/* Assumes all CPUs still execute in init_mm */
-void zap_low_mappings(void)
+/* Compute zone sizes for the DMA and DMA32 zones in a node. */
+__init void
+size_zones(unsigned long *z, unsigned long *h,
+ unsigned long start_pfn, unsigned long end_pfn)
{
- pgd_t *pgd = pgd_offset_k(0UL);
- pgd_clear(pgd);
- flush_tlb_all();
+ int i;
+ unsigned long w;
+
+ for (i = 0; i < MAX_NR_ZONES; i++)
+ z[i] = 0;
+
+ if (start_pfn < MAX_DMA_PFN)
+ z[ZONE_DMA] = MAX_DMA_PFN - start_pfn;
+ if (start_pfn < MAX_DMA32_PFN) {
+ unsigned long dma32_pfn = MAX_DMA32_PFN;
+ if (dma32_pfn > end_pfn)
+ dma32_pfn = end_pfn;
+ z[ZONE_DMA32] = dma32_pfn - start_pfn;
+ }
+ z[ZONE_NORMAL] = end_pfn - start_pfn;
+
+ /* Remove lower zones from higher ones. */
+ w = 0;
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+ if (z[i])
+ z[i] -= w;
+ w += z[i];
+ }
+
+ /* Compute holes */
+ w = 0;
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+ unsigned long s = w;
+ w += z[i];
+ h[i] = e820_hole_size(s, w);
+ }
+
+ /* Add the space pace needed for mem_map to the holes too. */
+ for (i = 0; i < MAX_NR_ZONES; i++)
+ h[i] += (z[i] * sizeof(struct page)) / PAGE_SIZE;
+
+ /* The 16MB DMA zone has the kernel and other misc mappings.
+ Account them too */
+ if (h[ZONE_DMA]) {
+ h[ZONE_DMA] += dma_reserve;
+ if (h[ZONE_DMA] >= z[ZONE_DMA]) {
+ printk(KERN_WARNING
+ "Kernel too large and filling up ZONE_DMA?\n");
+ h[ZONE_DMA] = z[ZONE_DMA];
+ }
+ }
}
#ifndef CONFIG_NUMA
void __init paging_init(void)
{
- {
- unsigned long zones_size[MAX_NR_ZONES];
- unsigned long holes[MAX_NR_ZONES];
- unsigned int max_dma;
-
- memset(zones_size, 0, sizeof(zones_size));
- memset(holes, 0, sizeof(holes));
-
- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-
- if (end_pfn < max_dma) {
- zones_size[ZONE_DMA] = end_pfn;
- holes[ZONE_DMA] = e820_hole_size(0, end_pfn);
- } else {
- zones_size[ZONE_DMA] = max_dma;
- holes[ZONE_DMA] = e820_hole_size(0, max_dma);
- zones_size[ZONE_NORMAL] = end_pfn - max_dma;
- holes[ZONE_NORMAL] = e820_hole_size(max_dma, end_pfn);
- }
- free_area_init_node(0, NODE_DATA(0), zones_size,
- __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes);
- }
- return;
+ unsigned long zones[MAX_NR_ZONES], holes[MAX_NR_ZONES];
+ size_zones(zones, holes, 0, end_pfn);
+ free_area_init_node(0, NODE_DATA(0), zones,
+ __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes);
}
#endif
@@ -438,19 +472,16 @@ void __init mem_init(void)
datasize >> 10,
initsize >> 10);
+#ifdef CONFIG_SMP
/*
- * Subtle. SMP is doing its boot stuff late (because it has to
- * fork idle threads) - but it also needs low mappings for the
- * protected-mode entry to work. We zap these entries only after
- * the WP-bit has been tested.
+ * Sync boot_level4_pgt mappings with the init_level4_pgt
+ * except for the low identity mappings which are already zapped
+ * in init_level4_pgt. This sync-up is essential for AP's bringup
*/
-#ifndef CONFIG_SMP
- zap_low_mappings();
+ memcpy(boot_level4_pgt+1, init_level4_pgt+1, (PTRS_PER_PGD-1)*sizeof(pgd_t));
#endif
}
-extern char __initdata_begin[], __initdata_end[];
-
void free_initmem(void)
{
unsigned long addr;
@@ -464,7 +495,7 @@ void free_initmem(void)
totalram_pages++;
}
memset(__initdata_begin, 0xba, __initdata_end - __initdata_begin);
- printk ("Freeing unused kernel memory: %luk freed\n", (&__init_end - &__init_begin) >> 10);
+ printk ("Freeing unused kernel memory: %luk freed\n", (__init_end - __init_begin) >> 10);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -491,6 +522,8 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
#else
reserve_bootmem(phys, len);
#endif
+ if (phys+len <= MAX_DMA_PFN*PAGE_SIZE)
+ dma_reserve += len / PAGE_SIZE;
}
int kern_addr_valid(unsigned long addr)
@@ -532,10 +565,6 @@ extern int exception_trace, page_fault_trace;
static ctl_table debug_table2[] = {
{ 99, "exception-trace", &exception_trace, sizeof(int), 0644, NULL,
proc_dointvec },
-#ifdef CONFIG_CHECKING
- { 100, "page-fault-trace", &page_fault_trace, sizeof(int), 0644, NULL,
- proc_dointvec },
-#endif
{ 0, }
};
diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c
index 65417b040c1..a5663e0bb01 100644
--- a/arch/x86_64/mm/k8topology.c
+++ b/arch/x86_64/mm/k8topology.c
@@ -108,6 +108,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
limit >>= 16;
limit <<= 24;
limit |= (1<<24)-1;
+ limit++;
if (limit > end_pfn << PAGE_SHIFT)
limit = end_pfn << PAGE_SHIFT;
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 21480382100..a828a01739c 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -38,38 +38,57 @@ cpumask_t node_to_cpumask[MAX_NUMNODES] __read_mostly;
int numa_off __initdata;
-int __init compute_hash_shift(struct node *nodes, int numnodes)
+
+/*
+ * Given a shift value, try to populate memnodemap[]
+ * Returns :
+ * 1 if OK
+ * 0 if memnodmap[] too small (of shift too small)
+ * -1 if node overlap or lost ram (shift too big)
+ */
+static int __init populate_memnodemap(
+ const struct node *nodes, int numnodes, int shift)
{
int i;
- int shift = 20;
- unsigned long addr,maxend=0;
-
- for (i = 0; i < numnodes; i++)
- if ((nodes[i].start != nodes[i].end) && (nodes[i].end > maxend))
- maxend = nodes[i].end;
+ int res = -1;
+ unsigned long addr, end;
- while ((1UL << shift) < (maxend / NODEMAPSIZE))
- shift++;
-
- printk (KERN_DEBUG"Using %d for the hash shift. Max adder is %lx \n",
- shift,maxend);
- memset(memnodemap,0xff,sizeof(*memnodemap) * NODEMAPSIZE);
+ memset(memnodemap, 0xff, sizeof(memnodemap));
for (i = 0; i < numnodes; i++) {
- if (nodes[i].start == nodes[i].end)
+ addr = nodes[i].start;
+ end = nodes[i].end;
+ if (addr >= end)
continue;
- for (addr = nodes[i].start;
- addr < nodes[i].end;
- addr += (1UL << shift)) {
- if (memnodemap[addr >> shift] != 0xff) {
- printk(KERN_INFO
- "Your memory is not aligned you need to rebuild your kernel "
- "with a bigger NODEMAPSIZE shift=%d adder=%lu\n",
- shift,addr);
+ if ((end >> shift) >= NODEMAPSIZE)
+ return 0;
+ do {
+ if (memnodemap[addr >> shift] != 0xff)
return -1;
- }
memnodemap[addr >> shift] = i;
- }
+ addr += (1 << shift);
+ } while (addr < end);
+ res = 1;
}
+ return res;
+}
+
+int __init compute_hash_shift(struct node *nodes, int numnodes)
+{
+ int shift = 20;
+
+ while (populate_memnodemap(nodes, numnodes, shift + 1) >= 0)
+ shift++;
+
+ printk(KERN_DEBUG "Using %d for the hash shift.\n",
+ shift);
+
+ if (populate_memnodemap(nodes, numnodes, shift) != 1) {
+ printk(KERN_INFO
+ "Your memory is not aligned you need to rebuild your kernel "
+ "with a bigger NODEMAPSIZE shift=%d\n",
+ shift);
+ return -1;
+ }
return shift;
}
@@ -94,7 +113,6 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
start_pfn = start >> PAGE_SHIFT;
end_pfn = end >> PAGE_SHIFT;
- memory_present(nodeid, start_pfn, end_pfn);
nodedata_phys = find_e820_area(start, end, pgdat_size);
if (nodedata_phys == -1L)
panic("Cannot find memory pgdat in node %d\n", nodeid);
@@ -132,29 +150,14 @@ void __init setup_node_zones(int nodeid)
unsigned long start_pfn, end_pfn;
unsigned long zones[MAX_NR_ZONES];
unsigned long holes[MAX_NR_ZONES];
- unsigned long dma_end_pfn;
- memset(zones, 0, sizeof(unsigned long) * MAX_NR_ZONES);
- memset(holes, 0, sizeof(unsigned long) * MAX_NR_ZONES);
+ start_pfn = node_start_pfn(nodeid);
+ end_pfn = node_end_pfn(nodeid);
- start_pfn = node_start_pfn(nodeid);
- end_pfn = node_end_pfn(nodeid);
+ Dprintk(KERN_INFO "setting up node %d %lx-%lx\n",
+ nodeid, start_pfn, end_pfn);
- Dprintk(KERN_INFO "setting up node %d %lx-%lx\n", nodeid, start_pfn, end_pfn);
-
- /* All nodes > 0 have a zero length zone DMA */
- dma_end_pfn = __pa(MAX_DMA_ADDRESS) >> PAGE_SHIFT;
- if (start_pfn < dma_end_pfn) {
- zones[ZONE_DMA] = dma_end_pfn - start_pfn;
- holes[ZONE_DMA] = e820_hole_size(start_pfn, dma_end_pfn);
- zones[ZONE_NORMAL] = end_pfn - dma_end_pfn;
- holes[ZONE_NORMAL] = e820_hole_size(dma_end_pfn, end_pfn);
-
- } else {
- zones[ZONE_NORMAL] = end_pfn - start_pfn;
- holes[ZONE_NORMAL] = e820_hole_size(start_pfn, end_pfn);
- }
-
+ size_zones(zones, holes, start_pfn, end_pfn);
free_area_init_node(nodeid, NODE_DATA(nodeid), zones,
start_pfn, holes);
}
@@ -171,7 +174,7 @@ void __init numa_init_array(void)
for (i = 0; i < NR_CPUS; i++) {
if (cpu_to_node[i] != NUMA_NO_NODE)
continue;
- cpu_to_node[i] = rr;
+ numa_set_node(i, rr);
rr = next_node(rr, node_online_map);
if (rr == MAX_NUMNODES)
rr = first_node(node_online_map);
@@ -205,8 +208,6 @@ static int numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
if (i == numa_fake-1)
sz = (end_pfn<<PAGE_SHIFT) - nodes[i].start;
nodes[i].end = nodes[i].start + sz;
- if (i != numa_fake-1)
- nodes[i].end--;
printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n",
i,
nodes[i].start, nodes[i].end,
@@ -257,7 +258,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
nodes_clear(node_online_map);
node_set_online(0);
for (i = 0; i < NR_CPUS; i++)
- cpu_to_node[i] = 0;
+ numa_set_node(i, 0);
node_to_cpumask[0] = cpumask_of_cpu(0);
setup_node_bootmem(0, start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
}
@@ -267,6 +268,12 @@ __cpuinit void numa_add_cpu(int cpu)
set_bit(cpu, &node_to_cpumask[cpu_to_node(cpu)]);
}
+void __cpuinit numa_set_node(int cpu, int node)
+{
+ cpu_pda[cpu].nodenumber = node;
+ cpu_to_node[cpu] = node;
+}
+
unsigned long __init numa_free_all_bootmem(void)
{
int i;
@@ -277,9 +284,26 @@ unsigned long __init numa_free_all_bootmem(void)
return pages;
}
+#ifdef CONFIG_SPARSEMEM
+static void __init arch_sparse_init(void)
+{
+ int i;
+
+ for_each_online_node(i)
+ memory_present(i, node_start_pfn(i), node_end_pfn(i));
+
+ sparse_init();
+}
+#else
+#define arch_sparse_init() do {} while (0)
+#endif
+
void __init paging_init(void)
{
int i;
+
+ arch_sparse_init();
+
for_each_online_node(i) {
setup_node_zones(i);
}
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 4b2e844c15a..33340bd1e32 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -71,8 +71,6 @@ static __init void cutoff_node(int i, unsigned long start, unsigned long end)
nd->start = nd->end;
}
if (nd->end > end) {
- if (!(end & 0xfff))
- end--;
nd->end = end;
if (nd->start > nd->end)
nd->start = nd->end;
@@ -166,8 +164,6 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
if (nd->end < end)
nd->end = end;
}
- if (!(nd->end & 0xfff))
- nd->end--;
printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm,
nd->start, nd->end);
}
@@ -203,7 +199,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
if (cpu_to_node[i] == NUMA_NO_NODE)
continue;
if (!node_isset(cpu_to_node[i], nodes_parsed))
- cpu_to_node[i] = NUMA_NO_NODE;
+ numa_set_node(i, NUMA_NO_NODE);
}
numa_init_array();
return 0;
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 6a4da417c16..606f8733a77 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -28,6 +28,7 @@
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/device.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_X86
@@ -754,7 +755,7 @@ static int __init acpi_init(void)
result = acpi_bus_init();
if (!result) {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
if (!PM_IS_ACTIVE())
pm_active = 1;
else {
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 98f6c02d679..59dacb6552c 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -526,18 +526,23 @@ request_firmware_work_func(void *arg)
{
struct firmware_work *fw_work = arg;
const struct firmware *fw;
+ int ret;
if (!arg) {
WARN_ON(1);
return 0;
}
daemonize("%s/%s", "firmware", fw_work->name);
- _request_firmware(&fw, fw_work->name, fw_work->device,
+ ret = _request_firmware(&fw, fw_work->name, fw_work->device,
fw_work->hotplug);
- fw_work->cont(fw, fw_work->context);
- release_firmware(fw);
+ if (ret < 0)
+ fw_work->cont(NULL, fw_work->context);
+ else {
+ fw_work->cont(fw, fw_work->context);
+ release_firmware(fw);
+ }
module_put(fw_work->module);
kfree(fw_work);
- return 0;
+ return ret;
}
/**
@@ -586,6 +591,8 @@ request_firmware_nowait(
if (ret < 0) {
fw_work->cont(NULL, fw_work->context);
+ module_put(fw_work->module);
+ kfree(fw_work);
return ret;
}
return 0;
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 3226aa11c6e..2942d32280a 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -255,7 +255,7 @@ scsi_cmd_stack_free(int ctlr)
#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
"Unknown" : scsi_device_types[n]
-#if 1
+#if 0
static int xmargin=8;
static int amargin=60;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 59e5982a5db..c0233efabeb 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -1188,7 +1188,7 @@ static void pkt_count_states(struct pktcdvd_device *pd, int *states)
struct packet_data *pkt;
int i;
- for (i = 0; i <= PACKET_NUM_STATES; i++)
+ for (i = 0; i < PACKET_NUM_STATES; i++)
states[i] = 0;
spin_lock(&pd->cdrw.active_list_lock);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index fdf4370db99..970f70d498f 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -735,7 +735,7 @@ config SGI_IP27_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !PPC64 && !M32R && !SPARC32 && !SPARC64
+ depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC32 && !SPARC64
---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
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 78ce98a69f3..76589782adc 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -57,9 +57,8 @@ static int nr_garts;
static struct pci_dev * hammers[MAX_HAMMER_GARTS];
static struct resource *aperture_resource;
-static int __initdata agp_try_unsupported;
+static int __initdata agp_try_unsupported = 1;
-static int gart_iterator;
#define for_each_nb() for(gart_iterator=0;gart_iterator<nr_garts;gart_iterator++)
static void flush_amd64_tlb(struct pci_dev *dev)
@@ -73,6 +72,7 @@ static void flush_amd64_tlb(struct pci_dev *dev)
static void amd64_tlbflush(struct agp_memory *temp)
{
+ int gart_iterator;
for_each_nb()
flush_amd64_tlb(hammers[gart_iterator]);
}
@@ -222,6 +222,7 @@ static struct aper_size_info_32 amd_8151_sizes[7] =
static int amd_8151_configure(void)
{
unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real);
+ int gart_iterator;
/* Configure AGP regs in each x86-64 host bridge. */
for_each_nb() {
@@ -235,7 +236,7 @@ static int amd_8151_configure(void)
static void amd64_cleanup(void)
{
u32 tmp;
-
+ int gart_iterator;
for_each_nb() {
/* disable gart translation */
pci_read_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, &tmp);
@@ -697,6 +698,16 @@ static struct pci_device_id agp_amd64_pci_table[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
+ /* ALI/ULI M1695 */
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_AL,
+ .device = 0x1689,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+
{ }
};
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index c8255312b8c..50947e38501 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -557,6 +557,10 @@ static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = {
.device_id = PCI_DEVICE_ID_APPLE_U3H_AGP,
.chipset_name = "U3H",
},
+ {
+ .device_id = PCI_DEVICE_ID_APPLE_IPID2_AGP,
+ .chipset_name = "UniNorth/Intrepid2",
+ },
};
static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index d16bd4b5c11..6b302a930e5 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -48,7 +48,7 @@
#define PFX "IPMI message handler: "
-#define IPMI_DRIVER_VERSION "36.0"
+#define IPMI_DRIVER_VERSION "38.0"
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig
index d22bfdc1356..27c1179ee52 100644
--- a/drivers/char/pcmcia/Kconfig
+++ b/drivers/char/pcmcia/Kconfig
@@ -18,5 +18,29 @@ config SYNCLINK_CS
The module will be called synclinkmp. If you want to do that, say M
here.
+config CARDMAN_4000
+ tristate "Omnikey Cardman 4000 support"
+ depends on PCMCIA
+ help
+ Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard
+ reader.
+
+ This kernel driver requires additional userspace support, either
+ by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/),
+ or via the cm4000 backend of OpenCT (http://www.opensc.com/).
+
+config CARDMAN_4040
+ tristate "Omnikey CardMan 4040 support"
+ depends on PCMCIA
+ help
+ Enable support for the Omnikey CardMan 4040 PCMCIA Smartcard
+ reader.
+
+ This card is basically a USB CCID device connected to a FIFO
+ in I/O space. To use the kernel driver, you will need either the
+ PC/SC ifdhandler provided from the Omnikey homepage
+ (http://www.omnikey.com/), or a current development version of OpenCT
+ (http://www.opensc.org/).
+
endmenu
diff --git a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile
index 1fcd4c59195..0aae20985d5 100644
--- a/drivers/char/pcmcia/Makefile
+++ b/drivers/char/pcmcia/Makefile
@@ -5,3 +5,5 @@
#
obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o
+obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o
+obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
new file mode 100644
index 00000000000..ef011ef5dc4
--- /dev/null
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -0,0 +1,2078 @@
+ /*
+ * A driver for the PCMCIA Smartcard Reader "Omnikey CardMan Mobile 4000"
+ *
+ * cm4000_cs.c support.linux@omnikey.com
+ *
+ * Tue Oct 23 11:32:43 GMT 2001 herp - cleaned up header files
+ * Sun Jan 20 10:11:15 MET 2002 herp - added modversion header files
+ * Thu Nov 14 16:34:11 GMT 2002 mh - added PPS functionality
+ * Tue Nov 19 16:36:27 GMT 2002 mh - added SUSPEND/RESUME functionailty
+ * Wed Jul 28 12:55:01 CEST 2004 mh - kernel 2.6 adjustments
+ *
+ * current version: 2.4.0gm4
+ *
+ * (C) 2000,2001,2002,2003,2004 Omnikey AG
+ *
+ * (C) 2005 Harald Welte <laforge@gnumonks.org>
+ * - Adhere to Kernel CodingStyle
+ * - Port to 2.6.13 "new" style PCMCIA
+ * - Check for copy_{from,to}_user return values
+ * - Use nonseekable_open()
+ *
+ * All rights reserved. Licensed under dual BSD/GPL license.
+ */
+
+/* #define PCMCIA_DEBUG 6 */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+#include <linux/cm4000_cs.h>
+
+/* #define ATR_CSUM */
+
+#ifdef PCMCIA_DEBUG
+#define reader_to_dev(x) (&handle_to_dev(x->link.handle))
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0600);
+#define DEBUGP(n, rdr, x, args...) do { \
+ if (pc_debug >= (n)) \
+ dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
+ __FUNCTION__ , ## args); \
+ } while (0)
+#else
+#define DEBUGP(n, rdr, x, args...)
+#endif
+static char *version = "cm4000_cs.c v2.4.0gm5 - All bugs added by Harald Welte";
+
+#define T_1SEC (HZ)
+#define T_10MSEC msecs_to_jiffies(10)
+#define T_20MSEC msecs_to_jiffies(20)
+#define T_40MSEC msecs_to_jiffies(40)
+#define T_50MSEC msecs_to_jiffies(50)
+#define T_100MSEC msecs_to_jiffies(100)
+#define T_500MSEC msecs_to_jiffies(500)
+
+static void cm4000_detach(dev_link_t *link);
+static void cm4000_release(dev_link_t *link);
+
+static int major; /* major number we get from the kernel */
+
+/* note: the first state has to have number 0 always */
+
+#define M_FETCH_ATR 0
+#define M_TIMEOUT_WAIT 1
+#define M_READ_ATR_LEN 2
+#define M_READ_ATR 3
+#define M_ATR_PRESENT 4
+#define M_BAD_CARD 5
+#define M_CARDOFF 6
+
+#define LOCK_IO 0
+#define LOCK_MONITOR 1
+
+#define IS_AUTOPPS_ACT 6
+#define IS_PROCBYTE_PRESENT 7
+#define IS_INVREV 8
+#define IS_ANY_T0 9
+#define IS_ANY_T1 10
+#define IS_ATR_PRESENT 11
+#define IS_ATR_VALID 12
+#define IS_CMM_ABSENT 13
+#define IS_BAD_LENGTH 14
+#define IS_BAD_CSUM 15
+#define IS_BAD_CARD 16
+
+#define REG_FLAGS0(x) (x + 0)
+#define REG_FLAGS1(x) (x + 1)
+#define REG_NUM_BYTES(x) (x + 2)
+#define REG_BUF_ADDR(x) (x + 3)
+#define REG_BUF_DATA(x) (x + 4)
+#define REG_NUM_SEND(x) (x + 5)
+#define REG_BAUDRATE(x) (x + 6)
+#define REG_STOPBITS(x) (x + 7)
+
+struct cm4000_dev {
+ dev_link_t link; /* pcmcia link */
+ dev_node_t node; /* OS node (major,minor) */
+
+ unsigned char atr[MAX_ATR];
+ unsigned char rbuf[512];
+ unsigned char sbuf[512];
+
+ wait_queue_head_t devq; /* when removing cardman must not be
+ zeroed! */
+
+ wait_queue_head_t ioq; /* if IO is locked, wait on this Q */
+ wait_queue_head_t atrq; /* wait for ATR valid */
+ wait_queue_head_t readq; /* used by write to wake blk.read */
+
+ /* warning: do not move this fields.
+ * initialising to zero depends on it - see ZERO_DEV below. */
+ unsigned char atr_csum;
+ unsigned char atr_len_retry;
+ unsigned short atr_len;
+ unsigned short rlen; /* bytes avail. after write */
+ unsigned short rpos; /* latest read pos. write zeroes */
+ unsigned char procbyte; /* T=0 procedure byte */
+ unsigned char mstate; /* state of card monitor */
+ unsigned char cwarn; /* slow down warning */
+ unsigned char flags0; /* cardman IO-flags 0 */
+ unsigned char flags1; /* cardman IO-flags 1 */
+ unsigned int mdelay; /* variable monitor speeds, in jiffies */
+
+ unsigned int baudv; /* baud value for speed */
+ unsigned char ta1;
+ unsigned char proto; /* T=0, T=1, ... */
+ unsigned long flags; /* lock+flags (MONITOR,IO,ATR) * for concurrent
+ access */
+
+ unsigned char pts[4];
+
+ struct timer_list timer; /* used to keep monitor running */
+ int monitor_running;
+};
+
+#define ZERO_DEV(dev) \
+ memset(&dev->atr_csum,0, \
+ sizeof(struct cm4000_dev) - \
+ /*link*/ sizeof(dev_link_t) - \
+ /*node*/ sizeof(dev_node_t) - \
+ /*atr*/ MAX_ATR*sizeof(char) - \
+ /*rbuf*/ 512*sizeof(char) - \
+ /*sbuf*/ 512*sizeof(char) - \
+ /*queue*/ 4*sizeof(wait_queue_head_t))
+
+static dev_info_t dev_info = MODULE_NAME;
+static dev_link_t *dev_table[CM4000_MAX_DEV];
+
+/* This table doesn't use spaces after the comma between fields and thus
+ * violates CodingStyle. However, I don't really think wrapping it around will
+ * make it any clearer to read -HW */
+static unsigned char fi_di_table[10][14] = {
+/*FI 00 01 02 03 04 05 06 07 08 09 10 11 12 13 */
+/*DI */
+/* 0 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+/* 1 */ {0x01,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x91,0x11,0x11,0x11,0x11},
+/* 2 */ {0x02,0x12,0x22,0x32,0x11,0x11,0x11,0x11,0x11,0x92,0xA2,0xB2,0x11,0x11},
+/* 3 */ {0x03,0x13,0x23,0x33,0x43,0x53,0x63,0x11,0x11,0x93,0xA3,0xB3,0xC3,0xD3},
+/* 4 */ {0x04,0x14,0x24,0x34,0x44,0x54,0x64,0x11,0x11,0x94,0xA4,0xB4,0xC4,0xD4},
+/* 5 */ {0x00,0x15,0x25,0x35,0x45,0x55,0x65,0x11,0x11,0x95,0xA5,0xB5,0xC5,0xD5},
+/* 6 */ {0x06,0x16,0x26,0x36,0x46,0x56,0x66,0x11,0x11,0x96,0xA6,0xB6,0xC6,0xD6},
+/* 7 */ {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11},
+/* 8 */ {0x08,0x11,0x28,0x38,0x48,0x58,0x68,0x11,0x11,0x98,0xA8,0xB8,0xC8,0xD8},
+/* 9 */ {0x09,0x19,0x29,0x39,0x49,0x59,0x69,0x11,0x11,0x99,0xA9,0xB9,0xC9,0xD9}
+};
+
+#ifndef PCMCIA_DEBUG
+#define xoutb outb
+#define xinb inb
+#else
+static inline void xoutb(unsigned char val, unsigned short port)
+{
+ if (pc_debug >= 7)
+ printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port);
+ outb(val, port);
+}
+static inline unsigned char xinb(unsigned short port)
+{
+ unsigned char val;
+
+ val = inb(port);
+ if (pc_debug >= 7)
+ printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port);
+
+ return val;
+}
+#endif
+
+#define b_0000 15
+#define b_0001 14
+#define b_0010 13
+#define b_0011 12
+#define b_0100 11
+#define b_0101 10
+#define b_0110 9
+#define b_0111 8
+#define b_1000 7
+#define b_1001 6
+#define b_1010 5
+#define b_1011 4
+#define b_1100 3
+#define b_1101 2
+#define b_1110 1
+#define b_1111 0
+
+static unsigned char irtab[16] = {
+ b_0000, b_1000, b_0100, b_1100,
+ b_0010, b_1010, b_0110, b_1110,
+ b_0001, b_1001, b_0101, b_1101,
+ b_0011, b_1011, b_0111, b_1111
+};
+
+static void str_invert_revert(unsigned char *b, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ b[i] = (irtab[b[i] & 0x0f] << 4) | irtab[b[i] >> 4];
+}
+
+static unsigned char invert_revert(unsigned char ch)
+{
+ return (irtab[ch & 0x0f] << 4) | irtab[ch >> 4];
+}
+
+#define ATRLENCK(dev,pos) \
+ if (pos>=dev->atr_len || pos>=MAX_ATR) \
+ goto return_0;
+
+static unsigned int calc_baudv(unsigned char fidi)
+{
+ unsigned int wcrcf, wbrcf, fi_rfu, di_rfu;
+
+ fi_rfu = 372;
+ di_rfu = 1;
+
+ /* FI */
+ switch ((fidi >> 4) & 0x0F) {
+ case 0x00:
+ wcrcf = 372;
+ break;
+ case 0x01:
+ wcrcf = 372;
+ break;
+ case 0x02:
+ wcrcf = 558;
+ break;
+ case 0x03:
+ wcrcf = 744;
+ break;
+ case 0x04:
+ wcrcf = 1116;
+ break;
+ case 0x05:
+ wcrcf = 1488;
+ break;
+ case 0x06:
+ wcrcf = 1860;
+ break;
+ case 0x07:
+ wcrcf = fi_rfu;
+ break;
+ case 0x08:
+ wcrcf = fi_rfu;
+ break;
+ case 0x09:
+ wcrcf = 512;
+ break;
+ case 0x0A:
+ wcrcf = 768;
+ break;
+ case 0x0B:
+ wcrcf = 1024;
+ break;
+ case 0x0C:
+ wcrcf = 1536;
+ break;
+ case 0x0D:
+ wcrcf = 2048;
+ break;
+ default:
+ wcrcf = fi_rfu;
+ break;
+ }
+
+ /* DI */
+ switch (fidi & 0x0F) {
+ case 0x00:
+ wbrcf = di_rfu;
+ break;
+ case 0x01:
+ wbrcf = 1;
+ break;
+ case 0x02:
+ wbrcf = 2;
+ break;
+ case 0x03:
+ wbrcf = 4;
+ break;
+ case 0x04:
+ wbrcf = 8;
+ break;
+ case 0x05:
+ wbrcf = 16;
+ break;
+ case 0x06:
+ wbrcf = 32;
+ break;
+ case 0x07:
+ wbrcf = di_rfu;
+ break;
+ case 0x08:
+ wbrcf = 12;
+ break;
+ case 0x09:
+ wbrcf = 20;
+ break;
+ default:
+ wbrcf = di_rfu;
+ break;
+ }
+
+ return (wcrcf / wbrcf);
+}
+
+static unsigned short io_read_num_rec_bytes(ioaddr_t iobase, unsigned short *s)
+{
+ unsigned short tmp;
+
+ tmp = *s = 0;
+ do {
+ *s = tmp;
+ tmp = inb(REG_NUM_BYTES(iobase)) |
+ (inb(REG_FLAGS0(iobase)) & 4 ? 0x100 : 0);
+ } while (tmp != *s);
+
+ return *s;
+}
+
+static int parse_atr(struct cm4000_dev *dev)
+{
+ unsigned char any_t1, any_t0;
+ unsigned char ch, ifno;
+ int ix, done;
+
+ DEBUGP(3, dev, "-> parse_atr: dev->atr_len = %i\n", dev->atr_len);
+
+ if (dev->atr_len < 3) {
+ DEBUGP(5, dev, "parse_atr: atr_len < 3\n");
+ return 0;
+ }
+
+ if (dev->atr[0] == 0x3f)
+ set_bit(IS_INVREV, &dev->flags);
+ else
+ clear_bit(IS_INVREV, &dev->flags);
+ ix = 1;
+ ifno = 1;
+ ch = dev->atr[1];
+ dev->proto = 0; /* XXX PROTO */
+ any_t1 = any_t0 = done = 0;
+ dev->ta1 = 0x11; /* defaults to 9600 baud */
+ do {
+ if (ifno == 1 && (ch & 0x10)) {
+ /* read first interface byte and TA1 is present */
+ dev->ta1 = dev->atr[2];
+ DEBUGP(5, dev, "Card says FiDi is 0x%.2x\n", dev->ta1);
+ ifno++;
+ } else if ((ifno == 2) && (ch & 0x10)) { /* TA(2) */
+ dev->ta1 = 0x11;
+ ifno++;
+ }
+
+ DEBUGP(5, dev, "Yi=%.2x\n", ch & 0xf0);
+ ix += ((ch & 0x10) >> 4) /* no of int.face chars */
+ +((ch & 0x20) >> 5)
+ + ((ch & 0x40) >> 6)
+ + ((ch & 0x80) >> 7);
+ /* ATRLENCK(dev,ix); */
+ if (ch & 0x80) { /* TDi */
+ ch = dev->atr[ix];
+ if ((ch & 0x0f)) {
+ any_t1 = 1;
+ DEBUGP(5, dev, "card is capable of T=1\n");
+ } else {
+ any_t0 = 1;
+ DEBUGP(5, dev, "card is capable of T=0\n");
+ }
+ } else
+ done = 1;
+ } while (!done);
+
+ DEBUGP(5, dev, "ix=%d noHist=%d any_t1=%d\n",
+ ix, dev->atr[1] & 15, any_t1);
+ if (ix + 1 + (dev->atr[1] & 0x0f) + any_t1 != dev->atr_len) {
+ DEBUGP(5, dev, "length error\n");
+ return 0;
+ }
+ if (any_t0)
+ set_bit(IS_ANY_T0, &dev->flags);
+
+ if (any_t1) { /* compute csum */
+ dev->atr_csum = 0;
+#ifdef ATR_CSUM
+ for (i = 1; i < dev->atr_len; i++)
+ dev->atr_csum ^= dev->atr[i];
+ if (dev->atr_csum) {
+ set_bit(IS_BAD_CSUM, &dev->flags);
+ DEBUGP(5, dev, "bad checksum\n");
+ goto return_0;
+ }
+#endif
+ if (any_t0 == 0)
+ dev->proto = 1; /* XXX PROTO */
+ set_bit(IS_ANY_T1, &dev->flags);
+ }
+
+ return 1;
+}
+
+struct card_fixup {
+ char atr[12];
+ u_int8_t atr_len;
+ u_int8_t stopbits;
+};
+
+static struct card_fixup card_fixups[] = {
+ { /* ACOS */
+ .atr = { 0x3b, 0xb3, 0x11, 0x00, 0x00, 0x41, 0x01 },
+ .atr_len = 7,
+ .stopbits = 0x03,
+ },
+ { /* Motorola */
+ .atr = {0x3b, 0x76, 0x13, 0x00, 0x00, 0x80, 0x62, 0x07,
+ 0x41, 0x81, 0x81 },
+ .atr_len = 11,
+ .stopbits = 0x04,
+ },
+};
+
+static void set_cardparameter(struct cm4000_dev *dev)
+{
+ int i;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ u_int8_t stopbits = 0x02; /* ISO default */
+
+ DEBUGP(3, dev, "-> set_cardparameter\n");
+
+ dev->flags1 = dev->flags1 | (((dev->baudv - 1) & 0x0100) >> 8);
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ DEBUGP(5, dev, "flags1 = 0x%02x\n", dev->flags1);
+
+ /* set baudrate */
+ xoutb((unsigned char)((dev->baudv - 1) & 0xFF), REG_BAUDRATE(iobase));
+
+ DEBUGP(5, dev, "baudv = %i -> write 0x%02x\n", dev->baudv,
+ ((dev->baudv - 1) & 0xFF));
+
+ /* set stopbits */
+ for (i = 0; i < ARRAY_SIZE(card_fixups); i++) {
+ if (!memcmp(dev->atr, card_fixups[i].atr,
+ card_fixups[i].atr_len))
+ stopbits = card_fixups[i].stopbits;
+ }
+ xoutb(stopbits, REG_STOPBITS(iobase));
+
+ DEBUGP(3, dev, "<- set_cardparameter\n");
+}
+
+static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq)
+{
+
+ unsigned long tmp, i;
+ unsigned short num_bytes_read;
+ unsigned char pts_reply[4];
+ ssize_t rc;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+
+ rc = 0;
+
+ DEBUGP(3, dev, "-> set_protocol\n");
+ DEBUGP(5, dev, "ptsreq->Protocol = 0x%.8x, ptsreq->Flags=0x%.8x, "
+ "ptsreq->pts1=0x%.2x, ptsreq->pts2=0x%.2x, "
+ "ptsreq->pts3=0x%.2x\n", (unsigned int)ptsreq->protocol,
+ (unsigned int)ptsreq->flags, ptsreq->pts1, ptsreq->pts2,
+ ptsreq->pts3);
+
+ /* Fill PTS structure */
+ dev->pts[0] = 0xff;
+ dev->pts[1] = 0x00;
+ tmp = ptsreq->protocol;
+ while ((tmp = (tmp >> 1)) > 0)
+ dev->pts[1]++;
+ dev->proto = dev->pts[1]; /* Set new protocol */
+ dev->pts[1] = (0x01 << 4) | (dev->pts[1]);
+
+ /* Correct Fi/Di according to CM4000 Fi/Di table */
+ DEBUGP(5, dev, "Ta(1) from ATR is 0x%.2x\n", dev->ta1);
+ /* set Fi/Di according to ATR TA(1) */
+ dev->pts[2] = fi_di_table[dev->ta1 & 0x0F][(dev->ta1 >> 4) & 0x0F];
+
+ /* Calculate PCK character */
+ dev->pts[3] = dev->pts[0] ^ dev->pts[1] ^ dev->pts[2];
+
+ DEBUGP(5, dev, "pts0=%.2x, pts1=%.2x, pts2=%.2x, pts3=%.2x\n",
+ dev->pts[0], dev->pts[1], dev->pts[2], dev->pts[3]);
+
+ /* check card convention */
+ if (test_bit(IS_INVREV, &dev->flags))
+ str_invert_revert(dev->pts, 4);
+
+ /* reset SM */
+ xoutb(0x80, REG_FLAGS0(iobase));
+
+ /* Enable access to the message buffer */
+ DEBUGP(5, dev, "Enable access to the messages buffer\n");
+ dev->flags1 = 0x20 /* T_Active */
+ | (test_bit(IS_INVREV, &dev->flags) ? 0x02 : 0x00) /* inv parity */
+ | ((dev->baudv >> 8) & 0x01); /* MSB-baud */
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+ DEBUGP(5, dev, "Enable message buffer -> flags1 = 0x%.2x\n",
+ dev->flags1);
+
+ /* write challenge to the buffer */
+ DEBUGP(5, dev, "Write challenge to buffer: ");
+ for (i = 0; i < 4; i++) {
+ xoutb(i, REG_BUF_ADDR(iobase));
+ xoutb(dev->pts[i], REG_BUF_DATA(iobase)); /* buf data */
+#ifdef PCMCIA_DEBUG
+ if (pc_debug >= 5)
+ printk("0x%.2x ", dev->pts[i]);
+ }
+ if (pc_debug >= 5)
+ printk("\n");
+#else
+ }
+#endif
+
+ /* set number of bytes to write */
+ DEBUGP(5, dev, "Set number of bytes to write\n");
+ xoutb(0x04, REG_NUM_SEND(iobase));
+
+ /* Trigger CARDMAN CONTROLLER */
+ xoutb(0x50, REG_FLAGS0(iobase));
+
+ /* Monitor progress */
+ /* wait for xmit done */
+ DEBUGP(5, dev, "Waiting for NumRecBytes getting valid\n");
+
+ for (i = 0; i < 100; i++) {
+ if (inb(REG_FLAGS0(iobase)) & 0x08) {
+ DEBUGP(5, dev, "NumRecBytes is valid\n");
+ break;
+ }
+ mdelay(10);
+ }
+ if (i == 100) {
+ DEBUGP(5, dev, "Timeout waiting for NumRecBytes getting "
+ "valid\n");
+ rc = -EIO;
+ goto exit_setprotocol;
+ }
+
+ DEBUGP(5, dev, "Reading NumRecBytes\n");
+ for (i = 0; i < 100; i++) {
+ io_read_num_rec_bytes(iobase, &num_bytes_read);
+ if (num_bytes_read >= 4) {
+ DEBUGP(2, dev, "NumRecBytes = %i\n", num_bytes_read);
+ break;
+ }
+ mdelay(10);
+ }
+
+ /* check whether it is a short PTS reply? */
+ if (num_bytes_read == 3)
+ i = 0;
+
+ if (i == 100) {
+ DEBUGP(5, dev, "Timeout reading num_bytes_read\n");
+ rc = -EIO;
+ goto exit_setprotocol;
+ }
+
+ DEBUGP(5, dev, "Reset the CARDMAN CONTROLLER\n");
+ xoutb(0x80, REG_FLAGS0(iobase));
+
+ /* Read PPS reply */
+ DEBUGP(5, dev, "Read PPS reply\n");
+ for (i = 0; i < num_bytes_read; i++) {
+ xoutb(i, REG_BUF_ADDR(iobase));
+ pts_reply[i] = inb(REG_BUF_DATA(iobase));
+ }
+
+#ifdef PCMCIA_DEBUG
+ DEBUGP(2, dev, "PTSreply: ");
+ for (i = 0; i < num_bytes_read; i++) {
+ if (pc_debug >= 5)
+ printk("0x%.2x ", pts_reply[i]);
+ }
+ printk("\n");
+#endif /* PCMCIA_DEBUG */
+
+ DEBUGP(5, dev, "Clear Tactive in Flags1\n");
+ xoutb(0x20, REG_FLAGS1(iobase));
+
+ /* Compare ptsreq and ptsreply */
+ if ((dev->pts[0] == pts_reply[0]) &&
+ (dev->pts[1] == pts_reply[1]) &&
+ (dev->pts[2] == pts_reply[2]) && (dev->pts[3] == pts_reply[3])) {
+ /* setcardparameter according to PPS */
+ dev->baudv = calc_baudv(dev->pts[2]);
+ set_cardparameter(dev);
+ } else if ((dev->pts[0] == pts_reply[0]) &&
+ ((dev->pts[1] & 0xef) == pts_reply[1]) &&
+ ((pts_reply[0] ^ pts_reply[1]) == pts_reply[2])) {
+ /* short PTS reply, set card parameter to default values */
+ dev->baudv = calc_baudv(0x11);
+ set_cardparameter(dev);
+ } else
+ rc = -EIO;
+
+exit_setprotocol:
+ DEBUGP(3, dev, "<- set_protocol\n");
+ return rc;
+}
+
+static int io_detect_cm4000(ioaddr_t iobase, struct cm4000_dev *dev)
+{
+
+ /* note: statemachine is assumed to be reset */
+ if (inb(REG_FLAGS0(iobase)) & 8) {
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ return 0; /* detect CMM = 1 -> failure */
+ }
+ /* xoutb(0x40, REG_FLAGS1(iobase)); detectCMM */
+ xoutb(dev->flags1 | 0x40, REG_FLAGS1(iobase));
+ if ((inb(REG_FLAGS0(iobase)) & 8) == 0) {
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ return 0; /* detect CMM=0 -> failure */
+ }
+ /* clear detectCMM again by restoring original flags1 */
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ return 1;
+}
+
+static void terminate_monitor(struct cm4000_dev *dev)
+{
+
+ /* tell the monitor to stop and wait until
+ * it terminates.
+ */
+ DEBUGP(3, dev, "-> terminate_monitor\n");
+ wait_event_interruptible(dev->devq,
+ test_and_set_bit(LOCK_MONITOR,
+ (void *)&dev->flags));
+
+ /* now, LOCK_MONITOR has been set.
+ * allow a last cycle in the monitor.
+ * the monitor will indicate that it has
+ * finished by clearing this bit.
+ */
+ DEBUGP(5, dev, "Now allow last cycle of monitor!\n");
+ while (test_bit(LOCK_MONITOR, (void *)&dev->flags))
+ msleep(25);
+
+ DEBUGP(5, dev, "Delete timer\n");
+ del_timer_sync(&dev->timer);
+#ifdef PCMCIA_DEBUG
+ dev->monitor_running = 0;
+#endif
+
+ DEBUGP(3, dev, "<- terminate_monitor\n");
+}
+
+/*
+ * monitor the card every 50msec. as a side-effect, retrieve the
+ * atr once a card is inserted. another side-effect of retrieving the
+ * atr is that the card will be powered on, so there is no need to
+ * power on the card explictely from the application: the driver
+ * is already doing that for you.
+ */
+
+static void monitor_card(unsigned long p)
+{
+ struct cm4000_dev *dev = (struct cm4000_dev *) p;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ unsigned short s;
+ struct ptsreq ptsreq;
+ int i, atrc;
+
+ DEBUGP(7, dev, "-> monitor_card\n");
+
+ /* if someone has set the lock for us: we're done! */
+ if (test_and_set_bit(LOCK_MONITOR, &dev->flags)) {
+ DEBUGP(4, dev, "About to stop monitor\n");
+ /* no */
+ dev->rlen =
+ dev->rpos =
+ dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0;
+ dev->mstate = M_FETCH_ATR;
+ clear_bit(LOCK_MONITOR, &dev->flags);
+ /* close et al. are sleeping on devq, so wake it */
+ wake_up_interruptible(&dev->devq);
+ DEBUGP(2, dev, "<- monitor_card (we are done now)\n");
+ return;
+ }
+
+ /* try to lock io: if it is already locked, just add another timer */
+ if (test_and_set_bit(LOCK_IO, (void *)&dev->flags)) {
+ DEBUGP(4, dev, "Couldn't get IO lock\n");
+ goto return_with_timer;
+ }
+
+ /* is a card/a reader inserted at all ? */
+ dev->flags0 = xinb(REG_FLAGS0(iobase));
+ DEBUGP(7, dev, "dev->flags0 = 0x%2x\n", dev->flags0);
+ DEBUGP(7, dev, "smartcard present: %s\n",
+ dev->flags0 & 1 ? "yes" : "no");
+ DEBUGP(7, dev, "cardman present: %s\n",
+ dev->flags0 == 0xff ? "no" : "yes");
+
+ if ((dev->flags0 & 1) == 0 /* no smartcard inserted */
+ || dev->flags0 == 0xff) { /* no cardman inserted */
+ /* no */
+ dev->rlen =
+ dev->rpos =
+ dev->atr_csum = dev->atr_len_retry = dev->cwarn = 0;
+ dev->mstate = M_FETCH_ATR;
+
+ dev->flags &= 0x000000ff; /* only keep IO and MONITOR locks */
+
+ if (dev->flags0 == 0xff) {
+ DEBUGP(4, dev, "set IS_CMM_ABSENT bit\n");
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ } else if (test_bit(IS_CMM_ABSENT, &dev->flags)) {
+ DEBUGP(4, dev, "clear IS_CMM_ABSENT bit "
+ "(card is removed)\n");
+ clear_bit(IS_CMM_ABSENT, &dev->flags);
+ }
+
+ goto release_io;
+ } else if ((dev->flags0 & 1) && test_bit(IS_CMM_ABSENT, &dev->flags)) {
+ /* cardman and card present but cardman was absent before
+ * (after suspend with inserted card) */
+ DEBUGP(4, dev, "clear IS_CMM_ABSENT bit (card is inserted)\n");
+ clear_bit(IS_CMM_ABSENT, &dev->flags);
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 1) {
+ DEBUGP(7, dev, "believe ATR is already valid (do nothing)\n");
+ goto release_io;
+ }
+
+ switch (dev->mstate) {
+ unsigned char flags0;
+ case M_CARDOFF:
+ DEBUGP(4, dev, "M_CARDOFF\n");
+ flags0 = inb(REG_FLAGS0(iobase));
+ if (flags0 & 0x02) {
+ /* wait until Flags0 indicate power is off */
+ dev->mdelay = T_10MSEC;
+ } else {
+ /* Flags0 indicate power off and no card inserted now;
+ * Reset CARDMAN CONTROLLER */
+ xoutb(0x80, REG_FLAGS0(iobase));
+
+ /* prepare for fetching ATR again: after card off ATR
+ * is read again automatically */
+ dev->rlen =
+ dev->rpos =
+ dev->atr_csum =
+ dev->atr_len_retry = dev->cwarn = 0;
+ dev->mstate = M_FETCH_ATR;
+
+ /* minimal gap between CARDOFF and read ATR is 50msec */
+ dev->mdelay = T_50MSEC;
+ }
+ break;
+ case M_FETCH_ATR:
+ DEBUGP(4, dev, "M_FETCH_ATR\n");
+ xoutb(0x80, REG_FLAGS0(iobase));
+ DEBUGP(4, dev, "Reset BAUDV to 9600\n");
+ dev->baudv = 0x173; /* 9600 */
+ xoutb(0x02, REG_STOPBITS(iobase)); /* stopbits=2 */
+ xoutb(0x73, REG_BAUDRATE(iobase)); /* baud value */
+ xoutb(0x21, REG_FLAGS1(iobase)); /* T_Active=1, baud
+ value */
+ /* warm start vs. power on: */
+ xoutb(dev->flags0 & 2 ? 0x46 : 0x44, REG_FLAGS0(iobase));
+ dev->mdelay = T_40MSEC;
+ dev->mstate = M_TIMEOUT_WAIT;
+ break;
+ case M_TIMEOUT_WAIT:
+ DEBUGP(4, dev, "M_TIMEOUT_WAIT\n");
+ /* numRecBytes */
+ io_read_num_rec_bytes(iobase, &dev->atr_len);
+ dev->mdelay = T_10MSEC;
+ dev->mstate = M_READ_ATR_LEN;
+ break;
+ case M_READ_ATR_LEN:
+ DEBUGP(4, dev, "M_READ_ATR_LEN\n");
+ /* infinite loop possible, since there is no timeout */
+
+#define MAX_ATR_LEN_RETRY 100
+
+ if (dev->atr_len == io_read_num_rec_bytes(iobase, &s)) {
+ if (dev->atr_len_retry++ >= MAX_ATR_LEN_RETRY) { /* + XX msec */
+ dev->mdelay = T_10MSEC;
+ dev->mstate = M_READ_ATR;
+ }
+ } else {
+ dev->atr_len = s;
+ dev->atr_len_retry = 0; /* set new timeout */
+ }
+
+ DEBUGP(4, dev, "Current ATR_LEN = %i\n", dev->atr_len);
+ break;
+ case M_READ_ATR:
+ DEBUGP(4, dev, "M_READ_ATR\n");
+ xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */
+ for (i = 0; i < dev->atr_len; i++) {
+ xoutb(i, REG_BUF_ADDR(iobase));
+ dev->atr[i] = inb(REG_BUF_DATA(iobase));
+ }
+ /* Deactivate T_Active flags */
+ DEBUGP(4, dev, "Deactivate T_Active flags\n");
+ dev->flags1 = 0x01;
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+ /* atr is present (which doesnt mean it's valid) */
+ set_bit(IS_ATR_PRESENT, &dev->flags);
+ if (dev->atr[0] == 0x03)
+ str_invert_revert(dev->atr, dev->atr_len);
+ atrc = parse_atr(dev);
+ if (atrc == 0) { /* atr invalid */
+ dev->mdelay = 0;
+ dev->mstate = M_BAD_CARD;
+ } else {
+ dev->mdelay = T_50MSEC;
+ dev->mstate = M_ATR_PRESENT;
+ set_bit(IS_ATR_VALID, &dev->flags);
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 1) {
+ DEBUGP(4, dev, "monitor_card: ATR valid\n");
+ /* if ta1 == 0x11, no PPS necessary (default values) */
+ /* do not do PPS with multi protocol cards */
+ if ((test_bit(IS_AUTOPPS_ACT, &dev->flags) == 0) &&
+ (dev->ta1 != 0x11) &&
+ !(test_bit(IS_ANY_T0, &dev->flags) &&
+ test_bit(IS_ANY_T1, &dev->flags))) {
+ DEBUGP(4, dev, "Perform AUTOPPS\n");
+ set_bit(IS_AUTOPPS_ACT, &dev->flags);
+ ptsreq.protocol = ptsreq.protocol =
+ (0x01 << dev->proto);
+ ptsreq.flags = 0x01;
+ ptsreq.pts1 = 0x00;
+ ptsreq.pts2 = 0x00;
+ ptsreq.pts3 = 0x00;
+ if (set_protocol(dev, &ptsreq) == 0) {
+ DEBUGP(4, dev, "AUTOPPS ret SUCC\n");
+ clear_bit(IS_AUTOPPS_ACT, &dev->flags);
+ wake_up_interruptible(&dev->atrq);
+ } else {
+ DEBUGP(4, dev, "AUTOPPS failed: "
+ "repower using defaults\n");
+ /* prepare for repowering */
+ clear_bit(IS_ATR_PRESENT, &dev->flags);
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ dev->rlen =
+ dev->rpos =
+ dev->atr_csum =
+ dev->atr_len_retry = dev->cwarn = 0;
+ dev->mstate = M_FETCH_ATR;
+
+ dev->mdelay = T_50MSEC;
+ }
+ } else {
+ /* for cards which use slightly different
+ * params (extra guard time) */
+ set_cardparameter(dev);
+ if (test_bit(IS_AUTOPPS_ACT, &dev->flags) == 1)
+ DEBUGP(4, dev, "AUTOPPS already active "
+ "2nd try:use default values\n");
+ if (dev->ta1 == 0x11)
+ DEBUGP(4, dev, "No AUTOPPS necessary "
+ "TA(1)==0x11\n");
+ if (test_bit(IS_ANY_T0, &dev->flags)
+ && test_bit(IS_ANY_T1, &dev->flags))
+ DEBUGP(4, dev, "Do NOT perform AUTOPPS "
+ "with multiprotocol cards\n");
+ clear_bit(IS_AUTOPPS_ACT, &dev->flags);
+ wake_up_interruptible(&dev->atrq);
+ }
+ } else {
+ DEBUGP(4, dev, "ATR invalid\n");
+ wake_up_interruptible(&dev->atrq);
+ }
+ break;
+ case M_BAD_CARD:
+ DEBUGP(4, dev, "M_BAD_CARD\n");
+ /* slow down warning, but prompt immediately after insertion */
+ if (dev->cwarn == 0 || dev->cwarn == 10) {
+ set_bit(IS_BAD_CARD, &dev->flags);
+ printk(KERN_WARNING MODULE_NAME ": device %s: ",
+ dev->node.dev_name);
+ if (test_bit(IS_BAD_CSUM, &dev->flags)) {
+ DEBUGP(4, dev, "ATR checksum (0x%.2x, should "
+ "be zero) failed\n", dev->atr_csum);
+ }
+#ifdef PCMCIA_DEBUG
+ else if (test_bit(IS_BAD_LENGTH, &dev->flags)) {
+ DEBUGP(4, dev, "ATR length error\n");
+ } else {
+ DEBUGP(4, dev, "card damaged or wrong way "
+ "inserted\n");
+ }
+#endif
+ dev->cwarn = 0;
+ wake_up_interruptible(&dev->atrq); /* wake open */
+ }
+ dev->cwarn++;
+ dev->mdelay = T_100MSEC;
+ dev->mstate = M_FETCH_ATR;
+ break;
+ default:
+ DEBUGP(7, dev, "Unknown action\n");
+ break; /* nothing */
+ }
+
+release_io:
+ DEBUGP(7, dev, "release_io\n");
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq); /* whoever needs IO */
+
+return_with_timer:
+ DEBUGP(7, dev, "<- monitor_card (returns with timer)\n");
+ dev->timer.expires = jiffies + dev->mdelay;
+ add_timer(&dev->timer);
+ clear_bit(LOCK_MONITOR, &dev->flags);
+}
+
+/* Interface to userland (file_operations) */
+
+static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct cm4000_dev *dev = filp->private_data;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ ssize_t rc;
+ int i, j, k;
+
+ DEBUGP(2, dev, "-> cmm_read(%s,%d)\n", current->comm, current->pid);
+
+ if (count == 0) /* according to manpage */
+ return 0;
+
+ if ((dev->link.state & DEV_PRESENT) == 0 || /* socket removed */
+ test_bit(IS_CMM_ABSENT, &dev->flags))
+ return -ENODEV;
+
+ if (test_bit(IS_BAD_CSUM, &dev->flags))
+ return -EIO;
+
+ /* also see the note about this in cmm_write */
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 0)
+ return -EIO;
+
+ /* this one implements blocking IO */
+ if (wait_event_interruptible
+ (dev->readq,
+ ((filp->f_flags & O_NONBLOCK) || (dev->rpos < dev->rlen)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ /* lock io */
+ if (wait_event_interruptible
+ (dev->ioq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ rc = 0;
+ dev->flags0 = inb(REG_FLAGS0(iobase));
+ if ((dev->flags0 & 1) == 0 /* no smartcard inserted */
+ || dev->flags0 == 0xff) { /* no cardman inserted */
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ if (dev->flags0 & 1) {
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ rc = -ENODEV;
+ }
+ rc = -EIO;
+ goto release_io;
+ }
+
+ DEBUGP(4, dev, "begin read answer\n");
+ j = min(count, (size_t)(dev->rlen - dev->rpos));
+ k = dev->rpos;
+ if (k + j > 255)
+ j = 256 - k;
+ DEBUGP(4, dev, "read1 j=%d\n", j);
+ for (i = 0; i < j; i++) {
+ xoutb(k++, REG_BUF_ADDR(iobase));
+ dev->rbuf[i] = xinb(REG_BUF_DATA(iobase));
+ }
+ j = min(count, (size_t)(dev->rlen - dev->rpos));
+ if (k + j > 255) {
+ DEBUGP(4, dev, "read2 j=%d\n", j);
+ dev->flags1 |= 0x10; /* MSB buf addr set */
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ for (; i < j; i++) {
+ xoutb(k++, REG_BUF_ADDR(iobase));
+ dev->rbuf[i] = xinb(REG_BUF_DATA(iobase));
+ }
+ }
+
+ if (dev->proto == 0 && count > dev->rlen - dev->rpos) {
+ DEBUGP(4, dev, "T=0 and count > buffer\n");
+ dev->rbuf[i] = dev->rbuf[i - 1];
+ dev->rbuf[i - 1] = dev->procbyte;
+ j++;
+ }
+ count = j;
+
+ dev->rpos = dev->rlen + 1;
+
+ /* Clear T1Active */
+ DEBUGP(4, dev, "Clear T1Active\n");
+ dev->flags1 &= 0xdf;
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+ xoutb(0, REG_FLAGS1(iobase)); /* clear detectCMM */
+ /* last check before exit */
+ if (!io_detect_cm4000(iobase, dev))
+ count = -ENODEV;
+
+ if (test_bit(IS_INVREV, &dev->flags) && count > 0)
+ str_invert_revert(dev->rbuf, count);
+
+ if (copy_to_user(buf, dev->rbuf, count))
+ return -EFAULT;
+
+release_io:
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq);
+
+ DEBUGP(2, dev, "<- cmm_read returns: rc = %Zi\n",
+ (rc < 0 ? rc : count));
+ return rc < 0 ? rc : count;
+}
+
+static ssize_t cmm_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ unsigned short s;
+ unsigned char tmp;
+ unsigned char infolen;
+ unsigned char sendT0;
+ unsigned short nsend;
+ unsigned short nr;
+ ssize_t rc;
+ int i;
+
+ DEBUGP(2, dev, "-> cmm_write(%s,%d)\n", current->comm, current->pid);
+
+ if (count == 0) /* according to manpage */
+ return 0;
+
+ if (dev->proto == 0 && count < 4) {
+ /* T0 must have at least 4 bytes */
+ DEBUGP(4, dev, "T0 short write\n");
+ return -EIO;
+ }
+
+ nr = count & 0x1ff; /* max bytes to write */
+
+ sendT0 = dev->proto ? 0 : nr > 5 ? 0x08 : 0;
+
+ if ((dev->link.state & DEV_PRESENT) == 0 || /* socket removed */
+ test_bit(IS_CMM_ABSENT, &dev->flags))
+ return -ENODEV;
+
+ if (test_bit(IS_BAD_CSUM, &dev->flags)) {
+ DEBUGP(4, dev, "bad csum\n");
+ return -EIO;
+ }
+
+ /*
+ * wait for atr to become valid.
+ * note: it is important to lock this code. if we dont, the monitor
+ * could be run between test_bit and the the call the sleep on the
+ * atr-queue. if *then* the monitor detects atr valid, it will wake up
+ * any process on the atr-queue, *but* since we have been interrupted,
+ * we do not yet sleep on this queue. this would result in a missed
+ * wake_up and the calling process would sleep forever (until
+ * interrupted). also, do *not* restore_flags before sleep_on, because
+ * this could result in the same situation!
+ */
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { /* invalid atr */
+ DEBUGP(4, dev, "invalid ATR\n");
+ return -EIO;
+ }
+
+ /* lock io */
+ if (wait_event_interruptible
+ (dev->ioq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if (copy_from_user(dev->sbuf, buf, ((count > 512) ? 512 : count)))
+ return -EFAULT;
+
+ rc = 0;
+ dev->flags0 = inb(REG_FLAGS0(iobase));
+ if ((dev->flags0 & 1) == 0 /* no smartcard inserted */
+ || dev->flags0 == 0xff) { /* no cardman inserted */
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ if (dev->flags0 & 1) {
+ set_bit(IS_CMM_ABSENT, &dev->flags);
+ rc = -ENODEV;
+ } else {
+ DEBUGP(4, dev, "IO error\n");
+ rc = -EIO;
+ }
+ goto release_io;
+ }
+
+ xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */
+
+ if (!io_detect_cm4000(iobase, dev)) {
+ rc = -ENODEV;
+ goto release_io;
+ }
+
+ /* reflect T=0 send/read mode in flags1 */
+ dev->flags1 |= (sendT0);
+
+ set_cardparameter(dev);
+
+ /* dummy read, reset flag procedure received */
+ tmp = inb(REG_FLAGS1(iobase));
+
+ dev->flags1 = 0x20 /* T_Active */
+ | (sendT0)
+ | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0)/* inverse parity */
+ | (((dev->baudv - 1) & 0x0100) >> 8); /* MSB-Baud */
+ DEBUGP(1, dev, "set dev->flags1 = 0x%.2x\n", dev->flags1);
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+
+ /* xmit data */
+ DEBUGP(4, dev, "Xmit data\n");
+ for (i = 0; i < nr; i++) {
+ if (i >= 256) {
+ dev->flags1 = 0x20 /* T_Active */
+ | (sendT0) /* SendT0 */
+ /* inverse parity: */
+ | (test_bit(IS_INVREV, &dev->flags) ? 2 : 0)
+ | (((dev->baudv - 1) & 0x0100) >> 8) /* MSB-Baud */
+ | 0x10; /* set address high */
+ DEBUGP(4, dev, "dev->flags = 0x%.2x - set address "
+ "high\n", dev->flags1);
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ }
+ if (test_bit(IS_INVREV, &dev->flags)) {
+ DEBUGP(4, dev, "Apply inverse convention for 0x%.2x "
+ "-> 0x%.2x\n", (unsigned char)dev->sbuf[i],
+ invert_revert(dev->sbuf[i]));
+ xoutb(i, REG_BUF_ADDR(iobase));
+ xoutb(invert_revert(dev->sbuf[i]),
+ REG_BUF_DATA(iobase));
+ } else {
+ xoutb(i, REG_BUF_ADDR(iobase));
+ xoutb(dev->sbuf[i], REG_BUF_DATA(iobase));
+ }
+ }
+ DEBUGP(4, dev, "Xmit done\n");
+
+ if (dev->proto == 0) {
+ /* T=0 proto: 0 byte reply */
+ if (nr == 4) {
+ DEBUGP(4, dev, "T=0 assumes 0 byte reply\n");
+ xoutb(i, REG_BUF_ADDR(iobase));
+ if (test_bit(IS_INVREV, &dev->flags))
+ xoutb(0xff, REG_BUF_DATA(iobase));
+ else
+ xoutb(0x00, REG_BUF_DATA(iobase));
+ }
+
+ /* numSendBytes */
+ if (sendT0)
+ nsend = nr;
+ else {
+ if (nr == 4)
+ nsend = 5;
+ else {
+ nsend = 5 + (unsigned char)dev->sbuf[4];
+ if (dev->sbuf[4] == 0)
+ nsend += 0x100;
+ }
+ }
+ } else
+ nsend = nr;
+
+ /* T0: output procedure byte */
+ if (test_bit(IS_INVREV, &dev->flags)) {
+ DEBUGP(4, dev, "T=0 set Procedure byte (inverse-reverse) "
+ "0x%.2x\n", invert_revert(dev->sbuf[1]));
+ xoutb(invert_revert(dev->sbuf[1]), REG_NUM_BYTES(iobase));
+ } else {
+ DEBUGP(4, dev, "T=0 set Procedure byte 0x%.2x\n", dev->sbuf[1]);
+ xoutb(dev->sbuf[1], REG_NUM_BYTES(iobase));
+ }
+
+ DEBUGP(1, dev, "set NumSendBytes = 0x%.2x\n",
+ (unsigned char)(nsend & 0xff));
+ xoutb((unsigned char)(nsend & 0xff), REG_NUM_SEND(iobase));
+
+ DEBUGP(1, dev, "Trigger CARDMAN CONTROLLER (0x%.2x)\n",
+ 0x40 /* SM_Active */
+ | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */
+ |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */
+ |(nsend & 0x100) >> 8 /* MSB numSendBytes */ );
+ xoutb(0x40 /* SM_Active */
+ | (dev->flags0 & 2 ? 0 : 4) /* power on if needed */
+ |(dev->proto ? 0x10 : 0x08) /* T=1/T=0 */
+ |(nsend & 0x100) >> 8, /* MSB numSendBytes */
+ REG_FLAGS0(iobase));
+
+ /* wait for xmit done */
+ if (dev->proto == 1) {
+ DEBUGP(4, dev, "Wait for xmit done\n");
+ for (i = 0; i < 1000; i++) {
+ if (inb(REG_FLAGS0(iobase)) & 0x08)
+ break;
+ msleep_interruptible(10);
+ }
+ if (i == 1000) {
+ DEBUGP(4, dev, "timeout waiting for xmit done\n");
+ rc = -EIO;
+ goto release_io;
+ }
+ }
+
+ /* T=1: wait for infoLen */
+
+ infolen = 0;
+ if (dev->proto) {
+ /* wait until infoLen is valid */
+ for (i = 0; i < 6000; i++) { /* max waiting time of 1 min */
+ io_read_num_rec_bytes(iobase, &s);
+ if (s >= 3) {
+ infolen = inb(REG_FLAGS1(iobase));
+ DEBUGP(4, dev, "infolen=%d\n", infolen);
+ break;
+ }
+ msleep_interruptible(10);
+ }
+ if (i == 6000) {
+ DEBUGP(4, dev, "timeout waiting for infoLen\n");
+ rc = -EIO;
+ goto release_io;
+ }
+ } else
+ clear_bit(IS_PROCBYTE_PRESENT, &dev->flags);
+
+ /* numRecBytes | bit9 of numRecytes */
+ io_read_num_rec_bytes(iobase, &dev->rlen);
+ for (i = 0; i < 600; i++) { /* max waiting time of 2 sec */
+ if (dev->proto) {
+ if (dev->rlen >= infolen + 4)
+ break;
+ }
+ msleep_interruptible(10);
+ /* numRecBytes | bit9 of numRecytes */
+ io_read_num_rec_bytes(iobase, &s);
+ if (s > dev->rlen) {
+ DEBUGP(1, dev, "NumRecBytes inc (reset timeout)\n");
+ i = 0; /* reset timeout */
+ dev->rlen = s;
+ }
+ /* T=0: we are done when numRecBytes doesn't
+ * increment any more and NoProcedureByte
+ * is set and numRecBytes == bytes sent + 6
+ * (header bytes + data + 1 for sw2)
+ * except when the card replies an error
+ * which means, no data will be sent back.
+ */
+ else if (dev->proto == 0) {
+ if ((inb(REG_BUF_ADDR(iobase)) & 0x80)) {
+ /* no procedure byte received since last read */
+ DEBUGP(1, dev, "NoProcedure byte set\n");
+ /* i=0; */
+ } else {
+ /* procedure byte received since last read */
+ DEBUGP(1, dev, "NoProcedure byte unset "
+ "(reset timeout)\n");
+ dev->procbyte = inb(REG_FLAGS1(iobase));
+ DEBUGP(1, dev, "Read procedure byte 0x%.2x\n",
+ dev->procbyte);
+ i = 0; /* resettimeout */
+ }
+ if (inb(REG_FLAGS0(iobase)) & 0x08) {
+ DEBUGP(1, dev, "T0Done flag (read reply)\n");
+ break;
+ }
+ }
+ if (dev->proto)
+ infolen = inb(REG_FLAGS1(iobase));
+ }
+ if (i == 600) {
+ DEBUGP(1, dev, "timeout waiting for numRecBytes\n");
+ rc = -EIO;
+ goto release_io;
+ } else {
+ if (dev->proto == 0) {
+ DEBUGP(1, dev, "Wait for T0Done bit to be set\n");
+ for (i = 0; i < 1000; i++) {
+ if (inb(REG_FLAGS0(iobase)) & 0x08)
+ break;
+ msleep_interruptible(10);
+ }
+ if (i == 1000) {
+ DEBUGP(1, dev, "timeout waiting for T0Done\n");
+ rc = -EIO;
+ goto release_io;
+ }
+
+ dev->procbyte = inb(REG_FLAGS1(iobase));
+ DEBUGP(4, dev, "Read procedure byte 0x%.2x\n",
+ dev->procbyte);
+
+ io_read_num_rec_bytes(iobase, &dev->rlen);
+ DEBUGP(4, dev, "Read NumRecBytes = %i\n", dev->rlen);
+
+ }
+ }
+ /* T=1: read offset=zero, T=0: read offset=after challenge */
+ dev->rpos = dev->proto ? 0 : nr == 4 ? 5 : nr > dev->rlen ? 5 : nr;
+ DEBUGP(4, dev, "dev->rlen = %i, dev->rpos = %i, nr = %i\n",
+ dev->rlen, dev->rpos, nr);
+
+release_io:
+ DEBUGP(4, dev, "Reset SM\n");
+ xoutb(0x80, REG_FLAGS0(iobase)); /* reset SM */
+
+ if (rc < 0) {
+ DEBUGP(4, dev, "Write failed but clear T_Active\n");
+ dev->flags1 &= 0xdf;
+ xoutb(dev->flags1, REG_FLAGS1(iobase));
+ }
+
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq);
+ wake_up_interruptible(&dev->readq); /* tell read we have data */
+
+ /* ITSEC E2: clear write buffer */
+ memset((char *)dev->sbuf, 0, 512);
+
+ /* return error or actually written bytes */
+ DEBUGP(2, dev, "<- cmm_write\n");
+ return rc < 0 ? rc : nr;
+}
+
+static void start_monitor(struct cm4000_dev *dev)
+{
+ DEBUGP(3, dev, "-> start_monitor\n");
+ if (!dev->monitor_running) {
+ DEBUGP(5, dev, "create, init and add timer\n");
+ init_timer(&dev->timer);
+ dev->monitor_running = 1;
+ dev->timer.expires = jiffies;
+ dev->timer.data = (unsigned long) dev;
+ dev->timer.function = monitor_card;
+ add_timer(&dev->timer);
+ } else
+ DEBUGP(5, dev, "monitor already running\n");
+ DEBUGP(3, dev, "<- start_monitor\n");
+}
+
+static void stop_monitor(struct cm4000_dev *dev)
+{
+ DEBUGP(3, dev, "-> stop_monitor\n");
+ if (dev->monitor_running) {
+ DEBUGP(5, dev, "stopping monitor\n");
+ terminate_monitor(dev);
+ /* reset monitor SM */
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ clear_bit(IS_ATR_PRESENT, &dev->flags);
+ } else
+ DEBUGP(5, dev, "monitor already stopped\n");
+ DEBUGP(3, dev, "<- stop_monitor\n");
+}
+
+static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cm4000_dev *dev = filp->private_data;
+ ioaddr_t iobase = dev->link.io.BasePort1;
+ dev_link_t *link;
+ int size;
+ int rc;
+#ifdef PCMCIA_DEBUG
+ char *ioctl_names[CM_IOC_MAXNR + 1] = {
+ [_IOC_NR(CM_IOCGSTATUS)] "CM_IOCGSTATUS",
+ [_IOC_NR(CM_IOCGATR)] "CM_IOCGATR",
+ [_IOC_NR(CM_IOCARDOFF)] "CM_IOCARDOFF",
+ [_IOC_NR(CM_IOCSPTS)] "CM_IOCSPTS",
+ [_IOC_NR(CM_IOSDBGLVL)] "CM4000_DBGLVL",
+ };
+#endif
+ DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode),
+ iminor(inode), ioctl_names[_IOC_NR(cmd)]);
+
+ link = dev_table[iminor(inode)];
+ if (!(DEV_OK(link))) {
+ DEBUGP(4, dev, "DEV_OK false\n");
+ return -ENODEV;
+ }
+
+ if (test_bit(IS_CMM_ABSENT, &dev->flags)) {
+ DEBUGP(4, dev, "CMM_ABSENT flag set\n");
+ return -ENODEV;
+ }
+
+ if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) {
+ DEBUGP(4, dev, "ioctype mismatch\n");
+ return -EINVAL;
+ }
+ if (_IOC_NR(cmd) > CM_IOC_MAXNR) {
+ DEBUGP(4, dev, "iocnr mismatch\n");
+ return -EINVAL;
+ }
+ size = _IOC_SIZE(cmd);
+ rc = 0;
+ DEBUGP(4, dev, "iocdir=%.4x iocr=%.4x iocw=%.4x iocsize=%d cmd=%.4x\n",
+ _IOC_DIR(cmd), _IOC_READ, _IOC_WRITE, size, cmd);
+
+ if (_IOC_DIR(cmd) & _IOC_READ) {
+ if (!access_ok(VERIFY_WRITE, (void *)arg, size))
+ return -EFAULT;
+ }
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ if (!access_ok(VERIFY_READ, (void *)arg, size))
+ return -EFAULT;
+ }
+
+ switch (cmd) {
+ case CM_IOCGSTATUS:
+ DEBUGP(4, dev, " ... in CM_IOCGSTATUS\n");
+ {
+ int status;
+
+ /* clear other bits, but leave inserted & powered as
+ * they are */
+ status = dev->flags0 & 3;
+ if (test_bit(IS_ATR_PRESENT, &dev->flags))
+ status |= CM_ATR_PRESENT;
+ if (test_bit(IS_ATR_VALID, &dev->flags))
+ status |= CM_ATR_VALID;
+ if (test_bit(IS_CMM_ABSENT, &dev->flags))
+ status |= CM_NO_READER;
+ if (test_bit(IS_BAD_CARD, &dev->flags))
+ status |= CM_BAD_CARD;
+ if (copy_to_user((int *)arg, &status, sizeof(int)))
+ return -EFAULT;
+ }
+ return 0;
+ case CM_IOCGATR:
+ DEBUGP(4, dev, "... in CM_IOCGATR\n");
+ {
+ struct atreq *atreq = (struct atreq *) arg;
+ int tmp;
+ /* allow nonblocking io and being interrupted */
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags)
+ != 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if (test_bit(IS_ATR_VALID, &dev->flags) == 0) {
+ tmp = -1;
+ if (copy_to_user(&(atreq->atr_len), &tmp,
+ sizeof(int)))
+ return -EFAULT;
+ } else {
+ if (copy_to_user(atreq->atr, dev->atr,
+ dev->atr_len))
+ return -EFAULT;
+
+ tmp = dev->atr_len;
+ if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int)))
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case CM_IOCARDOFF:
+
+#ifdef PCMCIA_DEBUG
+ DEBUGP(4, dev, "... in CM_IOCARDOFF\n");
+ if (dev->flags0 & 0x01) {
+ DEBUGP(4, dev, " Card inserted\n");
+ } else {
+ DEBUGP(2, dev, " No card inserted\n");
+ }
+ if (dev->flags0 & 0x02) {
+ DEBUGP(4, dev, " Card powered\n");
+ } else {
+ DEBUGP(2, dev, " Card not powered\n");
+ }
+#endif
+
+ /* is a card inserted and powered? */
+ if ((dev->flags0 & 0x01) && (dev->flags0 & 0x02)) {
+
+ /* get IO lock */
+ if (wait_event_interruptible
+ (dev->ioq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)
+ == 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+ /* Set Flags0 = 0x42 */
+ DEBUGP(4, dev, "Set Flags0=0x42 \n");
+ xoutb(0x42, REG_FLAGS0(iobase));
+ clear_bit(IS_ATR_PRESENT, &dev->flags);
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ dev->mstate = M_CARDOFF;
+ clear_bit(LOCK_IO, &dev->flags);
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_VALID, (void *)&dev->flags) !=
+ 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+ }
+ /* release lock */
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq);
+
+ return 0;
+ case CM_IOCSPTS:
+ {
+ struct ptsreq krnptsreq;
+
+ if (copy_from_user(&krnptsreq, (struct ptsreq *) arg,
+ sizeof(struct ptsreq)))
+ return -EFAULT;
+
+ rc = 0;
+ DEBUGP(4, dev, "... in CM_IOCSPTS\n");
+ /* wait for ATR to get valid */
+ if (wait_event_interruptible
+ (dev->atrq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags)
+ != 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+ /* get IO lock */
+ if (wait_event_interruptible
+ (dev->ioq,
+ ((filp->f_flags & O_NONBLOCK)
+ || (test_and_set_bit(LOCK_IO, (void *)&dev->flags)
+ == 0)))) {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ return -ERESTARTSYS;
+ }
+
+ if ((rc = set_protocol(dev, &krnptsreq)) != 0) {
+ /* auto power_on again */
+ dev->mstate = M_FETCH_ATR;
+ clear_bit(IS_ATR_VALID, &dev->flags);
+ }
+ /* release lock */
+ clear_bit(LOCK_IO, &dev->flags);
+ wake_up_interruptible(&dev->ioq);
+
+ }
+ return rc;
+#ifdef PCMCIA_DEBUG
+ case CM_IOSDBGLVL: /* set debug log level */
+ {
+ int old_pc_debug = 0;
+
+ old_pc_debug = pc_debug;
+ if (copy_from_user(&pc_debug, (int *)arg, sizeof(int)))
+ return -EFAULT;
+
+ if (old_pc_debug != pc_debug)
+ DEBUGP(0, dev, "Changed debug log level "
+ "to %i\n", pc_debug);
+ }
+ return rc;
+#endif
+ default:
+ DEBUGP(4, dev, "... in default (unknown IOCTL code)\n");
+ return -EINVAL;
+ }
+}
+
+static int cmm_open(struct inode *inode, struct file *filp)
+{
+ struct cm4000_dev *dev;
+ dev_link_t *link;
+ int rc, minor = iminor(inode);
+
+ if (minor >= CM4000_MAX_DEV)
+ return -ENODEV;
+
+ link = dev_table[minor];
+ if (link == NULL || !(DEV_OK(link)))
+ return -ENODEV;
+
+ if (link->open)
+ return -EBUSY;
+
+ dev = link->priv;
+ filp->private_data = dev;
+
+ DEBUGP(2, dev, "-> cmm_open(device=%d.%d process=%s,%d)\n",
+ imajor(inode), minor, current->comm, current->pid);
+
+ /* init device variables, they may be "polluted" after close
+ * or, the device may never have been closed (i.e. open failed)
+ */
+
+ ZERO_DEV(dev);
+
+ /* opening will always block since the
+ * monitor will be started by open, which
+ * means we have to wait for ATR becoming
+ * vaild = block until valid (or card
+ * inserted)
+ */
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ dev->mdelay = T_50MSEC;
+
+ /* start monitoring the cardstatus */
+ start_monitor(dev);
+
+ link->open = 1; /* only one open per device */
+ rc = 0;
+
+ DEBUGP(2, dev, "<- cmm_open\n");
+ return nonseekable_open(inode, filp);
+}
+
+static int cmm_close(struct inode *inode, struct file *filp)
+{
+ struct cm4000_dev *dev;
+ dev_link_t *link;
+ int minor = iminor(inode);
+
+ if (minor >= CM4000_MAX_DEV)
+ return -ENODEV;
+
+ link = dev_table[minor];
+ if (link == NULL)
+ return -ENODEV;
+
+ dev = link->priv;
+
+ DEBUGP(2, dev, "-> cmm_close(maj/min=%d.%d)\n",
+ imajor(inode), minor);
+
+ stop_monitor(dev);
+
+ ZERO_DEV(dev);
+
+ link->open = 0; /* only one open per device */
+ wake_up(&dev->devq); /* socket removed? */
+
+ DEBUGP(2, dev, "cmm_close\n");
+ return 0;
+}
+
+static void cmm_cm4000_release(dev_link_t * link)
+{
+ struct cm4000_dev *dev = link->priv;
+
+ /* dont terminate the monitor, rather rely on
+ * close doing that for us.
+ */
+ DEBUGP(3, dev, "-> cmm_cm4000_release\n");
+ while (link->open) {
+ printk(KERN_INFO MODULE_NAME ": delaying release until "
+ "process has terminated\n");
+ /* note: don't interrupt us:
+ * close the applications which own
+ * the devices _first_ !
+ */
+ wait_event(dev->devq, (link->open == 0));
+ }
+ /* dev->devq=NULL; this cannot be zeroed earlier */
+ DEBUGP(3, dev, "<- cmm_cm4000_release\n");
+ return;
+}
+
+/*==== Interface to PCMCIA Layer =======================================*/
+
+static void cm4000_config(dev_link_t * link, int devno)
+{
+ client_handle_t handle = link->handle;
+ struct cm4000_dev *dev;
+ tuple_t tuple;
+ cisparse_t parse;
+ config_info_t conf;
+ u_char buf[64];
+ int fail_fn, fail_rc;
+ int rc;
+
+ /* read the config-tuples */
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+
+ if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) {
+ fail_fn = GetFirstTuple;
+ goto cs_failed;
+ }
+ if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) {
+ fail_fn = GetTupleData;
+ goto cs_failed;
+ }
+ if ((fail_rc =
+ pcmcia_parse_tuple(handle, &tuple, &parse)) != CS_SUCCESS) {
+ fail_fn = ParseTuple;
+ goto cs_failed;
+ }
+ if ((fail_rc =
+ pcmcia_get_configuration_info(handle, &conf)) != CS_SUCCESS) {
+ fail_fn = GetConfigurationInfo;
+ goto cs_failed;
+ }
+
+ link->state |= DEV_CONFIG;
+ link->conf.ConfigBase = parse.config.base;
+ link->conf.Present = parse.config.rmask[0];
+ link->conf.Vcc = conf.Vcc;
+
+ link->io.BasePort2 = 0;
+ link->io.NumPorts2 = 0;
+ link->io.Attributes2 = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ for (rc = pcmcia_get_first_tuple(handle, &tuple);
+ rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(handle, &tuple)) {
+
+ rc = pcmcia_get_tuple_data(handle, &tuple);
+ if (rc != CS_SUCCESS)
+ continue;
+ rc = pcmcia_parse_tuple(handle, &tuple, &parse);
+ if (rc != CS_SUCCESS)
+ continue;
+
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+
+ if (!parse.cftable_entry.io.nwin)
+ continue;
+
+ /* Get the IOaddr */
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines = parse.cftable_entry.io.flags
+ & CISTPL_IO_LINES_MASK;
+
+ rc = pcmcia_request_io(handle, &link->io);
+ if (rc == CS_SUCCESS)
+ break; /* we are done */
+ }
+ if (rc != CS_SUCCESS)
+ goto cs_release;
+
+ link->conf.IntType = 00000002;
+
+ if ((fail_rc =
+ pcmcia_request_configuration(handle, &link->conf)) != CS_SUCCESS) {
+ fail_fn = RequestConfiguration;
+ goto cs_release;
+ }
+
+ dev = link->priv;
+ sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);
+ dev->node.major = major;
+ dev->node.minor = devno;
+ dev->node.next = NULL;
+ link->dev = &dev->node;
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ return;
+
+cs_failed:
+ cs_error(handle, fail_fn, fail_rc);
+cs_release:
+ cm4000_release(link);
+
+ link->state &= ~DEV_CONFIG_PENDING;
+}
+
+static int cm4000_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link;
+ struct cm4000_dev *dev;
+ int devno;
+
+ link = args->client_data;
+ dev = link->priv;
+
+ DEBUGP(3, dev, "-> cm4000_event\n");
+ for (devno = 0; devno < CM4000_MAX_DEV; devno++)
+ if (dev_table[devno] == link)
+ break;
+
+ if (devno == CM4000_MAX_DEV)
+ return CS_BAD_ADAPTER;
+
+ switch (event) {
+ case CS_EVENT_CARD_INSERTION:
+ DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n");
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ cm4000_config(link, devno);
+ break;
+ case CS_EVENT_CARD_REMOVAL:
+ DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n");
+ link->state &= ~DEV_PRESENT;
+ stop_monitor(dev);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND "
+ "(fall-through to CS_EVENT_RESET_PHYSICAL)\n");
+ link->state |= DEV_SUSPEND;
+ /* fall-through */
+ case CS_EVENT_RESET_PHYSICAL:
+ DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n");
+ if (link->state & DEV_CONFIG) {
+ DEBUGP(5, dev, "ReleaseConfiguration\n");
+ pcmcia_release_configuration(link->handle);
+ }
+ stop_monitor(dev);
+ break;
+ case CS_EVENT_PM_RESUME:
+ DEBUGP(5, dev, "CS_EVENT_PM_RESUME "
+ "(fall-through to CS_EVENT_CARD_RESET)\n");
+ link->state &= ~DEV_SUSPEND;
+ /* fall-through */
+ case CS_EVENT_CARD_RESET:
+ DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n");
+ if ((link->state & DEV_CONFIG)) {
+ DEBUGP(5, dev, "RequestConfiguration\n");
+ pcmcia_request_configuration(link->handle, &link->conf);
+ }
+ if (link->open)
+ start_monitor(dev);
+ break;
+ default:
+ DEBUGP(5, dev, "unknown event %.2x\n", event);
+ break;
+ }
+ DEBUGP(3, dev, "<- cm4000_event\n");
+ return CS_SUCCESS;
+}
+
+static void cm4000_release(dev_link_t *link)
+{
+ cmm_cm4000_release(link->priv); /* delay release until device closed */
+ pcmcia_release_configuration(link->handle);
+ pcmcia_release_io(link->handle, &link->io);
+}
+
+static dev_link_t *cm4000_attach(void)
+{
+ struct cm4000_dev *dev;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int i;
+
+ for (i = 0; i < CM4000_MAX_DEV; i++)
+ if (dev_table[i] == NULL)
+ break;
+
+ if (i == CM4000_MAX_DEV) {
+ printk(KERN_NOTICE MODULE_NAME ": all devices in use\n");
+ return NULL;
+ }
+
+ /* create a new cm4000_cs device */
+ dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL);
+ if (dev == NULL)
+ return NULL;
+
+ link = &dev->link;
+ link->priv = dev;
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ dev_table[i] = link;
+
+ /* register with card services */
+ client_reg.dev_info = &dev_info;
+ client_reg.EventMask =
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+
+ i = pcmcia_register_client(&link->handle, &client_reg);
+ if (i) {
+ cs_error(link->handle, RegisterClient, i);
+ cm4000_detach(link);
+ return NULL;
+ }
+
+ init_waitqueue_head(&dev->devq);
+ init_waitqueue_head(&dev->ioq);
+ init_waitqueue_head(&dev->atrq);
+ init_waitqueue_head(&dev->readq);
+
+ return link;
+}
+
+static void cm4000_detach_by_devno(int devno, dev_link_t * link)
+{
+ struct cm4000_dev *dev = link->priv;
+
+ DEBUGP(3, dev, "-> detach_by_devno(devno=%d)\n", devno);
+
+ if (link->state & DEV_CONFIG) {
+ DEBUGP(5, dev, "device still configured (try to release it)\n");
+ cm4000_release(link);
+ }
+
+ if (link->handle) {
+ pcmcia_deregister_client(link->handle);
+ }
+
+ dev_table[devno] = NULL;
+ kfree(dev);
+ return;
+}
+
+static void cm4000_detach(dev_link_t * link)
+{
+ int i;
+
+ /* find device */
+ for (i = 0; i < CM4000_MAX_DEV; i++)
+ if (dev_table[i] == link)
+ break;
+
+ if (i == CM4000_MAX_DEV)
+ return;
+
+ cm4000_detach_by_devno(i, link);
+ return;
+}
+
+static struct file_operations cm4000_fops = {
+ .owner = THIS_MODULE,
+ .read = cmm_read,
+ .write = cmm_write,
+ .ioctl = cmm_ioctl,
+ .open = cmm_open,
+ .release= cmm_close,
+};
+
+static struct pcmcia_device_id cm4000_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002),
+ PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, cm4000_ids);
+
+static struct pcmcia_driver cm4000_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "cm4000_cs",
+ },
+ .attach = cm4000_attach,
+ .detach = cm4000_detach,
+ .event = cm4000_event,
+ .id_table = cm4000_ids,
+};
+
+static int __init cmm_init(void)
+{
+ printk(KERN_INFO "%s\n", version);
+ pcmcia_register_driver(&cm4000_driver);
+ major = register_chrdev(0, DEVICE_NAME, &cm4000_fops);
+ if (major < 0) {
+ printk(KERN_WARNING MODULE_NAME
+ ": could not get major number\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __exit cmm_exit(void)
+{
+ int i;
+
+ printk(KERN_INFO MODULE_NAME ": unloading\n");
+ pcmcia_unregister_driver(&cm4000_driver);
+ for (i = 0; i < CM4000_MAX_DEV; i++)
+ if (dev_table[i])
+ cm4000_detach_by_devno(i, dev_table[i]);
+ unregister_chrdev(major, DEVICE_NAME);
+};
+
+module_init(cmm_init);
+module_exit(cmm_exit);
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
new file mode 100644
index 00000000000..4c698d908ff
--- /dev/null
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -0,0 +1,841 @@
+/*
+ * A driver for the Omnikey PCMCIA smartcard reader CardMan 4040
+ *
+ * (c) 2000-2004 Omnikey AG (http://www.omnikey.com/)
+ *
+ * (C) 2005 Harald Welte <laforge@gnumonks.org>
+ * - add support for poll()
+ * - driver cleanup
+ * - add waitqueues
+ * - adhere to linux kernel coding style and policies
+ * - support 2.6.13 "new style" pcmcia interface
+ *
+ * The device basically is a USB CCID compliant device that has been
+ * attached to an I/O-Mapped FIFO.
+ *
+ * All rights reserved, Dual BSD/GPL Licensed.
+ */
+
+/* #define PCMCIA_DEBUG 6 */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+#include "cm4040_cs.h"
+
+
+#ifdef PCMCIA_DEBUG
+#define reader_to_dev(x) (&handle_to_dev(x->link.handle))
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0600);
+#define DEBUGP(n, rdr, x, args...) do { \
+ if (pc_debug >= (n)) \
+ dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
+ __FUNCTION__ , ##args); \
+ } while (0)
+#else
+#define DEBUGP(n, rdr, x, args...)
+#endif
+
+static char *version =
+"OMNIKEY CardMan 4040 v1.1.0gm4 - All bugs added by Harald Welte";
+
+#define CCID_DRIVER_BULK_DEFAULT_TIMEOUT (150*HZ)
+#define CCID_DRIVER_ASYNC_POWERUP_TIMEOUT (35*HZ)
+#define CCID_DRIVER_MINIMUM_TIMEOUT (3*HZ)
+#define READ_WRITE_BUFFER_SIZE 512
+#define POLL_LOOP_COUNT 1000
+
+/* how often to poll for fifo status change */
+#define POLL_PERIOD msecs_to_jiffies(10)
+
+static void reader_release(dev_link_t *link);
+static void reader_detach(dev_link_t *link);
+
+static int major;
+
+#define BS_READABLE 0x01
+#define BS_WRITABLE 0x02
+
+struct reader_dev {
+ dev_link_t link;
+ dev_node_t node;
+ wait_queue_head_t devq;
+ wait_queue_head_t poll_wait;
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+ unsigned long buffer_status;
+ unsigned long timeout;
+ unsigned char s_buf[READ_WRITE_BUFFER_SIZE];
+ unsigned char r_buf[READ_WRITE_BUFFER_SIZE];
+ struct timer_list poll_timer;
+};
+
+static dev_info_t dev_info = MODULE_NAME;
+static dev_link_t *dev_table[CM_MAX_DEV];
+
+#ifndef PCMCIA_DEBUG
+#define xoutb outb
+#define xinb inb
+#else
+static inline void xoutb(unsigned char val, unsigned short port)
+{
+ if (pc_debug >= 7)
+ printk(KERN_DEBUG "outb(val=%.2x,port=%.4x)\n", val, port);
+ outb(val, port);
+}
+
+static inline unsigned char xinb(unsigned short port)
+{
+ unsigned char val;
+
+ val = inb(port);
+ if (pc_debug >= 7)
+ printk(KERN_DEBUG "%.2x=inb(%.4x)\n", val, port);
+ return val;
+}
+#endif
+
+/* poll the device fifo status register. not to be confused with
+ * the poll syscall. */
+static void cm4040_do_poll(unsigned long dummy)
+{
+ struct reader_dev *dev = (struct reader_dev *) dummy;
+ unsigned int obs = xinb(dev->link.io.BasePort1
+ + REG_OFFSET_BUFFER_STATUS);
+
+ if ((obs & BSR_BULK_IN_FULL)) {
+ set_bit(BS_READABLE, &dev->buffer_status);
+ DEBUGP(4, dev, "waking up read_wait\n");
+ wake_up_interruptible(&dev->read_wait);
+ } else
+ clear_bit(BS_READABLE, &dev->buffer_status);
+
+ if (!(obs & BSR_BULK_OUT_FULL)) {
+ set_bit(BS_WRITABLE, &dev->buffer_status);
+ DEBUGP(4, dev, "waking up write_wait\n");
+ wake_up_interruptible(&dev->write_wait);
+ } else
+ clear_bit(BS_WRITABLE, &dev->buffer_status);
+
+ if (dev->buffer_status)
+ wake_up_interruptible(&dev->poll_wait);
+
+ mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);
+}
+
+static void cm4040_stop_poll(struct reader_dev *dev)
+{
+ del_timer_sync(&dev->poll_timer);
+}
+
+static int wait_for_bulk_out_ready(struct reader_dev *dev)
+{
+ int i, rc;
+ int iobase = dev->link.io.BasePort1;
+
+ for (i = 0; i < POLL_LOOP_COUNT; i++) {
+ if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
+ & BSR_BULK_OUT_FULL) == 0) {
+ DEBUGP(4, dev, "BulkOut empty (i=%d)\n", i);
+ return 1;
+ }
+ }
+
+ DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",
+ dev->timeout);
+ rc = wait_event_interruptible_timeout(dev->write_wait,
+ test_and_clear_bit(BS_WRITABLE,
+ &dev->buffer_status),
+ dev->timeout);
+
+ if (rc > 0)
+ DEBUGP(4, dev, "woke up: BulkOut empty\n");
+ else if (rc == 0)
+ DEBUGP(4, dev, "woke up: BulkOut full, returning 0 :(\n");
+ else if (rc < 0)
+ DEBUGP(4, dev, "woke up: signal arrived\n");
+
+ return rc;
+}
+
+/* Write to Sync Control Register */
+static int write_sync_reg(unsigned char val, struct reader_dev *dev)
+{
+ int iobase = dev->link.io.BasePort1;
+ int rc;
+
+ rc = wait_for_bulk_out_ready(dev);
+ if (rc <= 0)
+ return rc;
+
+ xoutb(val, iobase + REG_OFFSET_SYNC_CONTROL);
+ rc = wait_for_bulk_out_ready(dev);
+ if (rc <= 0)
+ return rc;
+
+ return 1;
+}
+
+static int wait_for_bulk_in_ready(struct reader_dev *dev)
+{
+ int i, rc;
+ int iobase = dev->link.io.BasePort1;
+
+ for (i = 0; i < POLL_LOOP_COUNT; i++) {
+ if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS)
+ & BSR_BULK_IN_FULL) == BSR_BULK_IN_FULL) {
+ DEBUGP(3, dev, "BulkIn full (i=%d)\n", i);
+ return 1;
+ }
+ }
+
+ DEBUGP(4, dev, "wait_event_interruptible_timeout(timeout=%ld\n",
+ dev->timeout);
+ rc = wait_event_interruptible_timeout(dev->read_wait,
+ test_and_clear_bit(BS_READABLE,
+ &dev->buffer_status),
+ dev->timeout);
+ if (rc > 0)
+ DEBUGP(4, dev, "woke up: BulkIn full\n");
+ else if (rc == 0)
+ DEBUGP(4, dev, "woke up: BulkIn not full, returning 0 :(\n");
+ else if (rc < 0)
+ DEBUGP(4, dev, "woke up: signal arrived\n");
+
+ return rc;
+}
+
+static ssize_t cm4040_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct reader_dev *dev = filp->private_data;
+ int iobase = dev->link.io.BasePort1;
+ size_t bytes_to_read;
+ unsigned long i;
+ size_t min_bytes_to_read;
+ int rc;
+ unsigned char uc;
+
+ DEBUGP(2, dev, "-> cm4040_read(%s,%d)\n", current->comm, current->pid);
+
+ if (count == 0)
+ return 0;
+
+ if (count < 10)
+ return -EFAULT;
+
+ if (filp->f_flags & O_NONBLOCK) {
+ DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
+ DEBUGP(2, dev, "<- cm4040_read (failure)\n");
+ return -EAGAIN;
+ }
+
+ if ((dev->link.state & DEV_PRESENT)==0)
+ return -ENODEV;
+
+ for (i = 0; i < 5; i++) {
+ rc = wait_for_bulk_in_ready(dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
+ DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ return -EIO;
+ }
+ dev->r_buf[i] = xinb(iobase + REG_OFFSET_BULK_IN);
+#ifdef PCMCIA_DEBUG
+ if (pc_debug >= 6)
+ printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);
+ }
+ printk("\n");
+#else
+ }
+#endif
+
+ bytes_to_read = 5 + le32_to_cpu(*(__le32 *)&dev->r_buf[1]);
+
+ DEBUGP(6, dev, "BytesToRead=%lu\n", bytes_to_read);
+
+ min_bytes_to_read = min(count, bytes_to_read + 5);
+
+ DEBUGP(6, dev, "Min=%lu\n", min_bytes_to_read);
+
+ for (i = 0; i < (min_bytes_to_read-5); i++) {
+ rc = wait_for_bulk_in_ready(dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
+ DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ return -EIO;
+ }
+ dev->r_buf[i+5] = xinb(iobase + REG_OFFSET_BULK_IN);
+#ifdef PCMCIA_DEBUG
+ if (pc_debug >= 6)
+ printk(KERN_DEBUG "%lu:%2x ", i, dev->r_buf[i]);
+ }
+ printk("\n");
+#else
+ }
+#endif
+
+ *ppos = min_bytes_to_read;
+ if (copy_to_user(buf, dev->r_buf, min_bytes_to_read))
+ return -EFAULT;
+
+ rc = wait_for_bulk_in_ready(dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "wait_for_bulk_in_ready rc=%.2x\n", rc);
+ DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ return -EIO;
+ }
+
+ rc = write_sync_reg(SCR_READER_TO_HOST_DONE, dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "write_sync_reg c=%.2x\n", rc);
+ DEBUGP(2, dev, "<- cm4040_read (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ else
+ return -EIO;
+ }
+
+ uc = xinb(iobase + REG_OFFSET_BULK_IN);
+
+ DEBUGP(2, dev, "<- cm4040_read (successfully)\n");
+ return min_bytes_to_read;
+}
+
+static ssize_t cm4040_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct reader_dev *dev = filp->private_data;
+ int iobase = dev->link.io.BasePort1;
+ ssize_t rc;
+ int i;
+ unsigned int bytes_to_write;
+
+ DEBUGP(2, dev, "-> cm4040_write(%s,%d)\n", current->comm, current->pid);
+
+ if (count == 0) {
+ DEBUGP(2, dev, "<- cm4040_write empty read (successfully)\n");
+ return 0;
+ }
+
+ if (count < 5) {
+ DEBUGP(2, dev, "<- cm4040_write buffersize=%Zd < 5\n", count);
+ return -EIO;
+ }
+
+ if (filp->f_flags & O_NONBLOCK) {
+ DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
+ DEBUGP(4, dev, "<- cm4040_write (failure)\n");
+ return -EAGAIN;
+ }
+
+ if ((dev->link.state & DEV_PRESENT) == 0)
+ return -ENODEV;
+
+ bytes_to_write = count;
+ if (copy_from_user(dev->s_buf, buf, bytes_to_write))
+ return -EFAULT;
+
+ switch (dev->s_buf[0]) {
+ case CMD_PC_TO_RDR_XFRBLOCK:
+ case CMD_PC_TO_RDR_SECURE:
+ case CMD_PC_TO_RDR_TEST_SECURE:
+ case CMD_PC_TO_RDR_OK_SECURE:
+ dev->timeout = CCID_DRIVER_BULK_DEFAULT_TIMEOUT;
+ break;
+
+ case CMD_PC_TO_RDR_ICCPOWERON:
+ dev->timeout = CCID_DRIVER_ASYNC_POWERUP_TIMEOUT;
+ break;
+
+ case CMD_PC_TO_RDR_GETSLOTSTATUS:
+ case CMD_PC_TO_RDR_ICCPOWEROFF:
+ case CMD_PC_TO_RDR_GETPARAMETERS:
+ case CMD_PC_TO_RDR_RESETPARAMETERS:
+ case CMD_PC_TO_RDR_SETPARAMETERS:
+ case CMD_PC_TO_RDR_ESCAPE:
+ case CMD_PC_TO_RDR_ICCCLOCK:
+ default:
+ dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
+ break;
+ }
+
+ rc = write_sync_reg(SCR_HOST_TO_READER_START, dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
+ DEBUGP(2, dev, "<- cm4040_write (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ else
+ return -EIO;
+ }
+
+ DEBUGP(4, dev, "start \n");
+
+ for (i = 0; i < bytes_to_write; i++) {
+ rc = wait_for_bulk_out_ready(dev);
+ if (rc <= 0) {
+ DEBUGP(5, dev, "wait_for_bulk_out_ready rc=%.2Zx\n",
+ rc);
+ DEBUGP(2, dev, "<- cm4040_write (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ else
+ return -EIO;
+ }
+
+ xoutb(dev->s_buf[i],iobase + REG_OFFSET_BULK_OUT);
+ }
+ DEBUGP(4, dev, "end\n");
+
+ rc = write_sync_reg(SCR_HOST_TO_READER_DONE, dev);
+
+ if (rc <= 0) {
+ DEBUGP(5, dev, "write_sync_reg c=%.2Zx\n", rc);
+ DEBUGP(2, dev, "<- cm4040_write (failed)\n");
+ if (rc == -ERESTARTSYS)
+ return rc;
+ else
+ return -EIO;
+ }
+
+ DEBUGP(2, dev, "<- cm4040_write (successfully)\n");
+ return count;
+}
+
+static unsigned int cm4040_poll(struct file *filp, poll_table *wait)
+{
+ struct reader_dev *dev = filp->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(filp, &dev->poll_wait, wait);
+
+ if (test_and_clear_bit(BS_READABLE, &dev->buffer_status))
+ mask |= POLLIN | POLLRDNORM;
+ if (test_and_clear_bit(BS_WRITABLE, &dev->buffer_status))
+ mask |= POLLOUT | POLLWRNORM;
+
+ DEBUGP(2, dev, "<- cm4040_poll(%u)\n", mask);
+
+ return mask;
+}
+
+static int cm4040_open(struct inode *inode, struct file *filp)
+{
+ struct reader_dev *dev;
+ dev_link_t *link;
+ int minor = iminor(inode);
+
+ if (minor >= CM_MAX_DEV)
+ return -ENODEV;
+
+ link = dev_table[minor];
+ if (link == NULL || !(DEV_OK(link)))
+ return -ENODEV;
+
+ if (link->open)
+ return -EBUSY;
+
+ dev = link->priv;
+ filp->private_data = dev;
+
+ if (filp->f_flags & O_NONBLOCK) {
+ DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n");
+ return -EAGAIN;
+ }
+
+ link->open = 1;
+
+ dev->poll_timer.data = (unsigned long) dev;
+ mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD);
+
+ DEBUGP(2, dev, "<- cm4040_open (successfully)\n");
+ return nonseekable_open(inode, filp);
+}
+
+static int cm4040_close(struct inode *inode, struct file *filp)
+{
+ struct reader_dev *dev = filp->private_data;
+ dev_link_t *link;
+ int minor = iminor(inode);
+
+ DEBUGP(2, dev, "-> cm4040_close(maj/min=%d.%d)\n", imajor(inode),
+ iminor(inode));
+
+ if (minor >= CM_MAX_DEV)
+ return -ENODEV;
+
+ link = dev_table[minor];
+ if (link == NULL)
+ return -ENODEV;
+
+ cm4040_stop_poll(dev);
+
+ link->open = 0;
+ wake_up(&dev->devq);
+
+ DEBUGP(2, dev, "<- cm4040_close\n");
+ return 0;
+}
+
+static void cm4040_reader_release(dev_link_t *link)
+{
+ struct reader_dev *dev = link->priv;
+
+ DEBUGP(3, dev, "-> cm4040_reader_release\n");
+ while (link->open) {
+ DEBUGP(3, dev, KERN_INFO MODULE_NAME ": delaying release "
+ "until process has terminated\n");
+ wait_event(dev->devq, (link->open == 0));
+ }
+ DEBUGP(3, dev, "<- cm4040_reader_release\n");
+ return;
+}
+
+static void reader_config(dev_link_t *link, int devno)
+{
+ client_handle_t handle;
+ struct reader_dev *dev;
+ tuple_t tuple;
+ cisparse_t parse;
+ config_info_t conf;
+ u_char buf[64];
+ int fail_fn, fail_rc;
+ int rc;
+
+ handle = link->handle;
+
+ tuple.DesiredTuple = CISTPL_CONFIG;
+ tuple.Attributes = 0;
+ tuple.TupleData = buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+
+ if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) {
+ fail_fn = GetFirstTuple;
+ goto cs_failed;
+ }
+ if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) {
+ fail_fn = GetTupleData;
+ goto cs_failed;
+ }
+ if ((fail_rc = pcmcia_parse_tuple(handle, &tuple, &parse))
+ != CS_SUCCESS) {
+ fail_fn = ParseTuple;
+ goto cs_failed;
+ }
+ if ((fail_rc = pcmcia_get_configuration_info(handle, &conf))
+ != CS_SUCCESS) {
+ fail_fn = GetConfigurationInfo;
+ goto cs_failed;
+ }
+
+ link->state |= DEV_CONFIG;
+ link->conf.ConfigBase = parse.config.base;
+ link->conf.Present = parse.config.rmask[0];
+ link->conf.Vcc = conf.Vcc;
+
+ link->io.BasePort2 = 0;
+ link->io.NumPorts2 = 0;
+ link->io.Attributes2 = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ for (rc = pcmcia_get_first_tuple(handle, &tuple);
+ rc == CS_SUCCESS;
+ rc = pcmcia_get_next_tuple(handle, &tuple)) {
+ rc = pcmcia_get_tuple_data(handle, &tuple);
+ if (rc != CS_SUCCESS)
+ continue;
+ rc = pcmcia_parse_tuple(handle, &tuple, &parse);
+ if (rc != CS_SUCCESS)
+ continue;
+
+ link->conf.ConfigIndex = parse.cftable_entry.index;
+
+ if (!parse.cftable_entry.io.nwin)
+ continue;
+
+ link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+ link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+ if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
+ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ link->io.IOAddrLines = parse.cftable_entry.io.flags
+ & CISTPL_IO_LINES_MASK;
+ rc = pcmcia_request_io(handle, &link->io);
+
+ dev_printk(KERN_INFO, &handle_to_dev(handle), "foo");
+ if (rc == CS_SUCCESS)
+ break;
+ else
+ dev_printk(KERN_INFO, &handle_to_dev(handle),
+ "pcmcia_request_io failed 0x%x\n", rc);
+ }
+ if (rc != CS_SUCCESS)
+ goto cs_release;
+
+ link->conf.IntType = 00000002;
+
+ if ((fail_rc = pcmcia_request_configuration(handle,&link->conf))
+ !=CS_SUCCESS) {
+ fail_fn = RequestConfiguration;
+ dev_printk(KERN_INFO, &handle_to_dev(handle),
+ "pcmcia_request_configuration failed 0x%x\n",
+ fail_rc);
+ goto cs_release;
+ }
+
+ dev = link->priv;
+ sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);
+ dev->node.major = major;
+ dev->node.minor = devno;
+ dev->node.next = NULL;
+ link->dev = &dev->node;
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4x-0x%.4x\n", devno,
+ link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1);
+ DEBUGP(2, dev, "<- reader_config (succ)\n");
+
+ return;
+
+cs_failed:
+ cs_error(handle, fail_fn, fail_rc);
+cs_release:
+ reader_release(link);
+ link->state &= ~DEV_CONFIG_PENDING;
+}
+
+static int reader_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link;
+ struct reader_dev *dev;
+ int devno;
+
+ link = args->client_data;
+ dev = link->priv;
+ DEBUGP(3, dev, "-> reader_event\n");
+ for (devno = 0; devno < CM_MAX_DEV; devno++) {
+ if (dev_table[devno] == link)
+ break;
+ }
+ if (devno == CM_MAX_DEV)
+ return CS_BAD_ADAPTER;
+
+ switch (event) {
+ case CS_EVENT_CARD_INSERTION:
+ DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n");
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ reader_config(link, devno);
+ break;
+ case CS_EVENT_CARD_REMOVAL:
+ DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n");
+ link->state &= ~DEV_PRESENT;
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND "
+ "(fall-through to CS_EVENT_RESET_PHYSICAL)\n");
+ link->state |= DEV_SUSPEND;
+
+ case CS_EVENT_RESET_PHYSICAL:
+ DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n");
+ if (link->state & DEV_CONFIG) {
+ DEBUGP(5, dev, "ReleaseConfiguration\n");
+ pcmcia_release_configuration(link->handle);
+ }
+ break;
+ case CS_EVENT_PM_RESUME:
+ DEBUGP(5, dev, "CS_EVENT_PM_RESUME "
+ "(fall-through to CS_EVENT_CARD_RESET)\n");
+ link->state &= ~DEV_SUSPEND;
+
+ case CS_EVENT_CARD_RESET:
+ DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n");
+ if ((link->state & DEV_CONFIG)) {
+ DEBUGP(5, dev, "RequestConfiguration\n");
+ pcmcia_request_configuration(link->handle,
+ &link->conf);
+ }
+ break;
+ default:
+ DEBUGP(5, dev, "reader_event: unknown event %.2x\n",
+ event);
+ break;
+ }
+ DEBUGP(3, dev, "<- reader_event\n");
+ return CS_SUCCESS;
+}
+
+static void reader_release(dev_link_t *link)
+{
+ cm4040_reader_release(link->priv);
+ pcmcia_release_configuration(link->handle);
+ pcmcia_release_io(link->handle, &link->io);
+}
+
+static dev_link_t *reader_attach(void)
+{
+ struct reader_dev *dev;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int i;
+
+ for (i = 0; i < CM_MAX_DEV; i++) {
+ if (dev_table[i] == NULL)
+ break;
+ }
+
+ if (i == CM_MAX_DEV)
+ return NULL;
+
+ dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL);
+ if (dev == NULL)
+ return NULL;
+
+ dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
+ dev->buffer_status = 0;
+
+ link = &dev->link;
+ link->priv = dev;
+
+ link->conf.IntType = INT_MEMORY_AND_IO;
+ dev_table[i] = link;
+
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.EventMask=
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ i = pcmcia_register_client(&link->handle, &client_reg);
+ if (i) {
+ cs_error(link->handle, RegisterClient, i);
+ reader_detach(link);
+ return NULL;
+ }
+ init_waitqueue_head(&dev->devq);
+ init_waitqueue_head(&dev->poll_wait);
+ init_waitqueue_head(&dev->read_wait);
+ init_waitqueue_head(&dev->write_wait);
+ init_timer(&dev->poll_timer);
+ dev->poll_timer.function = &cm4040_do_poll;
+
+ return link;
+}
+
+static void reader_detach_by_devno(int devno, dev_link_t *link)
+{
+ struct reader_dev *dev = link->priv;
+
+ if (link->state & DEV_CONFIG) {
+ DEBUGP(5, dev, "device still configured (try to release it)\n");
+ reader_release(link);
+ }
+
+ pcmcia_deregister_client(link->handle);
+ dev_table[devno] = NULL;
+ DEBUGP(5, dev, "freeing dev=%p\n", dev);
+ cm4040_stop_poll(dev);
+ kfree(dev);
+ return;
+}
+
+static void reader_detach(dev_link_t *link)
+{
+ int i;
+
+ /* find device */
+ for (i = 0; i < CM_MAX_DEV; i++) {
+ if (dev_table[i] == link)
+ break;
+ }
+ if (i == CM_MAX_DEV)
+ return;
+
+ reader_detach_by_devno(i, link);
+ return;
+}
+
+static struct file_operations reader_fops = {
+ .owner = THIS_MODULE,
+ .read = cm4040_read,
+ .write = cm4040_write,
+ .open = cm4040_open,
+ .release = cm4040_close,
+ .poll = cm4040_poll,
+};
+
+static struct pcmcia_device_id cm4040_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0200),
+ PCMCIA_DEVICE_PROD_ID12("OMNIKEY", "CardMan 4040",
+ 0xE32CDD8C, 0x8F23318B),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, cm4040_ids);
+
+static struct pcmcia_driver reader_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "cm4040_cs",
+ },
+ .attach = reader_attach,
+ .detach = reader_detach,
+ .event = reader_event,
+ .id_table = cm4040_ids,
+};
+
+static int __init cm4040_init(void)
+{
+ printk(KERN_INFO "%s\n", version);
+ pcmcia_register_driver(&reader_driver);
+ major = register_chrdev(0, DEVICE_NAME, &reader_fops);
+ if (major < 0) {
+ printk(KERN_WARNING MODULE_NAME
+ ": could not get major number\n");
+ return -1;
+ }
+ return 0;
+}
+
+static void __exit cm4040_exit(void)
+{
+ int i;
+
+ printk(KERN_INFO MODULE_NAME ": unloading\n");
+ pcmcia_unregister_driver(&reader_driver);
+ for (i = 0; i < CM_MAX_DEV; i++) {
+ if (dev_table[i])
+ reader_detach_by_devno(i, dev_table[i]);
+ }
+ unregister_chrdev(major, DEVICE_NAME);
+}
+
+module_init(cm4040_init);
+module_exit(cm4040_exit);
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/char/pcmcia/cm4040_cs.h b/drivers/char/pcmcia/cm4040_cs.h
new file mode 100644
index 00000000000..9a8b805c509
--- /dev/null
+++ b/drivers/char/pcmcia/cm4040_cs.h
@@ -0,0 +1,47 @@
+#ifndef _CM4040_H_
+#define _CM4040_H_
+
+#define CM_MAX_DEV 4
+
+#define DEVICE_NAME "cmx"
+#define MODULE_NAME "cm4040_cs"
+
+#define REG_OFFSET_BULK_OUT 0
+#define REG_OFFSET_BULK_IN 0
+#define REG_OFFSET_BUFFER_STATUS 1
+#define REG_OFFSET_SYNC_CONTROL 2
+
+#define BSR_BULK_IN_FULL 0x02
+#define BSR_BULK_OUT_FULL 0x01
+
+#define SCR_HOST_TO_READER_START 0x80
+#define SCR_ABORT 0x40
+#define SCR_EN_NOTIFY 0x20
+#define SCR_ACK_NOTIFY 0x10
+#define SCR_READER_TO_HOST_DONE 0x08
+#define SCR_HOST_TO_READER_DONE 0x04
+#define SCR_PULSE_INTERRUPT 0x02
+#define SCR_POWER_DOWN 0x01
+
+
+#define CMD_PC_TO_RDR_ICCPOWERON 0x62
+#define CMD_PC_TO_RDR_GETSLOTSTATUS 0x65
+#define CMD_PC_TO_RDR_ICCPOWEROFF 0x63
+#define CMD_PC_TO_RDR_SECURE 0x69
+#define CMD_PC_TO_RDR_GETPARAMETERS 0x6C
+#define CMD_PC_TO_RDR_RESETPARAMETERS 0x6D
+#define CMD_PC_TO_RDR_SETPARAMETERS 0x61
+#define CMD_PC_TO_RDR_XFRBLOCK 0x6F
+#define CMD_PC_TO_RDR_ESCAPE 0x6B
+#define CMD_PC_TO_RDR_ICCCLOCK 0x6E
+#define CMD_PC_TO_RDR_TEST_SECURE 0x74
+#define CMD_PC_TO_RDR_OK_SECURE 0x89
+
+
+#define CMD_RDR_TO_PC_SLOTSTATUS 0x81
+#define CMD_RDR_TO_PC_DATABLOCK 0x80
+#define CMD_RDR_TO_PC_PARAMETERS 0x82
+#define CMD_RDR_TO_PC_ESCAPE 0x83
+#define CMD_RDR_TO_PC_OK_SECURE 0x89
+
+#endif /* _CM4040_H_ */
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 82c6abde68d..62aa0e534a6 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/char/synclink.c
*
- * $Id: synclink.c,v 4.37 2005/09/07 13:13:19 paulkf Exp $
+ * $Id: synclink.c,v 4.38 2005/11/07 16:30:34 paulkf Exp $
*
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
@@ -101,6 +101,7 @@
#include <linux/termios.h>
#include <linux/workqueue.h>
#include <linux/hdlc.h>
+#include <linux/dma-mapping.h>
#ifdef CONFIG_HDLC_MODULE
#define CONFIG_HDLC 1
@@ -148,6 +149,7 @@ typedef struct _DMABUFFERENTRY
u32 link; /* 32-bit flat link to next buffer entry */
char *virt_addr; /* virtual address of data buffer */
u32 phys_entry; /* physical address of this buffer entry */
+ dma_addr_t dma_addr;
} DMABUFFERENTRY, *DMAPBUFFERENTRY;
/* The queue of BH actions to be performed */
@@ -233,7 +235,8 @@ struct mgsl_struct {
int ri_chkcount;
char *buffer_list; /* virtual address of Rx & Tx buffer lists */
- unsigned long buffer_list_phys;
+ u32 buffer_list_phys;
+ dma_addr_t buffer_list_dma_addr;
unsigned int rx_buffer_count; /* count of total allocated Rx buffers */
DMABUFFERENTRY *rx_buffer_list; /* list of receive buffer entries */
@@ -896,7 +899,7 @@ module_param_array(txdmabufs, int, NULL, 0);
module_param_array(txholdbufs, int, NULL, 0);
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.37 $";
+static char *driver_version = "$Revision: 4.38 $";
static int synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent);
@@ -3811,11 +3814,10 @@ static int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info )
/* inspect portions of the buffer while other portions are being */
/* updated by the adapter using Bus Master DMA. */
- info->buffer_list = kmalloc(BUFFERLISTSIZE, GFP_KERNEL | GFP_DMA);
- if ( info->buffer_list == NULL )
+ info->buffer_list = dma_alloc_coherent(NULL, BUFFERLISTSIZE, &info->buffer_list_dma_addr, GFP_KERNEL);
+ if (info->buffer_list == NULL)
return -ENOMEM;
-
- info->buffer_list_phys = isa_virt_to_bus(info->buffer_list);
+ info->buffer_list_phys = (u32)(info->buffer_list_dma_addr);
}
/* We got the memory for the buffer entry lists. */
@@ -3882,8 +3884,8 @@ static int mgsl_alloc_buffer_list_memory( struct mgsl_struct *info )
*/
static void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
{
- if ( info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI )
- kfree(info->buffer_list);
+ if (info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI)
+ dma_free_coherent(NULL, BUFFERLISTSIZE, info->buffer_list, info->buffer_list_dma_addr);
info->buffer_list = NULL;
info->rx_buffer_list = NULL;
@@ -3910,7 +3912,7 @@ static void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
static int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *BufferList,int Buffercount)
{
int i;
- unsigned long phys_addr;
+ u32 phys_addr;
/* Allocate page sized buffers for the receive buffer list */
@@ -3922,11 +3924,10 @@ static int mgsl_alloc_frame_memory(struct mgsl_struct *info,DMABUFFERENTRY *Buff
info->last_mem_alloc += DMABUFFERSIZE;
} else {
/* ISA adapter uses system memory. */
- BufferList[i].virt_addr =
- kmalloc(DMABUFFERSIZE, GFP_KERNEL | GFP_DMA);
- if ( BufferList[i].virt_addr == NULL )
+ BufferList[i].virt_addr = dma_alloc_coherent(NULL, DMABUFFERSIZE, &BufferList[i].dma_addr, GFP_KERNEL);
+ if (BufferList[i].virt_addr == NULL)
return -ENOMEM;
- phys_addr = isa_virt_to_bus(BufferList[i].virt_addr);
+ phys_addr = (u32)(BufferList[i].dma_addr);
}
BufferList[i].phys_addr = phys_addr;
}
@@ -3957,7 +3958,7 @@ static void mgsl_free_frame_memory(struct mgsl_struct *info, DMABUFFERENTRY *Buf
for ( i = 0 ; i < Buffercount ; i++ ) {
if ( BufferList[i].virt_addr ) {
if ( info->bus_type != MGSL_BUS_TYPE_PCI )
- kfree(BufferList[i].virt_addr);
+ dma_free_coherent(NULL, DMABUFFERSIZE, BufferList[i].virt_addr, BufferList[i].dma_addr);
BufferList[i].virt_addr = NULL;
}
}
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 303f1588046..0b283d24673 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -43,6 +43,13 @@ static void user_reader_timeout(unsigned long ptr)
{
struct tpm_chip *chip = (struct tpm_chip *) ptr;
+ schedule_work(&chip->work);
+}
+
+static void timeout_work(void * ptr)
+{
+ struct tpm_chip *chip = ptr;
+
down(&chip->buffer_mutex);
atomic_set(&chip->data_pending, 0);
memset(chip->data_buffer, 0, TPM_BUFSIZE);
@@ -428,8 +435,7 @@ ssize_t tpm_read(struct file * file, char __user *buf,
ret_size = size;
down(&chip->buffer_mutex);
- if (copy_to_user
- ((void __user *) buf, chip->data_buffer, ret_size))
+ if (copy_to_user(buf, chip->data_buffer, ret_size))
ret_size = -EFAULT;
up(&chip->buffer_mutex);
}
@@ -460,7 +466,7 @@ void tpm_remove_hardware(struct device *dev)
sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &=
- !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
+ ~(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
kfree(chip);
@@ -528,6 +534,8 @@ int tpm_register_hardware(struct device *dev, struct tpm_vendor_specific *entry)
init_MUTEX(&chip->tpm_mutex);
INIT_LIST_HEAD(&chip->list);
+ INIT_WORK(&chip->work, timeout_work, chip);
+
init_timer(&chip->user_read_timer);
chip->user_read_timer.function = user_reader_timeout;
chip->user_read_timer.data = (unsigned long) chip;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 9293bcc4dc6..159882ca69d 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -50,7 +50,11 @@ struct tpm_vendor_specific {
u8 req_complete_mask;
u8 req_complete_val;
u8 req_canceled;
- u16 base; /* TPM base address */
+ void __iomem *iobase; /* ioremapped address */
+ unsigned long base; /* TPM base address */
+
+ int region_size;
+ int have_region;
int (*recv) (struct tpm_chip *, u8 *, size_t);
int (*send) (struct tpm_chip *, u8 *, size_t);
@@ -73,6 +77,7 @@ struct tpm_chip {
struct semaphore buffer_mutex;
struct timer_list user_read_timer; /* user needs to claim result */
+ struct work_struct work;
struct semaphore tpm_mutex; /* tpm is processing */
struct tpm_vendor_specific *vendor;
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 32e01450c42..deb4b5c8091 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -19,14 +19,8 @@
*
*/
-#include <linux/platform_device.h>
#include "tpm.h"
-
-/* Atmel definitions */
-enum tpm_atmel_addr {
- TPM_ATMEL_BASE_ADDR_LO = 0x08,
- TPM_ATMEL_BASE_ADDR_HI = 0x09
-};
+#include "tpm_atmel.h"
/* write status bits */
enum tpm_atmel_write_status {
@@ -53,13 +47,13 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
return -EIO;
for (i = 0; i < 6; i++) {
- status = inb(chip->vendor->base + 1);
+ status = atmel_getb(chip, 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev,
"error reading header\n");
return -EIO;
}
- *buf++ = inb(chip->vendor->base);
+ *buf++ = atmel_getb(chip, 0);
}
/* size of the data received */
@@ -70,7 +64,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
dev_err(chip->dev,
"Recv size(%d) less than available space\n", size);
for (; i < size; i++) { /* clear the waiting data anyway */
- status = inb(chip->vendor->base + 1);
+ status = atmel_getb(chip, 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev,
"error reading data\n");
@@ -82,17 +76,17 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
/* read all the data available */
for (; i < size; i++) {
- status = inb(chip->vendor->base + 1);
+ status = atmel_getb(chip, 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
dev_err(chip->dev,
"error reading data\n");
return -EIO;
}
- *buf++ = inb(chip->vendor->base);
+ *buf++ = atmel_getb(chip, 0);
}
/* make sure data available is gone */
- status = inb(chip->vendor->base + 1);
+ status = atmel_getb(chip, 1);
if (status & ATML_STATUS_DATA_AVAIL) {
dev_err(chip->dev, "data available is stuck\n");
return -EIO;
@@ -108,7 +102,7 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
dev_dbg(chip->dev, "tpm_atml_send:\n");
for (i = 0; i < count; i++) {
dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
- outb(buf[i], chip->vendor->base);
+ atmel_putb(buf[i], chip, 0);
}
return count;
@@ -116,12 +110,12 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
static void tpm_atml_cancel(struct tpm_chip *chip)
{
- outb(ATML_STATUS_ABORT, chip->vendor->base + 1);
+ atmel_putb(ATML_STATUS_ABORT, chip, 1);
}
static u8 tpm_atml_status(struct tpm_chip *chip)
{
- return inb(chip->vendor->base + 1);
+ return atmel_getb(chip, 1);
}
static struct file_operations atmel_ops = {
@@ -162,12 +156,16 @@ static struct tpm_vendor_specific tpm_atmel = {
static struct platform_device *pdev;
-static void __devexit tpm_atml_remove(struct device *dev)
+static void atml_plat_remove(void)
{
- struct tpm_chip *chip = dev_get_drvdata(dev);
+ struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
+
if (chip) {
- release_region(chip->vendor->base, 2);
+ if (chip->vendor->have_region)
+ atmel_release_region(chip->vendor->base, chip->vendor->region_size);
+ atmel_put_base_addr(chip->vendor);
tpm_remove_hardware(chip->dev);
+ platform_device_unregister(pdev);
}
}
@@ -182,72 +180,40 @@ static struct device_driver atml_drv = {
static int __init init_atmel(void)
{
int rc = 0;
- int lo, hi;
driver_register(&atml_drv);
- lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
- hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
-
- tpm_atmel.base = (hi<<8)|lo;
-
- /* verify that it is an Atmel part */
- if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T'
- || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') {
- return -ENODEV;
- }
-
- /* verify chip version number is 1.1 */
- if ( (tpm_read_index(TPM_ADDR, 0x00) != 0x01) ||
- (tpm_read_index(TPM_ADDR, 0x01) != 0x01 ))
- return -ENODEV;
-
- pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
- if ( !pdev )
- return -ENOMEM;
-
- pdev->name = "tpm_atmel0";
- pdev->id = -1;
- pdev->num_resources = 0;
- pdev->dev.release = tpm_atml_remove;
- pdev->dev.driver = &atml_drv;
-
- if ((rc = platform_device_register(pdev)) < 0) {
- kfree(pdev);
- pdev = NULL;
- return rc;
+ if (atmel_get_base_addr(&tpm_atmel) != 0) {
+ rc = -ENODEV;
+ goto err_unreg_drv;
}
- if (request_region(tpm_atmel.base, 2, "tpm_atmel0") == NULL ) {
- platform_device_unregister(pdev);
- kfree(pdev);
- pdev = NULL;
- return -EBUSY;
- }
+ tpm_atmel.have_region = (atmel_request_region( tpm_atmel.base, tpm_atmel.region_size, "tpm_atmel0") == NULL) ? 0 : 1;
- if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) {
- release_region(tpm_atmel.base, 2);
- platform_device_unregister(pdev);
- kfree(pdev);
- pdev = NULL;
- return rc;
+ if (IS_ERR(pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0 ))) {
+ rc = PTR_ERR(pdev);
+ goto err_rel_reg;
}
- dev_info(&pdev->dev, "Atmel TPM 1.1, Base Address: 0x%x\n",
- tpm_atmel.base);
+ if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0)
+ goto err_unreg_dev;
return 0;
+
+err_unreg_dev:
+ platform_device_unregister(pdev);
+err_rel_reg:
+ if (tpm_atmel.have_region)
+ atmel_release_region(tpm_atmel.base, tpm_atmel.region_size);
+ atmel_put_base_addr(&tpm_atmel);
+err_unreg_drv:
+ driver_unregister(&atml_drv);
+ return rc;
}
static void __exit cleanup_atmel(void)
{
- if (pdev) {
- tpm_atml_remove(&pdev->dev);
- platform_device_unregister(pdev);
- kfree(pdev);
- pdev = NULL;
- }
-
driver_unregister(&atml_drv);
+ atml_plat_remove();
}
module_init(init_atmel);
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
new file mode 100644
index 00000000000..3c5b9a8d1c4
--- /dev/null
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ * These difference are required on power because the device must be
+ * discovered through the device tree and iomap must be used to get
+ * around the need for holes in the io_page_mask. This does not happen
+ * automatically because the tpm is not a normal pci device and lives
+ * under the root node.
+ *
+ */
+
+#ifdef CONFIG_PPC64
+#define atmel_getb(chip, offset) readb(chip->vendor->iobase + offset);
+#define atmel_putb(val, chip, offset) writeb(val, chip->vendor->iobase + offset)
+#define atmel_request_region request_mem_region
+#define atmel_release_region release_mem_region
+static inline void atmel_put_base_addr(struct tpm_vendor_specific *vendor)
+{
+ iounmap(vendor->iobase);
+}
+
+static int atmel_get_base_addr(struct tpm_vendor_specific *vendor)
+{
+ struct device_node *dn;
+ unsigned long address, size;
+ unsigned int *reg;
+ int reglen;
+ int naddrc;
+ int nsizec;
+
+ dn = of_find_node_by_name(NULL, "tpm");
+
+ if (!dn)
+ return 1;
+
+ if (!device_is_compatible(dn, "AT97SC3201")) {
+ of_node_put(dn);
+ return 1;
+ }
+
+ reg = (unsigned int *) get_property(dn, "reg", &reglen);
+ naddrc = prom_n_addr_cells(dn);
+ nsizec = prom_n_size_cells(dn);
+
+ of_node_put(dn);
+
+
+ if (naddrc == 2)
+ address = ((unsigned long) reg[0] << 32) | reg[1];
+ else
+ address = reg[0];
+
+ if (nsizec == 2)
+ size =
+ ((unsigned long) reg[naddrc] << 32) | reg[naddrc + 1];
+ else
+ size = reg[naddrc];
+
+ vendor->base = address;
+ vendor->region_size = size;
+ vendor->iobase = ioremap(address, size);
+ return 0;
+}
+#else
+#define atmel_getb(chip, offset) inb(chip->vendor->base + offset)
+#define atmel_putb(val, chip, offset) outb(val, chip->vendor->base + offset)
+#define atmel_request_region request_region
+#define atmel_release_region release_region
+/* Atmel definitions */
+enum tpm_atmel_addr {
+ TPM_ATMEL_BASE_ADDR_LO = 0x08,
+ TPM_ATMEL_BASE_ADDR_HI = 0x09
+};
+
+/* Verify this is a 1.1 Atmel TPM */
+static int atmel_verify_tpm11(void)
+{
+
+ /* verify that it is an Atmel part */
+ if (tpm_read_index(TPM_ADDR, 4) != 'A' ||
+ tpm_read_index(TPM_ADDR, 5) != 'T' ||
+ tpm_read_index(TPM_ADDR, 6) != 'M' ||
+ tpm_read_index(TPM_ADDR, 7) != 'L')
+ return 1;
+
+ /* query chip for its version number */
+ if (tpm_read_index(TPM_ADDR, 0x00) != 1 ||
+ tpm_read_index(TPM_ADDR, 0x01) != 1)
+ return 1;
+
+ /* This is an atmel supported part */
+ return 0;
+}
+
+static inline void atmel_put_base_addr(struct tpm_vendor_specific *vendor)
+{
+}
+
+/* Determine where to talk to device */
+static unsigned long atmel_get_base_addr(struct tpm_vendor_specific
+ *vendor)
+{
+ int lo, hi;
+
+ if (atmel_verify_tpm11() != 0)
+ return 1;
+
+ lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
+ hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
+
+ vendor->base = (hi << 8) | lo;
+ vendor->region_size = 2;
+
+ return 0;
+}
+#endif
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index abc30cca664..65830ec7104 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -4,7 +4,7 @@
* Watchdog timer for PowerPC Book-E systems
*
* Author: Matthew McClintock
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor Inc.
*
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index ea0806c82be..8a5c7b286b2 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -399,34 +399,6 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
return dev->irq;
}
-static void __devinit init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
-{
- unsigned int rev;
- u8 dma_state;
-
- DBG(("init_dma_sl82c105(hwif: ide%d, dma_base: 0x%08x)\n", hwif->index, dma_base));
-
- hwif->autodma = 0;
-
- if (!dma_base)
- return;
-
- dma_state = hwif->INB(dma_base + 2);
- rev = sl82c105_bridge_revision(hwif->pci_dev);
- if (rev <= 5) {
- printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
- hwif->name, rev);
- dma_state &= ~0x60;
- } else {
- dma_state |= 0x60;
- if (!noautodma)
- hwif->autodma = 1;
- }
- hwif->OUTB(dma_state, dma_base + 2);
-
- ide_setup_dma(hwif, dma_base, 8);
-}
-
/*
* Initialise the chip
*/
@@ -434,6 +406,8 @@ static void __devinit init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base
static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
+ unsigned int rev;
+ u8 dma_state;
u32 val;
DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
@@ -455,33 +429,54 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
pci_read_config_dword(dev, 0x40, &val);
*((u32 *)&hwif->hwif_data) = val;
+ hwif->atapi_dma = 0;
+ hwif->mwdma_mask = 0;
+ hwif->swdma_mask = 0;
+ hwif->autodma = 0;
+
if (!hwif->dma_base)
return;
- hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
-
+ dma_state = hwif->INB(hwif->dma_base + 2) & ~0x60;
+ rev = sl82c105_bridge_revision(hwif->pci_dev);
+ if (rev <= 5) {
+ /*
+ * Never ever EVER under any circumstances enable
+ * DMA when the bridge is this old.
+ */
+ printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
+ hwif->name, rev);
+ } else {
#ifdef CONFIG_BLK_DEV_IDEDMA
- hwif->ide_dma_check = &sl82c105_check_drive;
- hwif->ide_dma_on = &sl82c105_ide_dma_on;
- hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
- hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
- hwif->dma_start = &sl82c105_ide_dma_start;
- hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
+ dma_state |= 0x60;
+
+ hwif->atapi_dma = 1;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ hwif->ide_dma_check = &sl82c105_check_drive;
+ hwif->ide_dma_on = &sl82c105_ide_dma_on;
+ hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly;
+ hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
+ hwif->dma_start = &sl82c105_ide_dma_start;
+ hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
#endif /* CONFIG_BLK_DEV_IDEDMA */
+ }
+ hwif->OUTB(dma_state, hwif->dma_base + 2);
}
static ide_pci_device_t sl82c105_chipset __devinitdata = {
.name = "W82C105",
.init_chipset = init_chipset_sl82c105,
.init_hwif = init_hwif_sl82c105,
- .init_dma = init_dma_sl82c105,
.channels = 2,
.autodma = NOAUTODMA,
.enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index b3e65a65d20..136911a86e8 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1667,11 +1667,16 @@ static struct macio_driver pmac_ide_macio_driver =
};
static struct pci_device_id pmac_ide_pci_match[] = {
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_ATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_ATA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
};
static struct pci_driver pmac_ide_pci_driver = {
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 32bf0d5d0f9..f8457ef4882 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -71,78 +71,68 @@ typedef struct {
/****************************************/
static struct usb_device_id hfcusb_idtab[] = {
{
- .idVendor = 0x0959,
- .idProduct = 0x2bd0,
+ USB_DEVICE(0x0959, 0x2bd0),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_OFF, {4, 0, 2, 1},
"ISDN USB TA (Cologne Chip HFC-S USB based)"}),
},
{
- .idVendor = 0x0675,
- .idProduct = 0x1688,
+ USB_DEVICE(0x0675, 0x1688),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {1, 2, 0, 0},
"DrayTek miniVigor 128 USB ISDN TA"}),
},
{
- .idVendor = 0x07b0,
- .idProduct = 0x0007,
+ USB_DEVICE(0x07b0, 0x0007),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {0x80, -64, -32, -16},
"Billion tiny USB ISDN TA 128"}),
},
{
- .idVendor = 0x0742,
- .idProduct = 0x2008,
+ USB_DEVICE(0x0742, 0x2008),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {4, 0, 2, 1},
"Stollmann USB TA"}),
},
{
- .idVendor = 0x0742,
- .idProduct = 0x2009,
+ USB_DEVICE(0x0742, 0x2009),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {4, 0, 2, 1},
"Aceex USB ISDN TA"}),
},
{
- .idVendor = 0x0742,
- .idProduct = 0x200A,
+ USB_DEVICE(0x0742, 0x200A),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {4, 0, 2, 1},
"OEM USB ISDN TA"}),
},
{
- .idVendor = 0x08e3,
- .idProduct = 0x0301,
+ USB_DEVICE(0x08e3, 0x0301),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {2, 0, 1, 4},
"Olitec USB RNIS"}),
},
{
- .idVendor = 0x07fa,
- .idProduct = 0x0846,
+ USB_DEVICE(0x07fa, 0x0846),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {0x80, -64, -32, -16},
"Bewan Modem RNIS USB"}),
},
{
- .idVendor = 0x07fa,
- .idProduct = 0x0847,
+ USB_DEVICE(0x07fa, 0x0847),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {0x80, -64, -32, -16},
"Djinn Numeris USB"}),
},
{
- .idVendor = 0x07b0,
- .idProduct = 0x0006,
+ USB_DEVICE(0x07b0, 0x0006),
.driver_info = (unsigned long) &((hfcsusb_vdata)
{LED_SCHEME1, {0x80, -64, -32, -16},
"Twister ISDN TA"}),
},
+ { }
};
-
/***************************************************************/
/* structure defining input+output fifos (interrupt/bulk mode) */
/***************************************************************/
diff --git a/drivers/md/md.c b/drivers/md/md.c
index adf960d8a7c..f3fed662f32 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3156,7 +3156,7 @@ static int md_ioctl(struct inode *inode, struct file *file,
if (cnt > 0 ) {
printk(KERN_WARNING
"md: %s(pid %d) used deprecated START_ARRAY ioctl. "
- "This will not be supported beyond 2.6\n",
+ "This will not be supported beyond July 2006\n",
current->comm, current->pid);
cnt--;
}
@@ -3437,10 +3437,19 @@ static int md_thread(void * arg)
allow_signal(SIGKILL);
while (!kthread_should_stop()) {
- wait_event_timeout(thread->wqueue,
- test_bit(THREAD_WAKEUP, &thread->flags)
- || kthread_should_stop(),
- thread->timeout);
+ /* We need to wait INTERRUPTIBLE so that
+ * we don't add to the load-average.
+ * That means we need to be sure no signals are
+ * pending
+ */
+ if (signal_pending(current))
+ flush_signals(current);
+
+ wait_event_interruptible_timeout
+ (thread->wqueue,
+ test_bit(THREAD_WAKEUP, &thread->flags)
+ || kthread_should_stop(),
+ thread->timeout);
try_to_freeze();
clear_bit(THREAD_WAKEUP, &thread->flags);
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c
index 4b71fd6f7ae..7972c73bc14 100644
--- a/drivers/media/common/ir-common.c
+++ b/drivers/media/common/ir-common.c
@@ -126,6 +126,66 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_winfast);
+IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+ [ 0x59 ] = KEY_MUTE,
+ [ 0x4a ] = KEY_POWER,
+
+ [ 0x18 ] = KEY_TEXT,
+ [ 0x26 ] = KEY_TV,
+ [ 0x3d ] = KEY_PRINT,
+
+ [ 0x48 ] = KEY_RED,
+ [ 0x04 ] = KEY_GREEN,
+ [ 0x11 ] = KEY_YELLOW,
+ [ 0x00 ] = KEY_BLUE,
+
+ [ 0x2d ] = KEY_VOLUMEUP,
+ [ 0x1e ] = KEY_VOLUMEDOWN,
+
+ [ 0x49 ] = KEY_MENU,
+
+ [ 0x16 ] = KEY_CHANNELUP,
+ [ 0x17 ] = KEY_CHANNELDOWN,
+
+ [ 0x20 ] = KEY_UP,
+ [ 0x21 ] = KEY_DOWN,
+ [ 0x22 ] = KEY_LEFT,
+ [ 0x23 ] = KEY_RIGHT,
+ [ 0x0d ] = KEY_SELECT,
+
+
+
+ [ 0x08 ] = KEY_BACK,
+ [ 0x07 ] = KEY_REFRESH,
+
+ [ 0x2f ] = KEY_ZOOM,
+ [ 0x29 ] = KEY_RECORD,
+
+ [ 0x4b ] = KEY_PAUSE,
+ [ 0x4d ] = KEY_REWIND,
+ [ 0x2e ] = KEY_PLAY,
+ [ 0x4e ] = KEY_FORWARD,
+ [ 0x53 ] = KEY_PREVIOUS,
+ [ 0x4c ] = KEY_STOP,
+ [ 0x54 ] = KEY_NEXT,
+
+ [ 0x69 ] = KEY_KP0,
+ [ 0x6a ] = KEY_KP1,
+ [ 0x6b ] = KEY_KP2,
+ [ 0x6c ] = KEY_KP3,
+ [ 0x6d ] = KEY_KP4,
+ [ 0x6e ] = KEY_KP5,
+ [ 0x6f ] = KEY_KP6,
+ [ 0x70 ] = KEY_KP7,
+ [ 0x71 ] = KEY_KP8,
+ [ 0x72 ] = KEY_KP9,
+
+ [ 0x74 ] = KEY_CHANNEL,
+ [ 0x0a ] = KEY_BACKSPACE,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+
/* empty keytable, can be used as placeholder for not-yet created keytables */
IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
[ 42 ] = KEY_COFFEE,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 199b0118885..1a3b3c7e5e9 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -333,4 +333,18 @@ config VIDEO_M32R_AR_M64278
Say Y here to use the Renesas M64278E-800 camera module,
which supports VGA(640x480 pixcels) size of images.
+config VIDEO_AUDIO_DECODER
+ tristate "Add support for additional audio chipsets"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Say Y here to compile drivers for WM8775 and CS53L32A audio
+ decoders.
+
+config VIDEO_DECODER
+ tristate "Add support for additional video chipsets"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Say Y here to compile drivers for SAA7115, SAA7127 and CX25840
+ video decoders.
+
endmenu
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 3ac46599240..82060f9909d 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -36,10 +36,11 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o
+obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
@@ -55,4 +56,6 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
+obj-$(CONFIG_VIDEO_DECODER) += saa7115.o cx25840/ saa7127.o
+
EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 3413bace443..e31ebb11c46 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -2133,7 +2133,10 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_dvb = 1,
+ .has_remote = 1,
+ .gpiomask = 0x1b,
.no_gpioirq = 1,
+ .any_irq = 1,
},
[BTTV_BOARD_PV143] = {
/* Jorge Boncompte - DTI2 <jorge@dti2.net> */
@@ -2796,7 +2799,24 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
-
+ /* ---- card 0x8e ---------------------------------- */
+ [BTTV_BOARD_SABRENT_TVFM] = {
+ .name = "Sabrent TV-FM (bttv version)",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x108007,
+ .muxsel = { 2, 3, 1, 1},
+ .audiomux = { 100000, 100002, 100002, 100000},
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_28,
+ .tuner_type = TUNER_TNF_5335MF,
+ .tuner_addr = ADDR_UNSET,
+ .has_radio = 1,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3367,6 +3387,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->has_remote=1;
if (!bttv_tvcards[btv->c.type].no_gpioirq)
btv->gpioirq=1;
+ if (bttv_tvcards[btv->c.type].any_irq)
+ btv->any_irq = 1;
if (bttv_tvcards[btv->c.type].audio_hook)
btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook;
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index 0005741d551..709099f03bd 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -3667,6 +3667,10 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
int handled = 0;
btv=(struct bttv *)dev_id;
+
+ if (btv->any_irq)
+ handled = bttv_any_irq(&btv->c);
+
count=0;
while (1) {
/* get/clear interrupt status bits */
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c
index 575ce8b8e71..616a5b7e510 100644
--- a/drivers/media/video/bttv-gpio.c
+++ b/drivers/media/video/bttv-gpio.c
@@ -113,6 +113,24 @@ void bttv_gpio_irq(struct bttv_core *core)
}
}
+int bttv_any_irq(struct bttv_core *core)
+{
+ struct bttv_sub_driver *drv;
+ struct bttv_sub_device *dev;
+ struct list_head *item;
+ int handled = 0;
+
+ list_for_each(item,&core->subs) {
+ dev = list_entry(item,struct bttv_sub_device,list);
+ drv = to_bttv_sub_drv(dev->dev.driver);
+ if (drv && drv->any_irq) {
+ if (drv->any_irq(dev))
+ handled = 1;
+ }
+ }
+ return handled;
+}
+
/* ----------------------------------------------------------------------- */
/* external: sub-driver register/unregister */
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index 124ea41dada..93298f06e01 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -162,6 +162,7 @@
#define BTTV_BOARD_PV_M4900 0x8b
#define BTTV_BOARD_OSPREY440 0x8c
#define BTTV_BOARD_ASOUND_SKYEYE 0x8d
+#define BTTV_BOARD_SABRENT_TVFM 0x8e
/* i2c address list */
#define I2C_TSA5522 0xc2
@@ -234,6 +235,7 @@ struct tvcard
unsigned int has_dvb:1;
unsigned int has_remote:1;
unsigned int no_gpioirq:1;
+ unsigned int any_irq:1;
/* other settings */
unsigned int pll;
@@ -333,6 +335,7 @@ struct bttv_sub_driver {
struct device_driver drv;
char wanted[BUS_ID_SIZE];
void (*gpio_irq)(struct bttv_sub_device *sub);
+ int (*any_irq)(struct bttv_sub_device *sub);
};
#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
index 386f546f7d1..3aa9c6e4fc3 100644
--- a/drivers/media/video/bttvp.h
+++ b/drivers/media/video/bttvp.h
@@ -208,6 +208,7 @@ extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
void bttv_gpio_irq(struct bttv_core *core);
+int bttv_any_irq(struct bttv_core *core);
/* ---------------------------------------------------------- */
@@ -273,6 +274,7 @@ struct bttv {
struct bttv_pll_info pll;
int triton1;
int gpioirq;
+ int any_irq;
int use_i2c_hw;
/* old gpio interface */
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile
new file mode 100644
index 00000000000..543ebacdc9d
--- /dev/null
+++ b/drivers/media/video/cx25840/Makefile
@@ -0,0 +1,6 @@
+cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
+ cx25840-vbi.o
+
+obj-$(CONFIG_VIDEO_DECODER) += cx25840.o
+
+EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
new file mode 100644
index 00000000000..740908f8027
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -0,0 +1,368 @@
+/* cx25840 audio functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/audiochip.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+inline static int set_audclk_freq(struct i2c_client *client,
+ enum v4l2_audio_clock_freq freq)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ /* assert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
+ /* common for all inputs and rates */
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
+ cx25840_write(client, 0x127, 0x50);
+
+ switch (state->audio_input) {
+ case AUDIO_TUNER:
+ switch (freq) {
+ case V4L2_AUDCLK_32_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040610);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xee39bb01);
+
+ /* src3/4/6_ctl = 0x0801f77f */
+ cx25840_write4(client, 0x900, 0x7ff70108);
+ cx25840_write4(client, 0x904, 0x7ff70108);
+ cx25840_write4(client, 0x90c, 0x7ff70108);
+ break;
+
+ case V4L2_AUDCLK_441_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040910);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xd66bec00);
+
+ /* src3/4/6_ctl = 0x08016d59 */
+ cx25840_write4(client, 0x900, 0x596d0108);
+ cx25840_write4(client, 0x904, 0x596d0108);
+ cx25840_write4(client, 0x90c, 0x596d0108);
+ break;
+
+ case V4L2_AUDCLK_48_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040a10);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xe5d69800);
+
+ /* src3/4/6_ctl = 0x08014faa */
+ cx25840_write4(client, 0x900, 0xaa4f0108);
+ cx25840_write4(client, 0x904, 0xaa4f0108);
+ cx25840_write4(client, 0x90c, 0xaa4f0108);
+ break;
+ }
+ break;
+
+ case AUDIO_EXTERN_1:
+ case AUDIO_EXTERN_2:
+ case AUDIO_INTERN:
+ case AUDIO_RADIO:
+ switch (freq) {
+ case V4L2_AUDCLK_32_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f04081e);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0x69082a01);
+
+ /* src1_ctl = 0x08010000 */
+ cx25840_write4(client, 0x8f8, 0x00000108);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx25840_write4(client, 0x900, 0x00000208);
+ cx25840_write4(client, 0x904, 0x00000208);
+ cx25840_write4(client, 0x90c, 0x00000208);
+
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
+ cx25840_write(client, 0x127, 0x54);
+ break;
+
+ case V4L2_AUDCLK_441_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040918);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xd66bec00);
+
+ /* src1_ctl = 0x08010000 */
+ cx25840_write4(client, 0x8f8, 0xcd600108);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx25840_write4(client, 0x900, 0x85730108);
+ cx25840_write4(client, 0x904, 0x85730108);
+ cx25840_write4(client, 0x90c, 0x85730108);
+ break;
+
+ case V4L2_AUDCLK_48_KHZ:
+ /* VID_PLL and AUX_PLL */
+ cx25840_write4(client, 0x108, 0x0f040a18);
+
+ /* AUX_PLL_FRAC */
+ cx25840_write4(client, 0x110, 0xe5d69800);
+
+ /* src1_ctl = 0x08010000 */
+ cx25840_write4(client, 0x8f8, 0x00800108);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx25840_write4(client, 0x900, 0x55550108);
+ cx25840_write4(client, 0x904, 0x55550108);
+ cx25840_write4(client, 0x90c, 0x55550108);
+ break;
+ }
+ break;
+ }
+
+ /* deassert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+ state->audclk_freq = freq;
+
+ return 0;
+}
+
+static int set_input(struct i2c_client *client, int audio_input)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ cx25840_dbg("set audio input (%d)\n", audio_input);
+
+ /* stop microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0);
+
+ /* Mute everything to prevent the PFFT! */
+ cx25840_write(client, 0x8d3, 0x1f);
+
+ switch (audio_input) {
+ case AUDIO_TUNER:
+ /* Set Path1 to Analog Demod Main Channel */
+ cx25840_write4(client, 0x8d0, 0x7038061f);
+
+ /* When the microcontroller detects the
+ * audio format, it will unmute the lines */
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ break;
+
+ case AUDIO_EXTERN_1:
+ case AUDIO_EXTERN_2:
+ case AUDIO_INTERN:
+ case AUDIO_RADIO:
+ /* Set Path1 to Serial Audio Input */
+ cx25840_write4(client, 0x8d0, 0x12100101);
+
+ /* The microcontroller should not be started for the
+ * non-tuner inputs: autodetection is specific for
+ * TV audio. */
+ break;
+
+ default:
+ cx25840_dbg("Invalid audio input selection %d\n", audio_input);
+ return -EINVAL;
+ }
+
+ state->audio_input = audio_input;
+
+ return set_audclk_freq(client, state->audclk_freq);
+}
+
+inline static int get_volume(struct i2c_client *client)
+{
+ /* Volume runs +18dB to -96dB in 1/2dB steps
+ * change to fit the msp3400 -114dB to +12dB range */
+
+ /* check PATH1_VOLUME */
+ int vol = 228 - cx25840_read(client, 0x8d4);
+ vol = (vol / 2) + 23;
+ return vol << 9;
+}
+
+inline static void set_volume(struct i2c_client *client, int volume)
+{
+ /* First convert the volume to msp3400 values (0-127) */
+ int vol = volume >> 9;
+ /* now scale it up to cx25840 values
+ * -114dB to -96dB maps to 0
+ * this should be 19, but in my testing that was 4dB too loud */
+ if (vol <= 23) {
+ vol = 0;
+ } else {
+ vol -= 23;
+ }
+
+ /* PATH1_VOLUME */
+ cx25840_write(client, 0x8d4, 228 - (vol * 2));
+}
+
+inline static int get_bass(struct i2c_client *client)
+{
+ /* bass is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_BASS_VOL */
+ int bass = cx25840_read(client, 0x8d9) & 0x3f;
+ bass = (((48 - bass) * 0xffff) + 47) / 48;
+ return bass;
+}
+
+inline static void set_bass(struct i2c_client *client, int bass)
+{
+ /* PATH1_EQ_BASS_VOL */
+ cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
+}
+
+inline static int get_treble(struct i2c_client *client)
+{
+ /* treble is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_TREBLE_VOL */
+ int treble = cx25840_read(client, 0x8db) & 0x3f;
+ treble = (((48 - treble) * 0xffff) + 47) / 48;
+ return treble;
+}
+
+inline static void set_treble(struct i2c_client *client, int treble)
+{
+ /* PATH1_EQ_TREBLE_VOL */
+ cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
+}
+
+inline static int get_balance(struct i2c_client *client)
+{
+ /* balance is 7 bit, 0 to -96dB */
+
+ /* check PATH1_BAL_LEVEL */
+ int balance = cx25840_read(client, 0x8d5) & 0x7f;
+ /* check PATH1_BAL_LEFT */
+ if ((cx25840_read(client, 0x8d5) & 0x80) == 0)
+ balance = 0x80 - balance;
+ else
+ balance = 0x80 + balance;
+ return balance << 8;
+}
+
+inline static void set_balance(struct i2c_client *client, int balance)
+{
+ int bal = balance >> 8;
+ if (bal > 0x80) {
+ /* PATH1_BAL_LEFT */
+ cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
+ /* PATH1_BAL_LEVEL */
+ cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
+ } else {
+ /* PATH1_BAL_LEFT */
+ cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
+ /* PATH1_BAL_LEVEL */
+ cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
+ }
+}
+
+inline static int get_mute(struct i2c_client *client)
+{
+ /* check SRC1_MUTE_EN */
+ return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
+}
+
+inline static void set_mute(struct i2c_client *client, int mute)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ if (state->audio_input == AUDIO_TUNER) {
+ /* Must turn off microcontroller in order to mute sound.
+ * Not sure if this is the best method, but it does work.
+ * If the microcontroller is running, then it will undo any
+ * changes to the mute register. */
+ if (mute) {
+ /* disable microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x00);
+ cx25840_write(client, 0x8d3, 0x1f);
+ } else {
+ /* enable microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ }
+ } else {
+ /* SRC1_MUTE_EN */
+ cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+ }
+}
+
+int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct v4l2_control *ctrl = arg;
+
+ switch (cmd) {
+ case AUDC_SET_INPUT:
+ return set_input(client, *(int *)arg);
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+ case VIDIOC_G_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = get_volume(client);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ ctrl->value = get_bass(client);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ ctrl->value = get_treble(client);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ ctrl->value = get_balance(client);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = get_mute(client);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case VIDIOC_S_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ set_volume(client, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ set_bass(client, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ set_treble(client, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ set_balance(client, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ set_mute(client, ctrl->value);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
new file mode 100644
index 00000000000..f6afeec499c
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -0,0 +1,1020 @@
+/* cx25840 - Conexant CX25840 audio/video decoder driver
+ *
+ * Copyright (C) 2004 Ulf Eklund
+ *
+ * Based on the saa7115 driver and on the first verison of Chris Kennedy's
+ * cx25840 driver.
+ *
+ * Changes by Tyler Trafford <tatrafford@comcast.net>
+ * - cleanup/rewrite for V4L2 API (2005)
+ *
+ * VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/audiochip.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
+MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+
+
+int cx25840_debug = 0;
+
+module_param(cx25840_debug, bool, 0644);
+
+MODULE_PARM_DESC(cx25840_debug, "Debugging messages [0=Off (default) 1=On]");
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
+{
+ u8 buffer[3];
+ buffer[0] = addr >> 8;
+ buffer[1] = addr & 0xff;
+ buffer[2] = value;
+ return i2c_master_send(client, buffer, 3);
+}
+
+int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
+{
+ u8 buffer[6];
+ buffer[0] = addr >> 8;
+ buffer[1] = addr & 0xff;
+ buffer[2] = value >> 24;
+ buffer[3] = (value >> 16) & 0xff;
+ buffer[4] = (value >> 8) & 0xff;
+ buffer[5] = value & 0xff;
+ return i2c_master_send(client, buffer, 6);
+}
+
+u8 cx25840_read(struct i2c_client * client, u16 addr)
+{
+ u8 buffer[2];
+ buffer[0] = addr >> 8;
+ buffer[1] = addr & 0xff;
+
+ if (i2c_master_send(client, buffer, 2) < 2)
+ return 0;
+
+ if (i2c_master_recv(client, buffer, 1) < 1)
+ return 0;
+
+ return buffer[0];
+}
+
+u32 cx25840_read4(struct i2c_client * client, u16 addr)
+{
+ u8 buffer[4];
+ buffer[0] = addr >> 8;
+ buffer[1] = addr & 0xff;
+
+ if (i2c_master_send(client, buffer, 2) < 2)
+ return 0;
+
+ if (i2c_master_recv(client, buffer, 4) < 4)
+ return 0;
+
+ return (buffer[0] << 24) | (buffer[1] << 16) |
+ (buffer[2] << 8) | buffer[3];
+}
+
+int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
+ u8 or_value)
+{
+ return cx25840_write(client, addr,
+ (cx25840_read(client, addr) & and_mask) |
+ or_value);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_input(struct i2c_client *, enum cx25840_input);
+static void input_change(struct i2c_client *);
+static void log_status(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+
+static inline void init_dll1(struct i2c_client *client)
+{
+ /* This is the Hauppauge sequence used to
+ * initialize the Delay Lock Loop 1 (ADC DLL). */
+ cx25840_write(client, 0x159, 0x23);
+ cx25840_write(client, 0x15a, 0x87);
+ cx25840_write(client, 0x15b, 0x06);
+ cx25840_write(client, 0x159, 0xe1);
+ cx25840_write(client, 0x15a, 0x86);
+ cx25840_write(client, 0x159, 0xe0);
+ cx25840_write(client, 0x159, 0xe1);
+ cx25840_write(client, 0x15b, 0x10);
+}
+
+static inline void init_dll2(struct i2c_client *client)
+{
+ /* This is the Hauppauge sequence used to
+ * initialize the Delay Lock Loop 2 (ADC DLL). */
+ cx25840_write(client, 0x15d, 0xe3);
+ cx25840_write(client, 0x15e, 0x86);
+ cx25840_write(client, 0x15f, 0x06);
+ cx25840_write(client, 0x15d, 0xe1);
+ cx25840_write(client, 0x15d, 0xe0);
+ cx25840_write(client, 0x15d, 0xe1);
+}
+
+static void cx25840_initialize(struct i2c_client *client, int loadfw)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ /* datasheet startup in numbered steps, refer to page 3-77 */
+ /* 2. */
+ cx25840_and_or(client, 0x803, ~0x10, 0x00);
+ /* The default of this register should be 4, but I get 0 instead.
+ * Set this register to 4 manually. */
+ cx25840_write(client, 0x000, 0x04);
+ /* 3. */
+ init_dll1(client);
+ init_dll2(client);
+ cx25840_write(client, 0x136, 0x0a);
+ /* 4. */
+ cx25840_write(client, 0x13c, 0x01);
+ cx25840_write(client, 0x13c, 0x00);
+ /* 5. */
+ if (loadfw)
+ cx25840_loadfw(client);
+ /* 6. */
+ cx25840_write(client, 0x115, 0x8c);
+ cx25840_write(client, 0x116, 0x07);
+ cx25840_write(client, 0x118, 0x02);
+ /* 7. */
+ cx25840_write(client, 0x4a5, 0x80);
+ cx25840_write(client, 0x4a5, 0x00);
+ cx25840_write(client, 0x402, 0x00);
+ /* 8. */
+ cx25840_write(client, 0x401, 0x18);
+ cx25840_write(client, 0x4a2, 0x10);
+ cx25840_write(client, 0x402, 0x04);
+ /* 10. */
+ cx25840_write(client, 0x8d3, 0x1f);
+ cx25840_write(client, 0x8e3, 0x03);
+
+ cx25840_vbi_setup(client);
+
+ /* trial and error says these are needed to get audio */
+ cx25840_write(client, 0x914, 0xa0);
+ cx25840_write(client, 0x918, 0xa0);
+ cx25840_write(client, 0x919, 0x01);
+
+ /* stereo prefered */
+ cx25840_write(client, 0x809, 0x04);
+ /* AC97 shift */
+ cx25840_write(client, 0x8cf, 0x0f);
+
+ /* (re)set video input */
+ set_input(client, state->input);
+ /* (re)set audio input */
+ cx25840_audio(client, AUDC_SET_INPUT, &state->audio_input);
+
+ /* start microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void input_change(struct i2c_client *client)
+{
+ v4l2_std_id std = cx25840_get_v4lstd(client);
+
+ if (std & V4L2_STD_PAL) {
+ /* Follow tuner change procedure for PAL */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
+ } else if (std & V4L2_STD_SECAM) {
+ /* Select autodetect for SECAM */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
+ } else if (std & V4L2_STD_NTSC) {
+ /* NTSC */
+ cx25840_write(client, 0x808, 0xf6);
+ cx25840_write(client, 0x80b, 0x00);
+ }
+
+ if (cx25840_read(client, 0x803) & 0x10) {
+ /* restart audio decoder microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0x00);
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ }
+}
+
+static int set_input(struct i2c_client *client, enum cx25840_input input)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ cx25840_dbg("decoder set input (%d)\n", input);
+
+ switch (input) {
+ case CX25840_TUNER:
+ cx25840_dbg("now setting Tuner input\n");
+
+ if (state->cardtype == CARDTYPE_PVR150) {
+ /* CH_SEL_ADC2=1 */
+ cx25840_and_or(client, 0x102, ~0x2, 0x02);
+ }
+
+ /* Video Input Control */
+ if (state->cardtype == CARDTYPE_PG600) {
+ cx25840_write(client, 0x103, 0x11);
+ } else {
+ cx25840_write(client, 0x103, 0x46);
+ }
+
+ /* INPUT_MODE=0 */
+ cx25840_and_or(client, 0x401, ~0x6, 0x00);
+ break;
+
+ case CX25840_COMPOSITE0:
+ case CX25840_COMPOSITE1:
+ cx25840_dbg("now setting Composite input\n");
+
+ /* Video Input Control */
+ if (state->cardtype == CARDTYPE_PG600) {
+ cx25840_write(client, 0x103, 0x00);
+ } else {
+ cx25840_write(client, 0x103, 0x02);
+ }
+
+ /* INPUT_MODE=0 */
+ cx25840_and_or(client, 0x401, ~0x6, 0x00);
+ break;
+
+ case CX25840_SVIDEO0:
+ case CX25840_SVIDEO1:
+ cx25840_dbg("now setting S-Video input\n");
+
+ /* CH_SEL_ADC2=0 */
+ cx25840_and_or(client, 0x102, ~0x2, 0x00);
+
+ /* Video Input Control */
+ if (state->cardtype == CARDTYPE_PG600) {
+ cx25840_write(client, 0x103, 0x02);
+ } else {
+ cx25840_write(client, 0x103, 0x10);
+ }
+
+ /* INPUT_MODE=1 */
+ cx25840_and_or(client, 0x401, ~0x6, 0x02);
+ break;
+
+ default:
+ cx25840_err("%d is not a valid input!\n", input);
+ return -EINVAL;
+ }
+
+ state->input = input;
+ input_change(client);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+{
+ u8 fmt;
+
+ switch (std) {
+ /* zero is autodetect */
+ case 0: fmt = 0x0; break;
+ /* default ntsc to ntsc-m */
+ case V4L2_STD_NTSC:
+ case V4L2_STD_NTSC_M: fmt = 0x1; break;
+ case V4L2_STD_NTSC_M_JP: fmt = 0x2; break;
+ case V4L2_STD_NTSC_443: fmt = 0x3; break;
+ case V4L2_STD_PAL: fmt = 0x4; break;
+ case V4L2_STD_PAL_M: fmt = 0x5; break;
+ case V4L2_STD_PAL_N: fmt = 0x6; break;
+ case V4L2_STD_PAL_Nc: fmt = 0x7; break;
+ case V4L2_STD_PAL_60: fmt = 0x8; break;
+ case V4L2_STD_SECAM: fmt = 0xc; break;
+ default:
+ return -ERANGE;
+ }
+
+ cx25840_and_or(client, 0x400, ~0xf, fmt);
+ cx25840_vbi_setup(client);
+ return 0;
+}
+
+v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
+{
+ /* check VID_FMT_SEL first */
+ u8 fmt = cx25840_read(client, 0x400) & 0xf;
+
+ if (!fmt) {
+ /* check AFD_FMT_STAT if set to autodetect */
+ fmt = cx25840_read(client, 0x40d) & 0xf;
+ }
+
+ switch (fmt) {
+ case 0x1: return V4L2_STD_NTSC_M;
+ case 0x2: return V4L2_STD_NTSC_M_JP;
+ case 0x3: return V4L2_STD_NTSC_443;
+ case 0x4: return V4L2_STD_PAL;
+ case 0x5: return V4L2_STD_PAL_M;
+ case 0x6: return V4L2_STD_PAL_N;
+ case 0x7: return V4L2_STD_PAL_Nc;
+ case 0x8: return V4L2_STD_PAL_60;
+ case 0xc: return V4L2_STD_SECAM;
+ default: return V4L2_STD_UNKNOWN;
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case CX25840_CID_CARDTYPE:
+ switch (ctrl->value) {
+ case CARDTYPE_PVR150:
+ case CARDTYPE_PG600:
+ state->cardtype = ctrl->value;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ set_input(client, state->input);
+ break;
+
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ cx25840_err("invalid brightness setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx25840_write(client, 0x414, ctrl->value - 128);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ cx25840_err("invalid contrast setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx25840_write(client, 0x415, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ cx25840_err("invalid saturation setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx25840_write(client, 0x420, ctrl->value << 1);
+ cx25840_write(client, 0x421, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_HUE:
+ if (ctrl->value < -127 || ctrl->value > 127) {
+ cx25840_err("invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ cx25840_write(client, 0x422, ctrl->value);
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
+ }
+
+ return 0;
+}
+
+static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case CX25840_CID_CARDTYPE:
+ ctrl->value = state->cardtype;
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = cx25840_read(client, 0x414) + 128;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = cx25840_read(client, 0x415) >> 1;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = cx25840_read(client, 0x420) >> 1;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = cx25840_read(client, 0x422);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx25840_vbi(client, VIDIOC_G_FMT, fmt);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+ struct v4l2_pix_format *pix;
+ int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
+ int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pix = &(fmt->fmt.pix);
+
+ Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+
+ Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+
+ Vlines = pix->height + (is_pal ? 4 : 7);
+
+ if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ cx25840_err("%dx%d is not a valid size!\n",
+ pix->width, pix->height);
+ return -ERANGE;
+ }
+
+ HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
+ VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+ VSC &= 0x1fff;
+
+ if (pix->width >= 385)
+ filter = 0;
+ else if (pix->width > 192)
+ filter = 1;
+ else if (pix->width > 96)
+ filter = 2;
+ else
+ filter = 3;
+
+ cx25840_dbg("decoder set size %dx%d -> scale %ux%u\n",
+ pix->width, pix->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx25840_write(client, 0x418, HSC & 0xff);
+ cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
+ cx25840_write(client, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx25840_write(client, 0x41c, VSC & 0xff);
+ cx25840_write(client, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx25840_write(client, 0x41e, 0x8 | filter);
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return cx25840_vbi(client, VIDIOC_S_FMT, fmt);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cx25840_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ struct v4l2_tuner *vt = arg;
+ int result = 0;
+
+ switch (cmd) {
+ case 0:
+ break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /* ioctls to allow direct access to the
+ * cx25840 registers for testing */
+ case VIDIOC_INT_G_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_CX25840)
+ return -EINVAL;
+ reg->val = cx25840_read(client, reg->reg & 0x0fff);
+ break;
+ }
+
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_CX25840)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+ break;
+ }
+#endif
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ return cx25840_vbi(client, cmd, arg);
+
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ case AUDC_SET_INPUT:
+ result = cx25840_audio(client, cmd, arg);
+ break;
+
+ case VIDIOC_STREAMON:
+ cx25840_dbg("enable output\n");
+ cx25840_write(client, 0x115, 0x8c);
+ cx25840_write(client, 0x116, 0x07);
+ break;
+
+ case VIDIOC_STREAMOFF:
+ cx25840_dbg("disable output\n");
+ cx25840_write(client, 0x115, 0x00);
+ cx25840_write(client, 0x116, 0x00);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ log_status(client);
+ break;
+
+ case VIDIOC_G_CTRL:
+ result = get_v4lctrl(client, (struct v4l2_control *)arg);
+ break;
+
+ case VIDIOC_S_CTRL:
+ result = set_v4lctrl(client, (struct v4l2_control *)arg);
+ break;
+
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = cx25840_get_v4lstd(client);
+ break;
+
+ case VIDIOC_S_STD:
+ result = set_v4lstd(client, *(v4l2_std_id *)arg);
+ break;
+
+ case VIDIOC_G_INPUT:
+ *(int *)arg = state->input;
+ break;
+
+ case VIDIOC_S_INPUT:
+ result = set_input(client, *(int *)arg);
+ break;
+
+ case VIDIOC_S_FREQUENCY:
+ input_change(client);
+ break;
+
+ case VIDIOC_G_TUNER:
+ {
+ u8 mode = cx25840_read(client, 0x804);
+ u8 pref = cx25840_read(client, 0x809) & 0xf;
+ u8 vpres = cx25840_read(client, 0x80a) & 0x10;
+ int val = 0;
+
+ vt->capability |=
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+ vt->signal = vpres ? 0xffff : 0x0;
+
+ /* get rxsubchans and audmode */
+ if ((mode & 0xf) == 1)
+ val |= V4L2_TUNER_SUB_STEREO;
+ else
+ val |= V4L2_TUNER_SUB_MONO;
+
+ if (mode == 2 || mode == 4)
+ val |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+ if (mode & 0x10)
+ val |= V4L2_TUNER_SUB_SAP;
+
+ vt->rxsubchans = val;
+
+ switch (pref) {
+ case 0:
+ vt->audmode = V4L2_TUNER_MODE_MONO;
+ break;
+ case 1:
+ case 2:
+ vt->audmode = V4L2_TUNER_MODE_LANG2;
+ break;
+ case 4:
+ default:
+ vt->audmode = V4L2_TUNER_MODE_STEREO;
+ }
+ break;
+ }
+
+ case VIDIOC_S_TUNER:
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ case V4L2_TUNER_MODE_LANG1:
+ /* Force PREF_MODE to MONO */
+ cx25840_and_or(client, 0x809, ~0xf, 0x00);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ /* Force PREF_MODE to STEREO */
+ cx25840_and_or(client, 0x809, ~0xf, 0x04);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ /* Force PREF_MODE to LANG2 */
+ cx25840_and_or(client, 0x809, ~0xf, 0x01);
+ break;
+ }
+ break;
+
+ case VIDIOC_G_FMT:
+ result = get_v4lfmt(client, (struct v4l2_format *)arg);
+ break;
+
+ case VIDIOC_S_FMT:
+ result = set_v4lfmt(client, (struct v4l2_format *)arg);
+ break;
+
+ case VIDIOC_INT_RESET:
+ cx25840_initialize(client, 0);
+ break;
+
+ case VIDIOC_INT_G_CHIP_IDENT:
+ *(enum v4l2_chip_ident *)arg =
+ V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf);
+ break;
+
+ default:
+ cx25840_err("invalid ioctl %x\n", cmd);
+ return -EINVAL;
+ }
+
+ return result;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_cx25840;
+
+static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
+ int kind)
+{
+ struct i2c_client *client;
+ struct cx25840_state *state;
+ u16 device_id;
+
+ /* Check if the adapter supports the needed features
+ * Not until kernel version 2.6.11 did the bit-algo
+ * correctly report that it would do an I2C-level xfer */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver_cx25840;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "cx25840");
+
+ cx25840_dbg("detecting cx25840 client on address 0x%x\n", address << 1);
+
+ device_id = cx25840_read(client, 0x101) << 8;
+ device_id |= cx25840_read(client, 0x100);
+
+ /* The high byte of the device ID should be
+ * 0x84 if chip is present */
+ if ((device_id & 0xff00) != 0x8400) {
+ cx25840_dbg("cx25840 not found\n");
+ kfree(client);
+ return 0;
+ }
+
+ cx25840_info("cx25%3x-2%x found @ 0x%x (%s)\n",
+ (device_id & 0xfff0) >> 4,
+ (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
+ address << 1, adapter->name);
+
+ state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, state);
+ memset(state, 0, sizeof(struct cx25840_state));
+ state->input = CX25840_TUNER;
+ state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+ state->audio_input = AUDIO_TUNER;
+ state->cardtype = CARDTYPE_PVR150;
+
+ cx25840_initialize(client, 1);
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int cx25840_attach_adapter(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, &cx25840_detect_client);
+ return 0;
+}
+
+static int cx25840_detach_client(struct i2c_client *client)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+
+ kfree(state);
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_cx25840 = {
+ .name = "cx25840",
+
+ .id = I2C_DRIVERID_CX25840,
+ .flags = I2C_DF_NOTIFY,
+
+ .attach_adapter = cx25840_attach_adapter,
+ .detach_client = cx25840_detach_client,
+ .command = cx25840_command,
+ .owner = THIS_MODULE,
+};
+
+
+static int __init m__init(void)
+{
+ return i2c_add_driver(&i2c_driver_cx25840);
+}
+
+static void __exit m__exit(void)
+{
+ i2c_del_driver(&i2c_driver_cx25840);
+}
+
+module_init(m__init);
+module_exit(m__exit);
+
+/* ----------------------------------------------------------------------- */
+
+static void log_status(struct i2c_client *client)
+{
+ static const char *const fmt_strs[] = {
+ "0x0",
+ "NTSC-M", "NTSC-J", "NTSC-4.43",
+ "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+ "0x9", "0xA", "0xB",
+ "SECAM",
+ "0xD", "0xE", "0xF"
+ };
+
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ u8 microctrl_vidfmt = cx25840_read(client, 0x80a);
+ u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
+ u8 gen_stat1 = cx25840_read(client, 0x40d);
+ u8 download_ctl = cx25840_read(client, 0x803);
+ u8 mod_det_stat0 = cx25840_read(client, 0x804);
+ u8 mod_det_stat1 = cx25840_read(client, 0x805);
+ u8 audio_config = cx25840_read(client, 0x808);
+ u8 pref_mode = cx25840_read(client, 0x809);
+ u8 afc0 = cx25840_read(client, 0x80b);
+ u8 mute_ctl = cx25840_read(client, 0x8d3);
+ char *p;
+
+ cx25840_info("Video signal: %spresent\n",
+ (microctrl_vidfmt & 0x10) ? "" : "not ");
+ cx25840_info("Detected format: %s\n",
+ fmt_strs[gen_stat1 & 0xf]);
+
+ switch (mod_det_stat0) {
+ case 0x00: p = "mono"; break;
+ case 0x01: p = "stereo"; break;
+ case 0x02: p = "dual"; break;
+ case 0x04: p = "tri"; break;
+ case 0x10: p = "mono with SAP"; break;
+ case 0x11: p = "stereo with SAP"; break;
+ case 0x12: p = "dual with SAP"; break;
+ case 0x14: p = "tri with SAP"; break;
+ case 0xfe: p = "forced mode"; break;
+ default: p = "not defined";
+ }
+ cx25840_info("Detected audio mode: %s\n", p);
+
+ switch (mod_det_stat1) {
+ case 0x00: p = "not defined"; break;
+ case 0x01: p = "EIAJ"; break;
+ case 0x02: p = "A2-M"; break;
+ case 0x03: p = "A2-BG"; break;
+ case 0x04: p = "A2-DK1"; break;
+ case 0x05: p = "A2-DK2"; break;
+ case 0x06: p = "A2-DK3"; break;
+ case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x08: p = "AM-L"; break;
+ case 0x09: p = "NICAM-BG"; break;
+ case 0x0a: p = "NICAM-DK"; break;
+ case 0x0b: p = "NICAM-I"; break;
+ case 0x0c: p = "NICAM-L"; break;
+ case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+ case 0x0e: p = "IF FM Radio"; break;
+ case 0x0f: p = "BTSC"; break;
+ case 0x10: p = "high-deviation FM"; break;
+ case 0x11: p = "very high-deviation FM"; break;
+ case 0xfd: p = "unknown audio standard"; break;
+ case 0xfe: p = "forced audio standard"; break;
+ case 0xff: p = "no detected audio standard"; break;
+ default: p = "not defined";
+ }
+ cx25840_info("Detected audio standard: %s\n", p);
+ cx25840_info("Audio muted: %s\n",
+ (mute_ctl & 0x2) ? "yes" : "no");
+ cx25840_info("Audio microcontroller: %s\n",
+ (download_ctl & 0x10) ? "running" : "stopped");
+
+ switch (audio_config >> 4) {
+ case 0x00: p = "undefined"; break;
+ case 0x01: p = "BTSC"; break;
+ case 0x02: p = "EIAJ"; break;
+ case 0x03: p = "A2-M"; break;
+ case 0x04: p = "A2-BG"; break;
+ case 0x05: p = "A2-DK1"; break;
+ case 0x06: p = "A2-DK2"; break;
+ case 0x07: p = "A2-DK3"; break;
+ case 0x08: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x09: p = "AM-L"; break;
+ case 0x0a: p = "NICAM-BG"; break;
+ case 0x0b: p = "NICAM-DK"; break;
+ case 0x0c: p = "NICAM-I"; break;
+ case 0x0d: p = "NICAM-L"; break;
+ case 0x0e: p = "FM radio"; break;
+ case 0x0f: p = "automatic detection"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Configured audio standard: %s\n", p);
+
+ if ((audio_config >> 4) < 0xF) {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+ case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+ case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+ case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+ case 0x04: p = "STEREO"; break;
+ case 0x05: p = "DUAL1 (AB)"; break;
+ case 0x06: p = "DUAL2 (AC) (FM)"; break;
+ case 0x07: p = "DUAL3 (BC) (FM)"; break;
+ case 0x08: p = "DUAL4 (AC) (AM)"; break;
+ case 0x09: p = "DUAL5 (BC) (AM)"; break;
+ case 0x0a: p = "SAP"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Configured audio mode: %s\n", p);
+ } else {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "BG"; break;
+ case 0x01: p = "DK1"; break;
+ case 0x02: p = "DK2"; break;
+ case 0x03: p = "DK3"; break;
+ case 0x04: p = "I"; break;
+ case 0x05: p = "L"; break;
+ case 0x06: p = "BTSC"; break;
+ case 0x07: p = "EIAJ"; break;
+ case 0x08: p = "A2-M"; break;
+ case 0x09: p = "FM Radio"; break;
+ case 0x0f: p = "automatic standard and mode detection"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Configured audio system: %s\n", p);
+ }
+
+ cx25840_info("Specified standard: %s\n",
+ vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+ switch (state->input) {
+ case CX25840_COMPOSITE0: p = "Composite 0"; break;
+ case CX25840_COMPOSITE1: p = "Composite 1"; break;
+ case CX25840_SVIDEO0: p = "S-Video 0"; break;
+ case CX25840_SVIDEO1: p = "S-Video 1"; break;
+ case CX25840_TUNER: p = "Tuner"; break;
+ }
+ cx25840_info("Specified input: %s\n", p);
+ cx25840_info("Specified audio input: %s\n",
+ state->audio_input == 0 ? "Tuner" : "External");
+
+ switch (state->audclk_freq) {
+ case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break;
+ case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break;
+ case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Specified audioclock freq: %s\n", p);
+
+ switch (pref_mode & 0xf) {
+ case 0: p = "mono/language A"; break;
+ case 1: p = "language B"; break;
+ case 2: p = "language C"; break;
+ case 3: p = "analog fallback"; break;
+ case 4: p = "stereo"; break;
+ case 5: p = "language AC"; break;
+ case 6: p = "language BC"; break;
+ case 7: p = "language AB"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Preferred audio mode: %s\n", p);
+
+ if ((audio_config & 0xf) == 0xf) {
+ switch ((afc0 >> 3) & 0x3) {
+ case 0: p = "system DK"; break;
+ case 1: p = "system L"; break;
+ case 2: p = "autodetect"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Selected 65 MHz format: %s\n", p);
+
+ switch (afc0 & 0x7) {
+ case 0: p = "chroma"; break;
+ case 1: p = "BTSC"; break;
+ case 2: p = "EIAJ"; break;
+ case 3: p = "A2-M"; break;
+ case 4: p = "autodetect"; break;
+ default: p = "undefined";
+ }
+ cx25840_info("Selected 45 MHz format: %s\n", p);
+ }
+}
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
new file mode 100644
index 00000000000..df9d50a7554
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -0,0 +1,167 @@
+/* cx25840 firmware functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+#define FWFILE "v4l-cx25840.fw"
+#define FWSEND 1024
+
+#define FWDEV(x) &((x)->adapter->dev)
+
+static int fastfw = 1;
+static char *firmware = FWFILE;
+
+module_param(fastfw, bool, 0444);
+module_param(firmware, charp, 0444);
+
+MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]");
+MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]");
+
+static inline void set_i2c_delay(struct i2c_client *client, int delay)
+{
+ struct i2c_algo_bit_data *algod = client->adapter->algo_data;
+
+ /* We aren't guaranteed to be using algo_bit,
+ * so avoid the null pointer dereference
+ * and disable the 'fast firmware load' */
+ if (algod) {
+ algod->udelay = delay;
+ } else {
+ fastfw = 0;
+ }
+}
+
+static inline void start_fw_load(struct i2c_client *client)
+{
+ /* DL_ADDR_LB=0 DL_ADDR_HB=0 */
+ cx25840_write(client, 0x800, 0x00);
+ cx25840_write(client, 0x801, 0x00);
+ // DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1
+ cx25840_write(client, 0x803, 0x0b);
+ /* AUTO_INC_DIS=1 */
+ cx25840_write(client, 0x000, 0x20);
+
+ if (fastfw)
+ set_i2c_delay(client, 3);
+}
+
+static inline void end_fw_load(struct i2c_client *client)
+{
+ if (fastfw)
+ set_i2c_delay(client, 10);
+
+ /* AUTO_INC_DIS=0 */
+ cx25840_write(client, 0x000, 0x00);
+ /* DL_ENABLE=0 */
+ cx25840_write(client, 0x803, 0x03);
+}
+
+static inline int check_fw_load(struct i2c_client *client, int size)
+{
+ /* DL_ADDR_HB DL_ADDR_LB */
+ int s = cx25840_read(client, 0x801) << 8;
+ s |= cx25840_read(client, 0x800);
+
+ if (size != s) {
+ cx25840_err("firmware %s load failed\n", firmware);
+ return -EINVAL;
+ }
+
+ cx25840_info("loaded %s firmware (%d bytes)\n", firmware, size);
+ return 0;
+}
+
+static inline int fw_write(struct i2c_client *client, u8 * data, int size)
+{
+ if (i2c_master_send(client, data, size) < size) {
+
+ if (fastfw) {
+ cx25840_err("333MHz i2c firmware load failed\n");
+ fastfw = 0;
+ set_i2c_delay(client, 10);
+
+ if (i2c_master_send(client, data, size) < size) {
+ cx25840_err
+ ("100MHz i2c firmware load failed\n");
+ return -ENOSYS;
+ }
+
+ } else {
+ cx25840_err("firmware load i2c failure\n");
+ return -ENOSYS;
+ }
+
+ }
+
+ return 0;
+}
+
+int cx25840_loadfw(struct i2c_client *client)
+{
+ const struct firmware *fw = NULL;
+ u8 buffer[4], *ptr;
+ int size, send, retval;
+
+ if (request_firmware(&fw, firmware, FWDEV(client)) != 0) {
+ cx25840_err("unable to open firmware %s\n", firmware);
+ return -EINVAL;
+ }
+
+ start_fw_load(client);
+
+ buffer[0] = 0x08;
+ buffer[1] = 0x02;
+ buffer[2] = fw->data[0];
+ buffer[3] = fw->data[1];
+ retval = fw_write(client, buffer, 4);
+
+ if (retval < 0) {
+ release_firmware(fw);
+ return retval;
+ }
+
+ size = fw->size - 2;
+ ptr = fw->data;
+ while (size > 0) {
+ ptr[0] = 0x08;
+ ptr[1] = 0x02;
+ send = size > (FWSEND - 2) ? FWSEND : size + 2;
+ retval = fw_write(client, ptr, send);
+
+ if (retval < 0) {
+ release_firmware(fw);
+ return retval;
+ }
+
+ size -= FWSEND - 2;
+ ptr += FWSEND - 2;
+ }
+
+ end_fw_load(client);
+
+ size = fw->size;
+ release_firmware(fw);
+
+ return check_fw_load(client, size);
+}
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
new file mode 100644
index 00000000000..13ba4e15dde
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -0,0 +1,315 @@
+/* cx25840 VBI functions
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+
+#include "cx25840.h"
+
+static inline int odd_parity(u8 c)
+{
+ c ^= (c >> 4);
+ c ^= (c >> 2);
+ c ^= (c >> 1);
+
+ return c & 1;
+}
+
+static inline int decode_vps(u8 * dst, u8 * p)
+{
+ static const u8 biphase_tbl[] = {
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+ 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+ 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+ 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+ 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+ 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+ 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ };
+
+ u8 c, err = 0;
+ int i;
+
+ for (i = 0; i < 2 * 13; i += 2) {
+ err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+ c = (biphase_tbl[p[i + 1]] & 0xf) |
+ ((biphase_tbl[p[i]] & 0xf) << 4);
+ dst[i / 2] = c;
+ }
+
+ return err & 0xf0;
+}
+
+void cx25840_vbi_setup(struct i2c_client *client)
+{
+ v4l2_std_id std = cx25840_get_v4lstd(client);
+
+ if (std & ~V4L2_STD_NTSC) {
+ /* datasheet startup, step 8d */
+ cx25840_write(client, 0x49f, 0x11);
+
+ cx25840_write(client, 0x470, 0x84);
+ cx25840_write(client, 0x471, 0x00);
+ cx25840_write(client, 0x472, 0x2d);
+ cx25840_write(client, 0x473, 0x5d);
+
+ cx25840_write(client, 0x474, 0x24);
+ cx25840_write(client, 0x475, 0x40);
+ cx25840_write(client, 0x476, 0x24);
+ cx25840_write(client, 0x477, 0x28);
+
+ cx25840_write(client, 0x478, 0x1f);
+ cx25840_write(client, 0x479, 0x02);
+
+ if (std & V4L2_STD_SECAM) {
+ cx25840_write(client, 0x47a, 0x80);
+ cx25840_write(client, 0x47b, 0x00);
+ cx25840_write(client, 0x47c, 0x5f);
+ cx25840_write(client, 0x47d, 0x42);
+ } else {
+ cx25840_write(client, 0x47a, 0x90);
+ cx25840_write(client, 0x47b, 0x20);
+ cx25840_write(client, 0x47c, 0x63);
+ cx25840_write(client, 0x47d, 0x82);
+ }
+
+ cx25840_write(client, 0x47e, 0x0a);
+ cx25840_write(client, 0x47f, 0x01);
+ } else {
+ /* datasheet startup, step 8d */
+ cx25840_write(client, 0x49f, 0x14);
+
+ cx25840_write(client, 0x470, 0x7a);
+ cx25840_write(client, 0x471, 0x00);
+ cx25840_write(client, 0x472, 0x2d);
+ cx25840_write(client, 0x473, 0x5b);
+
+ cx25840_write(client, 0x474, 0x1a);
+ cx25840_write(client, 0x475, 0x70);
+ cx25840_write(client, 0x476, 0x1e);
+ cx25840_write(client, 0x477, 0x1e);
+
+ cx25840_write(client, 0x478, 0x1f);
+ cx25840_write(client, 0x479, 0x02);
+ cx25840_write(client, 0x47a, 0x50);
+ cx25840_write(client, 0x47b, 0x66);
+
+ cx25840_write(client, 0x47c, 0x1f);
+ cx25840_write(client, 0x47d, 0x7c);
+ cx25840_write(client, 0x47e, 0x08);
+ cx25840_write(client, 0x47f, 0x00);
+ }
+}
+
+int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct v4l2_format *fmt;
+ struct v4l2_sliced_vbi_format *svbi;
+
+ switch (cmd) {
+ case VIDIOC_G_FMT:
+ {
+ static u16 lcr2vbi[] = {
+ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+ 0, V4L2_SLICED_WSS_625, 0, /* 4 */
+ V4L2_SLICED_CAPTION_525, /* 6 */
+ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
+ 0, 0, 0, 0
+ };
+ int i;
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ memset(svbi, 0, sizeof(*svbi));
+ /* we're done if raw VBI is active */
+ if ((cx25840_read(client, 0x404) & 0x10) == 0)
+ break;
+
+ for (i = 7; i <= 23; i++) {
+ u8 v = cx25840_read(client, 0x424 + i - 7);
+
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |=
+ svbi->service_lines[0][i] | svbi->service_lines[1][i];
+ }
+ break;
+ }
+
+ case VIDIOC_S_FMT:
+ {
+ int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+ int vbi_offset = is_pal ? 1 : 0;
+ int i, x;
+ u8 lcr[24];
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ if (svbi->service_set == 0) {
+ /* raw VBI */
+ memset(svbi, 0, sizeof(*svbi));
+
+ /* Setup VBI */
+ cx25840_vbi_setup(client);
+
+ /* VBI Offset */
+ cx25840_write(client, 0x47f, vbi_offset);
+ cx25840_write(client, 0x404, 0x2e);
+ break;
+ }
+
+ for (x = 0; x <= 23; x++)
+ lcr[x] = 0x00;
+
+ /* Setup VBI */
+ cx25840_vbi_setup(client);
+
+ /* Sliced VBI */
+ cx25840_write(client, 0x404, 0x36); /* Ancillery data */
+ cx25840_write(client, 0x406, 0x13);
+ cx25840_write(client, 0x47f, vbi_offset);
+
+ if (is_pal) {
+ for (i = 0; i <= 6; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ } else {
+ for (i = 0; i <= 9; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+
+ for (i = 22; i <= 23; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ }
+
+ for (i = 7; i <= 23; i++) {
+ for (x = 0; x <= 1; x++) {
+ switch (svbi->service_lines[1-x][i]) {
+ case V4L2_SLICED_TELETEXT_B:
+ lcr[i] |= 1 << (4 * x);
+ break;
+ case V4L2_SLICED_WSS_625:
+ lcr[i] |= 4 << (4 * x);
+ break;
+ case V4L2_SLICED_CAPTION_525:
+ lcr[i] |= 6 << (4 * x);
+ break;
+ case V4L2_SLICED_VPS:
+ lcr[i] |= 9 << (4 * x);
+ break;
+ }
+ }
+ }
+
+ for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+ cx25840_write(client, i, lcr[6 + x]);
+ }
+
+ cx25840_write(client, 0x43c, 0x16);
+
+ if (is_pal) {
+ cx25840_write(client, 0x474, 0x2a);
+ } else {
+ cx25840_write(client, 0x474, 0x1a + 6);
+ }
+ break;
+ }
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ {
+ struct v4l2_decode_vbi_line *vbi = arg;
+ u8 *p = vbi->p;
+ int id1, id2, l, err = 0;
+
+ if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+ (p[3] != 0x55 && p[3] != 0x91)) {
+ vbi->line = vbi->type = 0;
+ break;
+ }
+
+ p += 4;
+ id1 = p[-1];
+ id2 = p[0] & 0xf;
+ l = p[2] & 0x3f;
+ l += 5;
+ p += 4;
+
+ switch (id2) {
+ case 1:
+ id2 = V4L2_SLICED_TELETEXT_B;
+ break;
+ case 4:
+ id2 = V4L2_SLICED_WSS_625;
+ break;
+ case 6:
+ id2 = V4L2_SLICED_CAPTION_525;
+ err = !odd_parity(p[0]) || !odd_parity(p[1]);
+ break;
+ case 9:
+ id2 = V4L2_SLICED_VPS;
+ if (decode_vps(p, p) != 0) {
+ err = 1;
+ }
+ break;
+ default:
+ id2 = 0;
+ err = 1;
+ break;
+ }
+
+ vbi->type = err ? 0 : id2;
+ vbi->line = err ? 0 : l;
+ vbi->is_second_field = err ? 0 : (id1 == 0x55);
+ vbi->p = p;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h
new file mode 100644
index 00000000000..5c3f0639fb7
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840.h
@@ -0,0 +1,85 @@
+/* cx25840 API header
+ *
+ * Copyright (C) 2003-2004 Chris Kennedy
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _CX25840_H_
+#define _CX25840_H_
+
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+extern int cx25840_debug;
+
+#define cx25840_dbg(fmt, arg...) do { if (cx25840_debug) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+#define cx25840_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+#define cx25840_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+#define CX25840_CID_CARDTYPE (V4L2_CID_PRIVATE_BASE+0)
+
+enum cx25840_cardtype {
+ CARDTYPE_PVR150,
+ CARDTYPE_PG600
+};
+
+enum cx25840_input {
+ CX25840_TUNER,
+ CX25840_COMPOSITE0,
+ CX25840_COMPOSITE1,
+ CX25840_SVIDEO0,
+ CX25840_SVIDEO1
+};
+
+struct cx25840_state {
+ enum cx25840_cardtype cardtype;
+ enum cx25840_input input;
+ int audio_input;
+ enum v4l2_audio_clock_freq audclk_freq;
+};
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-core.c */
+int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
+int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
+u8 cx25840_read(struct i2c_client *client, u16 addr);
+u32 cx25840_read4(struct i2c_client *client, u16 addr);
+int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value);
+v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-firmware.c */
+int cx25840_loadfw(struct i2c_client *client);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-audio.c */
+int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------------------- */
+/* cx25850-vbi.c */
+void cx25840_vbi_setup(struct i2c_client *client);
+int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg);
+
+#endif
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 9cce91ec334..99ea955f598 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -439,9 +439,6 @@ static int dvb_register(struct cx8802_dev *dev)
/* Put the analog decoder in standby to keep it quiet */
cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
- /* Put the analog decoder in standby to keep it quiet */
- cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-
/* register everything */
return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 32c49df58ad..9b94f77d6fd 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -120,9 +120,6 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if (buf[1]==0xff)
return 0;
- /* avoid fast reapeating */
- if (buf[1]==ir->old)
- return 0;
ir->old=buf[1];
/* Rearranges bits to the right order */
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c
index ed81934ef3c..5abfc0fbf6d 100644
--- a/drivers/media/video/ir-kbd-gpio.c
+++ b/drivers/media/video/ir-kbd-gpio.c
@@ -221,24 +221,99 @@ static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = {
[ 24 ] = KEY_MUTE // mute/unmute
};
+static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
+ [0x00] = KEY_KP0,
+ [0x01] = KEY_KP1,
+ [0x02] = KEY_KP2,
+ [0x03] = KEY_KP3,
+ [0x04] = KEY_KP4,
+ [0x05] = KEY_KP5,
+ [0x06] = KEY_KP6,
+ [0x07] = KEY_KP7,
+ [0x08] = KEY_KP8,
+ [0x09] = KEY_KP9,
+ [0x0a] = KEY_TV,
+ [0x0b] = KEY_AUX,
+ [0x0c] = KEY_DVD,
+ [0x0d] = KEY_POWER,
+ [0x0e] = KEY_MHP, /* labelled 'Picture' */
+ [0x0f] = KEY_AUDIO,
+ [0x10] = KEY_INFO,
+ [0x11] = KEY_F13, /* 16:9 */
+ [0x12] = KEY_F14, /* 14:9 */
+ [0x13] = KEY_EPG,
+ [0x14] = KEY_EXIT,
+ [0x15] = KEY_MENU,
+ [0x16] = KEY_UP,
+ [0x17] = KEY_DOWN,
+ [0x18] = KEY_LEFT,
+ [0x19] = KEY_RIGHT,
+ [0x1a] = KEY_ENTER,
+ [0x1b] = KEY_CHANNELUP,
+ [0x1c] = KEY_CHANNELDOWN,
+ [0x1d] = KEY_VOLUMEUP,
+ [0x1e] = KEY_VOLUMEDOWN,
+ [0x1f] = KEY_RED,
+ [0x20] = KEY_GREEN,
+ [0x21] = KEY_YELLOW,
+ [0x22] = KEY_BLUE,
+ [0x23] = KEY_SUBTITLE,
+ [0x24] = KEY_F15, /* AD */
+ [0x25] = KEY_TEXT,
+ [0x26] = KEY_MUTE,
+ [0x27] = KEY_REWIND,
+ [0x28] = KEY_STOP,
+ [0x29] = KEY_PLAY,
+ [0x2a] = KEY_FASTFORWARD,
+ [0x2b] = KEY_F16, /* chapter */
+ [0x2c] = KEY_PAUSE,
+ [0x2d] = KEY_PLAY,
+ [0x2e] = KEY_RECORD,
+ [0x2f] = KEY_F17, /* picture in picture */
+ [0x30] = KEY_KPPLUS, /* zoom in */
+ [0x31] = KEY_KPMINUS, /* zoom out */
+ [0x32] = KEY_F18, /* capture */
+ [0x33] = KEY_F19, /* web */
+ [0x34] = KEY_EMAIL,
+ [0x35] = KEY_PHONE,
+ [0x36] = KEY_PC
+};
+
struct IR {
struct bttv_sub_device *sub;
struct input_dev *input;
struct ir_input_state ir;
char name[32];
char phys[32];
+
+ /* Usual gpio signalling */
+
u32 mask_keycode;
u32 mask_keydown;
u32 mask_keyup;
-
- int polling;
+ u32 polling;
u32 last_gpio;
struct work_struct work;
struct timer_list timer;
+
+ /* RC5 gpio */
+
+ u32 rc5_gpio;
+ struct timer_list timer_end; /* timer_end for code completion */
+ struct timer_list timer_keyup; /* timer_end for key release */
+ u32 last_rc5; /* last good rc5 code */
+ u32 last_bit; /* last raw bit seen */
+ u32 code; /* raw code under construction */
+ struct timeval base_time; /* time of last seen code */
+ int active; /* building raw code */
};
static int debug;
module_param(debug, int, 0644); /* debug level (0,1,2) */
+static int repeat_delay = 500;
+module_param(repeat_delay, int, 0644);
+static int repeat_period = 33;
+module_param(repeat_period, int, 0644);
#define DEVNAME "ir-kbd-gpio"
#define dprintk(fmt, arg...) if (debug) \
@@ -254,7 +329,7 @@ static struct bttv_sub_driver driver = {
.probe = ir_probe,
.remove = ir_remove,
},
- .gpio_irq = ir_irq,
+ .gpio_irq = ir_irq,
};
/* ---------------------------------------------------------------------- */
@@ -327,6 +402,173 @@ static void ir_work(void *data)
mod_timer(&ir->timer, timeout);
}
+/* ---------------------------------------------------------------*/
+
+static int rc5_remote_gap = 885;
+module_param(rc5_remote_gap, int, 0644);
+static int rc5_key_timeout = 200;
+module_param(rc5_key_timeout, int, 0644);
+
+#define RC5_START(x) (((x)>>12)&3)
+#define RC5_TOGGLE(x) (((x)>>11)&1)
+#define RC5_ADDR(x) (((x)>>6)&31)
+#define RC5_INSTR(x) ((x)&63)
+
+/* decode raw bit pattern to RC5 code */
+static u32 rc5_decode(unsigned int code)
+{
+ unsigned int org_code = code;
+ unsigned int pair;
+ unsigned int rc5 = 0;
+ int i;
+
+ code = (code << 1) | 1;
+ for (i = 0; i < 14; ++i) {
+ pair = code & 0x3;
+ code >>= 2;
+
+ rc5 <<= 1;
+ switch (pair) {
+ case 0:
+ case 2:
+ break;
+ case 1:
+ rc5 |= 1;
+ break;
+ case 3:
+ dprintk("bad code: %x\n", org_code);
+ return 0;
+ }
+ }
+ dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+ "instr=%x\n", rc5, org_code, RC5_START(rc5),
+ RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+ return rc5;
+}
+
+static int ir_rc5_irq(struct bttv_sub_device *sub)
+{
+ struct IR *ir = dev_get_drvdata(&sub->dev);
+ struct timeval tv;
+ u32 gpio;
+ u32 gap;
+ unsigned long current_jiffies, timeout;
+
+ /* read gpio port */
+ gpio = bttv_gpio_read(ir->sub->core);
+
+ /* remote IRQ? */
+ if (!(gpio & 0x20))
+ return 0;
+
+ /* get time of bit */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* active code => add bit */
+ if (ir->active) {
+ /* only if in the code (otherwise spurious IRQ or timer
+ late) */
+ if (ir->last_bit < 28) {
+ ir->last_bit = (gap - rc5_remote_gap / 2) /
+ rc5_remote_gap;
+ ir->code |= 1 << ir->last_bit;
+ }
+ /* starting new code */
+ } else {
+ ir->active = 1;
+ ir->code = 0;
+ ir->base_time = tv;
+ ir->last_bit = 0;
+
+ timeout = current_jiffies + (500 + 30 * HZ) / 1000;
+ mod_timer(&ir->timer_end, timeout);
+ }
+
+ /* toggle GPIO pin 4 to reset the irq */
+ bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
+ bttv_gpio_write(ir->sub->core, gpio | (1 << 4));
+ return 1;
+}
+
+static void ir_rc5_timer_end(unsigned long data)
+{
+ struct IR *ir = (struct IR *)data;
+ struct timeval tv;
+ unsigned long current_jiffies, timeout;
+ u32 gap;
+
+ /* get time */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
+ if (gap < 28000) {
+ dprintk("spurious timer_end\n");
+ return;
+ }
+
+ ir->active = 0;
+ if (ir->last_bit < 20) {
+ /* ignore spurious codes (caused by light/other remotes) */
+ dprintk("short code: %x\n", ir->code);
+ } else {
+ u32 rc5 = rc5_decode(ir->code);
+
+ /* two start bits? */
+ if (RC5_START(rc5) != 3) {
+ dprintk("rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+ /* right address? */
+ } else if (RC5_ADDR(rc5) == 0x0) {
+ u32 toggle = RC5_TOGGLE(rc5);
+ u32 instr = RC5_INSTR(rc5);
+
+ /* Good code, decide if repeat/repress */
+ if (toggle != RC5_TOGGLE(ir->last_rc5) ||
+ instr != RC5_INSTR(ir->last_rc5)) {
+ dprintk("instruction %x, toggle %x\n", instr,
+ toggle);
+ ir_input_nokey(ir->input, &ir->ir);
+ ir_input_keydown(ir->input, &ir->ir, instr,
+ instr);
+ }
+
+ /* Set/reset key-up timer */
+ timeout = current_jiffies + (500 + rc5_key_timeout
+ * HZ) / 1000;
+ mod_timer(&ir->timer_keyup, timeout);
+
+ /* Save code for repeat test */
+ ir->last_rc5 = rc5;
+ }
+ }
+}
+
+static void ir_rc5_timer_keyup(unsigned long data)
+{
+ struct IR *ir = (struct IR *)data;
+
+ dprintk("key released\n");
+ ir_input_nokey(ir->input, &ir->ir);
+}
+
/* ---------------------------------------------------------------------- */
static int ir_probe(struct device *dev)
@@ -400,6 +642,12 @@ static int ir_probe(struct device *dev)
ir->mask_keyup = 0x006000;
ir->polling = 50; // ms
break;
+ case BTTV_BOARD_NEBULA_DIGITV:
+ ir_codes = ir_codes_nebula;
+ driver.any_irq = ir_rc5_irq;
+ driver.gpio_irq = NULL;
+ ir->rc5_gpio = 1;
+ break;
}
if (NULL == ir_codes) {
kfree(ir);
@@ -407,9 +655,17 @@ static int ir_probe(struct device *dev)
return -ENODEV;
}
- /* init hardware-specific stuff */
- bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0);
- ir->sub = sub;
+ if (ir->rc5_gpio) {
+ u32 gpio;
+ /* enable remote irq */
+ bttv_gpio_inout(sub->core, (1 << 4), 1 << 4);
+ gpio = bttv_gpio_read(sub->core);
+ bttv_gpio_write(sub->core, gpio & ~(1 << 4));
+ bttv_gpio_write(sub->core, gpio | (1 << 4));
+ } else {
+ /* init hardware-specific stuff */
+ bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0);
+ }
/* init input device */
snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
@@ -417,6 +673,7 @@ static int ir_probe(struct device *dev)
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
pci_name(sub->core->pci));
+ ir->sub = sub;
ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
input_dev->name = ir->name;
input_dev->phys = ir->phys;
@@ -437,11 +694,25 @@ static int ir_probe(struct device *dev)
ir->timer.function = ir_timer;
ir->timer.data = (unsigned long)ir;
schedule_work(&ir->work);
+ } else if (ir->rc5_gpio) {
+ /* set timer_end for code completion */
+ init_timer(&ir->timer_end);
+ ir->timer_end.function = ir_rc5_timer_end;
+ ir->timer_end.data = (unsigned long)ir;
+
+ init_timer(&ir->timer_keyup);
+ ir->timer_keyup.function = ir_rc5_timer_keyup;
+ ir->timer_keyup.data = (unsigned long)ir;
}
/* all done */
dev_set_drvdata(dev, ir);
input_register_device(ir->input);
+ printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys);
+
+ /* the remote isn't as bouncy as a keyboard */
+ ir->input->rep[REP_DELAY] = repeat_delay;
+ ir->input->rep[REP_PERIOD] = repeat_period;
return 0;
}
@@ -454,6 +725,15 @@ static int ir_remove(struct device *dev)
del_timer(&ir->timer);
flush_scheduled_work();
}
+ if (ir->rc5_gpio) {
+ u32 gpio;
+
+ del_timer(&ir->timer_end);
+ flush_scheduled_work();
+
+ gpio = bttv_gpio_read(ir->sub->core);
+ bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4));
+ }
input_unregister_device(ir->input);
kfree(ir);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 0085567a142..801c736e932 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -183,6 +183,58 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+
+int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char b[4];
+ unsigned int start = 0,parity = 0,code = 0;
+
+ /* poll IR chip */
+ if (4 != i2c_master_recv(&ir->c,b,4)) {
+ dprintk(2,"read error\n");
+ return -EIO;
+ }
+
+ for (start = 0; start<4; start++) {
+ if (b[start] == 0x80) {
+ code=b[(start+3)%4];
+ parity=b[(start+2)%4];
+ }
+ }
+
+ /* Empty Request */
+ if (parity==0)
+ return 0;
+
+ /* Repeating... */
+ if (ir->old == parity)
+ return 0;
+
+
+ ir->old = parity;
+
+ /* Reduce code value to fit inside IR_KEYTAB_SIZE
+ *
+ * this is the only value that results in 42 unique
+ * codes < 128
+ */
+
+ code %= 0x88;
+
+ *ir_raw = code;
+ *ir_key = code;
+
+ dprintk(1,"Pinnacle PCTV key %02x\n", code);
+
+ return 1;
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle);
+
/* ----------------------------------------------------------------------- */
static void ir_key_poll(struct IR_i2c *ir)
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
new file mode 100644
index 00000000000..0235cef07b3
--- /dev/null
+++ b/drivers/media/video/saa7115.c
@@ -0,0 +1,1376 @@
+/* saa7115 - Philips SAA7114/SAA7115 video decoder driver
+ *
+ * Based on saa7114 driver by Maxim Yevtyushkin, which is based on
+ * the saa7111 driver by Dave Perks.
+ *
+ * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+ * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
+ *
+ * Slight changes for video timing and attachment output by
+ * Wolfgang Scherr <scherr@net4you.net>
+ *
+ * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003)
+ * by Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com>
+ * (2/17/2003)
+ *
+ * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver");
+MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+#define saa7115_dbg(fmt,arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+#define saa7115_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define saa7115_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+struct saa7115_state {
+ v4l2_std_id std;
+ int input;
+ int enable;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+ enum v4l2_chip_ident ident;
+ enum v4l2_audio_clock_freq audclk_freq;
+};
+
+/* ----------------------------------------------------------------------- */
+
+static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
+{
+ unsigned char reg, data;
+
+ while (*regs != 0x00) {
+ reg = *(regs++);
+ data = *(regs++);
+ if (saa7115_write(client, reg, data) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static inline int saa7115_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* If a value differs from the Hauppauge driver values, then the comment starts with
+ 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
+ Hauppauge driver sets. */
+
+static const unsigned char saa7115_init_auto_input[] = {
+ 0x01, 0x48, /* white peak control disabled */
+ 0x03, 0x20, /* was 0x30. 0x20: long vertical blanking */
+ 0x04, 0x90, /* analog gain set to 0 */
+ 0x05, 0x90, /* analog gain set to 0 */
+ 0x06, 0xeb, /* horiz sync begin = -21 */
+ 0x07, 0xe0, /* horiz sync stop = -17 */
+ 0x0a, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
+ 0x0b, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
+ 0x0c, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
+ 0x0d, 0x00, /* chrominance hue control */
+ 0x0f, 0x00, /* chrominance gain control: use automicatic mode */
+ 0x10, 0x06, /* chrominance/luminance control: active adaptive combfilter */
+ 0x11, 0x00, /* delay control */
+ 0x12, 0x9d, /* RTS0 output control: VGATE */
+ 0x13, 0x80, /* X-port output control: ITU656 standard mode, RTCO output enable RTCE */
+ 0x14, 0x00, /* analog/ADC/auto compatibility control */
+ 0x18, 0x40, /* raw data gain 0x00 = nominal */
+ 0x19, 0x80, /* raw data offset 0x80 = 0 LSB */
+ 0x1a, 0x77, /* color killer level control 0x77 = recommended */
+ 0x1b, 0x42, /* misc chroma control 0x42 = recommended */
+ 0x1c, 0xa9, /* combfilter control 0xA9 = recommended */
+ 0x1d, 0x01, /* combfilter control 0x01 = recommended */
+ 0x88, 0xd0, /* reset device */
+ 0x88, 0xf0, /* set device programmed, all in operational mode */
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_reset_scaler[] = {
+ 0x87, 0x00, /* disable I-port output */
+ 0x88, 0xd0, /* reset scaler */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* enable I-port output */
+ 0x00, 0x00
+};
+
+/* ============== SAA7715 VIDEO templates ============= */
+
+static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
+ 0xcc, 0xd0, /* hsize low (output), hor. output window size = 0x2d0 = 720 */
+ 0xcd, 0x02, /* hsize hi (output) */
+
+ /* Why not in 60hz-Land, too? */
+ 0xd0, 0x01, /* downscale = 1 */
+ 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
+ 0xd9, 0x04,
+ 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+ 0xdd, 0x02, /* H-scaling incr chroma */
+
+ 0x00, 0x00
+};
+static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
+ 0xce, 0xf8, /* vsize low (output), ver. output window size = 248 (but 60hz is 240?) */
+ 0xcf, 0x00, /* vsize hi (output) */
+
+ /* Why not in 60hz-Land, too? */
+ 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
+ 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
+
+ 0xe0, 0x00, /* V-scaling incr luma low */
+ 0xe1, 0x04, /* " hi */
+ 0xe2, 0x00, /* V-scaling incr chroma low */
+ 0xe3, 0x04, /* " hi */
+
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_60hz_video[] = {
+ 0x80, 0x00, /* reset tasks */
+ 0x88, 0xd0, /* reset scaler */
+
+ 0x15, 0x03, /* VGATE pulse start */
+ 0x16, 0x11, /* VGATE pulse stop */
+ 0x17, 0x9c, /* VGATE MSB and other values */
+
+ 0x08, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
+ 0x0e, 0x07, /* lots of different stuff... video autodetection is on */
+
+ 0x5a, 0x06, /* Vertical offset, standard 60hz value for ITU656 line counting */
+
+ /* Task A */
+ 0x90, 0x80, /* Task Handling Control */
+ 0x91, 0x48, /* X-port formats/config */
+ 0x92, 0x40, /* Input Ref. signal Def. */
+ 0x93, 0x84, /* I-port config */
+ 0x94, 0x01, /* hoffset low (input), 0x0002 is minimum */
+ 0x95, 0x00, /* hoffset hi (input) */
+ 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+ 0x97, 0x02, /* hsize hi (input) */
+ 0x98, 0x05, /* voffset low (input) */
+ 0x99, 0x00, /* voffset hi (input) */
+ 0x9a, 0x0c, /* vsize low (input), 0x0c = 12 */
+ 0x9b, 0x00, /* vsize hi (input) */
+ 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
+ 0x9d, 0x05, /* hsize hi (output) */
+ 0x9e, 0x0c, /* vsize low (output), 0x0c = 12 */
+ 0x9f, 0x00, /* vsize hi (output) */
+
+ /* Task B */
+ 0xc0, 0x00, /* Task Handling Control */
+ 0xc1, 0x08, /* X-port formats/config */
+ 0xc2, 0x00, /* Input Ref. signal Def. */
+ 0xc3, 0x80, /* I-port config */
+ 0xc4, 0x02, /* hoffset low (input), 0x0002 is minimum */
+ 0xc5, 0x00, /* hoffset hi (input) */
+ 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+ 0xc7, 0x02, /* hsize hi (input) */
+ 0xc8, 0x12, /* voffset low (input), 0x12 = 18 */
+ 0xc9, 0x00, /* voffset hi (input) */
+ 0xca, 0xf8, /* vsize low (input), 0xf8 = 248 */
+ 0xcb, 0x00, /* vsize hi (input) */
+ 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
+ 0xcd, 0x02, /* hsize hi (output) */
+
+ 0xf0, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
+ 0xf1, 0x05, /* low bit with 0xF0 */
+ 0xf5, 0xad, /* Set pulse generator register */
+ 0xf6, 0x01,
+
+ 0x87, 0x00, /* Disable I-port output */
+ 0x88, 0xd0, /* reset scaler */
+ 0x80, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* Enable I-port output */
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
+ 0xcc, 0xd0, /* hsize low (output), 720 same as 60hz */
+ 0xcd, 0x02, /* hsize hi (output) */
+
+ 0xd0, 0x01, /* down scale = 1 */
+ 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
+ 0xd9, 0x04,
+ 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+ 0xdd, 0x02, /* H-scaling incr chroma */
+
+ 0x00, 0x00
+};
+static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
+ 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
+ 0xcf, 0x01, /* vsize hi (output) */
+
+ 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
+ 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
+
+ 0xe0, 0x00, /* V-scaling incr luma low */
+ 0xe1, 0x04, /* " hi */
+ 0xe2, 0x00, /* V-scaling incr chroma low */
+ 0xe3, 0x04, /* " hi */
+
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_50hz_video[] = {
+ 0x80, 0x00, /* reset tasks */
+ 0x88, 0xd0, /* reset scaler */
+
+ 0x15, 0x37, /* VGATE start */
+ 0x16, 0x16, /* VGATE stop */
+ 0x17, 0x99, /* VGATE MSB and other values */
+
+ 0x08, 0x28, /* 0x28 = PAL */
+ 0x0e, 0x07, /* chrominance control 1 */
+
+ 0x5a, 0x03, /* Vertical offset, standard 50hz value */
+
+ /* Task A */
+ 0x90, 0x81, /* Task Handling Control */
+ 0x91, 0x48, /* X-port formats/config */
+ 0x92, 0x40, /* Input Ref. signal Def. */
+ 0x93, 0x84, /* I-port config */
+ /* This is weird: the datasheet says that you should use 2 as the minimum value, */
+ /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
+ 0x94, 0x00, /* hoffset low (input), 0x0002 is minimum */
+ 0x95, 0x00, /* hoffset hi (input) */
+ 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+ 0x97, 0x02, /* hsize hi (input) */
+ 0x98, 0x03, /* voffset low (input) */
+ 0x99, 0x00, /* voffset hi (input) */
+ 0x9a, 0x12, /* vsize low (input), 0x12 = 18 */
+ 0x9b, 0x00, /* vsize hi (input) */
+ 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
+ 0x9d, 0x05, /* hsize hi (output) */
+ 0x9e, 0x12, /* vsize low (output), 0x12 = 18 */
+ 0x9f, 0x00, /* vsize hi (output) */
+
+ /* Task B */
+ 0xc0, 0x00, /* Task Handling Control */
+ 0xc1, 0x08, /* X-port formats/config */
+ 0xc2, 0x00, /* Input Ref. signal Def. */
+ 0xc3, 0x80, /* I-port config */
+ 0xc4, 0x00, /* hoffset low (input), 0x0002 is minimum. See comment at 0x94 above. */
+ 0xc5, 0x00, /* hoffset hi (input) */
+ 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
+ 0xc7, 0x02, /* hsize hi (input) */
+ 0xc8, 0x16, /* voffset low (input), 0x16 = 22 */
+ 0xc9, 0x00, /* voffset hi (input) */
+ 0xca, 0x20, /* vsize low (input), 0x0120 = 288 */
+ 0xcb, 0x01, /* vsize hi (input) */
+ 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
+ 0xcd, 0x02, /* hsize hi (output) */
+ 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
+ 0xcf, 0x01, /* vsize hi (output) */
+
+ 0xf0, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
+ 0xf1, 0x05, /* low bit with 0xF0, (was 0x05) */
+ 0xf5, 0xb0, /* Set pulse generator register */
+ 0xf6, 0x01,
+
+ 0x87, 0x00, /* Disable I-port output */
+ 0x88, 0xd0, /* reset scaler (was 0xD0) */
+ 0x80, 0x20, /* Activate only task "B" */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* Enable I-port output */
+ 0x00, 0x00
+};
+
+/* ============== SAA7715 VIDEO templates (end) ======= */
+
+static const unsigned char saa7115_cfg_vbi_on[] = {
+ 0x80, 0x00, /* reset tasks */
+ 0x88, 0xd0, /* reset scaler */
+ 0x80, 0x30, /* Activate both tasks */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* Enable I-port output */
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_cfg_vbi_off[] = {
+ 0x80, 0x00, /* reset tasks */
+ 0x88, 0xd0, /* reset scaler */
+ 0x80, 0x20, /* Activate only task "B" */
+ 0x88, 0xf0, /* activate scaler */
+ 0x87, 0x01, /* Enable I-port output */
+ 0x00, 0x00
+};
+
+static const unsigned char saa7115_init_misc[] = {
+ 0x38, 0x03, /* audio stuff */
+ 0x39, 0x10,
+ 0x3a, 0x08,
+
+ 0x81, 0x01, /* reg 0x15,0x16 define blanking window */
+ 0x82, 0x00,
+ 0x83, 0x01, /* I port settings */
+ 0x84, 0x20,
+ 0x85, 0x21,
+ 0x86, 0xc5,
+ 0x87, 0x01,
+
+ /* Task A */
+ 0xa0, 0x01, /* down scale = 1 */
+ 0xa1, 0x00, /* prescale accumulation length = 1 */
+ 0xa2, 0x00, /* dc gain and fir prefilter control */
+ 0xa4, 0x80, /* Lum Brightness, nominal value = 0x80 */
+ 0xa5, 0x40, /* Lum contrast, nominal value = 0x40 */
+ 0xa6, 0x40, /* Chroma satur. nominal value = 0x80 */
+ 0xa8, 0x00, /* hor lum scaling 0x0200 = 2 zoom */
+ 0xa9, 0x02, /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
+ 0xaa, 0x00, /* H-phase offset Luma = 0 */
+ 0xac, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+ 0xad, 0x01, /* H-scaling incr chroma */
+ 0xae, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
+
+ 0xb0, 0x00, /* V-scaling incr luma low */
+ 0xb1, 0x04, /* " hi */
+ 0xb2, 0x00, /* V-scaling incr chroma low */
+ 0xb3, 0x04, /* " hi */
+ 0xb4, 0x01, /* V-scaling mode control */
+ 0xb8, 0x00, /* V-phase offset chroma 00 */
+ 0xb9, 0x00, /* V-phase offset chroma 01 */
+ 0xba, 0x00, /* V-phase offset chroma 10 */
+ 0xbb, 0x00, /* V-phase offset chroma 11 */
+ 0xbc, 0x00, /* V-phase offset luma 00 */
+ 0xbd, 0x00, /* V-phase offset luma 01 */
+ 0xbe, 0x00, /* V-phase offset luma 10 */
+ 0xbf, 0x00, /* V-phase offset luma 11 */
+
+ /* Task B */
+ 0xd0, 0x01, /* down scale = 1 */
+ 0xd1, 0x00, /* prescale accumulation length = 1 */
+ 0xd2, 0x00, /* dc gain and fir prefilter control */
+ 0xd4, 0x80, /* Lum Brightness, nominal value = 0x80 */
+ 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
+ 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
+ 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
+ 0xd9, 0x04,
+ 0xda, 0x00, /* H-phase offset Luma = 0 */
+ 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
+ 0xdd, 0x02, /* H-scaling incr chroma */
+ 0xde, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
+
+ 0xe0, 0x00, /* V-scaling incr luma low */
+ 0xe1, 0x04, /* " hi */
+ 0xe2, 0x00, /* V-scaling incr chroma low */
+ 0xe3, 0x04, /* " hi */
+ 0xe4, 0x01, /* V-scaling mode control */
+ 0xe8, 0x00, /* V-phase offset chroma 00 */
+ 0xe9, 0x00, /* V-phase offset chroma 01 */
+ 0xea, 0x00, /* V-phase offset chroma 10 */
+ 0xeb, 0x00, /* V-phase offset chroma 11 */
+ 0xec, 0x00, /* V-phase offset luma 00 */
+ 0xed, 0x00, /* V-phase offset luma 01 */
+ 0xee, 0x00, /* V-phase offset luma 10 */
+ 0xef, 0x00, /* V-phase offset luma 11 */
+
+ 0xf2, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
+ 0xf3, 0x46,
+ 0xf4, 0x00,
+ 0xf7, 0x4b, /* not the recommended settings! */
+ 0xf8, 0x00,
+ 0xf9, 0x4b,
+ 0xfa, 0x00,
+ 0xfb, 0x4b,
+ 0xff, 0x88, /* PLL2 lock detection settings: 71 lines 50% phase error */
+
+ /* Turn off VBI */
+ 0x40, 0x20, /* No framing code errors allowed. */
+ 0x41, 0xff,
+ 0x42, 0xff,
+ 0x43, 0xff,
+ 0x44, 0xff,
+ 0x45, 0xff,
+ 0x46, 0xff,
+ 0x47, 0xff,
+ 0x48, 0xff,
+ 0x49, 0xff,
+ 0x4a, 0xff,
+ 0x4b, 0xff,
+ 0x4c, 0xff,
+ 0x4d, 0xff,
+ 0x4e, 0xff,
+ 0x4f, 0xff,
+ 0x50, 0xff,
+ 0x51, 0xff,
+ 0x52, 0xff,
+ 0x53, 0xff,
+ 0x54, 0xff,
+ 0x55, 0xff,
+ 0x56, 0xff,
+ 0x57, 0xff,
+ 0x58, 0x40,
+ 0x59, 0x47,
+ 0x5b, 0x83,
+ 0x5d, 0xbd,
+ 0x5e, 0x35,
+
+ 0x02, 0x84, /* input tuner -> input 4, amplifier active */
+ 0x09, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
+
+ 0x80, 0x20, /* enable task B */
+ 0x88, 0xd0,
+ 0x88, 0xf0,
+ 0x00, 0x00
+};
+
+/* ============== SAA7715 AUDIO settings ============= */
+
+/* 48.0 kHz */
+static const unsigned char saa7115_cfg_48_audio[] = {
+ 0x34, 0xce,
+ 0x35, 0xfb,
+ 0x36, 0x30,
+ 0x00, 0x00
+};
+
+/* 44.1 kHz */
+static const unsigned char saa7115_cfg_441_audio[] = {
+ 0x34, 0xf2,
+ 0x35, 0x00,
+ 0x36, 0x2d,
+ 0x00, 0x00
+};
+
+/* 32.0 kHz */
+static const unsigned char saa7115_cfg_32_audio[] = {
+ 0x34, 0xdf,
+ 0x35, 0xa7,
+ 0x36, 0x20,
+ 0x00, 0x00
+};
+
+/* 48.0 kHz 60hz */
+static const unsigned char saa7115_cfg_60hz_48_audio[] = {
+ 0x30, 0xcd,
+ 0x31, 0x20,
+ 0x32, 0x03,
+ 0x00, 0x00
+};
+
+/* 48.0 kHz 50hz */
+static const unsigned char saa7115_cfg_50hz_48_audio[] = {
+ 0x30, 0x00,
+ 0x31, 0xc0,
+ 0x32, 0x03,
+ 0x00, 0x00
+};
+
+/* 44.1 kHz 60hz */
+static const unsigned char saa7115_cfg_60hz_441_audio[] = {
+ 0x30, 0xbc,
+ 0x31, 0xdf,
+ 0x32, 0x02,
+ 0x00, 0x00
+};
+
+/* 44.1 kHz 50hz */
+static const unsigned char saa7115_cfg_50hz_441_audio[] = {
+ 0x30, 0x00,
+ 0x31, 0x72,
+ 0x32, 0x03,
+ 0x00, 0x00
+};
+
+/* 32.0 kHz 60hz */
+static const unsigned char saa7115_cfg_60hz_32_audio[] = {
+ 0x30, 0xde,
+ 0x31, 0x15,
+ 0x32, 0x02,
+ 0x00, 0x00
+};
+
+/* 32.0 kHz 50hz */
+static const unsigned char saa7115_cfg_50hz_32_audio[] = {
+ 0x30, 0x00,
+ 0x31, 0x80,
+ 0x32, 0x02,
+ 0x00, 0x00
+};
+
+static int saa7115_odd_parity(u8 c)
+{
+ c ^= (c >> 4);
+ c ^= (c >> 2);
+ c ^= (c >> 1);
+
+ return c & 1;
+}
+
+static int saa7115_decode_vps(u8 * dst, u8 * p)
+{
+ static const u8 biphase_tbl[] = {
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+ 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+ 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+ 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+ 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+ 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+ 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ };
+ int i;
+ u8 c, err = 0;
+
+ for (i = 0; i < 2 * 13; i += 2) {
+ err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+ c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4);
+ dst[i / 2] = c;
+ }
+ return err & 0xf0;
+}
+
+static int saa7115_decode_wss(u8 * p)
+{
+ static const int wss_bits[8] = {
+ 0, 0, 0, 1, 0, 1, 1, 1
+ };
+ unsigned char parity;
+ int wss = 0;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ int b1 = wss_bits[p[i] & 7];
+ int b2 = wss_bits[(p[i] >> 3) & 7];
+
+ if (b1 == b2)
+ return -1;
+ wss |= b2 << i;
+ }
+ parity = wss & 15;
+ parity ^= parity >> 2;
+ parity ^= parity >> 1;
+
+ if (!(parity & 1))
+ return -1;
+
+ return wss;
+}
+
+
+static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+
+ saa7115_dbg("set audio clock freq: %d\n", freq);
+ switch (freq) {
+ case V4L2_AUDCLK_32_KHZ:
+ saa7115_writeregs(client, saa7115_cfg_32_audio);
+ if (state->std & V4L2_STD_525_60) {
+ saa7115_writeregs(client, saa7115_cfg_60hz_32_audio);
+ } else {
+ saa7115_writeregs(client, saa7115_cfg_50hz_32_audio);
+ }
+ break;
+ case V4L2_AUDCLK_441_KHZ:
+ saa7115_writeregs(client, saa7115_cfg_441_audio);
+ if (state->std & V4L2_STD_525_60) {
+ saa7115_writeregs(client, saa7115_cfg_60hz_441_audio);
+ } else {
+ saa7115_writeregs(client, saa7115_cfg_50hz_441_audio);
+ }
+ break;
+ case V4L2_AUDCLK_48_KHZ:
+ saa7115_writeregs(client, saa7115_cfg_48_audio);
+ if (state->std & V4L2_STD_525_60) {
+ saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+ } else {
+ saa7115_writeregs(client, saa7115_cfg_50hz_48_audio);
+ }
+ break;
+ default:
+ saa7115_dbg("invalid audio setting %d\n", freq);
+ return -EINVAL;
+ }
+ state->audclk_freq = freq;
+ return 0;
+}
+
+static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ saa7115_err("invalid brightness setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->bright = ctrl->value;
+ saa7115_write(client, 0x0a, state->bright);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ saa7115_err("invalid contrast setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->contrast = ctrl->value;
+ saa7115_write(client, 0x0b, state->contrast);
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ saa7115_err("invalid saturation setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->sat = ctrl->value;
+ saa7115_write(client, 0x0c, state->sat);
+ break;
+
+ case V4L2_CID_HUE:
+ if (ctrl->value < -127 || ctrl->value > 127) {
+ saa7115_err("invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->hue = ctrl->value;
+ saa7115_write(client, 0x0d, state->hue);
+ break;
+ }
+
+ return 0;
+}
+
+static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = state->bright;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = state->contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = state->sat;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = state->hue;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int taskb = saa7115_read(client, 0x80) & 0x10;
+
+ // This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
+ if (std & V4L2_STD_525_60) {
+ saa7115_dbg("decoder set standard 60 Hz\n");
+ saa7115_writeregs(client, saa7115_cfg_60hz_video);
+ } else {
+ saa7115_dbg("decoder set standard 50 Hz\n");
+ saa7115_writeregs(client, saa7115_cfg_50hz_video);
+ }
+
+ state->std = std;
+
+ /* restart task B if needed */
+ if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+ saa7115_writeregs(client, saa7115_cfg_vbi_on);
+ }
+
+ /* switch audio mode too! */
+ saa7115_set_audio_clock_freq(client, state->audclk_freq);
+}
+
+static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+
+ return state->std;
+}
+
+static void saa7115_log_status(struct i2c_client *client)
+{
+ static const char * const audclk_freq_strs[] = {
+ "44.1 kHz",
+ "48 kHz",
+ "32 kHz"
+ };
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int reg1e, reg1f;
+ int signalOk;
+ int vcr;
+
+ saa7115_info("Audio frequency: %s\n", audclk_freq_strs[state->audclk_freq]);
+ if (client->name[6] == '4') {
+ /* status for the saa7114 */
+ reg1f = saa7115_read(client, 0x1f);
+ signalOk = (reg1f & 0xc1) == 0x81;
+ saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad");
+ saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+ return;
+ }
+
+ /* status for the saa7115 */
+ reg1e = saa7115_read(client, 0x1e);
+ reg1f = saa7115_read(client, 0x1f);
+
+ signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
+ vcr = !(reg1f & 0x10);
+
+ saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad");
+ saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz");
+
+ switch (reg1e & 0x03) {
+ case 1:
+ saa7115_info("Detected format: NTSC\n");
+ break;
+ case 2:
+ saa7115_info("Detected format: PAL\n");
+ break;
+ case 3:
+ saa7115_info("Detected format: SECAM\n");
+ break;
+ default:
+ saa7115_info("Detected format: BW/No color\n");
+ break;
+ }
+}
+
+/* setup the sliced VBI lcr registers according to the sliced VBI format */
+static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int is_50hz = (state->std & V4L2_STD_625_50);
+ u8 lcr[24];
+ int i, x;
+
+ /* saa7114 doesn't yet support VBI */
+ if (state->ident == V4L2_IDENT_SAA7114)
+ return;
+
+ for (i = 0; i <= 23; i++)
+ lcr[i] = 0xff;
+
+ if (fmt->service_set == 0) {
+ /* raw VBI */
+ if (is_50hz)
+ for (i = 6; i <= 23; i++)
+ lcr[i] = 0xdd;
+ else
+ for (i = 10; i <= 21; i++)
+ lcr[i] = 0xdd;
+ } else {
+ /* sliced VBI */
+ /* first clear lines that cannot be captured */
+ if (is_50hz) {
+ for (i = 0; i <= 5; i++)
+ fmt->service_lines[0][i] =
+ fmt->service_lines[1][i] = 0;
+ }
+ else {
+ for (i = 0; i <= 9; i++)
+ fmt->service_lines[0][i] =
+ fmt->service_lines[1][i] = 0;
+ for (i = 22; i <= 23; i++)
+ fmt->service_lines[0][i] =
+ fmt->service_lines[1][i] = 0;
+ }
+
+ /* Now set the lcr values according to the specified service */
+ for (i = 6; i <= 23; i++) {
+ lcr[i] = 0;
+ for (x = 0; x <= 1; x++) {
+ switch (fmt->service_lines[1-x][i]) {
+ case 0:
+ lcr[i] |= 0xf << (4 * x);
+ break;
+ case V4L2_SLICED_TELETEXT_B:
+ lcr[i] |= 1 << (4 * x);
+ break;
+ case V4L2_SLICED_CAPTION_525:
+ lcr[i] |= 4 << (4 * x);
+ break;
+ case V4L2_SLICED_WSS_625:
+ lcr[i] |= 5 << (4 * x);
+ break;
+ case V4L2_SLICED_VPS:
+ lcr[i] |= 7 << (4 * x);
+ break;
+ }
+ }
+ }
+ }
+
+ /* write the lcr registers */
+ for (i = 2; i <= 23; i++) {
+ saa7115_write(client, i - 2 + 0x41, lcr[i]);
+ }
+
+ /* enable/disable raw VBI capturing */
+ saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off);
+}
+
+static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+ static u16 lcr2vbi[] = {
+ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+ 0, V4L2_SLICED_CAPTION_525, /* 4 */
+ V4L2_SLICED_WSS_625, 0, /* 5 */
+ V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */
+ 0, 0, 0, 0
+ };
+ struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced;
+ int i;
+
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ memset(sliced, 0, sizeof(*sliced));
+ /* done if using raw VBI */
+ if (saa7115_read(client, 0x80) & 0x10)
+ return 0;
+ for (i = 2; i <= 23; i++) {
+ u8 v = saa7115_read(client, i - 2 + 0x41);
+
+ sliced->service_lines[0][i] = lcr2vbi[v >> 4];
+ sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
+ sliced->service_set |=
+ sliced->service_lines[0][i] | sliced->service_lines[1][i];
+ }
+ return 0;
+}
+
+static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ struct v4l2_pix_format *pix;
+ int HPSC, HFSC;
+ int VSCY, Vsrc;
+ int is_50hz = state->std & V4L2_STD_625_50;
+
+ if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ saa7115_set_lcr(client, &fmt->fmt.sliced);
+ return 0;
+ }
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ pix = &(fmt->fmt.pix);
+
+ saa7115_dbg("decoder set size\n");
+
+ /* FIXME need better bounds checking here */
+ if ((pix->width < 1) || (pix->width > 1440))
+ return -EINVAL;
+ if ((pix->height < 1) || (pix->height > 960))
+ return -EINVAL;
+
+ /* probably have a valid size, let's set it */
+ /* Set output width/height */
+ /* width */
+ saa7115_write(client, 0xcc, (u8) (pix->width & 0xff));
+ saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff));
+ /* height */
+ saa7115_write(client, 0xce, (u8) (pix->height & 0xff));
+ saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff));
+
+ /* Scaling settings */
+ /* Hprescaler is floor(inres/outres) */
+ /* FIXME hardcoding input res */
+ if (pix->width != 720) {
+ HPSC = (int)(720 / pix->width);
+ /* 0 is not allowed (div. by zero) */
+ HPSC = HPSC ? HPSC : 1;
+ HFSC = (int)((1024 * 720) / (HPSC * pix->width));
+
+ saa7115_dbg("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+ /* FIXME hardcodes to "Task B"
+ * write H prescaler integer */
+ saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
+
+ /* write H fine-scaling (luminance) */
+ saa7115_write(client, 0xd8, (u8) (HFSC & 0xff));
+ saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff));
+ /* write H fine-scaling (chrominance)
+ * must be lum/2, so i'll just bitshift :) */
+ saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff));
+ saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
+ } else {
+ if (is_50hz) {
+ saa7115_dbg("Setting full 50hz width\n");
+ saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
+ } else {
+ saa7115_dbg("Setting full 60hz width\n");
+ saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
+ }
+ }
+
+ Vsrc = is_50hz ? 576 : 480;
+
+ if (pix->height != Vsrc) {
+ VSCY = (int)((1024 * Vsrc) / pix->height);
+ saa7115_dbg("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+
+ /* Correct Contrast and Luminance */
+ saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
+ saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY));
+
+ /* write V fine-scaling (luminance) */
+ saa7115_write(client, 0xe0, (u8) (VSCY & 0xff));
+ saa7115_write(client, 0xe1, (u8) ((VSCY >> 8) & 0xff));
+ /* write V fine-scaling (chrominance) */
+ saa7115_write(client, 0xe2, (u8) (VSCY & 0xff));
+ saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
+ } else {
+ if (is_50hz) {
+ saa7115_dbg("Setting full 50Hz height\n");
+ saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
+ } else {
+ saa7115_dbg("Setting full 60hz height\n");
+ saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
+ }
+ }
+
+ saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+ return 0;
+}
+
+/* Decode the sliced VBI data stream as created by the saa7115.
+ The format is described in the saa7115 datasheet in Tables 25 and 26
+ and in Figure 33.
+ The current implementation uses SAV/EAV codes and not the ancillary data
+ headers. The vbi->p pointer points to the SDID byte right after the SAV
+ code. */
+static void saa7115_decode_vbi_line(struct i2c_client *client,
+ struct v4l2_decode_vbi_line *vbi)
+{
+ static const char vbi_no_data_pattern[] = {
+ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
+ };
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ u8 *p = vbi->p;
+ u32 wss;
+ int id1, id2; /* the ID1 and ID2 bytes from the internal header */
+
+ vbi->type = 0; /* mark result as a failure */
+ id1 = p[2];
+ id2 = p[3];
+ /* Note: the field bit is inverted for 60 Hz video */
+ if (state->std & V4L2_STD_525_60)
+ id1 ^= 0x40;
+
+ /* Skip internal header, p now points to the start of the payload */
+ p += 4;
+ vbi->p = p;
+
+ /* calculate field and line number of the VBI packet (1-23) */
+ vbi->is_second_field = ((id1 & 0x40) != 0);
+ vbi->line = (id1 & 0x3f) << 3;
+ vbi->line |= (id2 & 0x70) >> 4;
+
+ /* Obtain data type */
+ id2 &= 0xf;
+
+ /* If the VBI slicer does not detect any signal it will fill up
+ the payload buffer with 0xa0 bytes. */
+ if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern)))
+ return;
+
+ /* decode payloads */
+ switch (id2) {
+ case 1:
+ vbi->type = V4L2_SLICED_TELETEXT_B;
+ break;
+ case 4:
+ if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
+ return;
+ vbi->type = V4L2_SLICED_CAPTION_525;
+ break;
+ case 5:
+ wss = saa7115_decode_wss(p);
+ if (wss == -1)
+ return;
+ p[0] = wss & 0xff;
+ p[1] = wss >> 8;
+ vbi->type = V4L2_SLICED_WSS_625;
+ break;
+ case 7:
+ if (saa7115_decode_vps(p, p) != 0)
+ return;
+ vbi->type = V4L2_SLICED_VPS;
+ break;
+ default:
+ return;
+ }
+}
+
+/* ============ SAA7115 AUDIO settings (end) ============= */
+
+static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int *iarg = arg;
+
+ /* ioctls to allow direct access to the saa7115 registers for testing */
+ switch (cmd) {
+ case VIDIOC_S_FMT:
+ return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg);
+
+ case VIDIOC_G_FMT:
+ return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
+
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg);
+
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *vt = arg;
+ int status;
+
+ status = saa7115_read(client, 0x1f);
+
+ saa7115_dbg("status: 0x%02x\n", status);
+ vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ saa7115_log_status(client);
+ break;
+
+ case VIDIOC_G_CTRL:
+ return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_S_CTRL:
+ return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
+ break;
+
+ case VIDIOC_S_STD:
+ saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
+ break;
+
+ case VIDIOC_G_INPUT:
+ *(int *)arg = state->input;
+ break;
+
+ case VIDIOC_S_INPUT:
+ saa7115_dbg("decoder set input %d\n", *iarg);
+ /* inputs from 0-9 are available */
+ if (*iarg < 0 || *iarg > 9) {
+ return -EINVAL;
+ }
+
+ if (state->input == *iarg)
+ break;
+ saa7115_dbg("now setting %s input\n",
+ *iarg >= 6 ? "S-Video" : "Composite");
+ state->input = *iarg;
+
+ /* select mode */
+ saa7115_write(client, 0x02,
+ (saa7115_read(client, 0x02) & 0xf0) |
+ state->input);
+
+ /* bypass chrominance trap for modes 6..9 */
+ saa7115_write(client, 0x09,
+ (saa7115_read(client, 0x09) & 0x7f) |
+ (state->input < 6 ? 0x0 : 0x80));
+ break;
+
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF:
+ saa7115_dbg("%s output\n",
+ (cmd == VIDIOC_STREAMON) ? "enable" : "disable");
+
+ if (state->enable != (cmd == VIDIOC_STREAMON)) {
+ state->enable = (cmd == VIDIOC_STREAMON);
+ saa7115_write(client, 0x87, state->enable);
+ }
+ break;
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ saa7115_decode_vbi_line(client, arg);
+ break;
+
+ case VIDIOC_INT_RESET:
+ saa7115_dbg("decoder RESET\n");
+ saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+ break;
+
+ case VIDIOC_INT_G_VBI_DATA:
+ {
+ struct v4l2_sliced_vbi_data *data = arg;
+
+ switch (data->id) {
+ case V4L2_SLICED_WSS_625:
+ if (saa7115_read(client, 0x6b) & 0xc0)
+ return -EIO;
+ data->data[0] = saa7115_read(client, 0x6c);
+ data->data[1] = saa7115_read(client, 0x6d);
+ return 0;
+ case V4L2_SLICED_CAPTION_525:
+ if (data->field == 0) {
+ /* CC */
+ if (saa7115_read(client, 0x66) & 0xc0)
+ return -EIO;
+ data->data[0] = saa7115_read(client, 0x67);
+ data->data[1] = saa7115_read(client, 0x68);
+ return 0;
+ }
+ /* XDS */
+ if (saa7115_read(client, 0x66) & 0x30)
+ return -EIO;
+ data->data[0] = saa7115_read(client, 0x69);
+ data->data[1] = saa7115_read(client, 0x6a);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_INT_G_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_SAA711X)
+ return -EINVAL;
+ reg->val = saa7115_read(client, reg->reg & 0xff);
+ break;
+ }
+
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_SAA711X)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ saa7115_write(client, reg->reg & 0xff, reg->val & 0xff);
+ break;
+ }
+#endif
+
+ case VIDIOC_INT_G_CHIP_IDENT:
+ *iarg = state->ident;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_driver i2c_driver_saa7115;
+
+static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct saa7115_state *state;
+ u8 chip_id;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver_saa7115;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "saa7115");
+
+ saa7115_dbg("detecting saa7115 client on address 0x%x\n", address << 1);
+
+ saa7115_write(client, 0, 5);
+ chip_id = saa7115_read(client, 0) & 0x0f;
+ if (chip_id != 4 && chip_id != 5) {
+ saa7115_dbg("saa7115 not found\n");
+ kfree(client);
+ return 0;
+ }
+ if (chip_id == 4) {
+ snprintf(client->name, sizeof(client->name) - 1, "saa7114");
+ }
+ saa7115_info("saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
+
+ state = kmalloc(sizeof(struct saa7115_state), GFP_KERNEL);
+ i2c_set_clientdata(client, state);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ memset(state, 0, sizeof(struct saa7115_state));
+ state->std = V4L2_STD_NTSC;
+ state->input = -1;
+ state->enable = 1;
+ state->bright = 128;
+ state->contrast = 64;
+ state->hue = 0;
+ state->sat = 64;
+ state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115;
+ state->audclk_freq = V4L2_AUDCLK_48_KHZ;
+
+ saa7115_dbg("writing init values\n");
+
+ /* init to 60hz/48khz */
+ saa7115_writeregs(client, saa7115_init_auto_input);
+ saa7115_writeregs(client, saa7115_init_misc);
+ saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
+ saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
+ saa7115_writeregs(client, saa7115_cfg_60hz_video);
+ saa7115_writeregs(client, saa7115_cfg_48_audio);
+ saa7115_writeregs(client, saa7115_cfg_60hz_48_audio);
+ saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+
+ i2c_attach_client(client);
+
+ saa7115_dbg("status: (1E) 0x%02x, (1F) 0x%02x\n",
+ saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
+
+ return 0;
+}
+
+static int saa7115_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, &saa7115_attach);
+ return 0;
+}
+
+static int saa7115_detach(struct i2c_client *client)
+{
+ struct saa7115_state *state = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+
+ kfree(state);
+ kfree(client);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver_saa7115 = {
+ .name = "saa7115",
+ .id = I2C_DRIVERID_SAA711X,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = saa7115_probe,
+ .detach_client = saa7115_detach,
+ .command = saa7115_command,
+ .owner = THIS_MODULE,
+};
+
+
+static int __init saa7115_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver_saa7115);
+}
+
+static void __exit saa7115_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver_saa7115);
+}
+
+module_init(saa7115_init_module);
+module_exit(saa7115_cleanup_module);
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
index 9aa8827de2c..25b30f352d8 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -36,7 +36,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
-#include <asm/segment.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#include <linux/videodev.h>
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
new file mode 100644
index 00000000000..843431f10e3
--- /dev/null
+++ b/drivers/media/video/saa7127.c
@@ -0,0 +1,849 @@
+/*
+ * saa7127 - Philips SAA7127/SAA7129 video encoder driver
+ *
+ * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl>
+ *
+ * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter
+ *
+ * Copyright (C) 2000-2001 Gillem <htoa@gmx.net>
+ * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de>
+ *
+ * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo
+ *
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * This driver is designed for the Hauppauge 250/350 Linux driver
+ * from the ivtv Project
+ *
+ * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com>
+ *
+ * Dual output support:
+ * Copyright (C) 2004 Eric Varsanyi
+ *
+ * NTSC Tuning and 7.5 IRE Setup
+ * Copyright (C) 2004 Chris Kennedy <c@groovy.org>
+ *
+ * VBI additions & cleanup:
+ * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: the saa7126 is identical to the saa7127, and the saa7128 is
+ * identical to the saa7129, except that the saa7126 and saa7128 have
+ * macrovision anti-taping support. This driver will almost certainly
+ * work find for those chips, except of course for the missing anti-taping
+ * support.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+static int debug = 0;
+static int test_image = 0;
+
+MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver");
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
+MODULE_LICENSE("GPL");
+module_param(debug, int, 0644);
+module_param(test_image, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+MODULE_PARM_DESC(test_image, "test_image (0-1)");
+
+#define saa7127_dbg(fmt, arg...) \
+ do { \
+ if (debug >= 1) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+/* High volume debug. Use with care. */
+#define saa7127_dbg_highvol(fmt, arg...) \
+ do { \
+ if (debug == 2) \
+ printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); \
+ } while (0)
+
+#define saa7127_err(fmt, arg...) do { \
+ printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+#define saa7127_info(fmt, arg...) do { \
+ printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
+ i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
+
+static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/*
+ * SAA7127 registers
+ */
+
+#define SAA7127_REG_STATUS 0x00
+#define SAA7127_REG_WIDESCREEN_CONFIG 0x26
+#define SAA7127_REG_WIDESCREEN_ENABLE 0x27
+#define SAA7127_REG_BURST_START 0x28
+#define SAA7127_REG_BURST_END 0x29
+#define SAA7127_REG_COPYGEN_0 0x2a
+#define SAA7127_REG_COPYGEN_1 0x2b
+#define SAA7127_REG_COPYGEN_2 0x2c
+#define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d
+#define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38
+#define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39
+#define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a
+#define SAA7129_REG_FADE_KEY_COL2 0x4f
+#define SAA7127_REG_CHROMA_PHASE 0x5a
+#define SAA7127_REG_GAINU 0x5b
+#define SAA7127_REG_GAINV 0x5c
+#define SAA7127_REG_BLACK_LEVEL 0x5d
+#define SAA7127_REG_BLANKING_LEVEL 0x5e
+#define SAA7127_REG_VBI_BLANKING 0x5f
+#define SAA7127_REG_DAC_CONTROL 0x61
+#define SAA7127_REG_BURST_AMP 0x62
+#define SAA7127_REG_SUBC3 0x63
+#define SAA7127_REG_SUBC2 0x64
+#define SAA7127_REG_SUBC1 0x65
+#define SAA7127_REG_SUBC0 0x66
+#define SAA7127_REG_LINE_21_ODD_0 0x67
+#define SAA7127_REG_LINE_21_ODD_1 0x68
+#define SAA7127_REG_LINE_21_EVEN_0 0x69
+#define SAA7127_REG_LINE_21_EVEN_1 0x6a
+#define SAA7127_REG_RCV_PORT_CONTROL 0x6b
+#define SAA7127_REG_VTRIG 0x6c
+#define SAA7127_REG_HTRIG_HI 0x6d
+#define SAA7127_REG_MULTI 0x6e
+#define SAA7127_REG_CLOSED_CAPTION 0x6f
+#define SAA7127_REG_RCV2_OUTPUT_START 0x70
+#define SAA7127_REG_RCV2_OUTPUT_END 0x71
+#define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72
+#define SAA7127_REG_TTX_REQUEST_H_START 0x73
+#define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74
+#define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75
+#define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76
+#define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78
+#define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79
+#define SAA7127_REG_FIRST_ACTIVE 0x7a
+#define SAA7127_REG_LAST_ACTIVE 0x7b
+#define SAA7127_REG_MSB_VERTICAL 0x7c
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e
+#define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f
+
+/*
+ **********************************************************************
+ *
+ * Arrays with configuration parameters for the SAA7127
+ *
+ **********************************************************************
+ */
+
+struct i2c_reg_value {
+ unsigned char reg;
+ unsigned char value;
+};
+
+static const struct i2c_reg_value saa7129_init_config_extra[] = {
+ { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 },
+ { SAA7127_REG_VTRIG, 0xfa },
+};
+
+static const struct i2c_reg_value saa7127_init_config_common[] = {
+ { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d },
+ { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 },
+ { SAA7127_REG_COPYGEN_0, 0x77 },
+ { SAA7127_REG_COPYGEN_1, 0x41 },
+ { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */
+ { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x9e },
+ { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 },
+ { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 },
+ { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */
+ { SAA7127_REG_LINE_21_ODD_0, 0x77 },
+ { SAA7127_REG_LINE_21_ODD_1, 0x41 },
+ { SAA7127_REG_LINE_21_EVEN_0, 0x88 },
+ { SAA7127_REG_LINE_21_EVEN_1, 0x41 },
+ { SAA7127_REG_RCV_PORT_CONTROL, 0x12 },
+ { SAA7127_REG_VTRIG, 0xf9 },
+ { SAA7127_REG_HTRIG_HI, 0x00 },
+ { SAA7127_REG_RCV2_OUTPUT_START, 0x41 },
+ { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 },
+ { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 },
+ { SAA7127_REG_TTX_REQUEST_H_START, 0x3e },
+ { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 },
+ { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 },
+ { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 },
+ { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 },
+ { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 },
+ { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 },
+ { SAA7127_REG_FIRST_ACTIVE, 0x1a },
+ { SAA7127_REG_LAST_ACTIVE, 0x01 },
+ { SAA7127_REG_MSB_VERTICAL, 0xc0 },
+ { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 },
+ { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 },
+ { 0, 0 }
+};
+
+#define SAA7127_60HZ_DAC_CONTROL 0x15
+static const struct i2c_reg_value saa7127_init_config_60hz[] = {
+ { SAA7127_REG_BURST_START, 0x19 },
+ /* BURST_END is also used as a chip ID in saa7127_detect_client */
+ { SAA7127_REG_BURST_END, 0x1d },
+ { SAA7127_REG_CHROMA_PHASE, 0xa3 },
+ { SAA7127_REG_GAINU, 0x98 },
+ { SAA7127_REG_GAINV, 0xd3 },
+ { SAA7127_REG_BLACK_LEVEL, 0x39 },
+ { SAA7127_REG_BLANKING_LEVEL, 0x2e },
+ { SAA7127_REG_VBI_BLANKING, 0x2e },
+ { SAA7127_REG_DAC_CONTROL, 0x15 },
+ { SAA7127_REG_BURST_AMP, 0x4d },
+ { SAA7127_REG_SUBC3, 0x1f },
+ { SAA7127_REG_SUBC2, 0x7c },
+ { SAA7127_REG_SUBC1, 0xf0 },
+ { SAA7127_REG_SUBC0, 0x21 },
+ { SAA7127_REG_MULTI, 0x90 },
+ { SAA7127_REG_CLOSED_CAPTION, 0x11 },
+ { 0, 0 }
+};
+
+#define SAA7127_50HZ_DAC_CONTROL 0x02
+struct i2c_reg_value saa7127_init_config_50hz[] = {
+ { SAA7127_REG_BURST_START, 0x21 },
+ /* BURST_END is also used as a chip ID in saa7127_detect_client */
+ { SAA7127_REG_BURST_END, 0x1d },
+ { SAA7127_REG_CHROMA_PHASE, 0x3f },
+ { SAA7127_REG_GAINU, 0x7d },
+ { SAA7127_REG_GAINV, 0xaf },
+ { SAA7127_REG_BLACK_LEVEL, 0x33 },
+ { SAA7127_REG_BLANKING_LEVEL, 0x35 },
+ { SAA7127_REG_VBI_BLANKING, 0x35 },
+ { SAA7127_REG_DAC_CONTROL, 0x02 },
+ { SAA7127_REG_BURST_AMP, 0x2f },
+ { SAA7127_REG_SUBC3, 0xcb },
+ { SAA7127_REG_SUBC2, 0x8a },
+ { SAA7127_REG_SUBC1, 0x09 },
+ { SAA7127_REG_SUBC0, 0x2a },
+ { SAA7127_REG_MULTI, 0xa0 },
+ { SAA7127_REG_CLOSED_CAPTION, 0x00 },
+ { 0, 0 }
+};
+
+/* Enumeration for the Supported input types */
+enum saa7127_input_type {
+ SAA7127_INPUT_TYPE_NORMAL,
+ SAA7127_INPUT_TYPE_TEST_IMAGE
+};
+
+/* Enumeration for the Supported Output signal types */
+enum saa7127_output_type {
+ SAA7127_OUTPUT_TYPE_BOTH,
+ SAA7127_OUTPUT_TYPE_COMPOSITE,
+ SAA7127_OUTPUT_TYPE_SVIDEO,
+ SAA7127_OUTPUT_TYPE_RGB,
+ SAA7127_OUTPUT_TYPE_YUV_C,
+ SAA7127_OUTPUT_TYPE_YUV_V
+};
+
+/*
+ **********************************************************************
+ *
+ * Encoder Struct, holds the configuration state of the encoder
+ *
+ **********************************************************************
+ */
+
+struct saa7127_state {
+ v4l2_std_id std;
+ enum v4l2_chip_ident ident;
+ enum saa7127_input_type input_type;
+ enum saa7127_output_type output_type;
+ int video_enable;
+ int wss_enable;
+ u16 wss_mode;
+ int cc_enable;
+ u16 cc_data;
+ int xds_enable;
+ u16 xds_data;
+ int vps_enable;
+ u8 vps_data[5];
+ u8 reg_2d;
+ u8 reg_3a;
+ u8 reg_3a_cb; /* colorbar bit */
+ u8 reg_61;
+};
+
+static const char * const output_strs[] =
+{
+ "S-Video + Composite",
+ "Composite",
+ "S-Video",
+ "RGB",
+ "YUV C",
+ "YUV V"
+};
+
+static const char * const wss_strs[] = {
+ "invalid",
+ "letterbox 14:9 center",
+ "letterbox 14:9 top",
+ "invalid",
+ "letterbox 16:9 top",
+ "invalid",
+ "invalid",
+ "16:9 full format anamorphic"
+ "4:3 full format",
+ "invalid",
+ "invalid",
+ "letterbox 16:9 center",
+ "invalid",
+ "letterbox >16:9 center",
+ "14:9 full format center",
+ "invalid",
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_read(struct i2c_client *client, u8 reg)
+{
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (i2c_smbus_write_byte_data(client, reg, val) == 0)
+ return 0;
+ }
+ saa7127_err("I2C Write Problem\n");
+ return -1;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_write_inittab(struct i2c_client *client,
+ const struct i2c_reg_value *regs)
+{
+ while (regs->reg != 0) {
+ saa7127_write(client, regs->reg, regs->value);
+ regs++;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 0 || data->line != 16))
+ return -EINVAL;
+ if (state->vps_enable != enable) {
+ saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off");
+ saa7127_write(client, 0x54, enable << 7);
+ state->vps_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ state->vps_data[0] = data->data[4];
+ state->vps_data[1] = data->data[10];
+ state->vps_data[2] = data->data[11];
+ state->vps_data[3] = data->data[12];
+ state->vps_data[4] = data->data[13];
+ saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n",
+ state->vps_data[0], state->vps_data[1],
+ state->vps_data[2], state->vps_data[3],
+ state->vps_data[4]);
+ saa7127_write(client, 0x55, state->vps_data[0]);
+ saa7127_write(client, 0x56, state->vps_data[1]);
+ saa7127_write(client, 0x57, state->vps_data[2]);
+ saa7127_write(client, 0x58, state->vps_data[3]);
+ saa7127_write(client, 0x59, state->vps_data[4]);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ u16 cc = data->data[0] << 8 | data->data[1];
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 0 || data->line != 21))
+ return -EINVAL;
+ if (state->cc_enable != enable) {
+ saa7127_dbg("Turn CC %s\n", enable ? "on" : "off");
+ saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+ (enable << 6) | 0x11);
+ state->cc_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ saa7127_dbg_highvol("CC data: %04x\n", cc);
+ saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff);
+ saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8);
+ state->cc_data = cc;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ u16 xds = data->data[1] << 8 | data->data[0];
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 1 || data->line != 21))
+ return -EINVAL;
+ if (state->xds_enable != enable) {
+ saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off");
+ saa7127_write(client, SAA7127_REG_CLOSED_CAPTION,
+ (enable << 7) | 0x11);
+ state->xds_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ saa7127_dbg_highvol("XDS data: %04x\n", xds);
+ saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff);
+ saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8);
+ state->xds_data = xds;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_data *data)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ int enable = (data->line != 0);
+
+ if (enable && (data->field != 0 || data->line != 23))
+ return -EINVAL;
+ if (state->wss_enable != enable) {
+ saa7127_dbg("Turn WSS %s\n", enable ? "on" : "off");
+ saa7127_write(client, 0x27, enable << 7);
+ state->wss_enable = enable;
+ }
+ if (!enable)
+ return 0;
+
+ saa7127_write(client, 0x26, data->data[0]);
+ saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f));
+ saa7127_dbg("WSS mode: %s\n", wss_strs[data->data[0] & 0xf]);
+ state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0];
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_video_enable(struct i2c_client *client, int enable)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+
+ if (enable) {
+ saa7127_dbg("Enable Video Output\n");
+ saa7127_write(client, 0x2d, state->reg_2d);
+ saa7127_write(client, 0x61, state->reg_61);
+ } else {
+ saa7127_dbg("Disable Video Output\n");
+ saa7127_write(client, 0x2d, (state->reg_2d & 0xf0));
+ saa7127_write(client, 0x61, (state->reg_61 | 0xc0));
+ }
+ state->video_enable = enable;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ const struct i2c_reg_value *inittab;
+
+ if (std & V4L2_STD_525_60) {
+ saa7127_dbg("Selecting 60 Hz video Standard\n");
+ inittab = saa7127_init_config_60hz;
+ state->reg_61 = SAA7127_60HZ_DAC_CONTROL;
+ } else {
+ saa7127_dbg("Selecting 50 Hz video Standard\n");
+ inittab = saa7127_init_config_50hz;
+ state->reg_61 = SAA7127_50HZ_DAC_CONTROL;
+ }
+
+ /* Write Table */
+ saa7127_write_inittab(client, inittab);
+ state->std = std;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_output_type(struct i2c_client *client, int output)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+
+ switch (output) {
+ case SAA7127_OUTPUT_TYPE_RGB:
+ state->reg_2d = 0x0f; /* RGB + CVBS (for sync) */
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_COMPOSITE:
+ state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_SVIDEO:
+ state->reg_2d = 0xff; /* 11111111 croma -> R, luma -> CVBS + G + B */
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_YUV_V:
+ state->reg_2d = 0x4f; /* reg 2D = 01001111, all DAC's on, RGB + VBS */
+ state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_YUV_C:
+ state->reg_2d = 0x0f; /* reg 2D = 00001111, all DAC's on, RGB + CVBS */
+ state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */
+ break;
+
+ case SAA7127_OUTPUT_TYPE_BOTH:
+ state->reg_2d = 0xbf;
+ state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ saa7127_dbg("Selecting %s output type\n", output_strs[output]);
+
+ /* Configure Encoder */
+ saa7127_write(client, 0x2d, state->reg_2d);
+ saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+ state->output_type = output;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_set_input_type(struct i2c_client *client, int input)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+
+ switch (input) {
+ case SAA7127_INPUT_TYPE_NORMAL: /* avia */
+ saa7127_dbg("Selecting Normal Encoder Input\n");
+ state->reg_3a_cb = 0;
+ break;
+
+ case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */
+ saa7127_dbg("Selecting Color Bar generator\n");
+ state->reg_3a_cb = 0x80;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb);
+ state->input_type = input;
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ struct v4l2_format *fmt = arg;
+ int *iarg = arg;
+
+ switch (cmd) {
+ case VIDIOC_S_STD:
+ if (state->std == *(v4l2_std_id *)arg)
+ break;
+ return saa7127_set_std(client, *(v4l2_std_id *)arg);
+
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = state->std;
+ break;
+
+ case VIDIOC_S_INPUT:
+ if (state->input_type == *iarg)
+ break;
+ return saa7127_set_input_type(client, *iarg);
+
+ case VIDIOC_S_OUTPUT:
+ if (state->output_type == *iarg)
+ break;
+ return saa7127_set_output_type(client, *iarg);
+
+ case VIDIOC_STREAMON:
+ case VIDIOC_STREAMOFF:
+ if (state->video_enable == (cmd == VIDIOC_STREAMON))
+ break;
+ return saa7127_set_video_enable(client, cmd == VIDIOC_STREAMON);
+
+ case VIDIOC_G_FMT:
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+
+ memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced));
+ if (state->vps_enable)
+ fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS;
+ if (state->wss_enable)
+ fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
+ if (state->cc_enable) {
+ fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525;
+ fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525;
+ }
+ fmt->fmt.sliced.service_set =
+ (state->vps_enable ? V4L2_SLICED_VPS : 0) |
+ (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) |
+ (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ saa7127_info("Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz");
+ saa7127_info("Input: %s\n", state->input_type ? "color bars" : "normal");
+ saa7127_info("Output: %s\n", state->video_enable ?
+ output_strs[state->output_type] : "disabled");
+ saa7127_info("WSS: %s\n", state->wss_enable ?
+ wss_strs[state->wss_mode] : "disabled");
+ saa7127_info("VPS: %s\n", state->vps_enable ? "enabled" : "disabled");
+ saa7127_info("CC: %s\n", state->cc_enable ? "enabled" : "disabled");
+ break;
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_INT_G_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_SAA7127)
+ return -EINVAL;
+ reg->val = saa7127_read(client, reg->reg & 0xff);
+ break;
+ }
+
+ case VIDIOC_INT_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+
+ if (reg->i2c_id != I2C_DRIVERID_SAA7127)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
+ break;
+ }
+#endif
+
+ case VIDIOC_INT_S_VBI_DATA:
+ {
+ struct v4l2_sliced_vbi_data *data = arg;
+
+ switch (data->id) {
+ case V4L2_SLICED_WSS_625:
+ return saa7127_set_wss(client, data);
+ case V4L2_SLICED_VPS:
+ return saa7127_set_vps(client, data);
+ case V4L2_SLICED_CAPTION_525:
+ if (data->field == 0)
+ return saa7127_set_cc(client, data);
+ return saa7127_set_xds(client, data);
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case VIDIOC_INT_G_CHIP_IDENT:
+ *(enum v4l2_chip_ident *)arg = state->ident;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7127;
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct saa7127_state *state;
+ struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
+ int read_result = 0;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ memset(client, 0, sizeof(struct i2c_client));
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver_saa7127;
+ client->flags = I2C_CLIENT_ALLOW_USE;
+ snprintf(client->name, sizeof(client->name) - 1, "saa7127");
+
+ saa7127_dbg("detecting saa7127 client on address 0x%x\n", address << 1);
+
+ /* First test register 0: Bits 5-7 are a version ID (should be 0),
+ and bit 2 should also be 0.
+ This is rather general, so the second test is more specific and
+ looks at the 'ending point of burst in clock cycles' which is
+ 0x1d after a reset and not expected to ever change. */
+ if ((saa7127_read(client, 0) & 0xe4) != 0 ||
+ (saa7127_read(client, 0x29) & 0x3f) != 0x1d) {
+ saa7127_dbg("saa7127 not found\n");
+ kfree(client);
+ return 0;
+ }
+ state = kmalloc(sizeof(struct saa7127_state), GFP_KERNEL);
+
+ if (state == NULL) {
+ kfree(client);
+ return (-ENOMEM);
+ }
+
+ i2c_set_clientdata(client, state);
+ memset(state, 0, sizeof(struct saa7127_state));
+
+ /* Configure Encoder */
+
+ saa7127_dbg("Configuring encoder\n");
+ saa7127_write_inittab(client, saa7127_init_config_common);
+ saa7127_set_std(client, V4L2_STD_NTSC);
+ saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH);
+ saa7127_set_vps(client, &vbi);
+ saa7127_set_wss(client, &vbi);
+ saa7127_set_cc(client, &vbi);
+ saa7127_set_xds(client, &vbi);
+ if (test_image == 1) {
+ /* The Encoder has an internal Colorbar generator */
+ /* This can be used for debugging */
+ saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE);
+ } else {
+ saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL);
+ }
+ saa7127_set_video_enable(client, 1);
+
+ /* Detect if it's an saa7129 */
+ read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2);
+ saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa);
+ if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) {
+ saa7127_info("saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name);
+ saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result);
+ saa7127_write_inittab(client, saa7129_init_config_extra);
+ state->ident = V4L2_IDENT_SAA7129;
+ } else {
+ saa7127_info("saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name);
+ state->ident = V4L2_IDENT_SAA7127;
+ }
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_probe(struct i2c_adapter *adapter)
+{
+#ifdef I2C_CLASS_TV_ANALOG
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+#else
+ if (adapter->id == I2C_HW_B_BT848)
+#endif
+ return i2c_probe(adapter, &addr_data, saa7127_attach);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int saa7127_detach(struct i2c_client *client)
+{
+ struct saa7127_state *state = i2c_get_clientdata(client);
+ int err;
+
+ /* Turn off TV output */
+ saa7127_set_video_enable(client, 0);
+
+ err = i2c_detach_client(client);
+
+ if (err) {
+ return err;
+ }
+
+ kfree(state);
+ kfree(client);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct i2c_driver i2c_driver_saa7127 = {
+ .name = "saa7127",
+ .id = I2C_DRIVERID_SAA7127,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = saa7127_probe,
+ .detach_client = saa7127_detach,
+ .command = saa7127_command,
+ .owner = THIS_MODULE,
+};
+
+
+/* ----------------------------------------------------------------------- */
+
+static int __init saa7127_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver_saa7127);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void __exit saa7127_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver_saa7127);
+}
+
+/* ----------------------------------------------------------------------- */
+
+module_init(saa7127_init_module);
+module_exit(saa7127_cleanup_module);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 624e8808a51..7bdeabe638c 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -1,10 +1,11 @@
config VIDEO_SAA7134
tristate "Philips SAA7134 support"
- depends on VIDEO_DEV && PCI && I2C && SOUND
+ depends on VIDEO_DEV && PCI && I2C && SOUND && SND
select VIDEO_BUF
select VIDEO_IR
select VIDEO_TUNER
select CRC32
+ select SND_PCM_OSS
---help---
This is a video4linux driver for Philips SAA713x based
TV cards.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index e0b28f0533a..4226b61cc61 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -1,10 +1,11 @@
saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \
- saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o \
- saa7134-vbi.o saa7134-video.o saa7134-input.o
+ saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o \
+ saa7134-video.o saa7134-input.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \
- saa6752hs.o saa7134-alsa.o
+ saa6752hs.o saa7134-alsa.o \
+ saa7134-oss.o
obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
EXTRA_CFLAGS += -I$(src)/..
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 4f3c4235432..5707c666660 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -30,7 +30,9 @@
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include <sound/initval.h>
+#include <linux/interrupt.h>
#include "saa7134.h"
#include "saa7134-reg.h"
@@ -56,6 +58,8 @@ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s).");
+int position;
+
#define dprintk(fmt, arg...) if (debug) \
printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg)
@@ -68,7 +72,7 @@ typedef struct snd_card_saa7134 {
int mixer_volume[MIXER_ADDR_LAST+1][2];
int capture_source[MIXER_ADDR_LAST+1][2];
struct pci_dev *pci;
- struct saa7134_dev *saadev;
+ struct saa7134_dev *dev;
unsigned long iobase;
int irq;
@@ -83,12 +87,10 @@ typedef struct snd_card_saa7134 {
*/
typedef struct snd_card_saa7134_pcm {
- struct saa7134_dev *saadev;
+ struct saa7134_dev *dev;
spinlock_t lock;
- unsigned int pcm_size; /* buffer size */
- unsigned int pcm_count; /* bytes per period */
- unsigned int pcm_bps; /* bytes per second */
+
snd_pcm_substream_t *substream;
} snd_card_saa7134_pcm_t;
@@ -100,13 +102,11 @@ static snd_card_t *snd_saa7134_cards[SNDRV_CARDS];
*
* Called when the capture device is released or the buffer overflows
*
- * - Copied verbatim from saa7134-oss's dsp_dma_stop. Can be dropped
- * if we just share dsp_dma_stop and use it here
+ * - Copied verbatim from saa7134-oss's dsp_dma_stop.
*
*/
static void saa7134_dma_stop(struct saa7134_dev *dev)
-
{
dev->dmasound.dma_blk = -1;
dev->dmasound.dma_running = 0;
@@ -118,8 +118,7 @@ static void saa7134_dma_stop(struct saa7134_dev *dev)
*
* Called when preparing the capture device for use
*
- * - Copied verbatim from saa7134-oss's dsp_dma_start. Can be dropped
- * if we just share dsp_dma_start and use it here
+ * - Copied verbatim from saa7134-oss's dsp_dma_start.
*
*/
@@ -170,9 +169,9 @@ void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status)
if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) {
dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count,
dev->dmasound.bufsize, dev->dmasound.blocks);
+ spin_unlock(&dev->slock);
snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN);
- saa7134_dma_stop(dev);
- goto done;
+ return;
}
/* next block addr */
@@ -194,6 +193,7 @@ void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status)
snd_pcm_period_elapsed(dev->dmasound.substream);
spin_lock(&dev->slock);
}
+
done:
spin_unlock(&dev->slock);
@@ -209,7 +209,9 @@ void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status)
static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs)
{
- struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
+ struct saa7134_dmasound *dmasound = dev_id;
+ struct saa7134_dev *dev = dmasound->priv_data;
+
unsigned long report, status;
int loop, handled = 0;
@@ -248,56 +250,23 @@ static int snd_card_saa7134_capture_trigger(snd_pcm_substream_t * substream,
int cmd)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
- struct saa7134_dev *dev=saapcm->saadev;
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+ struct saa7134_dev *dev=pcm->dev;
int err = 0;
- spin_lock_irq(&dev->slock);
- if (cmd == SNDRV_PCM_TRIGGER_START) {
+ spin_lock(&dev->slock);
+ if (cmd == SNDRV_PCM_TRIGGER_START) {
/* start dma */
saa7134_dma_start(dev);
- } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
+ } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
/* stop dma */
saa7134_dma_stop(dev);
- } else {
- err = -EINVAL;
- }
- spin_unlock_irq(&dev->slock);
-
- return err;
-}
-
-/*
- * DMA buffer config
- *
- * Sets the values that will later be used as the size of the buffer,
- * size of the fragments, and total number of fragments.
- * Must be called during the preparation stage, before memory is
- * allocated
- *
- * - Copied verbatim from saa7134-oss. Can be dropped
- * if we just share dsp_buffer_conf from OSS.
- */
+ } else {
+ err = -EINVAL;
+ }
+ spin_unlock(&dev->slock);
-static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
-{
- if (blksize < 0x100)
- blksize = 0x100;
- if (blksize > 0x10000)
- blksize = 0x10000;
-
- if (blocks < 2)
- blocks = 2;
- if ((blksize * blocks) > 1024*1024)
- blocks = 1024*1024 / blksize;
-
- dev->dmasound.blocks = blocks;
- dev->dmasound.blksize = blksize;
- dev->dmasound.bufsize = blksize * blocks;
-
- dprintk("buffer config: %d blocks / %d bytes, %d kB total\n",
- blocks,blksize,blksize * blocks / 1024);
- return 0;
+ return err;
}
/*
@@ -307,16 +276,16 @@ static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
* ALSA, but I was unable to use ALSA's own DMA, and had to force the
* usage of V4L's
*
- * - Copied verbatim from saa7134-oss. Can be dropped
- * if we just share dsp_buffer_init from OSS.
+ * - Copied verbatim from saa7134-oss.
+ *
*/
static int dsp_buffer_init(struct saa7134_dev *dev)
{
int err;
- if (!dev->dmasound.bufsize)
- BUG();
+ BUG_ON(!dev->dmasound.bufsize);
+
videobuf_dma_init(&dev->dmasound.dma);
err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
(dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
@@ -326,6 +295,28 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
}
/*
+ * DMA buffer release
+ *
+ * Called after closing the device, during snd_card_saa7134_capture_close
+ *
+ */
+
+static int dsp_buffer_free(struct saa7134_dev *dev)
+{
+ if (!dev->dmasound.blksize)
+ BUG();
+
+ videobuf_dma_free(&dev->dmasound.dma);
+
+ dev->dmasound.blocks = 0;
+ dev->dmasound.blksize = 0;
+ dev->dmasound.bufsize = 0;
+
+ return 0;
+}
+
+
+/*
* ALSA PCM preparation
*
* - One of the ALSA capture callbacks.
@@ -340,84 +331,30 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- int err, bswap, sign;
+ int bswap, sign;
u32 fmt, control;
snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
struct saa7134_dev *dev;
- snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
- unsigned int bps;
- unsigned long size;
- unsigned count;
-
- size = snd_pcm_lib_buffer_bytes(substream);
- count = snd_pcm_lib_period_bytes(substream);
-
- saapcm->saadev->dmasound.substream = substream;
- bps = runtime->rate * runtime->channels;
- bps *= snd_pcm_format_width(runtime->format);
- bps /= 8;
- if (bps <= 0)
- return -EINVAL;
- saapcm->pcm_bps = bps;
- saapcm->pcm_size = snd_pcm_lib_buffer_bytes(substream);
- saapcm->pcm_count = snd_pcm_lib_period_bytes(substream);
-
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
- dev=saa7134->saadev;
+ pcm->dev->dmasound.substream = substream;
- dsp_buffer_conf(dev,saapcm->pcm_count,(saapcm->pcm_size/saapcm->pcm_count));
+ dev = saa7134->dev;
- err = dsp_buffer_init(dev);
- if (0 != err)
- goto fail2;
-
- /* prepare buffer */
- if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma)))
- return err;
- if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt)))
- goto fail1;
- if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
- dev->dmasound.dma.sglist,
- dev->dmasound.dma.sglen,
- 0)))
- goto fail2;
-
-
-
- switch (runtime->format) {
- case SNDRV_PCM_FORMAT_U8:
- case SNDRV_PCM_FORMAT_S8:
+ if (snd_pcm_format_width(runtime->format) == 8)
fmt = 0x00;
- break;
- case SNDRV_PCM_FORMAT_U16_LE:
- case SNDRV_PCM_FORMAT_U16_BE:
- case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FORMAT_S16_BE:
+ else
fmt = 0x01;
- break;
- default:
- err = -EINVAL;
- return 1;
- }
- switch (runtime->format) {
- case SNDRV_PCM_FORMAT_S8:
- case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FORMAT_S16_BE:
+ if (snd_pcm_format_signed(runtime->format))
sign = 1;
- break;
- default:
+ else
sign = 0;
- break;
- }
- switch (runtime->format) {
- case SNDRV_PCM_FORMAT_U16_BE:
- case SNDRV_PCM_FORMAT_S16_BE:
- bswap = 1; break;
- default:
- bswap = 0; break;
- }
+ if (snd_pcm_format_big_endian(runtime->format))
+ bswap = 1;
+ else
+ bswap = 0;
switch (dev->pci->device) {
case PCI_DEVICE_ID_PHILIPS_SAA7134:
@@ -445,7 +382,6 @@ static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
fmt |= 0x04;
saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1);
saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24));
- //saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210);
break;
}
@@ -459,12 +395,6 @@ static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
if (bswap)
control |= SAA7134_RS_CONTROL_BSWAP;
- /* I should be able to use runtime->dma_addr in the control
- byte, but it doesn't work. So I allocate the DMA using the
- V4L functions, and force ALSA to use that as the DMA area */
-
- runtime->dma_area = dev->dmasound.dma.vmalloc;
-
saa_writel(SAA7134_RS_BA1(6),0);
saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize);
saa_writel(SAA7134_RS_PITCH(6),0);
@@ -473,12 +403,6 @@ static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
dev->dmasound.rate = runtime->rate;
return 0;
- fail2:
- saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
- fail1:
- videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
- return err;
-
}
@@ -496,10 +420,8 @@ static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream)
static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
- struct saa7134_dev *dev=saapcm->saadev;
-
-
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
+ struct saa7134_dev *dev=pcm->dev;
if (dev->dmasound.read_count) {
dev->dmasound.read_count -= snd_pcm_lib_period_bytes(substream);
@@ -540,9 +462,9 @@ static snd_pcm_hardware_t snd_card_saa7134_capture =
static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime)
{
- snd_card_saa7134_pcm_t *saapcm = runtime->private_data;
+ snd_card_saa7134_pcm_t *pcm = runtime->private_data;
- kfree(saapcm);
+ kfree(pcm);
}
@@ -552,17 +474,76 @@ static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime)
* - One of the ALSA capture callbacks.
*
* Called on initialization, right before the PCM preparation
- * Usually used in ALSA to allocate the DMA, but since we don't use the
- * ALSA DMA it does nothing
*
*/
static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
+ unsigned int period_size, periods;
+ int err;
- return 0;
+ period_size = params_period_bytes(hw_params);
+ periods = params_periods(hw_params);
+
+ snd_assert(period_size >= 0x100 && period_size <= 0x10000,
+ return -EINVAL);
+ snd_assert(periods >= 2, return -EINVAL);
+ snd_assert(period_size * periods <= 1024 * 1024, return -EINVAL);
+ dev = saa7134->dev;
+
+ if (dev->dmasound.blocks == periods &&
+ dev->dmasound.blksize == period_size)
+ return 0;
+
+ /* release the old buffer */
+ if (substream->runtime->dma_area) {
+ saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+ videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+ dsp_buffer_free(dev);
+ substream->runtime->dma_area = NULL;
+ }
+ dev->dmasound.blocks = periods;
+ dev->dmasound.blksize = period_size;
+ dev->dmasound.bufsize = period_size * periods;
+
+ err = dsp_buffer_init(dev);
+ if (0 != err) {
+ dev->dmasound.blocks = 0;
+ dev->dmasound.blksize = 0;
+ dev->dmasound.bufsize = 0;
+ return err;
+ }
+
+ if (0 != (err = videobuf_dma_pci_map(dev->pci, &dev->dmasound.dma))) {
+ dsp_buffer_free(dev);
+ return err;
+ }
+ if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
+ videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+ dsp_buffer_free(dev);
+ return err;
+ }
+ if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
+ dev->dmasound.dma.sglist,
+ dev->dmasound.dma.sglen,
+ 0))) {
+ saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+ videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+ dsp_buffer_free(dev);
+ return err;
+ }
+
+ /* I should be able to use runtime->dma_addr in the control
+ byte, but it doesn't work. So I allocate the DMA using the
+ V4L functions, and force ALSA to use that as the DMA area */
+
+ substream->runtime->dma_area = dev->dmasound.dma.vmalloc;
+
+ return 1;
}
@@ -572,33 +553,23 @@ static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream,
* - One of the ALSA capture callbacks.
*
* Called after closing the device, but before snd_card_saa7134_capture_close
- * Usually used in ALSA to free the DMA, but since we don't use the
- * ALSA DMA I'm almost sure this isn't necessary.
+ * It stops the DMA audio and releases the buffers.
*
*/
static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream)
{
- return 0;
-}
-
-/*
- * DMA buffer release
- *
- * Called after closing the device, during snd_card_saa7134_capture_close
- *
- */
-
-static int dsp_buffer_free(struct saa7134_dev *dev)
-{
- if (!dev->dmasound.blksize)
- BUG();
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev;
- videobuf_dma_free(&dev->dmasound.dma);
+ dev = saa7134->dev;
- dev->dmasound.blocks = 0;
- dev->dmasound.blksize = 0;
- dev->dmasound.bufsize = 0;
+ if (substream->runtime->dma_area) {
+ saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
+ videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma);
+ dsp_buffer_free(dev);
+ substream->runtime->dma_area = NULL;
+ }
return 0;
}
@@ -608,21 +579,12 @@ static int dsp_buffer_free(struct saa7134_dev *dev)
*
* - One of the ALSA capture callbacks.
*
- * Called after closing the device. It stops the DMA audio and releases
- * the buffers
+ * Called after closing the device.
*
*/
static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream)
{
- snd_card_saa7134_t *chip = snd_pcm_substream_chip(substream);
- struct saa7134_dev *dev = chip->saadev;
-
- /* unlock buffer */
- saa7134_pgtable_free(dev->pci,&dev->dmasound.pt);
- videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma);
-
- dsp_buffer_free(dev);
return 0;
}
@@ -639,29 +601,28 @@ static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream)
static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
- snd_card_saa7134_pcm_t *saapcm;
+ snd_card_saa7134_pcm_t *pcm;
snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
- struct saa7134_dev *dev = saa7134->saadev;
+ struct saa7134_dev *dev = saa7134->dev;
int err;
down(&dev->dmasound.lock);
- dev->dmasound.afmt = SNDRV_PCM_FORMAT_U8;
- dev->dmasound.channels = 2;
dev->dmasound.read_count = 0;
dev->dmasound.read_offset = 0;
up(&dev->dmasound.lock);
- saapcm = kzalloc(sizeof(*saapcm), GFP_KERNEL);
- if (saapcm == NULL)
+ pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
+ if (pcm == NULL)
return -ENOMEM;
- saapcm->saadev=saa7134->saadev;
- spin_lock_init(&saapcm->lock);
+ pcm->dev=saa7134->dev;
- saapcm->substream = substream;
- runtime->private_data = saapcm;
+ spin_lock_init(&pcm->lock);
+
+ pcm->substream = substream;
+ runtime->private_data = pcm;
runtime->private_free = snd_card_saa7134_runtime_free;
runtime->hw = snd_card_saa7134_capture;
@@ -736,7 +697,6 @@ static int snd_saa7134_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_
static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change, addr = kcontrol->private_value;
int left, right;
@@ -750,12 +710,12 @@ static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_
right = 0;
if (right > 20)
right = 20;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+ spin_lock_irq(&chip->mixer_lock);
change = chip->mixer_volume[addr][0] != left ||
chip->mixer_volume[addr][1] != right;
chip->mixer_volume[addr][0] = left;
chip->mixer_volume[addr][1] = right;
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ spin_unlock_irq(&chip->mixer_lock);
return change;
}
@@ -777,38 +737,37 @@ static int snd_saa7134_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_
static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int addr = kcontrol->private_value;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+ spin_lock_irq(&chip->mixer_lock);
ucontrol->value.integer.value[0] = chip->capture_source[addr][0];
ucontrol->value.integer.value[1] = chip->capture_source[addr][1];
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ spin_unlock_irq(&chip->mixer_lock);
+
return 0;
}
static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
{
snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol);
- unsigned long flags;
int change, addr = kcontrol->private_value;
int left, right;
u32 anabar, xbarin;
int analog_io, rate;
struct saa7134_dev *dev;
- dev = chip->saadev;
+ dev = chip->dev;
left = ucontrol->value.integer.value[0] & 1;
right = ucontrol->value.integer.value[1] & 1;
- spin_lock_irqsave(&chip->mixer_lock, flags);
+ spin_lock_irq(&chip->mixer_lock);
change = chip->capture_source[addr][0] != left ||
chip->capture_source[addr][1] != right;
chip->capture_source[addr][0] = left;
chip->capture_source[addr][1] = right;
dev->dmasound.input=addr;
- spin_unlock_irqrestore(&chip->mixer_lock, flags);
+ spin_unlock_irq(&chip->mixer_lock);
if (change) {
@@ -898,43 +857,44 @@ static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip)
return 0;
}
-static int snd_saa7134_free(snd_card_saa7134_t *chip)
+static void snd_saa7134_free(snd_card_t * card)
{
- return 0;
-}
+ snd_card_saa7134_t *chip = card->private_data;
+
+ if (chip->dev->dmasound.priv_data == NULL)
+ return;
+
+ if (chip->irq >= 0) {
+ synchronize_irq(chip->irq);
+ free_irq(chip->irq, &chip->dev->dmasound);
+ }
+
+ chip->dev->dmasound.priv_data = NULL;
-static int snd_saa7134_dev_free(snd_device_t *device)
-{
- snd_card_saa7134_t *chip = device->device_data;
- return snd_saa7134_free(chip);
}
/*
* ALSA initialization
*
- * Called by saa7134-core, it creates the basic structures and registers
- * the ALSA devices
+ * Called by the init routine, once for each saa7134 device present,
+ * it creates the basic structures and registers the ALSA devices
*
*/
-int alsa_card_saa7134_create (struct saa7134_dev *saadev)
+int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
{
- static int dev;
snd_card_t *card;
snd_card_saa7134_t *chip;
int err;
- static snd_device_ops_t ops = {
- .dev_free = snd_saa7134_dev_free,
- };
- if (dev >= SNDRV_CARDS)
+ if (devnum >= SNDRV_CARDS)
return -ENODEV;
- if (!enable[dev])
+ if (!enable[devnum])
return -ENODEV;
- card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+ card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, sizeof(snd_card_saa7134_t));
if (card == NULL)
return -ENOMEM;
@@ -943,34 +903,33 @@ int alsa_card_saa7134_create (struct saa7134_dev *saadev)
/* Card "creation" */
- chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
- if (chip == NULL) {
- return -ENOMEM;
- }
+ card->private_free = snd_saa7134_free;
+ chip = (snd_card_saa7134_t *) card->private_data;
spin_lock_init(&chip->lock);
spin_lock_init(&chip->mixer_lock);
- chip->saadev = saadev;
+ chip->dev = dev;
chip->card = card;
- chip->pci = saadev->pci;
- chip->irq = saadev->pci->irq;
- chip->iobase = pci_resource_start(saadev->pci, 0);
+ chip->pci = dev->pci;
+ chip->iobase = pci_resource_start(dev->pci, 0);
- err = request_irq(saadev->pci->irq, saa7134_alsa_irq,
- SA_SHIRQ | SA_INTERRUPT, saadev->name, saadev);
+
+ err = request_irq(dev->pci->irq, saa7134_alsa_irq,
+ SA_SHIRQ | SA_INTERRUPT, dev->name,
+ (void*) &dev->dmasound);
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n",
- saadev->name, saadev->pci->irq);
+ dev->name, dev->pci->irq);
goto __nodev;
}
- if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
- goto __nodev;
- }
+ chip->irq = dev->pci->irq;
+
+ init_MUTEX(&dev->dmasound.lock);
if ((err = snd_card_saa7134_new_mixer(chip)) < 0)
goto __nodev;
@@ -984,16 +943,15 @@ int alsa_card_saa7134_create (struct saa7134_dev *saadev)
strcpy(card->shortname, "SAA7134");
sprintf(card->longname, "%s at 0x%lx irq %d",
- chip->saadev->name, chip->iobase, chip->irq);
+ chip->dev->name, chip->iobase, chip->irq);
if ((err = snd_card_register(card)) == 0) {
- snd_saa7134_cards[dev] = card;
+ snd_saa7134_cards[devnum] = card;
return 0;
}
__nodev:
snd_card_free(card);
- kfree(chip);
return err;
}
@@ -1007,21 +965,29 @@ __nodev:
static int saa7134_alsa_init(void)
{
- struct saa7134_dev *saadev = NULL;
- struct list_head *list;
+ struct saa7134_dev *dev = NULL;
+ struct list_head *list;
- printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
+ position = 0;
- list_for_each(list,&saa7134_devlist) {
- saadev = list_entry(list, struct saa7134_dev, devlist);
- alsa_card_saa7134_create(saadev);
- }
+ printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n");
- if (saadev == NULL)
+ list_for_each(list,&saa7134_devlist) {
+ dev = list_entry(list, struct saa7134_dev, devlist);
+ if (dev->dmasound.priv_data == NULL) {
+ dev->dmasound.priv_data = dev;
+ alsa_card_saa7134_create(dev,position);
+ position++;
+ } else {
+ printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name);
+ return -EBUSY;
+ }
+ }
+
+ if (dev == NULL)
printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n");
return 0;
-
}
/*
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 663d03e5bc6..75abc20b0cc 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -2529,6 +2529,32 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
}},
},
+ [SAA7134_BOARD_MSI_TVATANYWHERE_PLUS] = {
+ .name = "MSI TV@Anywhere plus",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2970,6 +2996,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x2018,
.driver_data = SAA7134_BOARD_PHILIPS_TIGER,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1462,
+ .subdevice = 0x6231,
+ .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 19b88744fb3..4275d2ddb86 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -53,13 +53,13 @@ static unsigned int gpio_tracking = 0;
module_param(gpio_tracking, int, 0644);
MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
-static unsigned int oss = 0;
-module_param(oss, int, 0444);
-MODULE_PARM_DESC(oss,"register oss devices (default: no)");
-
static unsigned int alsa = 0;
-module_param(alsa, int, 0444);
-MODULE_PARM_DESC(alsa,"register alsa devices (default: no)");
+module_param(alsa, int, 0644);
+MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]");
+
+static unsigned int oss = 0;
+module_param(oss, int, 0644);
+MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]");
static unsigned int latency = UNSET;
module_param(latency, int, 0444);
@@ -68,24 +68,18 @@ MODULE_PARM_DESC(latency,"pci latency timer");
static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
-static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
module_param_array(video_nr, int, NULL, 0444);
module_param_array(vbi_nr, int, NULL, 0444);
module_param_array(radio_nr, int, NULL, 0444);
-module_param_array(dsp_nr, int, NULL, 0444);
-module_param_array(mixer_nr, int, NULL, 0444);
module_param_array(tuner, int, NULL, 0444);
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(video_nr, "video device number");
MODULE_PARM_DESC(vbi_nr, "vbi device number");
MODULE_PARM_DESC(radio_nr, "radio device number");
-MODULE_PARM_DESC(dsp_nr, "oss dsp device number");
-MODULE_PARM_DESC(mixer_nr, "oss mixer device number");
MODULE_PARM_DESC(tuner, "tuner type");
MODULE_PARM_DESC(card, "card type");
@@ -195,6 +189,7 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
static int need_empress;
static int need_dvb;
static int need_alsa;
+static int need_oss;
static int pending_call(struct notifier_block *self, unsigned long state,
void *module)
@@ -208,6 +203,8 @@ static int pending_call(struct notifier_block *self, unsigned long state,
request_module("saa7134-dvb");
if (need_alsa)
request_module("saa7134-alsa");
+ if (need_oss)
+ request_module("saa7134-oss");
return NOTIFY_DONE;
}
@@ -218,10 +215,11 @@ static struct notifier_block pending_notifier = {
static void request_module_depend(char *name, int *flag)
{
+ int err;
switch (THIS_MODULE->state) {
case MODULE_STATE_COMING:
if (!pending_registered) {
- register_module_notifier(&pending_notifier);
+ err = register_module_notifier(&pending_notifier);
pending_registered = 1;
}
*flag = 1;
@@ -578,12 +576,14 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
goto out;
}
- /* If alsa support is active and we get a sound report, exit
- and let the saa7134-alsa module deal with it */
+ /* If dmasound support is active and we get a sound report, exit
+ and let the saa7134-alsa/oss module deal with it */
- if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && alsa) {
+ if ((report & SAA7134_IRQ_REPORT_DONE_RA3) &&
+ (dev->dmasound.priv_data != NULL) )
+ {
if (irq_debug > 1)
- printk(KERN_DEBUG "%s/irq: ignoring interrupt for ALSA\n",
+ printk(KERN_DEBUG "%s/irq: ignoring interrupt for DMA sound\n",
dev->name);
goto out;
}
@@ -609,12 +609,6 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
card_has_mpeg(dev))
saa7134_irq_ts_done(dev,status);
- if ((report & SAA7134_IRQ_REPORT_DONE_RA3)) {
- if (oss) {
- saa7134_irq_oss_done(dev,status);
- }
- }
-
if ((report & (SAA7134_IRQ_REPORT_GPIO16 |
SAA7134_IRQ_REPORT_GPIO18)) &&
dev->remote)
@@ -689,14 +683,6 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
* audio will not work.
*/
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- saa7134_oss_init1(dev);
- break;
- }
-
/* enable peripheral devices */
saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
@@ -728,8 +714,6 @@ static int saa7134_hwinit2(struct saa7134_dev *dev)
irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 |
SAA7134_IRQ2_INTE_GPIO18A |
SAA7134_IRQ2_INTE_GPIO16 );
- else if (dev->has_remote == SAA7134_REMOTE_I2C)
- request_module("ir-kbd-i2c");
saa_writel(SAA7134_IRQ1, 0);
saa_writel(SAA7134_IRQ2, irq2_mask);
@@ -742,13 +726,6 @@ static int saa7134_hwfini(struct saa7134_dev *dev)
{
dprintk("hwfini\n");
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- saa7134_oss_fini(dev);
- break;
- }
if (card_has_mpeg(dev))
saa7134_ts_fini(dev);
saa7134_input_fini(dev);
@@ -986,11 +963,12 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (card_is_dvb(dev))
request_module_depend("saa7134-dvb",&need_dvb);
- if (!oss && alsa) {
- dprintk("Requesting ALSA module\n");
+
+ if (alsa)
request_module_depend("saa7134-alsa",&need_alsa);
- }
+ if (oss)
+ request_module_depend("saa7134-oss",&need_oss);
v4l2_prio_init(&dev->prio);
@@ -1024,32 +1002,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
dev->name,dev->radio_dev->minor & 0x1f);
}
- /* register oss devices */
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- if (oss) {
- err = dev->dmasound.minor_dsp =
- register_sound_dsp(&saa7134_dsp_fops,
- dsp_nr[dev->nr]);
- if (err < 0) {
- goto fail4;
- }
- printk(KERN_INFO "%s: registered device dsp%d\n",
- dev->name,dev->dmasound.minor_dsp >> 4);
-
- err = dev->dmasound.minor_mixer =
- register_sound_mixer(&saa7134_mixer_fops,
- mixer_nr[dev->nr]);
- if (err < 0)
- goto fail5;
- printk(KERN_INFO "%s: registered device mixer%d\n",
- dev->name,dev->dmasound.minor_mixer >> 4);
- }
- break;
- }
-
/* everything worked */
pci_set_drvdata(pci_dev,dev);
saa7134_devcount++;
@@ -1064,17 +1016,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
/* check for signal */
saa7134_irq_video_intl(dev);
+
return 0;
- fail5:
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- if (oss)
- unregister_sound_dsp(dev->dmasound.minor_dsp);
- break;
- }
fail4:
saa7134_unregister_video(dev);
saa7134_i2c_unregister(dev);
@@ -1125,19 +1069,16 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
saa7134_devcount--;
saa7134_i2c_unregister(dev);
- switch (dev->pci->device) {
- case PCI_DEVICE_ID_PHILIPS_SAA7134:
- case PCI_DEVICE_ID_PHILIPS_SAA7133:
- case PCI_DEVICE_ID_PHILIPS_SAA7135:
- if (oss) {
- unregister_sound_mixer(dev->dmasound.minor_mixer);
- unregister_sound_dsp(dev->dmasound.minor_dsp);
- }
- break;
- }
saa7134_unregister_video(dev);
- /* release ressources */
+ /* the DMA sound modules should be unloaded before reaching
+ this, but just in case they are still present... */
+ if (dev->dmasound.priv_data != NULL) {
+ free_irq(pci_dev->irq, &dev->dmasound);
+ dev->dmasound.priv_data = NULL;
+ }
+
+ /* release resources */
free_irq(pci_dev->irq, dev);
iounmap(dev->lmmio);
release_mem_region(pci_resource_start(pci_dev,0),
@@ -1225,7 +1166,7 @@ EXPORT_SYMBOL(saa7134_i2c_call_clients);
EXPORT_SYMBOL(saa7134_devlist);
EXPORT_SYMBOL(saa7134_boards);
-/* ----------------- For ALSA -------------------------------- */
+/* ----------------- for the DMA sound modules --------------- */
EXPORT_SYMBOL(saa7134_pgtable_free);
EXPORT_SYMBOL(saa7134_pgtable_build);
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 329accda6d4..e648cc3bc96 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -485,64 +485,6 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
};
-static IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
- [ 0x59 ] = KEY_MUTE,
- [ 0x4a ] = KEY_POWER,
-
- [ 0x18 ] = KEY_TEXT,
- [ 0x26 ] = KEY_TV,
- [ 0x3d ] = KEY_PRINT,
-
- [ 0x48 ] = KEY_RED,
- [ 0x04 ] = KEY_GREEN,
- [ 0x11 ] = KEY_YELLOW,
- [ 0x00 ] = KEY_BLUE,
-
- [ 0x2d ] = KEY_VOLUMEUP,
- [ 0x1e ] = KEY_VOLUMEDOWN,
-
- [ 0x49 ] = KEY_MENU,
-
- [ 0x16 ] = KEY_CHANNELUP,
- [ 0x17 ] = KEY_CHANNELDOWN,
-
- [ 0x20 ] = KEY_UP,
- [ 0x21 ] = KEY_DOWN,
- [ 0x22 ] = KEY_LEFT,
- [ 0x23 ] = KEY_RIGHT,
- [ 0x0d ] = KEY_SELECT,
-
-
-
- [ 0x08 ] = KEY_BACK,
- [ 0x07 ] = KEY_REFRESH,
-
- [ 0x2f ] = KEY_ZOOM,
- [ 0x29 ] = KEY_RECORD,
-
- [ 0x4b ] = KEY_PAUSE,
- [ 0x4d ] = KEY_REWIND,
- [ 0x2e ] = KEY_PLAY,
- [ 0x4e ] = KEY_FORWARD,
- [ 0x53 ] = KEY_PREVIOUS,
- [ 0x4c ] = KEY_STOP,
- [ 0x54 ] = KEY_NEXT,
-
- [ 0x69 ] = KEY_KP0,
- [ 0x6a ] = KEY_KP1,
- [ 0x6b ] = KEY_KP2,
- [ 0x6c ] = KEY_KP3,
- [ 0x6d ] = KEY_KP4,
- [ 0x6e ] = KEY_KP5,
- [ 0x6f ] = KEY_KP6,
- [ 0x70 ] = KEY_KP7,
- [ 0x71 ] = KEY_KP8,
- [ 0x72 ] = KEY_KP9,
-
- [ 0x74 ] = KEY_CHANNEL,
- [ 0x0a ] = KEY_BACKSPACE,
-};
-
/* Mapping for the 28 key remote control as seen at
http://www.sednacomputer.com/photo/cardbus-tv.jpg
Pavel Mihaylov <bin@bash.info> */
@@ -635,57 +577,6 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-/* The new pinnacle PCTV remote (with the colored buttons)
- *
- * Ricardo Cerqueira <v4l@cerqueira.org>
- */
-
-static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
- unsigned char b[4];
- unsigned int start = 0,parity = 0,code = 0;
-
- /* poll IR chip */
- if (4 != i2c_master_recv(&ir->c,b,4)) {
- i2cdprintk("read error\n");
- return -EIO;
- }
-
- for (start = 0; start<4; start++) {
- if (b[start] == 0x80) {
- code=b[(start+3)%4];
- parity=b[(start+2)%4];
- }
- }
-
- /* Empty Request */
- if (parity==0)
- return 0;
-
- /* Repeating... */
- if (ir->old == parity)
- return 0;
-
-
- ir->old = parity;
-
- /* Reduce code value to fit inside IR_KEYTAB_SIZE
- *
- * this is the only value that results in 42 unique
- * codes < 128
- */
-
- code %= 0x88;
-
- *ir_raw = code;
- *ir_key = code;
-
- i2cdprintk("Pinnacle PCTV key %02x\n", code);
-
- return 1;
-}
-
-
void saa7134_input_irq(struct saa7134_dev *dev)
{
struct saa7134_ir *ir = dev->remote;
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index fd53dfcc164..fd9ed11ab1e 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -4,6 +4,8 @@
* oss dsp interface
*
* (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ * 2005 conversion to standalone module:
+ * Ricardo Cerqueira <v4l@cerqueira.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
@@ -25,7 +27,9 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
+#include <linux/interrupt.h>
#include <linux/slab.h>
+#include <linux/sound.h>
#include <linux/soundcard.h>
#include "saa7134-reg.h"
@@ -33,15 +37,23 @@
/* ------------------------------------------------------------------ */
-static unsigned int oss_debug = 0;
-module_param(oss_debug, int, 0644);
-MODULE_PARM_DESC(oss_debug,"enable debug messages [oss]");
+static unsigned int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [oss]");
-static unsigned int oss_rate = 0;
-module_param(oss_rate, int, 0444);
-MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
+static unsigned int rate = 0;
+module_param(rate, int, 0444);
+MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)");
-#define dprintk(fmt, arg...) if (oss_debug) \
+static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s).");
+module_param_array(dsp_nr, int, NULL, 0444);
+
+static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
+MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s).");
+module_param_array(mixer_nr, int, NULL, 0444);
+
+#define dprintk(fmt, arg...) if (debug) \
printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg)
@@ -369,7 +381,7 @@ static int dsp_ioctl(struct inode *inode, struct file *file,
int __user *p = argp;
int val = 0;
- if (oss_debug > 1)
+ if (debug > 1)
saa7134_print_ioctl(dev->name,cmd);
switch (cmd) {
case OSS_GETVERSION:
@@ -665,7 +677,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file,
void __user *argp = (void __user *) arg;
int __user *p = argp;
- if (oss_debug > 1)
+ if (debug > 1)
saa7134_print_ioctl(dev->name,cmd);
switch (cmd) {
case OSS_GETVERSION:
@@ -768,8 +780,41 @@ struct file_operations saa7134_mixer_fops = {
/* ------------------------------------------------------------------ */
+static irqreturn_t saa7134_oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct saa7134_dmasound *dmasound = dev_id;
+ struct saa7134_dev *dev = dmasound->priv_data;
+ unsigned long report, status;
+ int loop, handled = 0;
+
+ for (loop = 0; loop < 10; loop++) {
+ report = saa_readl(SAA7134_IRQ_REPORT);
+ status = saa_readl(SAA7134_IRQ_STATUS);
+
+ if (report & SAA7134_IRQ_REPORT_DONE_RA3) {
+ handled = 1;
+ saa_writel(SAA7134_IRQ_REPORT,report);
+ saa7134_irq_oss_done(dev, status);
+ } else {
+ goto out;
+ }
+ }
+
+ if (loop == 10) {
+ dprintk("error! looping IRQ!");
+ }
+out:
+ return IRQ_RETVAL(handled);
+}
+
int saa7134_oss_init1(struct saa7134_dev *dev)
{
+
+ if ((request_irq(dev->pci->irq, saa7134_oss_irq,
+ SA_SHIRQ | SA_INTERRUPT, dev->name,
+ (void*) &dev->dmasound)) < 0)
+ return -1;
+
/* general */
init_MUTEX(&dev->dmasound.lock);
init_waitqueue_head(&dev->dmasound.wq);
@@ -785,8 +830,8 @@ int saa7134_oss_init1(struct saa7134_dev *dev)
/* dsp */
dev->dmasound.rate = 32000;
- if (oss_rate)
- dev->dmasound.rate = oss_rate;
+ if (rate)
+ dev->dmasound.rate = rate;
dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000;
/* mixer */
@@ -840,7 +885,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
/* next block addr */
next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks;
saa_writel(reg,next_blk * dev->dmasound.blksize);
- if (oss_debug > 2)
+ if (debug > 2)
dprintk("irq: ok, %s, next_blk=%d, addr=%x\n",
(status & 0x10000000) ? "even" : "odd ", next_blk,
next_blk * dev->dmasound.blksize);
@@ -854,6 +899,98 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
spin_unlock(&dev->slock);
}
+int saa7134_dsp_create(struct saa7134_dev *dev)
+{
+ int err;
+
+ err = dev->dmasound.minor_dsp =
+ register_sound_dsp(&saa7134_dsp_fops,
+ dsp_nr[dev->nr]);
+ if (err < 0) {
+ goto fail;
+ }
+ printk(KERN_INFO "%s: registered device dsp%d\n",
+ dev->name,dev->dmasound.minor_dsp >> 4);
+
+ err = dev->dmasound.minor_mixer =
+ register_sound_mixer(&saa7134_mixer_fops,
+ mixer_nr[dev->nr]);
+ if (err < 0)
+ goto fail;
+ printk(KERN_INFO "%s: registered device mixer%d\n",
+ dev->name,dev->dmasound.minor_mixer >> 4);
+
+ return 0;
+
+fail:
+ unregister_sound_dsp(dev->dmasound.minor_dsp);
+ return 0;
+
+
+}
+
+static int saa7134_oss_init(void)
+{
+ struct saa7134_dev *dev = NULL;
+ struct list_head *list;
+
+ printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n");
+
+ list_for_each(list,&saa7134_devlist) {
+ dev = list_entry(list, struct saa7134_dev, devlist);
+ if (dev->dmasound.priv_data == NULL) {
+ dev->dmasound.priv_data = dev;
+ saa7134_oss_init1(dev);
+ saa7134_dsp_create(dev);
+ } else {
+ printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name);
+ return -EBUSY;
+ }
+ }
+
+ if (dev == NULL)
+ printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n");
+
+ return 0;
+
+}
+
+void saa7134_oss_exit(void)
+{
+ struct saa7134_dev *dev = NULL;
+ struct list_head *list;
+
+ list_for_each(list,&saa7134_devlist) {
+ dev = list_entry(list, struct saa7134_dev, devlist);
+
+ /* Device isn't registered by OSS, probably ALSA's */
+ if (!dev->dmasound.minor_dsp)
+ continue;
+
+ unregister_sound_mixer(dev->dmasound.minor_mixer);
+ unregister_sound_dsp(dev->dmasound.minor_dsp);
+
+ saa7134_oss_fini(dev);
+
+ if (dev->pci->irq > 0) {
+ synchronize_irq(dev->pci->irq);
+ free_irq(dev->pci->irq,&dev->dmasound);
+ }
+
+ dev->dmasound.priv_data = NULL;
+
+ }
+
+ printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n");
+
+ return;
+}
+
+module_init(saa7134_oss_init);
+module_exit(saa7134_oss_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index fb972747166..244e1973081 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -208,6 +208,7 @@ struct saa7134_format {
#define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79
#define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80
#define SAA7134_BOARD_PHILIPS_TIGER 81
+#define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -383,6 +384,7 @@ struct saa7134_dmasound {
unsigned int dma_blk;
unsigned int read_offset;
unsigned int read_count;
+ void * priv_data;
snd_pcm_substream_t *substream;
};
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index b2dfe07e9f9..61d94ddaff4 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -437,6 +437,10 @@ static void set_audio(struct tuner *t)
t->sgIF = 124;
t->tda8290_easy_mode = 0x20;
mode = "L";
+ } else if (t->std & V4L2_STD_SECAM_LC) {
+ t->sgIF = 20;
+ t->tda8290_easy_mode = 0x40;
+ mode = "LC";
}
tuner_dbg("setting tda8290 to system %s\n", mode);
}
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 73c4041c35d..e58abdfcaab 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -251,7 +251,7 @@ static inline int check_mode(struct tuner *t, char *cmd)
static char pal[] = "-";
module_param_string(pal, pal, sizeof(pal), 0644);
-static char secam[] = "-";
+static char secam[] = "--";
module_param_string(secam, secam, sizeof(secam), 0644);
/* get more precise norm info from insmod option */
@@ -307,8 +307,13 @@ static int tuner_fixup_std(struct tuner *t)
break;
case 'l':
case 'L':
- tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
- t->std = V4L2_STD_SECAM_L;
+ if ((secam[1]=='C')||(secam[1]=='c')) {
+ tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n");
+ t->std = V4L2_STD_SECAM_LC;
+ } else {
+ tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
+ t->std = V4L2_STD_SECAM_L;
+ }
break;
case '-':
/* default parameter, do nothing */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index d832205818f..e0c9fdb9914 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -233,7 +233,7 @@ static struct tunertype tuners[] = {
{ "Ymec TVision TVF-5533MF", Philips, NTSC,
16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
- /* 60-68 */
+ /* 60-69 */
{ "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
{ "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
@@ -252,6 +252,8 @@ static struct tunertype tuners[] = {
16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 },
{ "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC,
16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 },
+ { "Tena TNF 5335 MF", Philips, NTSC,
+ 16*157.25,16*454.00,0x01,0x02,0x04,0x8e,732 },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 22f28622200..a6936ad74fc 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -5,6 +5,11 @@
*
* Based on saa7115 driver
*
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ * - Cleanup
+ * - V4L2 API update
+ * - sound fixes
+ *
* This program is free software; you can redistribute 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
@@ -31,7 +36,7 @@
#include <media/audiochip.h>
MODULE_DESCRIPTION("wm8775 driver");
-MODULE_AUTHOR("Ulf Eklund");
+MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
MODULE_LICENSE("GPL");
#define wm8775_err(fmt, arg...) do { \
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 1e6bdba2675..166c9b0ad04 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -22,7 +22,6 @@
#include <asm/div64.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <asm/scatterlist.h>
#include <asm/sizes.h>
#include <asm/hardware/amba.h>
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 977935a3d89..824e430486c 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -84,6 +84,7 @@ static int max_interrupt_work = 10;
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/skbuff.h>
#include <linux/delay.h> /* for udelay() */
#include <linux/spinlock.h>
@@ -173,7 +174,7 @@ struct el3_private {
/* skb send-queue */
int head, size;
struct sk_buff *queue[SKB_QUEUE_SIZE];
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
struct pm_dev *pmdev;
#endif
enum {
@@ -200,7 +201,7 @@ static void el3_tx_timeout (struct net_device *dev);
static void el3_down(struct net_device *dev);
static void el3_up(struct net_device *dev);
static struct ethtool_ops ethtool_ops;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
static int el3_suspend(struct pm_dev *pdev);
static int el3_resume(struct pm_dev *pdev);
static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data);
@@ -361,7 +362,7 @@ static void el3_common_remove (struct net_device *dev)
struct el3_private *lp = netdev_priv(dev);
(void) lp; /* Keep gcc quiet... */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
if (lp->pmdev)
pm_unregister(lp->pmdev);
#endif
@@ -571,7 +572,7 @@ no_pnp:
if (err)
goto out1;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
/* register power management */
lp->pmdev = pm_register(PM_ISA_DEV, card_idx, el3_pm_callback);
if (lp->pmdev) {
@@ -1479,7 +1480,7 @@ el3_up(struct net_device *dev)
}
/* Power Management support functions */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
static int
el3_suspend(struct pm_dev *pdev)
@@ -1548,7 +1549,7 @@ el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_LEGACY */
/* Parameters that may be passed into the module. */
static int debug = -1;
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index e3a329539f1..0f030b73cbb 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -6,7 +6,7 @@
* Based on 8260_io/fcc_enet.c
*
* Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala
*
* Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
*
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 220084e5334..5065ba82cb7 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -6,7 +6,7 @@
* Based on 8260_io/fcc_enet.c
*
* Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala
*
* Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
*
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 5a2d810ce57..cfa3cd7c91a 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -6,7 +6,7 @@
* Based on e1000 ethtool support
*
* Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala
*
* Copyright (c) 2003,2004 Freescale Semiconductor, Inc.
*
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index 9544279e8bc..04a462c2a5b 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -5,7 +5,7 @@
* Provides Bus interface for MIIM regs
*
* Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala
*
* Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
*
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index 56e5665d5c9..e85eb216fb5 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -5,7 +5,7 @@
* Driver for the MDIO bus controller in the Gianfar register space
*
* Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala
*
* Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
*
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 9bf34681d3d..2e7882eb7d6 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -40,6 +40,7 @@
#include <asm/byteorder.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda.h>
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 805714ec9a8..ee717d0e939 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -59,6 +59,7 @@
#include <asm/byteorder.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda.h>
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index a10cd184d59..5c2824be4ee 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -100,14 +100,14 @@
#define SMC_IO_SHIFT 0
#define SMC_NOWAIT 1
-#define SMC_inb(a, r) inb((a) + (r))
-#define SMC_insb(a, r, p, l) insb((a) + (r), p, (l))
-#define SMC_inw(a, r) inw((a) + (r))
-#define SMC_insw(a, r, p, l) insw((a) + (r), p, l)
-#define SMC_outb(v, a, r) outb(v, (a) + (r))
-#define SMC_outsb(a, r, p, l) outsb((a) + (r), p, (l))
-#define SMC_outw(v, a, r) outw(v, (a) + (r))
-#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l)
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_insb(a, r, p, l) readsb((a) + (r), p, (l))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outsb(a, r, p, l) writesb((a) + (r), p, (l))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
#define set_irq_type(irq, type) do {} while (0)
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index de399563a9d..081717d0137 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -128,6 +128,8 @@ static struct pci_device_id gem_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_SH_SUNGEM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_GMAC,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{0, }
};
diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c
index 7c2cf2e7630..032c0f81928 100644
--- a/drivers/net/wan/sdladrv.c
+++ b/drivers/net/wan/sdladrv.c
@@ -1994,7 +1994,7 @@ static int detect_s514 (sdlahw_t* hw)
modname, hw->irq);
/* map the physical PCI memory to virtual memory */
- (void *)hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr,
+ hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr,
(unsigned long)MAX_SIZEOF_S514_MEMORY);
/* map the physical control register memory to virtual memory */
hw->vector = (unsigned long)ioremap(
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 4a3cecca012..2387e75da0f 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -31,6 +31,8 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/interrupt.h>
+
#include "../pci.h"
#include "pciehp.h"
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
index a7859a84d1a..4b35097b3d9 100644
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -253,7 +253,7 @@ rpaphp_pci_config_slot(struct pci_bus *bus)
if (!dn || !dn->child)
return NULL;
- if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
+ if (_machine == PLATFORM_PSERIES_LPAR) {
of_scan_bus(dn, bus);
if (list_empty(&bus->devices)) {
err("%s: No new device found\n", __FUNCTION__);
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 40905a6c809..9987a6fd65b 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -31,6 +31,8 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/interrupt.h>
+
#include "shpchp.h"
#ifdef DEBUG
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 234cdca6fe1..a30aa74304a 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -513,6 +513,11 @@ static int socket_insert(struct pcmcia_socket *skt)
ret = socket_setup(skt, setup_delay);
if (ret == CS_SUCCESS) {
skt->state |= SOCKET_PRESENT;
+
+ printk(KERN_NOTICE "pccard: %s card inserted into slot %d\n",
+ (skt->state & SOCKET_CARDBUS) ? "CardBus" : "PCMCIA",
+ skt->sock);
+
#ifdef CONFIG_CARDBUS
if (skt->state & SOCKET_CARDBUS) {
cb_alloc(skt);
@@ -598,6 +603,7 @@ static int socket_resume(struct pcmcia_socket *skt)
static void socket_remove(struct pcmcia_socket *skt)
{
+ printk(KERN_NOTICE "pccard: card ejected from slot %d\n", skt->sock);
socket_shutdown(skt);
cs_socket_put(skt);
}
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 39d096b5292..7f8219f3fd9 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -544,6 +544,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
list_add_tail(&p_dev->socket_device_list, &s->devices_list);
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ printk(KERN_NOTICE "pcmcia: registering new device %s\n",
+ p_dev->devname);
+
pcmcia_device_query(p_dev);
if (device_register(&p_dev->dev)) {
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 4ddd76239b3..4d56bc9926d 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -1339,10 +1339,7 @@ static struct device_driver i82365_driver = {
.resume = pcmcia_socket_dev_resume,
};
-static struct platform_device i82365_device = {
- .name = "i82365",
- .id = 0,
-};
+static struct platform_device *i82365_device;
static int __init init_i82365(void)
{
@@ -1352,7 +1349,14 @@ static int __init init_i82365(void)
if (ret)
return ret;
- ret = platform_device_register(&i82365_device);
+ i82365_device = platform_device_alloc("i82365", 0);
+ if (i82365_device) {
+ ret = platform_device_add(i82365_device);
+ if (ret)
+ platform_device_put(i82365_device);
+ } else
+ ret = -ENOMEM;
+
if (ret) {
driver_unregister(&i82365_driver);
return ret;
@@ -1365,7 +1369,7 @@ static int __init init_i82365(void)
if (sockets == 0) {
printk("not found.\n");
- platform_device_unregister(&i82365_device);
+ platform_device_unregister(i82365_device);
release_region(i365_base, 2);
driver_unregister(&i82365_driver);
return -ENODEV;
@@ -1377,7 +1381,7 @@ static int __init init_i82365(void)
/* register sockets with the pcmcia core */
for (i = 0; i < sockets; i++) {
- socket[i].socket.dev.dev = &i82365_device.dev;
+ socket[i].socket.dev.dev = &i82365_device->dev;
socket[i].socket.ops = &pcic_operations;
socket[i].socket.resource_ops = &pccard_nonstatic_ops;
socket[i].socket.owner = THIS_MODULE;
@@ -1415,7 +1419,7 @@ static void __exit exit_i82365(void)
if (socket[i].flags & IS_REGISTERED)
pcmcia_unregister_socket(&socket[i].socket);
}
- platform_device_unregister(&i82365_device);
+ platform_device_unregister(i82365_device);
if (poll_interval != 0)
del_timer_sync(&poll_timer);
if (grab_irq != 0)
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 2efb317153c..67e9afa000c 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -34,6 +34,7 @@
#include <linux/keyboard.h>
#include <linux/init.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@@ -1343,7 +1344,7 @@ static void show_serial_version(void)
printk("MC68328 serial driver version 1.00\n");
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
/* Serial Power management
* The console (currently fixed at line 0) is a special case for power
* management because the kernel is so chatty. The console will be
@@ -1393,7 +1394,7 @@ void startup_console(void)
struct m68k_serial *info = &m68k_soft[0];
startup(info);
}
-#endif
+#endif /* CONFIG_PM_LEGACY */
static struct tty_operations rs_ops = {
@@ -1486,7 +1487,7 @@ rs68328_init(void)
IRQ_FLG_STD,
"M68328_UART", NULL))
panic("Unable to attach 68328 serial interrupt\n");
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
serial_pm[i] = pm_register(PM_SYS_DEV, PM_SYS_COM, serial_pm_callback);
if (serial_pm[i])
serial_pm[i]->data = info;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 3742753241e..e08510d09ff 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -999,7 +999,10 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
serial_outp(up, UART_MCR, save_mcr);
serial8250_clear_fifos(up);
(void)serial_in(up, UART_RX);
- serial_outp(up, UART_IER, 0);
+ if (up->capabilities & UART_CAP_UUE)
+ serial_outp(up, UART_IER, UART_IER_UUE);
+ else
+ serial_outp(up, UART_IER, 0);
out:
spin_unlock_irqrestore(&up->port.lock, flags);
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 5d8660a42b7..b79ed0665d5 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -323,6 +323,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "USR9180", 0 },
/* U.S. Robotics 56K Voice INT PnP*/
{ "USR9190", 0 },
+ /* HP Compaq Tablet PC tc1100 Wacom tablet */
+ { "WACF005", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
{ "WCI0003", 0 },
/* Unkown PnP modems */
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 25825f2aba2..987d22b53c2 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -7,7 +7,7 @@
* Based on ppc8xx.c by Thomas Gleixner
* Based on drivers/serial/amba.c by Russell King
*
- * Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
+ * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 4b0786e7eb7..d789ee55cbb 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -3,7 +3,7 @@
*
* Driver for CPM (SCC/SMC) serial ports; CPM1 definitions
*
- * Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
+ * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index 15ad58d9488..fd9e53ed3fe 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -3,7 +3,7 @@
*
* Driver for CPM (SCC/SMC) serial ports; CPM2 definitions
*
- * Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2)
+ * Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
* Pantelis Antoniou (panto@intracom.gr) (CPM1)
*
* Copyright (C) 2004 Freescale Semiconductor, Inc.
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index e63b9dffc8d..4d8516d1bb7 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -1,9 +1,9 @@
/*
- * dz.c: Serial port driver for DECStations equiped
+ * dz.c: Serial port driver for DECStations equiped
* with the DZ chipset.
*
- * Copyright (C) 1998 Olivier A. D. Lebaillif
- *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif
+ *
* Email: olivier.lebaillif@ifrsys.com
*
* [31-AUG-98] triemer
@@ -11,14 +11,14 @@
* removed base_addr code - moving address assignment to setup.c
* Changed name of dz_init to rs_init to be consistent with tc code
* [13-NOV-98] triemer fixed code to receive characters
- * after patches by harald to irq code.
+ * after patches by harald to irq code.
* [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
* field from "current" - somewhere between 2.1.121 and 2.1.131
Qua Jun 27 15:02:26 BRT 2001
* [27-JUN-2001] Arnaldo Carvalho de Melo <acme@conectiva.com.br> - cleanups
- *
- * Parts (C) 1999 David Airlie, airlied@linux.ie
- * [07-SEP-99] Bugfixes
+ *
+ * Parts (C) 1999 David Airlie, airlied@linux.ie
+ * [07-SEP-99] Bugfixes
*
* [06-Jan-2002] Russell King <rmk@arm.linux.org.uk>
* Converted to new serial core
@@ -64,7 +64,7 @@ static struct dz_port dz_ports[DZ_NB_PORT];
#ifdef DEBUG_DZ
/*
- * debugging code to send out chars via prom
+ * debugging code to send out chars via prom
*/
static void debug_console(const char *s, int count)
{
@@ -82,7 +82,7 @@ static void debug_console(const char *s, int count)
* ------------------------------------------------------------
* dz_in () and dz_out ()
*
- * These routines are used to access the registers of the DZ
+ * These routines are used to access the registers of the DZ
* chip, hiding relocation differences between implementation.
* ------------------------------------------------------------
*/
@@ -106,8 +106,8 @@ static inline void dz_out(struct dz_port *dport, unsigned offset,
* ------------------------------------------------------------
* rs_stop () and rs_start ()
*
- * These routines are called before setting or resetting
- * tty->stopped. They enable or disable transmitter interrupts,
+ * These routines are called before setting or resetting
+ * tty->stopped. They enable or disable transmitter interrupts,
* as necessary.
* ------------------------------------------------------------
*/
@@ -156,17 +156,17 @@ static void dz_enable_ms(struct uart_port *port)
/*
* ------------------------------------------------------------
- * Here starts the interrupt handling routines. All of the
- * following subroutines are declared as inline and are folded
- * into dz_interrupt. They were separated out for readability's
- * sake.
+ * Here starts the interrupt handling routines. All of the
+ * following subroutines are declared as inline and are folded
+ * into dz_interrupt. They were separated out for readability's
+ * sake.
*
* Note: rs_interrupt() is a "fast" interrupt, which means that it
* runs with interrupts turned off. People who may want to modify
* rs_interrupt() should try to keep the interrupt handler as fast as
* possible. After you are done making modifications, it is not a bad
* idea to do:
- *
+ *
* make drivers/serial/dz.s
*
* and look at the resulting assemble code in dz.s.
@@ -403,7 +403,7 @@ static void dz_set_mctrl(struct uart_port *uport, unsigned int mctrl)
* startup ()
*
* various initialization tasks
- * -------------------------------------------------------------------
+ * -------------------------------------------------------------------
*/
static int dz_startup(struct uart_port *uport)
{
@@ -430,13 +430,13 @@ static int dz_startup(struct uart_port *uport)
return 0;
}
-/*
+/*
* -------------------------------------------------------------------
* shutdown ()
*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
- * -------------------------------------------------------------------
+ * -------------------------------------------------------------------
*/
static void dz_shutdown(struct uart_port *uport)
{
@@ -451,7 +451,7 @@ static void dz_shutdown(struct uart_port *uport)
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
+ * allows an RS485 driver to be written in user space.
*/
static unsigned int dz_tx_empty(struct uart_port *uport)
{
@@ -645,9 +645,9 @@ static void __init dz_init_ports(void)
if (mips_machtype == MACH_DS23100 ||
mips_machtype == MACH_DS5100)
- base = (unsigned long) KN01_DZ11_BASE;
+ base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_DZ11);
else
- base = (unsigned long) KN02_DZ11_BASE;
+ base = CKSEG1ADDR(KN02_SLOT_BASE + KN02_DZ11);
for (i = 0, dport = dz_ports; i < DZ_NB_PORT; i++, dport++) {
spin_lock_init(&dport->port.lock);
@@ -695,13 +695,13 @@ static void dz_console_put_char(struct dz_port *dport, unsigned char ch)
spin_unlock_irqrestore(&dport->port.lock, flags);
}
-/*
+/*
* -------------------------------------------------------------------
* dz_console_print ()
*
* dz_console_print is registered for printk.
* The console must be locked when we get here.
- * -------------------------------------------------------------------
+ * -------------------------------------------------------------------
*/
static void dz_console_print(struct console *cons,
const char *str,
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 5d3cb848644..b8727d9bf69 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -725,7 +725,7 @@ mpc52xx_uart_probe(struct platform_device *dev)
int i, idx, ret;
/* Check validity & presence */
- idx = pdev->id;
+ idx = dev->id;
if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
return -EINVAL;
@@ -748,7 +748,7 @@ mpc52xx_uart_probe(struct platform_device *dev)
port->ops = &mpc52xx_uart_ops;
/* Search for IRQ and mapbase */
- for (i=0 ; i<pdev->num_resources ; i++, res++) {
+ for (i=0 ; i<dev->num_resources ; i++, res++) {
if (res->flags & IORESOURCE_MEM)
port->mapbase = res->start;
else if (res->flags & IORESOURCE_IRQ)
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index fd9deee20e0..0e3daf6d7b5 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -156,7 +156,7 @@ static void sa1100_stop_tx(struct uart_port *port)
}
/*
- * interrupts may not be disabled on entry
+ * port locked and interrupts disabled
*/
static void sa1100_start_tx(struct uart_port *port)
{
@@ -164,11 +164,9 @@ static void sa1100_start_tx(struct uart_port *port)
unsigned long flags;
u32 utcr3;
- spin_lock_irqsave(&sport->port.lock, flags);
utcr3 = UART_GET_UTCR3(sport);
sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS);
UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE);
- spin_unlock_irqrestore(&sport->port.lock, flags);
}
/*
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 427a2385807..2331296e1e1 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -209,33 +209,45 @@ static void uart_shutdown(struct uart_state *state)
struct uart_info *info = state->info;
struct uart_port *port = state->port;
- if (!(info->flags & UIF_INITIALIZED))
- return;
-
/*
- * Turn off DTR and RTS early.
+ * Set the TTY IO error marker
*/
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
- uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
- /*
- * clear delta_msr_wait queue to avoid mem leaks: we may free
- * the irq here so the queue might never be woken up. Note
- * that we won't end up waiting on delta_msr_wait again since
- * any outstanding file descriptors should be pointing at
- * hung_up_tty_fops now.
- */
- wake_up_interruptible(&info->delta_msr_wait);
+ if (info->flags & UIF_INITIALIZED) {
+ info->flags &= ~UIF_INITIALIZED;
- /*
- * Free the IRQ and disable the port.
- */
- port->ops->shutdown(port);
+ /*
+ * Turn off DTR and RTS early.
+ */
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free
+ * the irq here so the queue might never be woken up. Note
+ * that we won't end up waiting on delta_msr_wait again since
+ * any outstanding file descriptors should be pointing at
+ * hung_up_tty_fops now.
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ /*
+ * Free the IRQ and disable the port.
+ */
+ port->ops->shutdown(port);
+
+ /*
+ * Ensure that the IRQ handler isn't running on another CPU.
+ */
+ synchronize_irq(port->irq);
+ }
/*
- * Ensure that the IRQ handler isn't running on another CPU.
+ * kill off our tasklet
*/
- synchronize_irq(port->irq);
+ tasklet_kill(&info->tlet);
/*
* Free the transmit buffer page.
@@ -244,15 +256,6 @@ static void uart_shutdown(struct uart_state *state)
free_page((unsigned long)info->xmit.buf);
info->xmit.buf = NULL;
}
-
- /*
- * kill off our tasklet
- */
- tasklet_kill(&info->tlet);
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- info->flags &= ~UIF_INITIALIZED;
}
/**
@@ -1928,14 +1931,25 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
if (state->info && state->info->flags & UIF_INITIALIZED) {
struct uart_ops *ops = port->ops;
+ int ret;
ops->set_mctrl(port, 0);
- ops->startup(port);
- uart_change_speed(state, NULL);
- spin_lock_irq(&port->lock);
- ops->set_mctrl(port, port->mctrl);
- ops->start_tx(port);
- spin_unlock_irq(&port->lock);
+ ret = ops->startup(port);
+ if (ret == 0) {
+ uart_change_speed(state, NULL);
+ spin_lock_irq(&port->lock);
+ ops->set_mctrl(port, port->mctrl);
+ ops->start_tx(port);
+ spin_unlock_irq(&port->lock);
+ } else {
+ /*
+ * Failed to resume - maybe hardware went away?
+ * Clear the "initialized" flag so we won't try
+ * to call the low level drivers shutdown method.
+ */
+ state->info->flags &= ~UIF_INITIALIZED;
+ uart_shutdown(state);
+ }
}
up(&state->sem);
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index e7802ffe549..bcea87c3cc0 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -106,8 +106,7 @@ enum {
FBCON_LOGO_DONTSHOW = -3 /* do not show the logo */
};
-struct display fb_display[MAX_NR_CONSOLES];
-EXPORT_SYMBOL(fb_display);
+static struct display fb_display[MAX_NR_CONSOLES];
static signed char con2fb_map[MAX_NR_CONSOLES];
static signed char con2fb_map_boot[MAX_NR_CONSOLES];
@@ -653,13 +652,12 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
{
struct fbcon_ops *ops = info->fbcon_par;
+ ops->p = (p) ? p : &fb_display[vc->vc_num];
+
if ((info->flags & FBINFO_MISC_TILEBLITTING))
fbcon_set_tileops(vc, info, p, ops);
else {
- struct display *disp;
-
- disp = (p) ? p : &fb_display[vc->vc_num];
- fbcon_set_rotation(info, disp);
+ fbcon_set_rotation(info, ops->p);
fbcon_set_bitops(ops);
}
}
@@ -668,11 +666,10 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info,
struct display *p)
{
struct fbcon_ops *ops = info->fbcon_par;
- struct display *disp;
info->flags &= ~FBINFO_MISC_TILEBLITTING;
- disp = (p) ? p : &fb_display[vc->vc_num];
- fbcon_set_rotation(info, disp);
+ ops->p = (p) ? p : &fb_display[vc->vc_num];
+ fbcon_set_rotation(info, ops->p);
fbcon_set_bitops(ops);
}
#endif /* CONFIG_MISC_TILEBLITTING */
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index accfd7bd8e9..6892e7ff34d 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -52,8 +52,6 @@ struct display {
struct fb_videomode *mode;
};
-extern struct display fb_display[];
-
struct fbcon_ops {
void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int dy, int dx, int height, int width);
@@ -73,6 +71,7 @@ struct fbcon_ops {
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
struct timer_list cursor_timer; /* Cursor timer */
struct fb_cursor cursor_state;
+ struct display *p;
int currcon; /* Current VC. */
int cursor_flash;
int cursor_reset;
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
index 680aabab73c..3afd1eeb1ad 100644
--- a/drivers/video/console/fbcon_ccw.c
+++ b/drivers/video/console/fbcon_ccw.c
@@ -63,9 +63,9 @@ static inline void ccw_update_attr(u8 *dst, u8 *src, int attribute,
static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int dy, int dx, int height, int width)
{
- struct display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
struct fb_copyarea area;
- u32 vyres = GETVYRES(p->scrollmode, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
area.sx = sy * vc->vc_font.height;
area.sy = vyres - ((sx + width) * vc->vc_font.width);
@@ -80,10 +80,10 @@ static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width)
{
- struct display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- u32 vyres = GETVYRES(p->scrollmode, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
region.color = attr_bgcol_ec(bgshift,vc);
region.dx = sy * vc->vc_font.height;
@@ -131,7 +131,6 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
int fg, int bg)
{
struct fb_image image;
- struct display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par;
u32 width = (vc->vc_font.height + 7)/8;
u32 cellsize = width * vc->vc_font.width;
@@ -141,7 +140,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
u32 cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
u8 *dst, *buf = NULL;
- u32 vyres = GETVYRES(p->scrollmode, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
if (!ops->fontbuffer)
return;
@@ -397,9 +396,8 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info,
int ccw_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
- struct display *p = &fb_display[ops->currcon];
u32 yoffset;
- u32 vyres = GETVYRES(p->scrollmode, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
int err;
yoffset = (vyres - info->var.yres) - ops->var.xoffset;
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
index 6c6f3b6dd17..6d92b845620 100644
--- a/drivers/video/console/fbcon_cw.c
+++ b/drivers/video/console/fbcon_cw.c
@@ -49,9 +49,9 @@ static inline void cw_update_attr(u8 *dst, u8 *src, int attribute,
static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int dy, int dx, int height, int width)
{
- struct display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
struct fb_copyarea area;
- u32 vxres = GETVXRES(p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
area.sx = vxres - ((sy + height) * vc->vc_font.height);
area.sy = sx * vc->vc_font.width;
@@ -66,10 +66,10 @@ static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width)
{
- struct display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- u32 vxres = GETVXRES(p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
region.color = attr_bgcol_ec(bgshift,vc);
region.dx = vxres - ((sy + height) * vc->vc_font.height);
@@ -117,7 +117,6 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
int fg, int bg)
{
struct fb_image image;
- struct display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par;
u32 width = (vc->vc_font.height + 7)/8;
u32 cellsize = width * vc->vc_font.width;
@@ -127,7 +126,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
u32 cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
u8 *dst, *buf = NULL;
- u32 vxres = GETVXRES(p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
if (!ops->fontbuffer)
return;
@@ -381,8 +380,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info,
int cw_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
- struct display *p = &fb_display[ops->currcon];
- u32 vxres = GETVXRES(p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
u32 xoffset;
int err;
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
index 2e1d9d4249c..c4d7c89212b 100644
--- a/drivers/video/console/fbcon_ud.c
+++ b/drivers/video/console/fbcon_ud.c
@@ -48,10 +48,10 @@ static inline void ud_update_attr(u8 *dst, u8 *src, int attribute,
static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int dy, int dx, int height, int width)
{
- struct display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
struct fb_copyarea area;
- u32 vyres = GETVYRES(p->scrollmode, info);
- u32 vxres = GETVXRES(p->scrollmode, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
area.sy = vyres - ((sy + height) * vc->vc_font.height);
area.sx = vxres - ((sx + width) * vc->vc_font.width);
@@ -66,11 +66,11 @@ static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width)
{
- struct display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- u32 vyres = GETVYRES(p->scrollmode, info);
- u32 vxres = GETVXRES(p->scrollmode, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
region.color = attr_bgcol_ec(bgshift,vc);
region.dy = vyres - ((sy + height) * vc->vc_font.height);
@@ -153,7 +153,6 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
int fg, int bg)
{
struct fb_image image;
- struct display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par;
u32 width = (vc->vc_font.width + 7)/8;
u32 cellsize = width * vc->vc_font.height;
@@ -163,8 +162,8 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
u8 *dst, *buf = NULL;
- u32 vyres = GETVYRES(p->scrollmode, info);
- u32 vxres = GETVXRES(p->scrollmode, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
if (!ops->fontbuffer)
return;
@@ -421,10 +420,9 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info,
int ud_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
- struct display *p = &fb_display[ops->currcon];
u32 xoffset, yoffset;
- u32 vyres = GETVYRES(p->scrollmode, info);
- u32 vxres = GETVXRES(p->scrollmode, info);
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
int err;
xoffset = (vxres - info->var.xres) - ops->var.xoffset;
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index f60b1f43227..3353103e8b0 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -42,7 +42,7 @@ int nvidia_probe_i2c_connector(struct fb_info *info, int conn,
#define nvidia_probe_i2c_connector(p, c, edid) (-1)
#endif
-#ifdef CONFIG_FB_OF
+#ifdef CONFIG_PPC_OF
int nvidia_probe_of_connector(struct fb_info *info, int conn,
u8 ** out_edid);
#else
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 0b40a2a721c..bee09c6e48f 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -1301,7 +1301,7 @@ static int nvidiafb_pan_display(struct fb_var_screeninfo *var,
struct nvidia_par *par = info->par;
u32 total;
- total = info->var.yoffset * info->fix.line_length + info->var.xoffset;
+ total = var->yoffset * info->fix.line_length + var->xoffset;
NVSetStartAddress(par, total);
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 2c3aa2fcfd9..3e58ddc2bc3 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -413,6 +413,7 @@ static int __init vesafb_probe(struct platform_device *dev)
* region already (FIXME) */
request_region(0x3c0, 32, "vesafb");
+#ifdef CONFIG_MTRR
if (mtrr) {
unsigned int temp_size = size_total;
unsigned int type = 0;
@@ -450,6 +451,7 @@ static int __init vesafb_probe(struct platform_device *dev)
} while (temp_size >= PAGE_SIZE && rc == -EINVAL);
}
}
+#endif
info->fbops = &vesafb_ops;
info->var = vesafb_defined;
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index daa46051f55..f6e24ee85f0 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -514,7 +514,7 @@ int __init w100fb_probe(struct platform_device *pdev)
if (remapped_fbuf == NULL)
goto out;
- info=framebuffer_alloc(sizeof(struct w100fb_par), dev);
+ info=framebuffer_alloc(sizeof(struct w100fb_par), &pdev->dev);
if (!info) {
err = -ENOMEM;
goto out;
diff --git a/fs/aio.c b/fs/aio.c
index 20bb919eb19..5a28b69ad22 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -457,6 +457,8 @@ static inline struct kiocb *aio_get_req(struct kioctx *ctx)
static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
{
+ assert_spin_locked(&ctx->ctx_lock);
+
if (req->ki_dtor)
req->ki_dtor(req);
kmem_cache_free(kiocb_cachep, req);
@@ -498,6 +500,8 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
dprintk(KERN_DEBUG "aio_put(%p): f_count=%d\n",
req, atomic_read(&req->ki_filp->f_count));
+ assert_spin_locked(&ctx->ctx_lock);
+
req->ki_users --;
if (unlikely(req->ki_users < 0))
BUG();
@@ -619,14 +623,13 @@ static void unuse_mm(struct mm_struct *mm)
* the kiocb (to tell the caller to activate the work
* queue to process it), or 0, if it found that it was
* already queued.
- *
- * Should be called with the spin lock iocb->ki_ctx->ctx_lock
- * held
*/
static inline int __queue_kicked_iocb(struct kiocb *iocb)
{
struct kioctx *ctx = iocb->ki_ctx;
+ assert_spin_locked(&ctx->ctx_lock);
+
if (list_empty(&iocb->ki_run_list)) {
list_add_tail(&iocb->ki_run_list,
&ctx->run_list);
@@ -771,13 +774,15 @@ out:
* Process all pending retries queued on the ioctx
* run list.
* Assumes it is operating within the aio issuer's mm
- * context. Expects to be called with ctx->ctx_lock held
+ * context.
*/
static int __aio_run_iocbs(struct kioctx *ctx)
{
struct kiocb *iocb;
LIST_HEAD(run_list);
+ assert_spin_locked(&ctx->ctx_lock);
+
list_splice_init(&ctx->run_list, &run_list);
while (!list_empty(&run_list)) {
iocb = list_entry(run_list.next, struct kiocb,
@@ -937,28 +942,19 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2)
unsigned long tail;
int ret;
- /* Special case handling for sync iocbs: events go directly
- * into the iocb for fast handling. Note that this will not
- * work if we allow sync kiocbs to be cancelled. in which
- * case the usage count checks will have to move under ctx_lock
- * for all cases.
+ /*
+ * Special case handling for sync iocbs:
+ * - events go directly into the iocb for fast handling
+ * - the sync task with the iocb in its stack holds the single iocb
+ * ref, no other paths have a way to get another ref
+ * - the sync task helpfully left a reference to itself in the iocb
*/
if (is_sync_kiocb(iocb)) {
- int ret;
-
+ BUG_ON(iocb->ki_users != 1);
iocb->ki_user_data = res;
- if (iocb->ki_users == 1) {
- iocb->ki_users = 0;
- ret = 1;
- } else {
- spin_lock_irq(&ctx->ctx_lock);
- iocb->ki_users--;
- ret = (0 == iocb->ki_users);
- spin_unlock_irq(&ctx->ctx_lock);
- }
- /* sync iocbs put the task here for us */
+ iocb->ki_users = 0;
wake_up_process(iocb->ki_obj.tsk);
- return ret;
+ return 1;
}
info = &ctx->ring_info;
@@ -1613,12 +1609,14 @@ asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr,
/* lookup_kiocb
* Finds a given iocb for cancellation.
- * MUST be called with ctx->ctx_lock held.
*/
static struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb,
u32 key)
{
struct list_head *pos;
+
+ assert_spin_locked(&ctx->ctx_lock);
+
/* TODO: use a hash or array, this sucks. */
list_for_each(pos, &ctx->active_reqs) {
struct kiocb *kiocb = list_kiocb(pos);
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index e4ed4b31a43..522fa70dd8e 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -881,7 +881,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
}
if (EXT2_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL))
ext2_warning(sb, __FUNCTION__,
- "mounting ext3 filesystem as ext2\n");
+ "mounting ext3 filesystem as ext2");
ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
percpu_counter_mod(&sbi->s_freeblocks_counter,
ext2_count_free_blocks(sb));
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 5d9b00e2883..8824e84f8a5 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1384,8 +1384,10 @@ static int ext3_journalled_writepage(struct page *page,
ClearPageChecked(page);
ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
ext3_get_block);
- if (ret != 0)
+ if (ret != 0) {
+ ext3_journal_stop(handle);
goto out_unlock;
+ }
ret = walk_page_buffers(handle, page_buffers(page), 0,
PAGE_CACHE_SIZE, NULL, do_journal_get_write_access);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index d2fa42006d8..9ab97cef0da 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -195,7 +195,7 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
static int show_map(struct seq_file *m, void *v)
{
- return show_map_internal(m, v, 0);
+ return show_map_internal(m, v, NULL);
}
static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h
index 20ac3d95ecd..36505bb4e8c 100644
--- a/include/asm-alpha/atomic.h
+++ b/include/asm-alpha/atomic.h
@@ -177,6 +177,18 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
return result;
}
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#define atomic_dec_return(v) atomic_sub_return(1,(v))
#define atomic64_dec_return(v) atomic64_sub_return(1,(v))
diff --git a/include/asm-arm/arch-pxa/akita.h b/include/asm-arm/arch-pxa/akita.h
index 4a1fbcfccc3..5d8cc1d9cb1 100644
--- a/include/asm-arm/arch-pxa/akita.h
+++ b/include/asm-arm/arch-pxa/akita.h
@@ -25,6 +25,8 @@
/* Default Values */
#define AKITA_IOEXP_IO_OUT (AKITA_IOEXP_IR_ON | AKITA_IOEXP_AKIN_PULLUP)
+extern struct platform_device akitaioexp_device;
+
void akita_set_ioexp(struct device *dev, unsigned char bitmask);
void akita_reset_ioexp(struct device *dev, unsigned char bitmask);
diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h
index 2885972b085..75b80271972 100644
--- a/include/asm-arm/atomic.h
+++ b/include/asm-arm/atomic.h
@@ -80,6 +80,23 @@ static inline int atomic_sub_return(int i, atomic_t *v)
return result;
}
+static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new)
+{
+ u32 oldval, res;
+
+ do {
+ __asm__ __volatile__("@ atomic_cmpxchg\n"
+ "ldrex %1, [%2]\n"
+ "teq %1, %3\n"
+ "strexeq %0, %4, [%2]\n"
+ : "=&r" (res), "=&r" (oldval)
+ : "r" (&ptr->counter), "Ir" (old), "r" (new)
+ : "cc");
+ } while (res);
+
+ return oldval;
+}
+
static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
{
unsigned long tmp, tmp2;
@@ -131,6 +148,20 @@ static inline int atomic_sub_return(int i, atomic_t *v)
return val;
}
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ local_irq_restore(flags);
+
+ return ret;
+}
+
static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
{
unsigned long flags;
@@ -142,6 +173,17 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
#endif /* __LINUX_ARM_ARCH__ */
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+
+ c = atomic_read(v);
+ while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
+ c = old;
+ return c != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#define atomic_add(i, v) (void) atomic_add_return(i, v)
#define atomic_inc(v) (void) atomic_add_return(1, v)
#define atomic_sub(i, v) (void) atomic_sub_return(i, v)
diff --git a/include/asm-arm26/atomic.h b/include/asm-arm26/atomic.h
index 4a88235c0e7..a47cadc5968 100644
--- a/include/asm-arm26/atomic.h
+++ b/include/asm-arm26/atomic.h
@@ -62,6 +62,35 @@ static inline int atomic_sub_return(int i, atomic_t *v)
return val;
}
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (ret != u)
+ v->counter += a;
+ local_irq_restore(flags);
+
+ return ret != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
{
unsigned long flags;
diff --git a/include/asm-cris/atomic.h b/include/asm-cris/atomic.h
index 8c2e7830452..683b05a57d8 100644
--- a/include/asm-cris/atomic.h
+++ b/include/asm-cris/atomic.h
@@ -123,6 +123,33 @@ static inline int atomic_inc_and_test(volatile atomic_t *v)
return retval;
}
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ unsigned long flags;
+
+ cris_atomic_save(v, flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ cris_atomic_restore(v, flags);
+ return ret;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int ret;
+ unsigned long flags;
+
+ cris_atomic_save(v, flags);
+ ret = v->counter;
+ if (ret != u)
+ v->counter += a;
+ cris_atomic_restore(v, flags);
+ return ret != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
/* Atomic operations are already serializing */
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
diff --git a/include/asm-frv/atomic.h b/include/asm-frv/atomic.h
index e7596846342..f6539ff569c 100644
--- a/include/asm-frv/atomic.h
+++ b/include/asm-frv/atomic.h
@@ -414,4 +414,16 @@ extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
#endif
+#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#endif /* _ASM_ATOMIC_H */
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 886dbd11689..0b49f9e070f 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -13,5 +13,6 @@ extern char _eextratext[] __attribute__((weak));
extern char _end[];
extern char __per_cpu_start[], __per_cpu_end[];
extern char __kprobes_text_start[], __kprobes_text_end[];
+extern char __initdata_begin[], __initdata_end[];
#endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/include/asm-h8300/atomic.h b/include/asm-h8300/atomic.h
index 7230f650799..f23d86819ea 100644
--- a/include/asm-h8300/atomic.h
+++ b/include/asm-h8300/atomic.h
@@ -82,6 +82,33 @@ static __inline__ int atomic_dec_and_test(atomic_t *v)
return ret == 0;
}
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ local_irq_restore(flags);
+ return ret;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (ret != u)
+ v->counter += a;
+ local_irq_restore(flags);
+ return ret != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
static __inline__ void atomic_clear_mask(unsigned long mask, unsigned long *v)
{
__asm__ __volatile__("stc ccr,r1l\n\t"
diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h
index 509720be772..c68557aa04b 100644
--- a/include/asm-i386/atomic.h
+++ b/include/asm-i386/atomic.h
@@ -215,6 +215,27 @@ static __inline__ int atomic_sub_return(int i, atomic_t *v)
return atomic_add_return(-i,v);
}
+#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#define atomic_inc_return(v) (atomic_add_return(1,v))
#define atomic_dec_return(v) (atomic_sub_return(1,v))
diff --git a/include/asm-i386/mach-default/mach_reboot.h b/include/asm-i386/mach-default/mach_reboot.h
index 06ae4d81ba6..a955e57ad01 100644
--- a/include/asm-i386/mach-default/mach_reboot.h
+++ b/include/asm-i386/mach-default/mach_reboot.h
@@ -19,7 +19,7 @@ static inline void kb_wait(void)
static inline void mach_reboot(void)
{
int i;
- for (i = 0; i < 100; i++) {
+ for (i = 0; i < 10; i++) {
kb_wait();
udelay(50);
outb(0x60, 0x64); /* write Controller Command Byte */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 8c02b031870..5c96cf6dcb3 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -65,7 +65,9 @@ struct cpuinfo_x86 {
int f00f_bug;
int coma_bug;
unsigned long loops_per_jiffy;
- unsigned char x86_num_cores;
+ unsigned char x86_max_cores; /* cpuid returned max cores value */
+ unsigned char booted_cores; /* number of cores as seen by OS */
+ unsigned char apicid;
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
#define X86_VENDOR_INTEL 0
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index 97d52ac49e4..772f85da120 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -263,6 +263,10 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
#ifdef CONFIG_X86_CMPXCHG
#define __HAVE_ARCH_CMPXCHG 1
+#define cmpxchg(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
+#endif
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long new, int size)
@@ -291,10 +295,42 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
return old;
}
-#define cmpxchg(ptr,o,n)\
- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
- (unsigned long)(n),sizeof(*(ptr))))
+#ifndef CONFIG_X86_CMPXCHG
+/*
+ * Building a kernel capable running on 80386. It may be necessary to
+ * simulate the cmpxchg on the 80386 CPU. For that purpose we define
+ * a function for each of the sizes we support.
+ */
+extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
+extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
+extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
+
+static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
+ unsigned long new, int size)
+{
+ switch (size) {
+ case 1:
+ return cmpxchg_386_u8(ptr, old, new);
+ case 2:
+ return cmpxchg_386_u16(ptr, old, new);
+ case 4:
+ return cmpxchg_386_u32(ptr, old, new);
+ }
+ return old;
+}
+
+#define cmpxchg(ptr,o,n) \
+({ \
+ __typeof__(*(ptr)) __ret; \
+ if (likely(boot_cpu_data.x86 > 3)) \
+ __ret = __cmpxchg((ptr), (unsigned long)(o), \
+ (unsigned long)(n), sizeof(*(ptr))); \
+ else \
+ __ret = cmpxchg_386((ptr), (unsigned long)(o), \
+ (unsigned long)(n), sizeof(*(ptr))); \
+ __ret; \
+})
#endif
#ifdef CONFIG_X86_CMPXCHG64
diff --git a/include/asm-ia64/atomic.h b/include/asm-ia64/atomic.h
index 874a6f890e7..2fbebf85c31 100644
--- a/include/asm-ia64/atomic.h
+++ b/include/asm-ia64/atomic.h
@@ -88,6 +88,18 @@ ia64_atomic64_sub (__s64 i, atomic64_t *v)
return new;
}
+#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#define atomic_add_return(i,v) \
({ \
int __ia64_aar_i = (i); \
diff --git a/include/asm-m68k/atomic.h b/include/asm-m68k/atomic.h
index 38f3043e7fe..e3c962eeabf 100644
--- a/include/asm-m68k/atomic.h
+++ b/include/asm-m68k/atomic.h
@@ -139,6 +139,18 @@ static inline void atomic_set_mask(unsigned long mask, unsigned long *v)
__asm__ __volatile__("orl %1,%0" : "+m" (*v) : "id" (mask));
}
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
/* Atomic operations are already serializing */
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
diff --git a/include/asm-m68k/processor.h b/include/asm-m68k/processor.h
index df1575db32a..7982285e84e 100644
--- a/include/asm-m68k/processor.h
+++ b/include/asm-m68k/processor.h
@@ -14,6 +14,7 @@
#define current_text_addr() ({ __label__ _l; _l: &&_l;})
#include <linux/config.h>
+#include <linux/thread_info.h>
#include <asm/segment.h>
#include <asm/fpu.h>
#include <asm/ptrace.h>
@@ -55,17 +56,6 @@ static inline void wrusp(unsigned long usp)
#endif
#define TASK_UNMAPPED_ALIGN(addr, off) PAGE_ALIGN(addr)
-struct task_work {
- unsigned char sigpending;
- unsigned char notify_resume; /* request for notification on
- userspace execution resumption */
- char need_resched;
- unsigned char delayed_trace; /* single step a syscall */
- unsigned char syscall_trace; /* count of syscall interceptors */
- unsigned char memdie; /* task was selected to be killed */
- unsigned char pad[2];
-};
-
struct thread_struct {
unsigned long ksp; /* kernel stack pointer */
unsigned long usp; /* user stack pointer */
@@ -78,7 +68,7 @@ struct thread_struct {
unsigned long fp[8*3];
unsigned long fpcntl[3]; /* fp control regs */
unsigned char fpstate[FPSTATESIZE]; /* floating point state */
- struct task_work work;
+ struct thread_info info;
};
#define INIT_THREAD { \
diff --git a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h
index 2aed24f6fd2..9532ca3c45c 100644
--- a/include/asm-m68k/thread_info.h
+++ b/include/asm-m68k/thread_info.h
@@ -2,17 +2,15 @@
#define _ASM_M68K_THREAD_INFO_H
#include <asm/types.h>
-#include <asm/processor.h>
#include <asm/page.h>
struct thread_info {
struct task_struct *task; /* main task structure */
+ unsigned long flags;
struct exec_domain *exec_domain; /* execution domain */
int preempt_count; /* 0 => preemptable, <0 => BUG */
__u32 cpu; /* should always be 0 on m68k */
struct restart_block restart_block;
-
- __u8 supervisor_stack[0];
};
#define PREEMPT_ACTIVE 0x4000000
@@ -35,84 +33,29 @@ struct thread_info {
#define free_thread_info(ti) free_pages((unsigned long)(ti),1)
#endif /* PAGE_SHIFT == 13 */
-//#define init_thread_info (init_task.thread.info)
+#define init_thread_info (init_task.thread.info)
#define init_stack (init_thread_union.stack)
-#define current_thread_info() (current->thread_info)
-
+#define task_thread_info(tsk) (&(tsk)->thread.info)
+#define current_thread_info() task_thread_info(current)
#define __HAVE_THREAD_FUNCTIONS
-#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
-#define TIF_DELAYED_TRACE 1 /* single step a syscall */
-#define TIF_NOTIFY_RESUME 2 /* resumption notification requested */
-#define TIF_SIGPENDING 3 /* signal pending */
-#define TIF_NEED_RESCHED 4 /* rescheduling necessary */
-#define TIF_MEMDIE 5
-
-extern int thread_flag_fixme(void);
-
-/*
- * flag set/clear/test wrappers
- * - pass TIF_xxxx constants to these functions
- */
-
-#define __set_tsk_thread_flag(tsk, flag, val) ({ \
- switch (flag) { \
- case TIF_SIGPENDING: \
- tsk->thread.work.sigpending = val; \
- break; \
- case TIF_NEED_RESCHED: \
- tsk->thread.work.need_resched = val; \
- break; \
- case TIF_SYSCALL_TRACE: \
- tsk->thread.work.syscall_trace = val; \
- break; \
- case TIF_MEMDIE: \
- tsk->thread.work.memdie = val; \
- break; \
- default: \
- thread_flag_fixme(); \
- } \
+#define setup_thread_stack(p, org) ({ \
+ *(struct task_struct **)(p)->thread_info = (p); \
+ task_thread_info(p)->task = (p); \
})
-#define __get_tsk_thread_flag(tsk, flag) ({ \
- int ___res; \
- switch (flag) { \
- case TIF_SIGPENDING: \
- ___res = tsk->thread.work.sigpending; \
- break; \
- case TIF_NEED_RESCHED: \
- ___res = tsk->thread.work.need_resched; \
- break; \
- case TIF_SYSCALL_TRACE: \
- ___res = tsk->thread.work.syscall_trace;\
- break; \
- case TIF_MEMDIE: \
- ___res = tsk->thread.work.memdie;\
- break; \
- default: \
- ___res = thread_flag_fixme(); \
- } \
- ___res; \
-})
-
-#define __get_set_tsk_thread_flag(tsk, flag, val) ({ \
- int __res = __get_tsk_thread_flag(tsk, flag); \
- __set_tsk_thread_flag(tsk, flag, val); \
- __res; \
-})
+#define end_of_stack(p) ((unsigned long *)(p)->thread_info + 1)
-#define set_tsk_thread_flag(tsk, flag) __set_tsk_thread_flag(tsk, flag, ~0)
-#define clear_tsk_thread_flag(tsk, flag) __set_tsk_thread_flag(tsk, flag, 0)
-#define test_and_set_tsk_thread_flag(tsk, flag) __get_set_tsk_thread_flag(tsk, flag, ~0)
-#define test_tsk_thread_flag(tsk, flag) __get_tsk_thread_flag(tsk, flag)
-
-#define set_thread_flag(flag) set_tsk_thread_flag(current, flag)
-#define clear_thread_flag(flag) clear_tsk_thread_flag(current, flag)
-#define test_thread_flag(flag) test_tsk_thread_flag(current, flag)
-
-#define set_need_resched() set_thread_flag(TIF_NEED_RESCHED)
-#define clear_need_resched() clear_thread_flag(TIF_NEED_RESCHED)
+/* entry.S relies on these definitions!
+ * bits 0-7 are tested at every exception exit
+ * bits 8-15 are also tested at syscall exit
+ */
+#define TIF_SIGPENDING 6 /* signal pending */
+#define TIF_NEED_RESCHED 7 /* rescheduling necessary */
+#define TIF_DELAYED_TRACE 14 /* single step a syscall */
+#define TIF_SYSCALL_TRACE 15 /* syscall trace active */
+#define TIF_MEMDIE 16
#endif /* _ASM_M68K_THREAD_INFO_H */
diff --git a/include/asm-m68knommu/atomic.h b/include/asm-m68knommu/atomic.h
index a83631ed8c8..3c1cc153c41 100644
--- a/include/asm-m68knommu/atomic.h
+++ b/include/asm-m68knommu/atomic.h
@@ -128,6 +128,18 @@ static inline int atomic_sub_return(int i, atomic_t * v)
return temp;
}
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#define atomic_dec_return(v) atomic_sub_return(1,(v))
#define atomic_inc_return(v) atomic_add_return(1,(v))
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index 6202eb8a14b..2c87b41e69b 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -287,6 +287,27 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
return result;
}
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#define atomic_dec_return(v) atomic_sub_return(1,(v))
#define atomic_inc_return(v) atomic_add_return(1,(v))
diff --git a/include/asm-parisc/atomic.h b/include/asm-parisc/atomic.h
index 048a2c7fd0c..983e9a2b604 100644
--- a/include/asm-parisc/atomic.h
+++ b/include/asm-parisc/atomic.h
@@ -164,6 +164,26 @@ static __inline__ int atomic_read(const atomic_t *v)
}
/* exported interface */
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
#define atomic_add(i,v) ((void)(__atomic_add_return( ((int)i),(v))))
#define atomic_sub(i,v) ((void)(__atomic_add_return(-((int)i),(v))))
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h
index 9c0b372a46e..ec4b1446895 100644
--- a/include/asm-powerpc/atomic.h
+++ b/include/asm-powerpc/atomic.h
@@ -164,6 +164,33 @@ static __inline__ int atomic_dec_return(atomic_t *v)
return t;
}
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ for (;;) { \
+ if (unlikely(c == (u))) \
+ break; \
+ old = atomic_cmpxchg((v), c, c + (a)); \
+ if (likely(old == c)) \
+ break; \
+ c = old; \
+ } \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0)
#define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0)
diff --git a/include/asm-ppc64/btext.h b/include/asm-powerpc/btext.h
index 71cce36bc63..71cce36bc63 100644
--- a/include/asm-ppc64/btext.h
+++ b/include/asm-powerpc/btext.h
diff --git a/include/asm-ppc64/delay.h b/include/asm-powerpc/delay.h
index 05f198cf73d..1492aa9ab71 100644
--- a/include/asm-ppc64/delay.h
+++ b/include/asm-powerpc/delay.h
@@ -1,5 +1,5 @@
-#ifndef _PPC64_DELAY_H
-#define _PPC64_DELAY_H
+#ifndef _ASM_POWERPC_DELAY_H
+#define _ASM_POWERPC_DELAY_H
/*
* Copyright 1996, Paul Mackerras.
@@ -15,10 +15,17 @@
extern unsigned long tb_ticks_per_usec;
-/* define these here to prevent circular dependencies */
+#ifdef CONFIG_PPC64
+/* define these here to prevent circular dependencies */
+/* these instructions control the thread priority on multi-threaded cpus */
#define __HMT_low() asm volatile("or 1,1,1")
#define __HMT_medium() asm volatile("or 2,2,2")
-#define __barrier() asm volatile("":::"memory")
+#else
+#define __HMT_low()
+#define __HMT_medium()
+#endif
+
+#define __barrier() asm volatile("" ::: "memory")
static inline unsigned long __get_tb(void)
{
@@ -32,7 +39,7 @@ static inline void __delay(unsigned long loops)
{
unsigned long start = __get_tb();
- while((__get_tb()-start) < loops)
+ while((__get_tb() - start) < loops)
__HMT_low();
__HMT_medium();
__barrier();
@@ -45,4 +52,4 @@ static inline void udelay(unsigned long usecs)
__delay(loops);
}
-#endif /* _PPC64_DELAY_H */
+#endif /* _ASM_POWERPC_DELAY_H */
diff --git a/include/asm-ppc64/eeh.h b/include/asm-powerpc/eeh.h
index 89f26ab3190..89f26ab3190 100644
--- a/include/asm-ppc64/eeh.h
+++ b/include/asm-powerpc/eeh.h
diff --git a/include/asm-ppc64/floppy.h b/include/asm-powerpc/floppy.h
index 5c497b588e5..64276a3f615 100644
--- a/include/asm-ppc64/floppy.h
+++ b/include/asm-powerpc/floppy.h
@@ -7,22 +7,22 @@
*
* Copyright (C) 1995
*/
-#ifndef __ASM_PPC64_FLOPPY_H
-#define __ASM_PPC64_FLOPPY_H
+#ifndef __ASM_POWERPC_FLOPPY_H
+#define __ASM_POWERPC_FLOPPY_H
#include <linux/config.h>
#include <asm/machdep.h>
-#define fd_inb(port) inb_p(port)
-#define fd_outb(value,port) outb_p(value,port)
+#define fd_inb(port) inb_p(port)
+#define fd_outb(value,port) outb_p(value,port)
#define fd_enable_dma() enable_dma(FLOPPY_DMA)
#define fd_disable_dma() disable_dma(FLOPPY_DMA)
-#define fd_request_dma() request_dma(FLOPPY_DMA,"floppy")
+#define fd_request_dma() request_dma(FLOPPY_DMA, "floppy")
#define fd_free_dma() free_dma(FLOPPY_DMA)
#define fd_clear_dma_ff() clear_dma_ff(FLOPPY_DMA)
-#define fd_set_dma_mode(mode) set_dma_mode(FLOPPY_DMA,mode)
-#define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA,count)
+#define fd_set_dma_mode(mode) set_dma_mode(FLOPPY_DMA, mode)
+#define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA, count)
#define fd_enable_irq() enable_irq(FLOPPY_IRQ)
#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
#define fd_cacheflush(addr,size) /* nothing */
@@ -35,10 +35,10 @@
#include <linux/pci.h>
-#define fd_dma_setup(addr,size,mode,io) ppc64_fd_dma_setup(addr,size,mode,io)
+#define fd_dma_setup(addr,size,mode,io) powerpc_fd_dma_setup(addr,size,mode,io)
-static __inline__ int
-ppc64_fd_dma_setup(char *addr, unsigned long size, int mode, int io)
+static __inline__ int powerpc_fd_dma_setup(char *addr, unsigned long size,
+ int mode, int io)
{
static unsigned long prev_size;
static dma_addr_t bus_addr = 0;
@@ -55,9 +55,8 @@ ppc64_fd_dma_setup(char *addr, unsigned long size, int mode, int io)
bus_addr = 0;
}
- if (!bus_addr) /* need to map it */ {
+ if (!bus_addr) /* need to map it */
bus_addr = pci_map_single(NULL, addr, size, dir);
- }
/* remember this one as prev */
prev_addr = addr;
@@ -103,4 +102,4 @@ static int FDC2 = -1;
#define EXTRA_FLOPPY_PARAMS
-#endif /* __ASM_PPC64_FLOPPY_H */
+#endif /* __ASM_POWERPC_FLOPPY_H */
diff --git a/include/asm-ppc64/hvconsole.h b/include/asm-powerpc/hvconsole.h
index 6da93ce74dc..6da93ce74dc 100644
--- a/include/asm-ppc64/hvconsole.h
+++ b/include/asm-powerpc/hvconsole.h
diff --git a/include/asm-ppc64/hvcserver.h b/include/asm-powerpc/hvcserver.h
index aecba966579..aecba966579 100644
--- a/include/asm-ppc64/hvcserver.h
+++ b/include/asm-powerpc/hvcserver.h
diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h
index 062ab9ba68e..c72ffc709ea 100644
--- a/include/asm-powerpc/kexec.h
+++ b/include/asm-powerpc/kexec.h
@@ -40,6 +40,7 @@ extern note_buf_t crash_notes[];
#ifdef __powerpc64__
extern void kexec_smp_wait(void); /* get and clear naca physid, wait for
master to copy new code to 0 */
+extern void __init kexec_setup(void);
#else
struct kimage;
extern void machine_kexec_simple(struct kimage *image);
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 5670f0cd614..c011abb8b60 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -93,7 +93,9 @@ struct machdep_calls {
void (*init_IRQ)(void);
int (*get_irq)(struct pt_regs *);
- void (*cpu_irq_down)(int secondary);
+#ifdef CONFIG_KEXEC
+ void (*kexec_cpu_down)(int crash_shutdown, int secondary);
+#endif
/* PCI stuff */
/* Called after scanning the bus, before allocating resources */
diff --git a/include/asm-ppc64/nvram.h b/include/asm-powerpc/nvram.h
index def47d720d3..24bd8c2388e 100644
--- a/include/asm-ppc64/nvram.h
+++ b/include/asm-powerpc/nvram.h
@@ -1,6 +1,5 @@
/*
- * PreP compliant NVRAM access
- * This needs to be updated for PPC64
+ * NVRAM definitions and access functions.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -8,8 +7,8 @@
* 2 of the License, or (at your option) any later version.
*/
-#ifndef _PPC64_NVRAM_H
-#define _PPC64_NVRAM_H
+#ifndef _ASM_POWERPC_NVRAM_H
+#define _ASM_POWERPC_NVRAM_H
#define NVRW_CNT 0x20
#define NVRAM_HEADER_LEN 16 /* sizeof(struct nvram_header) */
@@ -69,7 +68,6 @@ extern int nvram_clear_error_log(void);
extern struct nvram_partition *nvram_find_partition(int sig, const char *name);
extern int pSeries_nvram_init(void);
-extern int pmac_nvram_init(void);
extern int mmio_nvram_init(void);
/* PowerMac specific nvram stuffs */
@@ -88,7 +86,11 @@ extern u8 pmac_xpram_read(int xpaddr);
extern void pmac_xpram_write(int xpaddr, u8 data);
/* Synchronize NVRAM */
-extern int nvram_sync(void);
+extern void nvram_sync(void);
+
+/* Normal access to NVRAM */
+extern unsigned char nvram_read_byte(int i);
+extern void nvram_write_byte(unsigned char c, int i);
/* Some offsets in XPRAM */
#define PMAC_XPRAM_MACHINE_LOC 0xe4
@@ -112,5 +114,6 @@ struct pmac_machine_location {
_IOWR('p', 0x40, int)
#define IOC_NVRAM_GET_OFFSET _IOWR('p', 0x42, int) /* Get NVRAM partition offset */
+#define IOC_NVRAM_SYNC _IO('p', 0x43) /* Sync NVRAM image */
-#endif /* _PPC64_NVRAM_H */
+#endif /* _ASM_POWERPC_NVRAM_H */
diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h
new file mode 100644
index 00000000000..18c1e5ee81a
--- /dev/null
+++ b/include/asm-powerpc/page.h
@@ -0,0 +1,179 @@
+#ifndef _ASM_POWERPC_PAGE_H
+#define _ASM_POWERPC_PAGE_H
+
+/*
+ * Copyright (C) 2001,2005 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.
+ */
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <asm/asm-compat.h>
+
+/*
+ * On PPC32 page size is 4K. For PPC64 we support either 4K or 64K software
+ * page size. When using 64K pages however, whether we are really supporting
+ * 64K pages in HW or not is irrelevant to those definitions.
+ */
+#ifdef CONFIG_PPC_64K_PAGES
+#define PAGE_SHIFT 16
+#else
+#define PAGE_SHIFT 12
+#endif
+
+#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT)
+
+/* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
+#define __HAVE_ARCH_GATE_AREA 1
+
+/*
+ * Subtle: (1 << PAGE_SHIFT) is an int, not an unsigned long. So if we
+ * assign PAGE_MASK to a larger type it gets extended the way we want
+ * (i.e. with 1s in the high bits)
+ */
+#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1))
+
+#define PAGE_OFFSET ASM_CONST(CONFIG_KERNEL_START)
+#define KERNELBASE PAGE_OFFSET
+
+#ifdef CONFIG_DISCONTIGMEM
+#define page_to_pfn(page) discontigmem_page_to_pfn(page)
+#define pfn_to_page(pfn) discontigmem_pfn_to_page(pfn)
+#define pfn_valid(pfn) discontigmem_pfn_valid(pfn)
+#endif
+
+#ifdef CONFIG_FLATMEM
+#define pfn_to_page(pfn) (mem_map + (pfn))
+#define page_to_pfn(page) ((unsigned long)((page) - mem_map))
+#define pfn_valid(pfn) ((pfn) < max_mapnr)
+#endif
+
+#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
+#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+
+#define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
+#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET)
+
+/*
+ * Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
+ * and needs to be executable. This means the whole heap ends
+ * up being executable.
+ */
+#define VM_DATA_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#define VM_DATA_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#ifdef __powerpc64__
+#include <asm/page_64.h>
+#else
+#include <asm/page_32.h>
+#endif
+
+/* align addr on a size boundary - adjust address up/down if needed */
+#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1)))
+
+/* align addr on a size boundary - adjust address up if needed */
+#define _ALIGN(addr,size) _ALIGN_UP(addr,size)
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
+
+#ifndef __ASSEMBLY__
+
+#undef STRICT_MM_TYPECHECKS
+
+#ifdef STRICT_MM_TYPECHECKS
+/* These are used to make use of C type-checking. */
+
+/* PTE level */
+typedef struct { pte_basic_t pte; } pte_t;
+#define pte_val(x) ((x).pte)
+#define __pte(x) ((pte_t) { (x) })
+
+/* 64k pages additionally define a bigger "real PTE" type that gathers
+ * the "second half" part of the PTE for pseudo 64k pages
+ */
+#ifdef CONFIG_PPC_64K_PAGES
+typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
+#else
+typedef struct { pte_t pte; } real_pte_t;
+#endif
+
+/* PMD level */
+typedef struct { unsigned long pmd; } pmd_t;
+#define pmd_val(x) ((x).pmd)
+#define __pmd(x) ((pmd_t) { (x) })
+
+/* PUD level exusts only on 4k pages */
+#ifndef CONFIG_PPC_64K_PAGES
+typedef struct { unsigned long pud; } pud_t;
+#define pud_val(x) ((x).pud)
+#define __pud(x) ((pud_t) { (x) })
+#endif
+
+/* PGD level */
+typedef struct { unsigned long pgd; } pgd_t;
+#define pgd_val(x) ((x).pgd)
+#define __pgd(x) ((pgd_t) { (x) })
+
+/* Page protection bits */
+typedef struct { unsigned long pgprot; } pgprot_t;
+#define pgprot_val(x) ((x).pgprot)
+#define __pgprot(x) ((pgprot_t) { (x) })
+
+#else
+
+/*
+ * .. while these make it easier on the compiler
+ */
+
+typedef pte_basic_t pte_t;
+#define pte_val(x) (x)
+#define __pte(x) (x)
+
+#ifdef CONFIG_PPC_64K_PAGES
+typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
+#else
+typedef unsigned long real_pte_t;
+#endif
+
+
+typedef unsigned long pmd_t;
+#define pmd_val(x) (x)
+#define __pmd(x) (x)
+
+#ifndef CONFIG_PPC_64K_PAGES
+typedef unsigned long pud_t;
+#define pud_val(x) (x)
+#define __pud(x) (x)
+#endif
+
+typedef unsigned long pgd_t;
+#define pgd_val(x) (x)
+#define pgprot_val(x) (x)
+
+typedef unsigned long pgprot_t;
+#define __pgd(x) (x)
+#define __pgprot(x) (x)
+
+#endif
+
+struct page;
+extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
+extern void copy_user_page(void *to, void *from, unsigned long vaddr,
+ struct page *p);
+extern int page_is_ram(unsigned long pfn);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_POWERPC_PAGE_H */
diff --git a/include/asm-powerpc/page_32.h b/include/asm-powerpc/page_32.h
new file mode 100644
index 00000000000..7259cfd85da
--- /dev/null
+++ b/include/asm-powerpc/page_32.h
@@ -0,0 +1,40 @@
+#ifndef _ASM_POWERPC_PAGE_32_H
+#define _ASM_POWERPC_PAGE_32_H
+
+#define VM_DATA_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS32
+
+#define PPC_MEMSTART 0
+
+#ifndef __ASSEMBLY__
+/*
+ * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
+ * physical addressing. For now this just the IBM PPC440.
+ */
+#ifdef CONFIG_PTE_64BIT
+typedef unsigned long long pte_basic_t;
+#define PTE_SHIFT (PAGE_SHIFT - 3) /* 512 ptes per page */
+#define PTE_FMT "%16Lx"
+#else
+typedef unsigned long pte_basic_t;
+#define PTE_SHIFT (PAGE_SHIFT - 2) /* 1024 ptes per page */
+#define PTE_FMT "%.8lx"
+#endif
+
+struct page;
+extern void clear_pages(void *page, int order);
+static inline void clear_page(void *page) { clear_pages(page, 0); }
+extern void copy_page(void *to, void *from);
+
+/* Pure 2^n version of get_order */
+extern __inline__ int get_order(unsigned long size)
+{
+ int lz;
+
+ size = (size-1) >> PAGE_SHIFT;
+ asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size));
+ return 32 - lz;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_PAGE_32_H */
diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h
new file mode 100644
index 00000000000..c16f106b537
--- /dev/null
+++ b/include/asm-powerpc/page_64.h
@@ -0,0 +1,174 @@
+#ifndef _ASM_POWERPC_PAGE_64_H
+#define _ASM_POWERPC_PAGE_64_H
+
+/*
+ * Copyright (C) 2001 PPC64 Team, 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.
+ */
+
+/*
+ * We always define HW_PAGE_SHIFT to 12 as use of 64K pages remains Linux
+ * specific, every notion of page number shared with the firmware, TCEs,
+ * iommu, etc... still uses a page size of 4K.
+ */
+#define HW_PAGE_SHIFT 12
+#define HW_PAGE_SIZE (ASM_CONST(1) << HW_PAGE_SHIFT)
+#define HW_PAGE_MASK (~(HW_PAGE_SIZE-1))
+
+/*
+ * PAGE_FACTOR is the number of bits factor between PAGE_SHIFT and
+ * HW_PAGE_SHIFT, that is 4K pages.
+ */
+#define PAGE_FACTOR (PAGE_SHIFT - HW_PAGE_SHIFT)
+
+#define REGION_SIZE 4UL
+#define REGION_SHIFT 60UL
+#define REGION_MASK (((1UL<<REGION_SIZE)-1UL)<<REGION_SHIFT)
+
+#define VMALLOCBASE ASM_CONST(0xD000000000000000)
+#define VMALLOC_REGION_ID (VMALLOCBASE >> REGION_SHIFT)
+#define KERNEL_REGION_ID (KERNELBASE >> REGION_SHIFT)
+#define USER_REGION_ID (0UL)
+#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT)
+
+/* Segment size */
+#define SID_SHIFT 28
+#define SID_MASK 0xfffffffffUL
+#define ESID_MASK 0xfffffffff0000000UL
+#define GET_ESID(x) (((x) >> SID_SHIFT) & SID_MASK)
+
+#ifndef __ASSEMBLY__
+#include <asm/cache.h>
+
+typedef unsigned long pte_basic_t;
+
+static __inline__ void clear_page(void *addr)
+{
+ unsigned long lines, line_size;
+
+ line_size = ppc64_caches.dline_size;
+ lines = ppc64_caches.dlines_per_page;
+
+ __asm__ __volatile__(
+ "mtctr %1 # clear_page\n\
+1: dcbz 0,%0\n\
+ add %0,%0,%3\n\
+ bdnz+ 1b"
+ : "=r" (addr)
+ : "r" (lines), "0" (addr), "r" (line_size)
+ : "ctr", "memory");
+}
+
+extern void copy_4K_page(void *to, void *from);
+
+#ifdef CONFIG_PPC_64K_PAGES
+static inline void copy_page(void *to, void *from)
+{
+ unsigned int i;
+ for (i=0; i < (1 << (PAGE_SHIFT - 12)); i++) {
+ copy_4K_page(to, from);
+ to += 4096;
+ from += 4096;
+ }
+}
+#else /* CONFIG_PPC_64K_PAGES */
+static inline void copy_page(void *to, void *from)
+{
+ copy_4K_page(to, from);
+}
+#endif /* CONFIG_PPC_64K_PAGES */
+
+/* Log 2 of page table size */
+extern u64 ppc64_pft_size;
+
+/* Large pages size */
+extern unsigned int HPAGE_SHIFT;
+#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
+#define HPAGE_MASK (~(HPAGE_SIZE - 1))
+#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
+
+#endif /* __ASSEMBLY__ */
+
+#ifdef CONFIG_HUGETLB_PAGE
+
+#define HTLB_AREA_SHIFT 40
+#define HTLB_AREA_SIZE (1UL << HTLB_AREA_SHIFT)
+#define GET_HTLB_AREA(x) ((x) >> HTLB_AREA_SHIFT)
+
+#define LOW_ESID_MASK(addr, len) (((1U << (GET_ESID(addr+len-1)+1)) \
+ - (1U << GET_ESID(addr))) & 0xffff)
+#define HTLB_AREA_MASK(addr, len) (((1U << (GET_HTLB_AREA(addr+len-1)+1)) \
+ - (1U << GET_HTLB_AREA(addr))) & 0xffff)
+
+#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
+#define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
+#define ARCH_HAS_SETCLEAR_HUGE_PTE
+
+#define touches_hugepage_low_range(mm, addr, len) \
+ (LOW_ESID_MASK((addr), (len)) & (mm)->context.low_htlb_areas)
+#define touches_hugepage_high_range(mm, addr, len) \
+ (HTLB_AREA_MASK((addr), (len)) & (mm)->context.high_htlb_areas)
+
+#define __within_hugepage_low_range(addr, len, segmask) \
+ ((LOW_ESID_MASK((addr), (len)) | (segmask)) == (segmask))
+#define within_hugepage_low_range(addr, len) \
+ __within_hugepage_low_range((addr), (len), \
+ current->mm->context.low_htlb_areas)
+#define __within_hugepage_high_range(addr, len, zonemask) \
+ ((HTLB_AREA_MASK((addr), (len)) | (zonemask)) == (zonemask))
+#define within_hugepage_high_range(addr, len) \
+ __within_hugepage_high_range((addr), (len), \
+ current->mm->context.high_htlb_areas)
+
+#define is_hugepage_only_range(mm, addr, len) \
+ (touches_hugepage_high_range((mm), (addr), (len)) || \
+ touches_hugepage_low_range((mm), (addr), (len)))
+#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+
+#define in_hugepage_area(context, addr) \
+ (cpu_has_feature(CPU_FTR_16M_PAGE) && \
+ ( ((1 << GET_HTLB_AREA(addr)) & (context).high_htlb_areas) || \
+ ( ((addr) < 0x100000000L) && \
+ ((1 << GET_ESID(addr)) & (context).low_htlb_areas) ) ) )
+
+#else /* !CONFIG_HUGETLB_PAGE */
+
+#define in_hugepage_area(mm, addr) 0
+
+#endif /* !CONFIG_HUGETLB_PAGE */
+
+#ifdef MODULE
+#define __page_aligned __attribute__((__aligned__(PAGE_SIZE)))
+#else
+#define __page_aligned \
+ __attribute__((__aligned__(PAGE_SIZE), \
+ __section__(".data.page_aligned")))
+#endif
+
+#define VM_DATA_DEFAULT_FLAGS \
+ (test_thread_flag(TIF_32BIT) ? \
+ VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64)
+
+/*
+ * This is the default if a program doesn't have a PT_GNU_STACK
+ * program header entry. The PPC64 ELF ABI has a non executable stack
+ * stack by default, so in the absense of a PT_GNU_STACK program header
+ * we turn execute permission off.
+ */
+#define VM_STACK_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#define VM_STACK_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#define VM_STACK_DEFAULT_FLAGS \
+ (test_thread_flag(TIF_32BIT) ? \
+ VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
+
+#include <asm-generic/page.h>
+
+#endif /* _ASM_POWERPC_PAGE_64_H */
diff --git a/include/asm-ppc64/serial.h b/include/asm-powerpc/serial.h
index d6bcb79b7d7..b273d630b32 100644
--- a/include/asm-ppc64/serial.h
+++ b/include/asm-powerpc/serial.h
@@ -1,21 +1,16 @@
/*
- * include/asm-ppc64/serial.h
- */
-#ifndef _PPC64_SERIAL_H
-#define _PPC64_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#ifndef _ASM_POWERPC_SERIAL_H
+#define _ASM_POWERPC_SERIAL_H
+
+/*
+ * Serial ports are not listed here, because they are discovered
+ * through the device tree.
+ */
/* Default baud base if not found in device-tree */
#define BASE_BAUD ( 1843200 / 16 )
diff --git a/include/asm-powerpc/vdso_datapage.h b/include/asm-powerpc/vdso_datapage.h
index fc323b51366..411832d5bbd 100644
--- a/include/asm-powerpc/vdso_datapage.h
+++ b/include/asm-powerpc/vdso_datapage.h
@@ -73,7 +73,7 @@ struct vdso_data {
/* those additional ones don't have to be located anywhere
* special as they were not part of the original systemcfg
*/
- __s64 wtom_clock_sec; /* Wall to monotonic clock */
+ __s32 wtom_clock_sec; /* Wall to monotonic clock */
__s32 wtom_clock_nsec;
__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls */
__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
diff --git a/include/asm-ppc/immap_85xx.h b/include/asm-ppc/immap_85xx.h
index 50fb5e47094..9383d0c13ff 100644
--- a/include/asm-ppc/immap_85xx.h
+++ b/include/asm-ppc/immap_85xx.h
@@ -3,7 +3,7 @@
*
* MPC85xx Internal Memory Map
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor, Inc
*
diff --git a/include/asm-ppc/ipic.h b/include/asm-ppc/ipic.h
index 9092b920997..0fe396a2b66 100644
--- a/include/asm-ppc/ipic.h
+++ b/include/asm-ppc/ipic.h
@@ -3,7 +3,7 @@
*
* IPIC external definitions and structure.
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor, Inc
*
diff --git a/include/asm-ppc/mpc83xx.h b/include/asm-ppc/mpc83xx.h
index ce212201db2..7cdf60fa69b 100644
--- a/include/asm-ppc/mpc83xx.h
+++ b/include/asm-ppc/mpc83xx.h
@@ -3,7 +3,7 @@
*
* MPC83xx definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor, Inc
*
diff --git a/include/asm-ppc/mpc85xx.h b/include/asm-ppc/mpc85xx.h
index d98db980cd4..9d14baea3d7 100644
--- a/include/asm-ppc/mpc85xx.h
+++ b/include/asm-ppc/mpc85xx.h
@@ -3,7 +3,7 @@
*
* MPC85xx definitions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor, Inc
*
diff --git a/include/asm-ppc/nvram.h b/include/asm-ppc/nvram.h
deleted file mode 100644
index 31ef16e3fc4..00000000000
--- a/include/asm-ppc/nvram.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * PreP compliant NVRAM access
- */
-
-#ifdef __KERNEL__
-#ifndef _PPC_NVRAM_H
-#define _PPC_NVRAM_H
-
-#define NVRAM_AS0 0x74
-#define NVRAM_AS1 0x75
-#define NVRAM_DATA 0x77
-
-
-/* RTC Offsets */
-
-#define MOTO_RTC_SECONDS 0x1FF9
-#define MOTO_RTC_MINUTES 0x1FFA
-#define MOTO_RTC_HOURS 0x1FFB
-#define MOTO_RTC_DAY_OF_WEEK 0x1FFC
-#define MOTO_RTC_DAY_OF_MONTH 0x1FFD
-#define MOTO_RTC_MONTH 0x1FFE
-#define MOTO_RTC_YEAR 0x1FFF
-#define MOTO_RTC_CONTROLA 0x1FF8
-#define MOTO_RTC_CONTROLB 0x1FF9
-
-/* PowerMac specific nvram stuffs */
-
-enum {
- pmac_nvram_OF, /* Open Firmware partition */
- pmac_nvram_XPRAM, /* MacOS XPRAM partition */
- pmac_nvram_NR /* MacOS Name Registry partition */
-};
-
-/* Return partition offset in nvram */
-extern int pmac_get_partition(int partition);
-
-/* Direct access to XPRAM on PowerMacs */
-extern u8 pmac_xpram_read(int xpaddr);
-extern void pmac_xpram_write(int xpaddr, u8 data);
-
-/* Synchronize NVRAM */
-extern void nvram_sync(void);
-
-/* Normal access to NVRAM */
-extern unsigned char nvram_read_byte(int i);
-extern void nvram_write_byte(unsigned char c, int i);
-
-/* Some offsets in XPRAM */
-#define PMAC_XPRAM_MACHINE_LOC 0xe4
-#define PMAC_XPRAM_SOUND_VOLUME 0x08
-
-/* Machine location structure in PowerMac XPRAM */
-struct pmac_machine_location {
- unsigned int latitude; /* 2+30 bit Fractional number */
- unsigned int longitude; /* 2+30 bit Fractional number */
- unsigned int delta; /* mix of GMT delta and DLS */
-};
-
-/*
- * /dev/nvram ioctls
- *
- * Note that PMAC_NVRAM_GET_OFFSET is still supported, but is
- * definitely obsolete. Do not use it if you can avoid it
- */
-
-#define OBSOLETE_PMAC_NVRAM_GET_OFFSET \
- _IOWR('p', 0x40, int)
-
-#define IOC_NVRAM_GET_OFFSET _IOWR('p', 0x42, int) /* Get NVRAM partition offset */
-#define IOC_NVRAM_SYNC _IO('p', 0x43) /* Sync NVRAM image */
-
-#endif
-#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h
index bba5305c29e..83d8c77c124 100644
--- a/include/asm-ppc/ppc_sys.h
+++ b/include/asm-ppc/ppc_sys.h
@@ -3,7 +3,7 @@
*
* PPC system definitions and library functions
*
- * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2005 Freescale Semiconductor, Inc
*
diff --git a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
deleted file mode 100644
index 3efc3288f7e..00000000000
--- a/include/asm-ppc64/page.h
+++ /dev/null
@@ -1,328 +0,0 @@
-#ifndef _PPC64_PAGE_H
-#define _PPC64_PAGE_H
-
-/*
- * Copyright (C) 2001 PPC64 Team, 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/config.h>
-#include <asm/asm-compat.h>
-
-/*
- * We support either 4k or 64k software page size. When using 64k pages
- * however, wether we are really supporting 64k pages in HW or not is
- * irrelevant to those definitions. We always define HW_PAGE_SHIFT to 12
- * as use of 64k pages remains a linux kernel specific, every notion of
- * page number shared with the firmware, TCEs, iommu, etc... still assumes
- * a page size of 4096.
- */
-#ifdef CONFIG_PPC_64K_PAGES
-#define PAGE_SHIFT 16
-#else
-#define PAGE_SHIFT 12
-#endif
-
-#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE-1))
-
-/* HW_PAGE_SHIFT is always 4k pages */
-#define HW_PAGE_SHIFT 12
-#define HW_PAGE_SIZE (ASM_CONST(1) << HW_PAGE_SHIFT)
-#define HW_PAGE_MASK (~(HW_PAGE_SIZE-1))
-
-/* PAGE_FACTOR is the number of bits factor between PAGE_SHIFT and
- * HW_PAGE_SHIFT, that is 4k pages
- */
-#define PAGE_FACTOR (PAGE_SHIFT - HW_PAGE_SHIFT)
-
-/* Segment size */
-#define SID_SHIFT 28
-#define SID_MASK 0xfffffffffUL
-#define ESID_MASK 0xfffffffff0000000UL
-#define GET_ESID(x) (((x) >> SID_SHIFT) & SID_MASK)
-
-/* Large pages size */
-
-#ifndef __ASSEMBLY__
-extern unsigned int HPAGE_SHIFT;
-#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
-#define HPAGE_MASK (~(HPAGE_SIZE - 1))
-#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
-#endif /* __ASSEMBLY__ */
-
-#ifdef CONFIG_HUGETLB_PAGE
-
-
-#define HTLB_AREA_SHIFT 40
-#define HTLB_AREA_SIZE (1UL << HTLB_AREA_SHIFT)
-#define GET_HTLB_AREA(x) ((x) >> HTLB_AREA_SHIFT)
-
-#define LOW_ESID_MASK(addr, len) (((1U << (GET_ESID(addr+len-1)+1)) \
- - (1U << GET_ESID(addr))) & 0xffff)
-#define HTLB_AREA_MASK(addr, len) (((1U << (GET_HTLB_AREA(addr+len-1)+1)) \
- - (1U << GET_HTLB_AREA(addr))) & 0xffff)
-
-#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
-#define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
-#define ARCH_HAS_SETCLEAR_HUGE_PTE
-
-#define touches_hugepage_low_range(mm, addr, len) \
- (LOW_ESID_MASK((addr), (len)) & (mm)->context.low_htlb_areas)
-#define touches_hugepage_high_range(mm, addr, len) \
- (HTLB_AREA_MASK((addr), (len)) & (mm)->context.high_htlb_areas)
-
-#define __within_hugepage_low_range(addr, len, segmask) \
- ((LOW_ESID_MASK((addr), (len)) | (segmask)) == (segmask))
-#define within_hugepage_low_range(addr, len) \
- __within_hugepage_low_range((addr), (len), \
- current->mm->context.low_htlb_areas)
-#define __within_hugepage_high_range(addr, len, zonemask) \
- ((HTLB_AREA_MASK((addr), (len)) | (zonemask)) == (zonemask))
-#define within_hugepage_high_range(addr, len) \
- __within_hugepage_high_range((addr), (len), \
- current->mm->context.high_htlb_areas)
-
-#define is_hugepage_only_range(mm, addr, len) \
- (touches_hugepage_high_range((mm), (addr), (len)) || \
- touches_hugepage_low_range((mm), (addr), (len)))
-#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
-
-#define in_hugepage_area(context, addr) \
- (cpu_has_feature(CPU_FTR_16M_PAGE) && \
- ( ((1 << GET_HTLB_AREA(addr)) & (context).high_htlb_areas) || \
- ( ((addr) < 0x100000000L) && \
- ((1 << GET_ESID(addr)) & (context).low_htlb_areas) ) ) )
-
-#else /* !CONFIG_HUGETLB_PAGE */
-
-#define in_hugepage_area(mm, addr) 0
-
-#endif /* !CONFIG_HUGETLB_PAGE */
-
-/* align addr on a size boundary - adjust address up/down if needed */
-#define _ALIGN_UP(addr,size) (((addr)+((size)-1))&(~((size)-1)))
-#define _ALIGN_DOWN(addr,size) ((addr)&(~((size)-1)))
-
-/* align addr on a size boundary - adjust address up if needed */
-#define _ALIGN(addr,size) _ALIGN_UP(addr,size)
-
-/* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE)
-
-#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
-#include <asm/cache.h>
-
-#undef STRICT_MM_TYPECHECKS
-
-#define REGION_SIZE 4UL
-#define REGION_SHIFT 60UL
-#define REGION_MASK (((1UL<<REGION_SIZE)-1UL)<<REGION_SHIFT)
-
-static __inline__ void clear_page(void *addr)
-{
- unsigned long lines, line_size;
-
- line_size = ppc64_caches.dline_size;
- lines = ppc64_caches.dlines_per_page;
-
- __asm__ __volatile__(
- "mtctr %1 # clear_page\n\
-1: dcbz 0,%0\n\
- add %0,%0,%3\n\
- bdnz+ 1b"
- : "=r" (addr)
- : "r" (lines), "0" (addr), "r" (line_size)
- : "ctr", "memory");
-}
-
-extern void copy_4K_page(void *to, void *from);
-
-#ifdef CONFIG_PPC_64K_PAGES
-static inline void copy_page(void *to, void *from)
-{
- unsigned int i;
- for (i=0; i < (1 << (PAGE_SHIFT - 12)); i++) {
- copy_4K_page(to, from);
- to += 4096;
- from += 4096;
- }
-}
-#else /* CONFIG_PPC_64K_PAGES */
-static inline void copy_page(void *to, void *from)
-{
- copy_4K_page(to, from);
-}
-#endif /* CONFIG_PPC_64K_PAGES */
-
-struct page;
-extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
-extern void copy_user_page(void *to, void *from, unsigned long vaddr, struct page *p);
-
-#ifdef STRICT_MM_TYPECHECKS
-/*
- * These are used to make use of C type-checking.
- * Entries in the pte table are 64b, while entries in the pgd & pmd are 32b.
- */
-
-/* PTE level */
-typedef struct { unsigned long pte; } pte_t;
-#define pte_val(x) ((x).pte)
-#define __pte(x) ((pte_t) { (x) })
-
-/* 64k pages additionally define a bigger "real PTE" type that gathers
- * the "second half" part of the PTE for pseudo 64k pages
- */
-#ifdef CONFIG_PPC_64K_PAGES
-typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
-#else
-typedef struct { pte_t pte; } real_pte_t;
-#endif
-
-/* PMD level */
-typedef struct { unsigned long pmd; } pmd_t;
-#define pmd_val(x) ((x).pmd)
-#define __pmd(x) ((pmd_t) { (x) })
-
-/* PUD level exusts only on 4k pages */
-#ifndef CONFIG_PPC_64K_PAGES
-typedef struct { unsigned long pud; } pud_t;
-#define pud_val(x) ((x).pud)
-#define __pud(x) ((pud_t) { (x) })
-#endif
-
-/* PGD level */
-typedef struct { unsigned long pgd; } pgd_t;
-#define pgd_val(x) ((x).pgd)
-#define __pgd(x) ((pgd_t) { (x) })
-
-/* Page protection bits */
-typedef struct { unsigned long pgprot; } pgprot_t;
-#define pgprot_val(x) ((x).pgprot)
-#define __pgprot(x) ((pgprot_t) { (x) })
-
-#else
-
-/*
- * .. while these make it easier on the compiler
- */
-
-typedef unsigned long pte_t;
-#define pte_val(x) (x)
-#define __pte(x) (x)
-
-#ifdef CONFIG_PPC_64K_PAGES
-typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
-#else
-typedef unsigned long real_pte_t;
-#endif
-
-
-typedef unsigned long pmd_t;
-#define pmd_val(x) (x)
-#define __pmd(x) (x)
-
-#ifndef CONFIG_PPC_64K_PAGES
-typedef unsigned long pud_t;
-#define pud_val(x) (x)
-#define __pud(x) (x)
-#endif
-
-typedef unsigned long pgd_t;
-#define pgd_val(x) (x)
-#define pgprot_val(x) (x)
-
-typedef unsigned long pgprot_t;
-#define __pgd(x) (x)
-#define __pgprot(x) (x)
-
-#endif
-
-#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
-
-extern int page_is_ram(unsigned long pfn);
-
-extern u64 ppc64_pft_size; /* Log 2 of page table size */
-
-/* We do define AT_SYSINFO_EHDR but don't use the gate mecanism */
-#define __HAVE_ARCH_GATE_AREA 1
-
-#endif /* __ASSEMBLY__ */
-
-#ifdef MODULE
-#define __page_aligned __attribute__((__aligned__(PAGE_SIZE)))
-#else
-#define __page_aligned \
- __attribute__((__aligned__(PAGE_SIZE), \
- __section__(".data.page_aligned")))
-#endif
-
-
-/* This must match the -Ttext linker address */
-/* Note: tophys & tovirt make assumptions about how */
-/* KERNELBASE is defined for performance reasons. */
-/* When KERNELBASE moves, those macros may have */
-/* to change! */
-#define PAGE_OFFSET ASM_CONST(0xC000000000000000)
-#define KERNELBASE PAGE_OFFSET
-#define VMALLOCBASE ASM_CONST(0xD000000000000000)
-
-#define VMALLOC_REGION_ID (VMALLOCBASE >> REGION_SHIFT)
-#define KERNEL_REGION_ID (KERNELBASE >> REGION_SHIFT)
-#define USER_REGION_ID (0UL)
-#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT)
-
-#define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
-
-#ifdef CONFIG_FLATMEM
-#define pfn_to_page(pfn) (mem_map + (pfn))
-#define page_to_pfn(page) ((unsigned long)((page) - mem_map))
-#define pfn_valid(pfn) ((pfn) < max_mapnr)
-#endif
-
-#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
-
-#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
-
-/*
- * Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
- * and needs to be executable. This means the whole heap ends
- * up being executable.
- */
-#define VM_DATA_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#define VM_DATA_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#define VM_DATA_DEFAULT_FLAGS \
- (test_thread_flag(TIF_32BIT) ? \
- VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64)
-
-/*
- * This is the default if a program doesn't have a PT_GNU_STACK
- * program header entry. The PPC64 ELF ABI has a non executable stack
- * stack by default, so in the absense of a PT_GNU_STACK program header
- * we turn execute permission off.
- */
-#define VM_STACK_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#define VM_STACK_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#define VM_STACK_DEFAULT_FLAGS \
- (test_thread_flag(TIF_32BIT) ? \
- VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
-
-#endif /* __KERNEL__ */
-
-#include <asm-generic/page.h>
-
-#endif /* _PPC64_PAGE_H */
diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h
deleted file mode 100644
index ddfe186589f..00000000000
--- a/include/asm-ppc64/prom.h
+++ /dev/null
@@ -1,220 +0,0 @@
-#ifndef _PPC64_PROM_H
-#define _PPC64_PROM_H
-
-/*
- * Definitions for talking to the Open Firmware PROM on
- * Power Macintosh computers.
- *
- * Copyright (C) 1996 Paul Mackerras.
- *
- * Updates for PPC64 by Peter Bergner & David Engebretsen, 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/config.h>
-#include <linux/proc_fs.h>
-#include <asm/atomic.h>
-
-#define PTRRELOC(x) ((typeof(x))((unsigned long)(x) - offset))
-#define PTRUNRELOC(x) ((typeof(x))((unsigned long)(x) + offset))
-#define RELOC(x) (*PTRRELOC(&(x)))
-
-/* Definitions used by the flattened device tree */
-#define OF_DT_HEADER 0xd00dfeed /* marker */
-#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
-#define OF_DT_END_NODE 0x2 /* End node */
-#define OF_DT_PROP 0x3 /* Property: name off, size,
- * content */
-#define OF_DT_NOP 0x4 /* nop */
-#define OF_DT_END 0x9
-
-#define OF_DT_VERSION 0x10
-
-/*
- * This is what gets passed to the kernel by prom_init or kexec
- *
- * The dt struct contains the device tree structure, full pathes and
- * property contents. The dt strings contain a separate block with just
- * the strings for the property names, and is fully page aligned and
- * self contained in a page, so that it can be kept around by the kernel,
- * each property name appears only once in this page (cheap compression)
- *
- * the mem_rsvmap contains a map of reserved ranges of physical memory,
- * passing it here instead of in the device-tree itself greatly simplifies
- * the job of everybody. It's just a list of u64 pairs (base/size) that
- * ends when size is 0
- */
-struct boot_param_header
-{
- u32 magic; /* magic word OF_DT_HEADER */
- u32 totalsize; /* total size of DT block */
- u32 off_dt_struct; /* offset to structure */
- u32 off_dt_strings; /* offset to strings */
- u32 off_mem_rsvmap; /* offset to memory reserve map */
- u32 version; /* format version */
- u32 last_comp_version; /* last compatible version */
- /* version 2 fields below */
- u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
- /* version 3 fields below */
- u32 dt_strings_size; /* size of the DT strings block */
-};
-
-
-
-typedef u32 phandle;
-typedef u32 ihandle;
-
-struct address_range {
- unsigned long space;
- unsigned long address;
- unsigned long size;
-};
-
-struct interrupt_info {
- int line;
- int sense; /* +ve/-ve logic, edge or level, etc. */
-};
-
-struct pci_address {
- u32 a_hi;
- u32 a_mid;
- u32 a_lo;
-};
-
-struct isa_address {
- u32 a_hi;
- u32 a_lo;
-};
-
-struct isa_range {
- struct isa_address isa_addr;
- struct pci_address pci_addr;
- unsigned int size;
-};
-
-struct reg_property {
- unsigned long address;
- unsigned long size;
-};
-
-struct reg_property32 {
- unsigned int address;
- unsigned int size;
-};
-
-struct reg_property64 {
- unsigned long address;
- unsigned long size;
-};
-
-struct property {
- char *name;
- int length;
- unsigned char *value;
- struct property *next;
-};
-
-struct device_node {
- char *name;
- char *type;
- phandle node;
- phandle linux_phandle;
- int n_addrs;
- struct address_range *addrs;
- int n_intrs;
- struct interrupt_info *intrs;
- char *full_name;
-
- struct property *properties;
- struct device_node *parent;
- struct device_node *child;
- struct device_node *sibling;
- struct device_node *next; /* next device of same type */
- struct device_node *allnext; /* next in list of all nodes */
- struct proc_dir_entry *pde; /* this node's proc directory */
- struct kref kref;
- unsigned long _flags;
- void *data;
-#ifdef CONFIG_PPC_ISERIES
- struct list_head Device_List;
-#endif
-};
-
-extern struct device_node *of_chosen;
-
-/* 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)
-
-/*
- * Until 32-bit ppc can add proc_dir_entries to its device_node
- * definition, we cannot refer to pde, name_link, and addr_link
- * in arch-independent code.
- */
-#define HAVE_ARCH_DEVTREE_FIXUPS
-
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
- dn->pde = de;
-}
-
-
-/* OBSOLETE: Old stlye node lookup */
-extern struct device_node *find_devices(const char *name);
-extern struct device_node *find_type_devices(const char *type);
-extern struct device_node *find_path_device(const char *path);
-extern struct device_node *find_compatible_devices(const char *type,
- const char *compat);
-extern struct device_node *find_all_nodes(void);
-
-/* New style node lookup */
-extern struct device_node *of_find_node_by_name(struct device_node *from,
- const char *name);
-extern struct device_node *of_find_node_by_type(struct device_node *from,
- const char *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_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 device_node *of_node_get(struct device_node *node);
-extern void of_node_put(struct device_node *node);
-
-/* For scanning the flat device-tree at boot time */
-int __init of_scan_flat_dt(int (*it)(unsigned long node,
- const char *uname, int depth,
- void *data),
- void *data);
-void* __init of_get_flat_dt_prop(unsigned long node, const char *name,
- unsigned long *size);
-
-/* For updating the device tree at runtime */
-extern void of_attach_node(struct device_node *);
-extern void of_detach_node(const struct device_node *);
-
-/* Other Prototypes */
-extern unsigned long prom_init(unsigned long, unsigned long, unsigned long,
- unsigned long, unsigned long);
-extern void finish_device_tree(void);
-extern void unflatten_device_tree(void);
-extern void early_init_devtree(void *);
-extern int device_is_compatible(struct device_node *device, const char *);
-extern int machine_is_compatible(const char *compat);
-extern unsigned char *get_property(struct device_node *node, const char *name,
- int *lenp);
-extern void print_properties(struct device_node *node);
-extern int prom_n_addr_cells(struct device_node* np);
-extern int prom_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);
-
-#endif /* _PPC64_PROM_H */
diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h
deleted file mode 100644
index bf9a6aba19c..00000000000
--- a/include/asm-ppc64/system.h
+++ /dev/null
@@ -1,310 +0,0 @@
-#ifndef __PPC64_SYSTEM_H
-#define __PPC64_SYSTEM_H
-
-/*
- * This program is free software; you can redistribute 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/config.h>
-#include <linux/compiler.h>
-#include <asm/page.h>
-#include <asm/processor.h>
-#include <asm/hw_irq.h>
-#include <asm/synch.h>
-
-/*
- * Memory barrier.
- * The sync instruction guarantees that all memory accesses initiated
- * by this processor have been performed (with respect to all other
- * mechanisms that access memory). The eieio instruction is a barrier
- * providing an ordering (separately) for (a) cacheable stores and (b)
- * loads and stores to non-cacheable memory (e.g. I/O devices).
- *
- * mb() prevents loads and stores being reordered across this point.
- * rmb() prevents loads being reordered across this point.
- * wmb() prevents stores being reordered across this point.
- * read_barrier_depends() prevents data-dependent loads being reordered
- * across this point (nop on PPC).
- *
- * We have to use the sync instructions for mb(), since lwsync doesn't
- * order loads with respect to previous stores. Lwsync is fine for
- * rmb(), though.
- * For wmb(), we use sync since wmb is used in drivers to order
- * stores to system memory with respect to writes to the device.
- * However, smp_wmb() can be a lighter-weight eieio barrier on
- * SMP since it is only used to order updates to system memory.
- */
-#define mb() __asm__ __volatile__ ("sync" : : : "memory")
-#define rmb() __asm__ __volatile__ ("lwsync" : : : "memory")
-#define wmb() __asm__ __volatile__ ("sync" : : : "memory")
-#define read_barrier_depends() do { } while(0)
-
-#define set_mb(var, value) do { var = value; smp_mb(); } while (0)
-#define set_wmb(var, value) do { var = value; smp_wmb(); } while (0)
-
-#ifdef CONFIG_SMP
-#define smp_mb() mb()
-#define smp_rmb() rmb()
-#define smp_wmb() eieio()
-#define smp_read_barrier_depends() read_barrier_depends()
-#else
-#define smp_mb() __asm__ __volatile__("": : :"memory")
-#define smp_rmb() __asm__ __volatile__("": : :"memory")
-#define smp_wmb() __asm__ __volatile__("": : :"memory")
-#define smp_read_barrier_depends() do { } while(0)
-#endif /* CONFIG_SMP */
-
-#ifdef __KERNEL__
-struct task_struct;
-struct pt_regs;
-
-#ifdef CONFIG_DEBUGGER
-
-extern int (*__debugger)(struct pt_regs *regs);
-extern int (*__debugger_ipi)(struct pt_regs *regs);
-extern int (*__debugger_bpt)(struct pt_regs *regs);
-extern int (*__debugger_sstep)(struct pt_regs *regs);
-extern int (*__debugger_iabr_match)(struct pt_regs *regs);
-extern int (*__debugger_dabr_match)(struct pt_regs *regs);
-extern int (*__debugger_fault_handler)(struct pt_regs *regs);
-
-#define DEBUGGER_BOILERPLATE(__NAME) \
-static inline int __NAME(struct pt_regs *regs) \
-{ \
- if (unlikely(__ ## __NAME)) \
- return __ ## __NAME(regs); \
- return 0; \
-}
-
-DEBUGGER_BOILERPLATE(debugger)
-DEBUGGER_BOILERPLATE(debugger_ipi)
-DEBUGGER_BOILERPLATE(debugger_bpt)
-DEBUGGER_BOILERPLATE(debugger_sstep)
-DEBUGGER_BOILERPLATE(debugger_iabr_match)
-DEBUGGER_BOILERPLATE(debugger_dabr_match)
-DEBUGGER_BOILERPLATE(debugger_fault_handler)
-
-#ifdef CONFIG_XMON
-extern void xmon_init(int enable);
-#endif
-
-#else
-static inline int debugger(struct pt_regs *regs) { return 0; }
-static inline int debugger_ipi(struct pt_regs *regs) { return 0; }
-static inline int debugger_bpt(struct pt_regs *regs) { return 0; }
-static inline int debugger_sstep(struct pt_regs *regs) { return 0; }
-static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; }
-static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; }
-static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
-#endif
-
-extern int set_dabr(unsigned long dabr);
-extern void _exception(int signr, struct pt_regs *regs, int code,
- unsigned long addr);
-extern int fix_alignment(struct pt_regs *regs);
-extern void bad_page_fault(struct pt_regs *regs, unsigned long address,
- int sig);
-extern void show_regs(struct pt_regs * regs);
-extern void low_hash_fault(struct pt_regs *regs, unsigned long address);
-extern int die(const char *str, struct pt_regs *regs, long err);
-
-extern int _get_PVR(void);
-extern void giveup_fpu(struct task_struct *);
-extern void disable_kernel_fp(void);
-extern void flush_fp_to_thread(struct task_struct *);
-extern void enable_kernel_fp(void);
-extern void giveup_altivec(struct task_struct *);
-extern void disable_kernel_altivec(void);
-extern void enable_kernel_altivec(void);
-extern int emulate_altivec(struct pt_regs *);
-extern void cvt_fd(float *from, double *to, struct thread_struct *thread);
-extern void cvt_df(double *from, float *to, struct thread_struct *thread);
-
-#ifdef CONFIG_ALTIVEC
-extern void flush_altivec_to_thread(struct task_struct *);
-#else
-static inline void flush_altivec_to_thread(struct task_struct *t)
-{
-}
-#endif
-
-static inline void flush_spe_to_thread(struct task_struct *t)
-{
-}
-
-extern int mem_init_done; /* set on boot once kmalloc can be called */
-extern unsigned long memory_limit;
-
-/* EBCDIC -> ASCII conversion for [0-9A-Z] on iSeries */
-extern unsigned char e2a(unsigned char);
-
-extern struct task_struct *__switch_to(struct task_struct *,
- struct task_struct *);
-#define switch_to(prev, next, last) ((last) = __switch_to((prev), (next)))
-
-struct thread_struct;
-extern struct task_struct * _switch(struct thread_struct *prev,
- struct thread_struct *next);
-
-extern unsigned long klimit;
-
-extern int powersave_nap; /* set if nap mode can be used in idle loop */
-
-/*
- * Atomic exchange
- *
- * Changes the memory location '*ptr' to be val and returns
- * the previous value stored there.
- *
- * Inline asm pulled from arch/ppc/kernel/misc.S so ppc64
- * is more like most of the other architectures.
- */
-static __inline__ unsigned long
-__xchg_u32(volatile unsigned int *m, unsigned long val)
-{
- unsigned long dummy;
-
- __asm__ __volatile__(
- EIEIO_ON_SMP
-"1: lwarx %0,0,%3 # __xchg_u32\n\
- stwcx. %2,0,%3\n\
-2: bne- 1b"
- ISYNC_ON_SMP
- : "=&r" (dummy), "=m" (*m)
- : "r" (val), "r" (m)
- : "cc", "memory");
-
- return (dummy);
-}
-
-static __inline__ unsigned long
-__xchg_u64(volatile long *m, unsigned long val)
-{
- unsigned long dummy;
-
- __asm__ __volatile__(
- EIEIO_ON_SMP
-"1: ldarx %0,0,%3 # __xchg_u64\n\
- stdcx. %2,0,%3\n\
-2: bne- 1b"
- ISYNC_ON_SMP
- : "=&r" (dummy), "=m" (*m)
- : "r" (val), "r" (m)
- : "cc", "memory");
-
- return (dummy);
-}
-
-/*
- * This function doesn't exist, so you'll get a linker error
- * if something tries to do an invalid xchg().
- */
-extern void __xchg_called_with_bad_pointer(void);
-
-static __inline__ unsigned long
-__xchg(volatile void *ptr, unsigned long x, unsigned int size)
-{
- switch (size) {
- case 4:
- return __xchg_u32(ptr, x);
- case 8:
- return __xchg_u64(ptr, x);
- }
- __xchg_called_with_bad_pointer();
- return x;
-}
-
-#define xchg(ptr,x) \
- ({ \
- __typeof__(*(ptr)) _x_ = (x); \
- (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
- })
-
-#define tas(ptr) (xchg((ptr),1))
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-static __inline__ unsigned long
-__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
-{
- unsigned int prev;
-
- __asm__ __volatile__ (
- EIEIO_ON_SMP
-"1: lwarx %0,0,%2 # __cmpxchg_u32\n\
- cmpw 0,%0,%3\n\
- bne- 2f\n\
- stwcx. %4,0,%2\n\
- bne- 1b"
- ISYNC_ON_SMP
- "\n\
-2:"
- : "=&r" (prev), "=m" (*p)
- : "r" (p), "r" (old), "r" (new), "m" (*p)
- : "cc", "memory");
-
- return prev;
-}
-
-static __inline__ unsigned long
-__cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
-{
- unsigned long prev;
-
- __asm__ __volatile__ (
- EIEIO_ON_SMP
-"1: ldarx %0,0,%2 # __cmpxchg_u64\n\
- cmpd 0,%0,%3\n\
- bne- 2f\n\
- stdcx. %4,0,%2\n\
- bne- 1b"
- ISYNC_ON_SMP
- "\n\
-2:"
- : "=&r" (prev), "=m" (*p)
- : "r" (p), "r" (old), "r" (new), "m" (*p)
- : "cc", "memory");
-
- return prev;
-}
-
-/* This function doesn't exist, so you'll get a linker error
- if something tries to do an invalid cmpxchg(). */
-extern void __cmpxchg_called_with_bad_pointer(void);
-
-static __inline__ unsigned long
-__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
- unsigned int size)
-{
- switch (size) {
- case 4:
- return __cmpxchg_u32(ptr, old, new);
- case 8:
- return __cmpxchg_u64(ptr, old, new);
- }
- __cmpxchg_called_with_bad_pointer();
- return old;
-}
-
-#define cmpxchg(ptr,o,n)\
- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
- (unsigned long)(n),sizeof(*(ptr))))
-
-/*
- * We handle most unaligned accesses in hardware. On the other hand
- * unaligned DMA can be very expensive on some ppc64 IO chips (it does
- * powers of 2 writes until it reaches sufficient alignment).
- *
- * Based on this we disable the IP header alignment in network drivers.
- */
-#define NET_IP_ALIGN 0
-
-#define arch_align_stack(x) (x)
-
-extern unsigned long reloc_offset(void);
-
-#endif /* __KERNEL__ */
-#endif
diff --git a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h
index 9d86ba6f12d..b3bd4f679f7 100644
--- a/include/asm-s390/atomic.h
+++ b/include/asm-s390/atomic.h
@@ -198,6 +198,18 @@ atomic_compare_and_swap(int expected_oldval,int new_val,atomic_t *v)
return retval;
}
+#define atomic_cmpxchg(v, o, n) (atomic_compare_and_swap((o), (n), &((v)->counter)))
+
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#define smp_mb__before_atomic_dec() smp_mb()
#define smp_mb__after_atomic_dec() smp_mb()
#define smp_mb__before_atomic_inc() smp_mb()
diff --git a/include/asm-sh/atomic.h b/include/asm-sh/atomic.h
index 3c4f805da1a..aabfd334462 100644
--- a/include/asm-sh/atomic.h
+++ b/include/asm-sh/atomic.h
@@ -87,6 +87,35 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
#define atomic_inc(v) atomic_add(1,(v))
#define atomic_dec(v) atomic_sub(1,(v))
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (ret != u)
+ v->counter += a;
+ local_irq_restore(flags);
+
+ return ret != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
{
unsigned long flags;
diff --git a/include/asm-sh64/atomic.h b/include/asm-sh64/atomic.h
index 8c3872d3e65..927a2bc27b3 100644
--- a/include/asm-sh64/atomic.h
+++ b/include/asm-sh64/atomic.h
@@ -99,6 +99,35 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
#define atomic_inc(v) atomic_add(1,(v))
#define atomic_dec(v) atomic_sub(1,(v))
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (ret != u)
+ v->counter += a;
+ local_irq_restore(flags);
+
+ return ret != u;
+}
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
{
unsigned long flags;
diff --git a/include/asm-sparc/atomic.h b/include/asm-sparc/atomic.h
index 37f6ab601c3..62bec7ad271 100644
--- a/include/asm-sparc/atomic.h
+++ b/include/asm-sparc/atomic.h
@@ -19,6 +19,8 @@ typedef struct { volatile int counter; } atomic_t;
#define ATOMIC_INIT(i) { (i) }
extern int __atomic_add_return(int, atomic_t *);
+extern int atomic_cmpxchg(atomic_t *, int, int);
+extern int atomic_add_unless(atomic_t *, int, int);
extern void atomic_set(atomic_t *, int);
#define atomic_read(v) ((v)->counter)
@@ -48,6 +50,8 @@ extern void atomic_set(atomic_t *, int);
#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
/* This is the old 24-bit implementation. It's still used internally
* by some sparc-specific code, notably the semaphore implementation.
*/
diff --git a/include/asm-sparc64/atomic.h b/include/asm-sparc64/atomic.h
index e175afcf2cd..8198c3d0d00 100644
--- a/include/asm-sparc64/atomic.h
+++ b/include/asm-sparc64/atomic.h
@@ -70,6 +70,18 @@ extern int atomic64_sub_ret(int, atomic64_t *);
#define atomic_add_negative(i, v) (atomic_add_ret(i, v) < 0)
#define atomic64_add_negative(i, v) (atomic64_add_ret(i, v) < 0)
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
/* Atomic operations are already serializing */
#ifdef CONFIG_SMP
#define smp_mb__before_atomic_dec() membar_storeload_loadload();
diff --git a/include/asm-v850/atomic.h b/include/asm-v850/atomic.h
index 395268a8c0d..bede3172ce7 100644
--- a/include/asm-v850/atomic.h
+++ b/include/asm-v850/atomic.h
@@ -90,6 +90,36 @@ static __inline__ void atomic_clear_mask (unsigned long mask, unsigned long *add
#define atomic_dec_and_test(v) (atomic_sub_return (1, (v)) == 0)
#define atomic_add_negative(i,v) (atomic_add_return ((i), (v)) < 0)
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (likely(ret == old))
+ v->counter = new;
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int ret;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ret = v->counter;
+ if (ret != u)
+ v->counter += a;
+ local_irq_restore(flags);
+
+ return ret != u;
+}
+
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
/* Atomic operations are already serializing on ARM */
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
diff --git a/include/asm-v850/hardirq.h b/include/asm-v850/hardirq.h
index 5dfca8047cb..d98488cd5af 100644
--- a/include/asm-v850/hardirq.h
+++ b/include/asm-v850/hardirq.h
@@ -5,6 +5,8 @@
#include <linux/threads.h>
#include <linux/cache.h>
+#include <asm/irq.h>
+
typedef struct {
unsigned int __softirq_pending;
} ____cacheline_aligned irq_cpustat_t;
@@ -22,4 +24,6 @@ typedef struct {
# error HARDIRQ_BITS is too low!
#endif
+void ack_bad_irq(unsigned int irq);
+
#endif /* __V850_HARDIRQ_H__ */
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index 6c5d5ca8383..5647b7de174 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -111,6 +111,8 @@ extern unsigned int nmi_watchdog;
extern int disable_timer_pin_1;
+extern void setup_threshold_lvt(unsigned long lvt_off);
+
#endif /* CONFIG_X86_LOCAL_APIC */
extern unsigned boot_cpu_id;
diff --git a/include/asm-x86_64/atomic.h b/include/asm-x86_64/atomic.h
index fc4c5956e1e..0866ef67f19 100644
--- a/include/asm-x86_64/atomic.h
+++ b/include/asm-x86_64/atomic.h
@@ -360,6 +360,27 @@ static __inline__ int atomic_sub_return(int i, atomic_t *v)
return atomic_add_return(-i,v);
}
+#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
#define atomic_inc_return(v) (atomic_add_return(1,v))
#define atomic_dec_return(v) (atomic_sub_return(1,v))
diff --git a/include/asm-x86_64/cache.h b/include/asm-x86_64/cache.h
index eda62bae124..33e53424128 100644
--- a/include/asm-x86_64/cache.h
+++ b/include/asm-x86_64/cache.h
@@ -9,6 +9,6 @@
/* L1 cache line size */
#define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT)
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
-#define L1_CACHE_SHIFT_MAX 6 /* largest L1 which this arch supports */
+#define L1_CACHE_SHIFT_MAX 7 /* largest L1 which this arch supports */
#endif
diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h
index 68ac3c62fe3..33764869387 100644
--- a/include/asm-x86_64/desc.h
+++ b/include/asm-x86_64/desc.h
@@ -98,16 +98,19 @@ static inline void _set_gate(void *adr, unsigned type, unsigned long func, unsig
static inline void set_intr_gate(int nr, void *func)
{
+ BUG_ON((unsigned)nr > 0xFF);
_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, 0);
}
static inline void set_intr_gate_ist(int nr, void *func, unsigned ist)
{
+ BUG_ON((unsigned)nr > 0xFF);
_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 0, ist);
}
static inline void set_system_gate(int nr, void *func)
{
+ BUG_ON((unsigned)nr > 0xFF);
_set_gate(&idt_table[nr], GATE_INTERRUPT, (unsigned long) func, 3, 0);
}
@@ -129,9 +132,16 @@ static inline void set_tssldt_descriptor(void *ptr, unsigned long tss, unsigned
static inline void set_tss_desc(unsigned cpu, void *addr)
{
- set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_TSS], (unsigned long)addr,
- DESC_TSS,
- sizeof(struct tss_struct) - 1);
+ /*
+ * sizeof(unsigned long) coming from an extra "long" at the end
+ * of the iobitmap. See tss_struct definition in processor.h
+ *
+ * -1? seg base+limit should be pointing to the address of the
+ * last valid byte
+ */
+ set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_TSS],
+ (unsigned long)addr, DESC_TSS,
+ IO_BITMAP_OFFSET + IO_BITMAP_BYTES + sizeof(unsigned long) - 1);
}
static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
diff --git a/include/asm-x86_64/dma.h b/include/asm-x86_64/dma.h
index 16fa3a064d0..6f2a817b6a7 100644
--- a/include/asm-x86_64/dma.h
+++ b/include/asm-x86_64/dma.h
@@ -72,8 +72,15 @@
#define MAX_DMA_CHANNELS 8
-/* The maximum address that we can perform a DMA transfer to on this platform */
-#define MAX_DMA_ADDRESS (PAGE_OFFSET+0x1000000)
+
+/* 16MB ISA DMA zone */
+#define MAX_DMA_PFN ((16*1024*1024) >> PAGE_SHIFT)
+
+/* 4GB broken PCI/AGP hardware bus master zone */
+#define MAX_DMA32_PFN ((4UL*1024*1024*1024) >> PAGE_SHIFT)
+
+/* Compat define for old dma zone */
+#define MAX_DMA_ADDRESS ((unsigned long)__va(MAX_DMA_PFN << PAGE_SHIFT))
/* 8237 DMA controllers */
#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
diff --git a/include/asm-x86_64/hpet.h b/include/asm-x86_64/hpet.h
index a3877f57099..c20c28f5c7a 100644
--- a/include/asm-x86_64/hpet.h
+++ b/include/asm-x86_64/hpet.h
@@ -14,18 +14,18 @@
#define HPET_CFG 0x010
#define HPET_STATUS 0x020
#define HPET_COUNTER 0x0f0
-#define HPET_T0_CFG 0x100
-#define HPET_T0_CMP 0x108
-#define HPET_T0_ROUTE 0x110
-#define HPET_T1_CFG 0x120
-#define HPET_T1_CMP 0x128
-#define HPET_T1_ROUTE 0x130
-#define HPET_T2_CFG 0x140
-#define HPET_T2_CMP 0x148
-#define HPET_T2_ROUTE 0x150
+#define HPET_Tn_OFFSET 0x20
+#define HPET_Tn_CFG(n) (0x100 + (n) * HPET_Tn_OFFSET)
+#define HPET_Tn_ROUTE(n) (0x104 + (n) * HPET_Tn_OFFSET)
+#define HPET_Tn_CMP(n) (0x108 + (n) * HPET_Tn_OFFSET)
+#define HPET_T0_CFG HPET_Tn_CFG(0)
+#define HPET_T0_CMP HPET_Tn_CMP(0)
+#define HPET_T1_CFG HPET_Tn_CFG(1)
+#define HPET_T1_CMP HPET_Tn_CMP(1)
#define HPET_ID_VENDOR 0xffff0000
#define HPET_ID_LEGSUP 0x00008000
+#define HPET_ID_64BIT 0x00002000
#define HPET_ID_NUMBER 0x00001f00
#define HPET_ID_REV 0x000000ff
#define HPET_ID_NUMBER_SHIFT 8
@@ -38,11 +38,18 @@
#define HPET_LEGACY_8254 2
#define HPET_LEGACY_RTC 8
-#define HPET_TN_ENABLE 0x004
-#define HPET_TN_PERIODIC 0x008
-#define HPET_TN_PERIODIC_CAP 0x010
-#define HPET_TN_SETVAL 0x040
-#define HPET_TN_32BIT 0x100
+#define HPET_TN_LEVEL 0x0002
+#define HPET_TN_ENABLE 0x0004
+#define HPET_TN_PERIODIC 0x0008
+#define HPET_TN_PERIODIC_CAP 0x0010
+#define HPET_TN_64BIT_CAP 0x0020
+#define HPET_TN_SETVAL 0x0040
+#define HPET_TN_32BIT 0x0100
+#define HPET_TN_ROUTE 0x3e00
+#define HPET_TN_FSB 0x4000
+#define HPET_TN_FSB_CAP 0x8000
+
+#define HPET_TN_ROUTE_SHIFT 9
extern int is_hpet_enabled(void);
extern int hpet_rtc_timer_init(void);
diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h
index dc97668ea0f..c14a8c7267a 100644
--- a/include/asm-x86_64/hw_irq.h
+++ b/include/asm-x86_64/hw_irq.h
@@ -55,7 +55,7 @@ struct hw_interrupt_type;
#define CALL_FUNCTION_VECTOR 0xfc
#define KDB_VECTOR 0xfb /* reserved for KDB */
#define THERMAL_APIC_VECTOR 0xfa
-/* 0xf9 free */
+#define THRESHOLD_APIC_VECTOR 0xf9
#define INVALIDATE_TLB_VECTOR_END 0xf8
#define INVALIDATE_TLB_VECTOR_START 0xf0 /* f0-f8 used for TLB flush */
diff --git a/include/asm-x86_64/ia32.h b/include/asm-x86_64/ia32.h
index 6efa00fe4e7..c7bc9c0525b 100644
--- a/include/asm-x86_64/ia32.h
+++ b/include/asm-x86_64/ia32.h
@@ -165,6 +165,11 @@ struct siginfo_t;
int do_get_thread_area(struct thread_struct *t, struct user_desc __user *info);
int do_set_thread_area(struct thread_struct *t, struct user_desc __user *info);
int ia32_child_tls(struct task_struct *p, struct pt_regs *childregs);
+
+struct linux_binprm;
+extern int ia32_setup_arg_pages(struct linux_binprm *bprm,
+ unsigned long stack_top, int exec_stack);
+
#endif
#endif /* !CONFIG_IA32_SUPPORT */
diff --git a/include/asm-x86_64/mce.h b/include/asm-x86_64/mce.h
index 869249db679..5d298b799a9 100644
--- a/include/asm-x86_64/mce.h
+++ b/include/asm-x86_64/mce.h
@@ -67,6 +67,8 @@ struct mce_log {
/* Software defined banks */
#define MCE_EXTENDED_BANK 128
#define MCE_THERMAL_BANK MCE_EXTENDED_BANK + 0
+#define MCE_THRESHOLD_BASE MCE_EXTENDED_BANK + 1 /* MCE_AMD */
+#define MCE_THRESHOLD_DRAM_ECC MCE_THRESHOLD_BASE + 4
void mce_log(struct mce *m);
#ifdef CONFIG_X86_MCE_INTEL
@@ -77,4 +79,12 @@ static inline void mce_intel_feature_init(struct cpuinfo_x86 *c)
}
#endif
+#ifdef CONFIG_X86_MCE_AMD
+void mce_amd_feature_init(struct cpuinfo_x86 *c);
+#else
+static inline void mce_amd_feature_init(struct cpuinfo_x86 *c)
+{
+}
+#endif
+
#endif
diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h
index b40c661f111..69baaa8a3ce 100644
--- a/include/asm-x86_64/mmzone.h
+++ b/include/asm-x86_64/mmzone.h
@@ -17,16 +17,15 @@
/* Simple perfect hash to map physical addresses to node numbers */
extern int memnode_shift;
extern u8 memnodemap[NODEMAPSIZE];
-extern int maxnode;
extern struct pglist_data *node_data[];
static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
{
- int nid;
+ unsigned nid;
VIRTUAL_BUG_ON((addr >> memnode_shift) >= NODEMAPSIZE);
nid = memnodemap[addr >> memnode_shift];
- VIRTUAL_BUG_ON(nid > maxnode);
+ VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
return nid;
}
@@ -41,9 +40,7 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
#define pfn_to_nid(pfn) phys_to_nid((unsigned long)(pfn) << PAGE_SHIFT)
#define kvaddr_to_nid(kaddr) phys_to_nid(__pa(kaddr))
-/* AK: this currently doesn't deal with invalid addresses. We'll see
- if the 2.5 kernel doesn't pass them
- (2.4 used to). */
+/* Requires pfn_valid(pfn) to be true */
#define pfn_to_page(pfn) ({ \
int nid = phys_to_nid(((unsigned long)(pfn)) << PAGE_SHIFT); \
((pfn) - node_start_pfn(nid)) + NODE_DATA(nid)->node_mem_map; \
diff --git a/include/asm-x86_64/mpspec.h b/include/asm-x86_64/mpspec.h
index f267e10c023..6f8a17d105a 100644
--- a/include/asm-x86_64/mpspec.h
+++ b/include/asm-x86_64/mpspec.h
@@ -16,7 +16,7 @@
/*
* A maximum of 255 APICs with the current APIC ID architecture.
*/
-#define MAX_APICS 128
+#define MAX_APICS 255
struct intel_mp_floating
{
@@ -157,7 +157,8 @@ struct mpc_config_lintsrc
*/
#define MAX_MP_BUSSES 256
-#define MAX_IRQ_SOURCES 256
+/* Each PCI slot may be a combo card with its own bus. 4 IRQ pins per slot. */
+#define MAX_IRQ_SOURCES (MAX_MP_BUSSES * 4)
enum mp_bustype {
MP_BUS_ISA = 1,
MP_BUS_EISA,
@@ -172,7 +173,7 @@ extern int smp_found_config;
extern void find_smp_config (void);
extern void get_smp_config (void);
extern int nr_ioapics;
-extern int apic_version [MAX_APICS];
+extern unsigned char apic_version [MAX_APICS];
extern int mp_irq_entries;
extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
extern int mpc_default_type;
diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
index 5a7fe3c6c3d..24dc39651bc 100644
--- a/include/asm-x86_64/msr.h
+++ b/include/asm-x86_64/msr.h
@@ -19,7 +19,7 @@
: "=a" (a__), "=d" (b__) \
: "c" (msr)); \
val = a__ | (b__<<32); \
-} while(0);
+} while(0)
#define wrmsr(msr,val1,val2) \
__asm__ __volatile__("wrmsr" \
diff --git a/include/asm-x86_64/numa.h b/include/asm-x86_64/numa.h
index bcf55c3f7f7..d51e56fdc3d 100644
--- a/include/asm-x86_64/numa.h
+++ b/include/asm-x86_64/numa.h
@@ -17,6 +17,8 @@ extern void numa_add_cpu(int cpu);
extern void numa_init_array(void);
extern int numa_off;
+extern void numa_set_node(int cpu, int node);
+
extern unsigned char apicid_to_node[256];
#define NUMA_NO_NODE 0xff
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index e5ab4d231f2..06e489f3247 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -11,7 +11,7 @@
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#endif
#define PAGE_MASK (~(PAGE_SIZE-1))
-#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & (__PHYSICAL_MASK << PAGE_SHIFT))
+#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK)
#define THREAD_ORDER 1
#ifdef __ASSEMBLY__
diff --git a/include/asm-x86_64/pda.h b/include/asm-x86_64/pda.h
index bbf89aa8a1a..8733ccfa442 100644
--- a/include/asm-x86_64/pda.h
+++ b/include/asm-x86_64/pda.h
@@ -15,6 +15,7 @@ struct x8664_pda {
int irqcount; /* Irq nesting counter. Starts with -1 */
int cpunumber; /* Logical CPU number */
char *irqstackptr; /* top of irqstack */
+ int nodenumber; /* number of current node */
unsigned int __softirq_pending;
unsigned int __nmi_count; /* number of NMI on this CPUs */
struct mm_struct *active_mm;
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 7309fffeec9..ecf58c7c165 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -16,6 +16,7 @@ extern pud_t level3_physmem_pgt[512];
extern pud_t level3_ident_pgt[512];
extern pmd_t level2_kernel_pgt[512];
extern pgd_t init_level4_pgt[];
+extern pgd_t boot_level4_pgt[];
extern unsigned long __supported_pte_mask;
#define swapper_pg_dir init_level4_pgt
@@ -247,7 +248,7 @@ static inline unsigned long pud_bad(pud_t pud)
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) /* FIXME: is this
right? */
#define pte_page(x) pfn_to_page(pte_pfn(x))
-#define pte_pfn(x) ((pte_val(x) >> PAGE_SHIFT) & __PHYSICAL_MASK)
+#define pte_pfn(x) ((pte_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT)
static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
{
@@ -354,7 +355,7 @@ static inline pud_t *__pud_offset_k(pud_t *pud, unsigned long address)
#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
#define pmd_bad(x) ((pmd_val(x) & (~PTE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE )
#define pfn_pmd(nr,prot) (__pmd(((nr) << PAGE_SHIFT) | pgprot_val(prot)))
-#define pmd_pfn(x) ((pmd_val(x) >> PAGE_SHIFT) & __PHYSICAL_MASK)
+#define pmd_pfn(x) ((pmd_val(x) & __PHYSICAL_MASK) >> PAGE_SHIFT)
#define pte_to_pgoff(pte) ((pte_val(pte) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT)
#define pgoff_to_pte(off) ((pte_t) { ((off) << PAGE_SHIFT) | _PAGE_FILE })
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index 03837d34fba..4861246548f 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -61,10 +61,12 @@ struct cpuinfo_x86 {
int x86_cache_alignment;
int x86_tlbsize; /* number of 4K pages in DTLB/ITLB combined(in pages)*/
__u8 x86_virt_bits, x86_phys_bits;
- __u8 x86_num_cores;
+ __u8 x86_max_cores; /* cpuid returned max cores value */
__u32 x86_power;
__u32 extended_cpuid_level; /* Max extended CPUID function supported */
unsigned long loops_per_jiffy;
+ __u8 apicid;
+ __u8 booted_cores; /* number of cores as seen by OS */
} ____cacheline_aligned;
#define X86_VENDOR_INTEL 0
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index dbb37b0adb4..34501086afe 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -11,6 +11,8 @@ struct pt_regs;
extern void start_kernel(void);
extern void pda_init(int);
+extern void zap_low_mappings(int cpu);
+
extern void early_idt_handler(void);
extern void mcheck_init(struct cpuinfo_x86 *c);
@@ -22,6 +24,8 @@ extern void mtrr_bp_init(void);
#define mtrr_bp_init() do {} while (0)
#endif
extern void init_memory_mapping(unsigned long start, unsigned long end);
+extern void size_zones(unsigned long *z, unsigned long *h,
+ unsigned long start_pfn, unsigned long end_pfn);
extern void system_call(void);
extern int kernel_syscall(void);
diff --git a/include/asm-x86_64/rwsem.h b/include/asm-x86_64/rwsem.h
deleted file mode 100644
index 46077e9c191..00000000000
--- a/include/asm-x86_64/rwsem.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/* rwsem.h: R/W semaphores implemented using XADD/CMPXCHG for x86_64+
- *
- * Written by David Howells (dhowells@redhat.com).
- * Ported by Andi Kleen <ak@suse.de> to x86-64.
- *
- * Derived from asm-i386/semaphore.h and asm-i386/rwsem.h
- *
- *
- * The MSW of the count is the negated number of active writers and waiting
- * lockers, and the LSW is the total number of active locks
- *
- * The lock count is initialized to 0 (no active and no waiting lockers).
- *
- * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
- * uncontended lock. This can be determined because XADD returns the old value.
- * Readers increment by 1 and see a positive value when uncontended, negative
- * if there are writers (and maybe) readers waiting (in which case it goes to
- * sleep).
- *
- * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
- * be extended to 65534 by manually checking the whole MSW rather than relying
- * on the S flag.
- *
- * The value of ACTIVE_BIAS supports up to 65535 active processes.
- *
- * This should be totally fair - if anything is waiting, a process that wants a
- * lock will go to the back of the queue. When the currently active lock is
- * released, if there's a writer at the front of the queue, then that and only
- * that will be woken up; if there's a bunch of consecutive readers at the
- * front, then they'll all be woken up, but no other readers will be.
- */
-
-#ifndef _X8664_RWSEM_H
-#define _X8664_RWSEM_H
-
-#ifndef _LINUX_RWSEM_H
-#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
-#endif
-
-#ifdef __KERNEL__
-
-#include <linux/list.h>
-#include <linux/spinlock.h>
-
-struct rwsem_waiter;
-
-extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
-extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
-extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
-
-/*
- * the semaphore definition
- */
-struct rw_semaphore {
- signed int count;
-#define RWSEM_UNLOCKED_VALUE 0x00000000
-#define RWSEM_ACTIVE_BIAS 0x00000001
-#define RWSEM_ACTIVE_MASK 0x0000ffff
-#define RWSEM_WAITING_BIAS (-0x00010000)
-#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
- spinlock_t wait_lock;
- struct list_head wait_list;
-#if RWSEM_DEBUG
- int debug;
-#endif
-};
-
-/*
- * initialisation
- */
-#if RWSEM_DEBUG
-#define __RWSEM_DEBUG_INIT , 0
-#else
-#define __RWSEM_DEBUG_INIT /* */
-#endif
-
-#define __RWSEM_INITIALIZER(name) \
-{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) \
- __RWSEM_DEBUG_INIT }
-
-#define DECLARE_RWSEM(name) \
- struct rw_semaphore name = __RWSEM_INITIALIZER(name)
-
-static inline void init_rwsem(struct rw_semaphore *sem)
-{
- sem->count = RWSEM_UNLOCKED_VALUE;
- spin_lock_init(&sem->wait_lock);
- INIT_LIST_HEAD(&sem->wait_list);
-#if RWSEM_DEBUG
- sem->debug = 0;
-#endif
-}
-
-/*
- * lock for reading
- */
-static inline void __down_read(struct rw_semaphore *sem)
-{
- __asm__ __volatile__(
- "# beginning down_read\n\t"
-LOCK_PREFIX " incl (%%rdi)\n\t" /* adds 0x00000001, returns the old value */
- " js 2f\n\t" /* jump if we weren't granted the lock */
- "1:\n\t"
- LOCK_SECTION_START("") \
- "2:\n\t"
- " call rwsem_down_read_failed_thunk\n\t"
- " jmp 1b\n"
- LOCK_SECTION_END \
- "# ending down_read\n\t"
- : "+m"(sem->count)
- : "D"(sem)
- : "memory", "cc");
-}
-
-
-/*
- * trylock for reading -- returns 1 if successful, 0 if contention
- */
-static inline int __down_read_trylock(struct rw_semaphore *sem)
-{
- __s32 result, tmp;
- __asm__ __volatile__(
- "# beginning __down_read_trylock\n\t"
- " movl %0,%1\n\t"
- "1:\n\t"
- " movl %1,%2\n\t"
- " addl %3,%2\n\t"
- " jle 2f\n\t"
-LOCK_PREFIX " cmpxchgl %2,%0\n\t"
- " jnz 1b\n\t"
- "2:\n\t"
- "# ending __down_read_trylock\n\t"
- : "+m"(sem->count), "=&a"(result), "=&r"(tmp)
- : "i"(RWSEM_ACTIVE_READ_BIAS)
- : "memory", "cc");
- return result>=0 ? 1 : 0;
-}
-
-
-/*
- * lock for writing
- */
-static inline void __down_write(struct rw_semaphore *sem)
-{
- int tmp;
-
- tmp = RWSEM_ACTIVE_WRITE_BIAS;
- __asm__ __volatile__(
- "# beginning down_write\n\t"
-LOCK_PREFIX " xaddl %0,(%%rdi)\n\t" /* subtract 0x0000ffff, returns the old value */
- " testl %0,%0\n\t" /* was the count 0 before? */
- " jnz 2f\n\t" /* jump if we weren't granted the lock */
- "1:\n\t"
- LOCK_SECTION_START("")
- "2:\n\t"
- " call rwsem_down_write_failed_thunk\n\t"
- " jmp 1b\n"
- LOCK_SECTION_END
- "# ending down_write"
- : "=&r" (tmp)
- : "0"(tmp), "D"(sem)
- : "memory", "cc");
-}
-
-/*
- * trylock for writing -- returns 1 if successful, 0 if contention
- */
-static inline int __down_write_trylock(struct rw_semaphore *sem)
-{
- signed long ret = cmpxchg(&sem->count,
- RWSEM_UNLOCKED_VALUE,
- RWSEM_ACTIVE_WRITE_BIAS);
- if (ret == RWSEM_UNLOCKED_VALUE)
- return 1;
- return 0;
-}
-
-/*
- * unlock after reading
- */
-static inline void __up_read(struct rw_semaphore *sem)
-{
- __s32 tmp = -RWSEM_ACTIVE_READ_BIAS;
- __asm__ __volatile__(
- "# beginning __up_read\n\t"
-LOCK_PREFIX " xaddl %[tmp],(%%rdi)\n\t" /* subtracts 1, returns the old value */
- " js 2f\n\t" /* jump if the lock is being waited upon */
- "1:\n\t"
- LOCK_SECTION_START("")
- "2:\n\t"
- " decw %w[tmp]\n\t" /* do nothing if still outstanding active readers */
- " jnz 1b\n\t"
- " call rwsem_wake_thunk\n\t"
- " jmp 1b\n"
- LOCK_SECTION_END
- "# ending __up_read\n"
- : "+m"(sem->count), [tmp] "+r" (tmp)
- : "D"(sem)
- : "memory", "cc");
-}
-
-/*
- * unlock after writing
- */
-static inline void __up_write(struct rw_semaphore *sem)
-{
- unsigned tmp;
- __asm__ __volatile__(
- "# beginning __up_write\n\t"
- " movl %[bias],%[tmp]\n\t"
-LOCK_PREFIX " xaddl %[tmp],(%%rdi)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */
- " jnz 2f\n\t" /* jump if the lock is being waited upon */
- "1:\n\t"
- LOCK_SECTION_START("")
- "2:\n\t"
- " decw %w[tmp]\n\t" /* did the active count reduce to 0? */
- " jnz 1b\n\t" /* jump back if not */
- " call rwsem_wake_thunk\n\t"
- " jmp 1b\n"
- LOCK_SECTION_END
- "# ending __up_write\n"
- : "+m"(sem->count), [tmp] "=r" (tmp)
- : "D"(sem), [bias] "i"(-RWSEM_ACTIVE_WRITE_BIAS)
- : "memory", "cc");
-}
-
-/*
- * downgrade write lock to read lock
- */
-static inline void __downgrade_write(struct rw_semaphore *sem)
-{
- __asm__ __volatile__(
- "# beginning __downgrade_write\n\t"
-LOCK_PREFIX " addl %[bias],(%%rdi)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */
- " js 2f\n\t" /* jump if the lock is being waited upon */
- "1:\n\t"
- LOCK_SECTION_START("")
- "2:\n\t"
- " call rwsem_downgrade_thunk\n"
- " jmp 1b\n"
- LOCK_SECTION_END
- "# ending __downgrade_write\n"
- : "=m"(sem->count)
- : "D"(sem), [bias] "i"(-RWSEM_WAITING_BIAS), "m"(sem->count)
- : "memory", "cc");
-}
-
-/*
- * implement atomic add functionality
- */
-static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
-{
- __asm__ __volatile__(
-LOCK_PREFIX "addl %1,%0"
- :"=m"(sem->count)
- :"ir"(delta), "m"(sem->count));
-}
-
-/*
- * implement exchange and add functionality
- */
-static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
-{
- int tmp = delta;
-
- __asm__ __volatile__(
-LOCK_PREFIX "xaddl %0,(%2)"
- : "=r"(tmp), "=m"(sem->count)
- : "r"(sem), "m"(sem->count), "0" (tmp)
- : "memory");
-
- return tmp+delta;
-}
-
-static inline int rwsem_is_locked(struct rw_semaphore *sem)
-{
- return (sem->count != 0);
-}
-
-#endif /* __KERNEL__ */
-#endif /* _X8664_RWSEM_H */
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
index b9fb2173ef9..d030409a8fb 100644
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -47,7 +47,6 @@ extern void lock_ipi_call_lock(void);
extern void unlock_ipi_call_lock(void);
extern int smp_num_siblings;
extern void smp_send_reschedule(int cpu);
-extern void zap_low_mappings(void);
void smp_stop_cpu(void);
extern int smp_call_function_single(int cpuid, void (*func) (void *info),
void *info, int retry, int wait);
@@ -82,6 +81,8 @@ extern int safe_smp_processor_id(void);
extern int __cpu_disable(void);
extern void __cpu_die(unsigned int cpu);
extern void prefill_possible_map(void);
+extern unsigned num_processors;
+extern unsigned disabled_cpus;
#endif /* !ASSEMBLY */
diff --git a/include/asm-x86_64/spinlock.h b/include/asm-x86_64/spinlock.h
index 69636831ad2..fe484a699cc 100644
--- a/include/asm-x86_64/spinlock.h
+++ b/include/asm-x86_64/spinlock.h
@@ -18,22 +18,22 @@
*/
#define __raw_spin_is_locked(x) \
- (*(volatile signed char *)(&(x)->slock) <= 0)
+ (*(volatile signed int *)(&(x)->slock) <= 0)
#define __raw_spin_lock_string \
"\n1:\t" \
- "lock ; decb %0\n\t" \
+ "lock ; decl %0\n\t" \
"js 2f\n" \
LOCK_SECTION_START("") \
"2:\t" \
"rep;nop\n\t" \
- "cmpb $0,%0\n\t" \
+ "cmpl $0,%0\n\t" \
"jle 2b\n\t" \
"jmp 1b\n" \
LOCK_SECTION_END
#define __raw_spin_unlock_string \
- "movb $1,%0" \
+ "movl $1,%0" \
:"=m" (lock->slock) : : "memory"
static inline void __raw_spin_lock(raw_spinlock_t *lock)
@@ -47,10 +47,10 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
static inline int __raw_spin_trylock(raw_spinlock_t *lock)
{
- char oldval;
+ int oldval;
__asm__ __volatile__(
- "xchgb %b0,%1"
+ "xchgl %0,%1"
:"=q" (oldval), "=m" (lock->slock)
:"0" (0) : "memory");
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index 1c603cd7e4d..d39ebd5263e 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -28,6 +28,8 @@ extern int __node_distance(int, int);
#define pcibus_to_node(bus) ((long)(bus->sysdata))
#define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus));
+#define numa_node_id() read_pda(nodenumber)
+
/* sched_domains SD_NODE_INIT for x86_64 machines */
#define SD_NODE_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index 3c494b65d33..2c42150bce0 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -462,7 +462,7 @@ __SYSCALL(__NR_fremovexattr, sys_fremovexattr)
#define __NR_tkill 200
__SYSCALL(__NR_tkill, sys_tkill)
#define __NR_time 201
-__SYSCALL(__NR_time, sys_time64)
+__SYSCALL(__NR_time, sys_time)
#define __NR_futex 202
__SYSCALL(__NR_futex, sys_futex)
#define __NR_sched_setaffinity 203
@@ -608,6 +608,7 @@ do { \
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_TIME
#define __ARCH_WANT_COMPAT_SYS_TIME
#endif
diff --git a/include/asm-xtensa/atomic.h b/include/asm-xtensa/atomic.h
index 12b5732dc6e..3670cc7695d 100644
--- a/include/asm-xtensa/atomic.h
+++ b/include/asm-xtensa/atomic.h
@@ -223,6 +223,26 @@ static inline int atomic_sub_return(int i, atomic_t * v)
*/
#define atomic_add_negative(i,v) (atomic_add_return((i),(v)) < 0)
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
{
diff --git a/include/linux/acct.h b/include/linux/acct.h
index 93c5b3cdf95..9a66401073f 100644
--- a/include/linux/acct.h
+++ b/include/linux/acct.h
@@ -16,6 +16,8 @@
#define _LINUX_ACCT_H
#include <linux/types.h>
+#include <linux/jiffies.h>
+
#include <asm/param.h>
#include <asm/byteorder.h>
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 403d71dcb7c..49fd37629ee 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -124,7 +124,7 @@ struct kiocb {
(x)->ki_users = 1; \
(x)->ki_key = KIOCB_SYNC_KEY; \
(x)->ki_filp = (filp); \
- (x)->ki_ctx = &tsk->active_mm->default_kioctx; \
+ (x)->ki_ctx = NULL; \
(x)->ki_cancel = NULL; \
(x)->ki_dtor = NULL; \
(x)->ki_obj.tsk = tsk; \
@@ -210,8 +210,15 @@ struct kioctx *lookup_ioctx(unsigned long ctx_id);
int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
struct iocb *iocb));
-#define get_ioctx(kioctx) do { if (unlikely(atomic_read(&(kioctx)->users) <= 0)) BUG(); atomic_inc(&(kioctx)->users); } while (0)
-#define put_ioctx(kioctx) do { if (unlikely(atomic_dec_and_test(&(kioctx)->users))) __put_ioctx(kioctx); else if (unlikely(atomic_read(&(kioctx)->users) < 0)) BUG(); } while (0)
+#define get_ioctx(kioctx) do { \
+ BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0)); \
+ atomic_inc(&(kioctx)->users); \
+} while (0)
+#define put_ioctx(kioctx) do { \
+ BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0)); \
+ if (unlikely(atomic_dec_and_test(&(kioctx)->users))) \
+ __put_ioctx(kioctx); \
+} while (0)
#define in_aio() !is_sync_wait(current->io_wait)
/* may be used for debugging */
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index cb3c3ef50f5..38c2fb7ebe0 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -84,6 +84,16 @@ static __inline__ int get_bitmask_order(unsigned int count)
return order; /* We could be slightly more clever with -1 here... */
}
+static __inline__ int get_count_order(unsigned int count)
+{
+ int order;
+
+ order = fls(count) - 1;
+ if (count & (count - 1))
+ order++;
+ return order;
+}
+
/*
* hweightN: returns the hamming weight (i.e. the number
* of bits set) of a N-bit word
diff --git a/include/linux/cm4000_cs.h b/include/linux/cm4000_cs.h
new file mode 100644
index 00000000000..605ebe24bb2
--- /dev/null
+++ b/include/linux/cm4000_cs.h
@@ -0,0 +1,66 @@
+#ifndef _CM4000_H_
+#define _CM4000_H_
+
+#define MAX_ATR 33
+
+#define CM4000_MAX_DEV 4
+
+/* those two structures are passed via ioctl() from/to userspace. They are
+ * used by existing userspace programs, so I kepth the awkward "bIFSD" naming
+ * not to break compilation of userspace apps. -HW */
+
+typedef struct atreq {
+ int32_t atr_len;
+ unsigned char atr[64];
+ int32_t power_act;
+ unsigned char bIFSD;
+ unsigned char bIFSC;
+} atreq_t;
+
+
+/* what is particularly stupid in the original driver is the arch-dependant
+ * member sizes. This leads to CONFIG_COMPAT breakage, since 32bit userspace
+ * will lay out the structure members differently than the 64bit kernel.
+ *
+ * I've changed "ptsreq.protocol" from "unsigned long" to "u_int32_t".
+ * On 32bit this will make no difference. With 64bit kernels, it will make
+ * 32bit apps work, too.
+ */
+
+typedef struct ptsreq {
+ u_int32_t protocol; /*T=0: 2^0, T=1: 2^1*/
+ unsigned char flags;
+ unsigned char pts1;
+ unsigned char pts2;
+ unsigned char pts3;
+} ptsreq_t;
+
+#define CM_IOC_MAGIC 'c'
+#define CM_IOC_MAXNR 255
+
+#define CM_IOCGSTATUS _IOR (CM_IOC_MAGIC, 0, unsigned char *)
+#define CM_IOCGATR _IOWR(CM_IOC_MAGIC, 1, atreq_t *)
+#define CM_IOCSPTS _IOW (CM_IOC_MAGIC, 2, ptsreq_t *)
+#define CM_IOCSRDR _IO (CM_IOC_MAGIC, 3)
+#define CM_IOCARDOFF _IO (CM_IOC_MAGIC, 4)
+
+#define CM_IOSDBGLVL _IOW(CM_IOC_MAGIC, 250, int*)
+
+/* card and device states */
+#define CM_CARD_INSERTED 0x01
+#define CM_CARD_POWERED 0x02
+#define CM_ATR_PRESENT 0x04
+#define CM_ATR_VALID 0x08
+#define CM_STATE_VALID 0x0f
+/* extra info only from CM4000 */
+#define CM_NO_READER 0x10
+#define CM_BAD_CARD 0x20
+
+
+#ifdef __KERNEL__
+
+#define DEVICE_NAME "cmm"
+#define MODULE_NAME "cm4000_cs"
+
+#endif /* __KERNEL__ */
+#endif /* _CM4000_H_ */
diff --git a/include/linux/file.h b/include/linux/file.h
index d3b1a15d5f2..418b6101b59 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -33,13 +33,13 @@ struct fdtable {
* Open file table structure
*/
struct files_struct {
- atomic_t count;
- spinlock_t file_lock; /* Protects all the below members. Nests inside tsk->alloc_lock */
+ atomic_t count;
struct fdtable *fdt;
struct fdtable fdtab;
- fd_set close_on_exec_init;
- fd_set open_fds_init;
- struct file * fd_array[NR_OPEN_DEFAULT];
+ fd_set close_on_exec_init;
+ fd_set open_fds_init;
+ struct file * fd_array[NR_OPEN_DEFAULT];
+ spinlock_t file_lock; /* Protects concurrent writers. Nests inside tsk->alloc_lock */
};
#define files_fdtable(files) (rcu_dereference((files)->fdt))
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 114d5d59f69..934aa9bda48 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -4,7 +4,7 @@
* Definitions for any platform device related flags or structures for
* Freescale processor devices
*
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
* Copyright 2004 Freescale Semiconductor, Inc
*
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index c3779432a72..313dfe9b443 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -14,6 +14,13 @@ struct vm_area_struct;
/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low two bits) */
#define __GFP_DMA ((__force gfp_t)0x01u)
#define __GFP_HIGHMEM ((__force gfp_t)0x02u)
+#ifdef CONFIG_DMA_IS_DMA32
+#define __GFP_DMA32 ((__force gfp_t)0x01) /* ZONE_DMA is ZONE_DMA32 */
+#elif BITS_PER_LONG < 64
+#define __GFP_DMA32 ((__force gfp_t)0x00) /* ZONE_NORMAL is ZONE_DMA32 */
+#else
+#define __GFP_DMA32 ((__force gfp_t)0x04) /* Has own ZONE_DMA32 */
+#endif
/*
* Action modifiers - doesn't change the zoning
@@ -39,8 +46,7 @@ struct vm_area_struct;
#define __GFP_COMP ((__force gfp_t)0x4000u)/* Add compound page metadata */
#define __GFP_ZERO ((__force gfp_t)0x8000u)/* Return zeroed page on success */
#define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
-#define __GFP_NORECLAIM ((__force gfp_t)0x20000u) /* No realy zone reclaim during allocation */
-#define __GFP_HARDWALL ((__force gfp_t)0x40000u) /* Enforce hardwall cpuset memory allocs */
+#define __GFP_HARDWALL ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
#define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */
#define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
@@ -49,7 +55,7 @@ struct vm_area_struct;
#define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
__GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
- __GFP_NOMEMALLOC|__GFP_NORECLAIM|__GFP_HARDWALL)
+ __GFP_NOMEMALLOC|__GFP_HARDWALL)
#define GFP_ATOMIC (__GFP_HIGH)
#define GFP_NOIO (__GFP_WAIT)
@@ -64,6 +70,10 @@ struct vm_area_struct;
#define GFP_DMA __GFP_DMA
+/* 4GB DMA on some platforms */
+#define GFP_DMA32 __GFP_DMA32
+
+
#define gfp_zone(mask) ((__force int)((mask) & (__force gfp_t)GFP_ZONEMASK))
/*
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 5912874ca83..71d2b8a723b 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -90,6 +90,8 @@ extern void synchronize_irq(unsigned int irq);
#define nmi_enter() irq_enter()
#define nmi_exit() sub_preempt_count(HARDIRQ_OFFSET)
+struct task_struct;
+
#ifndef CONFIG_VIRT_CPU_ACCOUNTING
static inline void account_user_vtime(struct task_struct *tsk)
{
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 0cea162b08c..1056717ee50 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -102,8 +102,8 @@ static inline unsigned long hugetlb_total_pages(void)
#define hugetlb_fault(mm, vma, addr, write) ({ BUG(); 0; })
#ifndef HPAGE_MASK
-#define HPAGE_MASK 0 /* Keep the compiler happy */
-#define HPAGE_SIZE 0
+#define HPAGE_MASK PAGE_MASK /* Keep the compiler happy */
+#define HPAGE_SIZE PAGE_SIZE
#endif
#endif /* !CONFIG_HUGETLB_PAGE */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 74abaecdb57..1543daaa9c5 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -107,6 +107,7 @@
#define I2C_DRIVERID_CX25840 71 /* cx2584x video encoder */
#define I2C_DRIVERID_SAA7127 72 /* saa7124 video encoder */
#define I2C_DRIVERID_SAA711X 73 /* saa711x video encoders */
+#define I2C_DRIVERID_AKITAIOEXP 74 /* IO Expander on Sharp SL-C1000 */
#define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */
#define I2C_DRIVERID_EXP1 0xF1
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 68ab5f2ab9c..dcfd2ecccb5 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -51,7 +51,6 @@
.page_table_lock = SPIN_LOCK_UNLOCKED, \
.mmlist = LIST_HEAD_INIT(name.mmlist), \
.cpu_vm_mask = CPU_MASK_ALL, \
- .default_kioctx = INIT_KIOCTX(name.default_kioctx, name), \
}
#define INIT_SIGNALS(sig) { \
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 0a90205184b..41f150a3d2d 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -9,6 +9,7 @@
#include <linux/preempt.h>
#include <linux/cpumask.h>
#include <linux/hardirq.h>
+#include <linux/sched.h>
#include <asm/atomic.h>
#include <asm/ptrace.h>
#include <asm/system.h>
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7b115feca4d..1013a42d10b 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -206,12 +206,6 @@ struct vm_operations_struct {
struct mmu_gather;
struct inode;
-#ifdef ARCH_HAS_ATOMIC_UNSIGNED
-typedef unsigned page_flags_t;
-#else
-typedef unsigned long page_flags_t;
-#endif
-
/*
* Each physical page in the system has a struct page associated with
* it to keep track of whatever it is we are using the page for at the
@@ -219,7 +213,7 @@ typedef unsigned long page_flags_t;
* a page.
*/
struct page {
- page_flags_t flags; /* Atomic flags, some possibly
+ unsigned long flags; /* Atomic flags, some possibly
* updated asynchronously */
atomic_t _count; /* Usage count, see below. */
atomic_t _mapcount; /* Count of ptes mapped in mms,
@@ -435,7 +429,7 @@ static inline void put_page(struct page *page)
#endif
/* Page flags: | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
-#define SECTIONS_PGOFF ((sizeof(page_flags_t)*8) - SECTIONS_WIDTH)
+#define SECTIONS_PGOFF ((sizeof(unsigned long)*8) - SECTIONS_WIDTH)
#define NODES_PGOFF (SECTIONS_PGOFF - NODES_WIDTH)
#define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index f5fa3082fd6..2c8edad5dcc 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -71,10 +71,11 @@ struct per_cpu_pageset {
#endif
#define ZONE_DMA 0
-#define ZONE_NORMAL 1
-#define ZONE_HIGHMEM 2
+#define ZONE_DMA32 1
+#define ZONE_NORMAL 2
+#define ZONE_HIGHMEM 3
-#define MAX_NR_ZONES 3 /* Sync this with ZONES_SHIFT */
+#define MAX_NR_ZONES 4 /* Sync this with ZONES_SHIFT */
#define ZONES_SHIFT 2 /* ceil(log2(MAX_NR_ZONES)) */
@@ -108,9 +109,10 @@ struct per_cpu_pageset {
/*
* On machines where it is needed (eg PCs) we divide physical memory
- * into multiple physical zones. On a PC we have 3 zones:
+ * into multiple physical zones. On a PC we have 4 zones:
*
* ZONE_DMA < 16 MB ISA DMA capable memory
+ * ZONE_DMA32 0 MB Empty
* ZONE_NORMAL 16-896 MB direct mapped by the kernel
* ZONE_HIGHMEM > 896 MB only page cache and user processes
*/
@@ -329,7 +331,7 @@ void get_zone_counts(unsigned long *active, unsigned long *inactive,
void build_all_zonelists(void);
void wakeup_kswapd(struct zone *zone, int order);
int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
- int alloc_type, int can_try_harder, gfp_t gfp_high);
+ int classzone_idx, int alloc_flags);
#ifdef CONFIG_HAVE_MEMORY_PRESENT
void memory_present(int nid, unsigned long start, unsigned long end);
@@ -433,7 +435,9 @@ int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *, int, struct file *,
#include <linux/topology.h>
/* Returns the number of the current Node. */
+#ifndef numa_node_id
#define numa_node_id() (cpu_to_node(raw_smp_processor_id()))
+#endif
#ifndef CONFIG_NEED_MULTIPLE_NODES
@@ -453,12 +457,12 @@ extern struct pglist_data contig_page_data;
#include <asm/sparsemem.h>
#endif
-#if BITS_PER_LONG == 32 || defined(ARCH_HAS_ATOMIC_UNSIGNED)
+#if BITS_PER_LONG == 32
/*
- * with 32 bit page->flags field, we reserve 8 bits for node/zone info.
- * there are 3 zones (2 bits) and this leaves 8-2=6 bits for nodes.
+ * with 32 bit page->flags field, we reserve 9 bits for node/zone info.
+ * there are 4 zones (3 bits) and this leaves 9-3=6 bits for nodes.
*/
-#define FLAGS_RESERVED 8
+#define FLAGS_RESERVED 9
#elif BITS_PER_LONG == 64
/*
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index 72975fa8795..934a2479f16 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -112,7 +112,6 @@ struct nfnl_callback
{
int (*call)(struct sock *nl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *cda[], int *errp);
- kernel_cap_t cap_required; /* capabilities required for this msg */
u_int16_t attr_count; /* number of nfattr's */
};
@@ -154,11 +153,14 @@ extern void nfattr_parse(struct nfattr *tb[], int maxattr,
#define nfattr_bad_size(tb, max, cta_min) \
({ int __i, __res = 0; \
- for (__i=0; __i<max; __i++) \
+ for (__i=0; __i<max; __i++) { \
+ if (!cta_min[__i]) \
+ continue; \
if (tb[__i] && NFA_PAYLOAD(tb[__i]) < cta_min[__i]){ \
__res = 1; \
break; \
} \
+ } \
__res; \
})
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index ba6c310a055..ee700c6eb44 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -53,12 +53,12 @@ void release_pages(struct page **pages, int nr, int cold);
static inline struct page *page_cache_alloc(struct address_space *x)
{
- return alloc_pages(mapping_gfp_mask(x)|__GFP_NORECLAIM, 0);
+ return alloc_pages(mapping_gfp_mask(x), 0);
}
static inline struct page *page_cache_alloc_cold(struct address_space *x)
{
- return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD|__GFP_NORECLAIM, 0);
+ return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0);
}
typedef int filler_t(void *, struct page *);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index d00f8ba7f22..d4c1c8fd292 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -805,6 +805,10 @@
#define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051
#define PCI_DEVICE_ID_APPLE_U3L_AGP 0x0058
#define PCI_DEVICE_ID_APPLE_U3H_AGP 0x0059
+#define PCI_DEVICE_ID_APPLE_IPID2_AGP 0x0066
+#define PCI_DEVICE_ID_APPLE_IPID2_ATA 0x0069
+#define PCI_DEVICE_ID_APPLE_IPID2_FW 0x006a
+#define PCI_DEVICE_ID_APPLE_IPID2_GMAC 0x006b
#define PCI_DEVICE_ID_APPLE_TIGON3 0x1645
#define PCI_VENDOR_ID_YAMAHA 0x1073
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 5451eb1e781..fb8d2d24e4b 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -38,7 +38,7 @@ extern void free_percpu(const void *);
#else /* CONFIG_SMP */
-#define per_cpu_ptr(ptr, cpu) (ptr)
+#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); (ptr); })
static inline void *__alloc_percpu(size_t size, size_t align)
{
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 1514098d156..5be87ba3b7a 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -94,55 +94,6 @@ struct pm_dev
struct list_head entry;
};
-#ifdef CONFIG_PM
-
-extern int pm_active;
-
-#define PM_IS_ACTIVE() (pm_active != 0)
-
-/*
- * Register a device with power management
- */
-struct pm_dev __deprecated *
-pm_register(pm_dev_t type, unsigned long id, pm_callback callback);
-
-/*
- * Unregister a device with power management
- */
-void __deprecated pm_unregister(struct pm_dev *dev);
-
-/*
- * Unregister all devices with matching callback
- */
-void __deprecated pm_unregister_all(pm_callback callback);
-
-/*
- * Send a request to all devices
- */
-int __deprecated pm_send_all(pm_request_t rqst, void *data);
-
-#else /* CONFIG_PM */
-
-#define PM_IS_ACTIVE() 0
-
-static inline struct pm_dev *pm_register(pm_dev_t type,
- unsigned long id,
- pm_callback callback)
-{
- return NULL;
-}
-
-static inline void pm_unregister(struct pm_dev *dev) {}
-
-static inline void pm_unregister_all(pm_callback callback) {}
-
-static inline int pm_send_all(pm_request_t rqst, void *data)
-{
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
/* Functions above this comment are list-based old-style power
* managment. Please avoid using them. */
diff --git a/include/linux/pm_legacy.h b/include/linux/pm_legacy.h
new file mode 100644
index 00000000000..1252b45face
--- /dev/null
+++ b/include/linux/pm_legacy.h
@@ -0,0 +1,56 @@
+#ifndef __LINUX_PM_LEGACY_H__
+#define __LINUX_PM_LEGACY_H__
+
+#include <linux/config.h>
+
+#ifdef CONFIG_PM_LEGACY
+
+extern int pm_active;
+
+#define PM_IS_ACTIVE() (pm_active != 0)
+
+/*
+ * Register a device with power management
+ */
+struct pm_dev __deprecated *
+pm_register(pm_dev_t type, unsigned long id, pm_callback callback);
+
+/*
+ * Unregister a device with power management
+ */
+void __deprecated pm_unregister(struct pm_dev *dev);
+
+/*
+ * Unregister all devices with matching callback
+ */
+void __deprecated pm_unregister_all(pm_callback callback);
+
+/*
+ * Send a request to all devices
+ */
+int __deprecated pm_send_all(pm_request_t rqst, void *data);
+
+#else /* CONFIG_PM_LEGACY */
+
+#define PM_IS_ACTIVE() 0
+
+static inline struct pm_dev *pm_register(pm_dev_t type,
+ unsigned long id,
+ pm_callback callback)
+{
+ return NULL;
+}
+
+static inline void pm_unregister(struct pm_dev *dev) {}
+
+static inline void pm_unregister_all(pm_callback callback) {}
+
+static inline int pm_send_all(pm_request_t rqst, void *data)
+{
+ return 0;
+}
+
+#endif /* CONFIG_PM_LEGACY */
+
+#endif /* __LINUX_PM_LEGACY_H__ */
+
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index dd98c54a23b..d9a2f5254a5 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -7,6 +7,7 @@
*/
#include <linux/config.h>
+#include <linux/thread_info.h>
#include <linux/linkage.h>
#ifdef CONFIG_DEBUG_PREEMPT
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 2bbf968b23d..2038bd27b04 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -357,7 +357,6 @@ struct mm_struct {
/* aio bits */
rwlock_t ioctx_list_lock;
struct kioctx *ioctx_list;
- struct kioctx default_kioctx;
};
struct sighand_struct {
@@ -1233,32 +1232,49 @@ static inline void task_unlock(struct task_struct *p)
spin_unlock(&p->alloc_lock);
}
+#ifndef __HAVE_THREAD_FUNCTIONS
+
+#define task_thread_info(task) (task)->thread_info
+
+static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
+{
+ *task_thread_info(p) = *task_thread_info(org);
+ task_thread_info(p)->task = p;
+}
+
+static inline unsigned long *end_of_stack(struct task_struct *p)
+{
+ return (unsigned long *)(p->thread_info + 1);
+}
+
+#endif
+
/* set thread flags in other task's structures
* - see asm/thread_info.h for TIF_xxxx flags available
*/
static inline void set_tsk_thread_flag(struct task_struct *tsk, int flag)
{
- set_ti_thread_flag(tsk->thread_info,flag);
+ set_ti_thread_flag(task_thread_info(tsk), flag);
}
static inline void clear_tsk_thread_flag(struct task_struct *tsk, int flag)
{
- clear_ti_thread_flag(tsk->thread_info,flag);
+ clear_ti_thread_flag(task_thread_info(tsk), flag);
}
static inline int test_and_set_tsk_thread_flag(struct task_struct *tsk, int flag)
{
- return test_and_set_ti_thread_flag(tsk->thread_info,flag);
+ return test_and_set_ti_thread_flag(task_thread_info(tsk), flag);
}
static inline int test_and_clear_tsk_thread_flag(struct task_struct *tsk, int flag)
{
- return test_and_clear_ti_thread_flag(tsk->thread_info,flag);
+ return test_and_clear_ti_thread_flag(task_thread_info(tsk), flag);
}
static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag)
{
- return test_ti_thread_flag(tsk->thread_info,flag);
+ return test_ti_thread_flag(task_thread_info(tsk), flag);
}
static inline void set_tsk_need_resched(struct task_struct *tsk)
@@ -1329,12 +1345,12 @@ extern void signal_wake_up(struct task_struct *t, int resume_stopped);
static inline unsigned int task_cpu(const struct task_struct *p)
{
- return p->thread_info->cpu;
+ return task_thread_info(p)->cpu;
}
static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
{
- p->thread_info->cpu = cpu;
+ task_thread_info(p)->cpu = cpu;
}
#else
diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h
index b63ce701409..fa1ff3b165f 100644
--- a/include/linux/smp_lock.h
+++ b/include/linux/smp_lock.h
@@ -2,11 +2,10 @@
#define __LINUX_SMPLOCK_H
#include <linux/config.h>
+#ifdef CONFIG_LOCK_KERNEL
#include <linux/sched.h>
#include <linux/spinlock.h>
-#ifdef CONFIG_LOCK_KERNEL
-
#define kernel_locked() (current->lock_depth >= 0)
extern int __lockfunc __reacquire_kernel_lock(void);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 64f203c4537..6bc03c911a8 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/list.h>
#include <linux/compiler.h>
struct file;
@@ -859,6 +858,7 @@ enum
};
#ifdef __KERNEL__
+#include <linux/list.h>
extern void sysctl_init(void);
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index d252f45a0f9..1c4eb41dbd8 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -27,31 +27,6 @@ extern long do_no_restart_syscall(struct restart_block *parm);
* - pass TIF_xxxx constants to these functions
*/
-static inline void set_thread_flag(int flag)
-{
- set_bit(flag,&current_thread_info()->flags);
-}
-
-static inline void clear_thread_flag(int flag)
-{
- clear_bit(flag,&current_thread_info()->flags);
-}
-
-static inline int test_and_set_thread_flag(int flag)
-{
- return test_and_set_bit(flag,&current_thread_info()->flags);
-}
-
-static inline int test_and_clear_thread_flag(int flag)
-{
- return test_and_clear_bit(flag,&current_thread_info()->flags);
-}
-
-static inline int test_thread_flag(int flag)
-{
- return test_bit(flag,&current_thread_info()->flags);
-}
-
static inline void set_ti_thread_flag(struct thread_info *ti, int flag)
{
set_bit(flag,&ti->flags);
@@ -77,15 +52,19 @@ static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
return test_bit(flag,&ti->flags);
}
-static inline void set_need_resched(void)
-{
- set_thread_flag(TIF_NEED_RESCHED);
-}
-
-static inline void clear_need_resched(void)
-{
- clear_thread_flag(TIF_NEED_RESCHED);
-}
+#define set_thread_flag(flag) \
+ set_ti_thread_flag(current_thread_info(), flag)
+#define clear_thread_flag(flag) \
+ clear_ti_thread_flag(current_thread_info(), flag)
+#define test_and_set_thread_flag(flag) \
+ test_and_set_ti_thread_flag(current_thread_info(), flag)
+#define test_and_clear_thread_flag(flag) \
+ test_and_clear_ti_thread_flag(current_thread_info(), flag)
+#define test_thread_flag(flag) \
+ test_ti_thread_flag(current_thread_info(), flag)
+
+#define set_need_resched() set_thread_flag(TIF_NEED_RESCHED)
+#define clear_need_resched() clear_thread_flag(TIF_NEED_RESCHED)
#endif
diff --git a/include/linux/time.h b/include/linux/time.h
index 8e83f4e778b..bfbe92d0767 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -101,7 +101,7 @@ extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
static inline void
set_normalized_timespec (struct timespec *ts, time_t sec, long nsec)
{
- while (nsec > NSEC_PER_SEC) {
+ while (nsec >= NSEC_PER_SEC) {
nsec -= NSEC_PER_SEC;
++sec;
}
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 748d0438525..856d232c756 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -819,7 +819,7 @@ typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
*/
struct urb
{
- /* private, usb core and host controller only fields in the urb */
+ /* private: usb core and host controller only fields in the urb */
struct kref kref; /* reference count of the URB */
spinlock_t lock; /* lock for the URB */
void *hcpriv; /* private data for host controller */
@@ -827,7 +827,7 @@ struct urb
atomic_t use_count; /* concurrent submissions counter */
u8 reject; /* submissions will fail */
- /* public, documented fields in the urb that can be used by drivers */
+ /* public: documented fields in the urb that can be used by drivers */
struct list_head urb_list; /* list head for use by the urb's
* current owner */
struct usb_device *dev; /* (in) pointer to associated device */
@@ -1045,7 +1045,7 @@ struct usb_sg_request {
size_t bytes;
/*
- * members below are private to usbcore,
+ * members below are private: to usbcore,
* and are not provided for driver access!
*/
spinlock_t lock;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index a114fff6568..1cded681eb6 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -636,6 +636,7 @@ typedef __u64 v4l2_std_id;
#define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000)
#define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000)
#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000)
+#define V4L2_STD_SECAM_LC ((v4l2_std_id)0x00800000)
/* ATSC/HDTV */
#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000)
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 0f1ba95ec8d..ad3e9bb670c 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -49,6 +49,7 @@ struct ir_input_state {
extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h
index 00fa57eb9fd..730f21ed91d 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/ir-kbd-i2c.h
@@ -19,4 +19,6 @@ struct IR_i2c {
char phys[32];
int (*get_key)(struct IR_i2c*, u32*, u32*);
};
+
+int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
#endif
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 9184e534b7e..faa0f8e3091 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -113,6 +113,7 @@
#define TUNER_PHILIPS_TD1316 67
#define TUNER_PHILIPS_TUV1236D 68 /* ATI HDTV Wonder */
+#define TUNER_TNF_5335MF 69 /* Sabrent Bt848 */
#define NOTUNER 0
#define PAL 1 /* PAL_BG */
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
new file mode 100644
index 00000000000..d3fd48157eb
--- /dev/null
+++ b/include/media/v4l2-common.h
@@ -0,0 +1,110 @@
+/*
+ v4l2 common internal API header
+
+ This header contains internal shared ioctl definitions for use by the
+ internal low-level v4l2 drivers.
+ Each ioctl begins with VIDIOC_INT_ to clearly mark that it is an internal
+ define,
+
+ Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+
+ This program is free software; you can redistribute 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 V4L2_COMMON_H_
+#define V4L2_COMMON_H_
+
+/* VIDIOC_INT_AUDIO_CLOCK_FREQ */
+enum v4l2_audio_clock_freq {
+ V4L2_AUDCLK_32_KHZ = 32000,
+ V4L2_AUDCLK_441_KHZ = 44100,
+ V4L2_AUDCLK_48_KHZ = 48000,
+};
+
+/* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
+struct v4l2_register {
+ u32 i2c_id; /* I2C driver ID of the I2C chip. 0 for the I2C adapter. */
+ unsigned long reg;
+ u32 val;
+};
+
+/* VIDIOC_INT_DECODE_VBI_LINE */
+struct v4l2_decode_vbi_line {
+ u32 is_second_field; /* Set to 0 for the first (odd) field,
+ set to 1 for the second (even) field. */
+ u8 *p; /* Pointer to the sliced VBI data from the decoder.
+ On exit points to the start of the payload. */
+ u32 line; /* Line number of the sliced VBI data (1-23) */
+ u32 type; /* VBI service type (V4L2_SLICED_*). 0 if no service found */
+};
+
+/* VIDIOC_INT_G_CHIP_IDENT: identifies the actual chip installed on the board */
+enum v4l2_chip_ident {
+ /* general idents: reserved range 0-49 */
+ V4L2_IDENT_UNKNOWN = 0,
+
+ /* module saa7115: reserved range 100-149 */
+ V4L2_IDENT_SAA7114 = 104,
+ V4L2_IDENT_SAA7115 = 105,
+
+ /* module saa7127: reserved range 150-199 */
+ V4L2_IDENT_SAA7127 = 157,
+ V4L2_IDENT_SAA7129 = 159,
+
+ /* module cx25840: reserved range 200-249 */
+ V4L2_IDENT_CX25840 = 240,
+ V4L2_IDENT_CX25841 = 241,
+ V4L2_IDENT_CX25842 = 242,
+ V4L2_IDENT_CX25843 = 243,
+};
+
+/* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
+#define VIDIOC_INT_S_REGISTER _IOR ('d', 100, struct v4l2_register)
+#define VIDIOC_INT_G_REGISTER _IOWR('d', 101, struct v4l2_register)
+
+/* Reset the I2C chip */
+#define VIDIOC_INT_RESET _IO ('d', 102)
+
+/* Set the frequency of the audio clock output.
+ Used to slave an audio processor to the video decoder, ensuring that audio
+ and video remain synchronized. */
+#define VIDIOC_INT_AUDIO_CLOCK_FREQ _IOR ('d', 103, enum v4l2_audio_clock_freq)
+
+/* Video decoders that support sliced VBI need to implement this ioctl.
+ Field p of the v4l2_sliced_vbi_line struct is set to the start of the VBI
+ data that was generated by the decoder. The driver then parses the sliced
+ VBI data and sets the other fields in the struct accordingly. The pointer p
+ is updated to point to the start of the payload which can be copied
+ verbatim into the data field of the v4l2_sliced_vbi_data struct. If no
+ valid VBI data was found, then the type field is set to 0 on return. */
+#define VIDIOC_INT_DECODE_VBI_LINE _IOWR('d', 104, struct v4l2_decode_vbi_line)
+
+/* Used to generate VBI signals on a video signal. v4l2_sliced_vbi_data is
+ filled with the data packets that should be output. Note that if you set
+ the line field to 0, then that VBI signal is disabled. */
+#define VIDIOC_INT_S_VBI_DATA _IOW ('d', 105, struct v4l2_sliced_vbi_data)
+
+/* Used to obtain the sliced VBI packet from a readback register. Not all
+ video decoders support this. If no data is available because the readback
+ register contains invalid or erroneous data -EIO is returned. Note that
+ you must fill in the 'id' member and the 'field' member (to determine
+ whether CC data from the first or second field should be obtained). */
+#define VIDIOC_INT_G_VBI_DATA _IOWR('d', 106, struct v4l2_sliced_vbi_data *)
+
+/* Returns the chip identifier or V4L2_IDENT_UNKNOWN if no identification can
+ be made. */
+#define VIDIOC_INT_G_CHIP_IDENT _IOR ('d', 107, enum v4l2_chip_ident *)
+
+#endif /* V4L2_COMMON_H_ */
diff --git a/include/net/llc_pdu.h b/include/net/llc_pdu.h
index c7a959428b4..8f6306581fa 100644
--- a/include/net/llc_pdu.h
+++ b/include/net/llc_pdu.h
@@ -357,7 +357,7 @@ static inline void llc_pdu_init_as_test_rsp(struct sk_buff *skb,
/* LLC Type 1 XID command/response information fields format */
struct llc_xid_info {
- u8 fmt_id; /* always 0x18 for LLC */
+ u8 fmt_id; /* always 0x81 for LLC */
u8 type; /* different if NULL/non-NULL LSAP */
u8 rw; /* sender receive window */
};
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 0f984801197..d78025f9fbe 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -552,8 +552,8 @@ extern u32 __tcp_select_window(struct sock *sk);
/* TCP timestamps are only 32-bits, this causes a slight
* complication on 64-bit systems since we store a snapshot
- * of jiffies in the buffer control blocks below. We decidedly
- * only use of the low 32-bits of jiffies and hide the ugly
+ * of jiffies in the buffer control blocks below. We decided
+ * to use only the low 32-bits of jiffies and hide the ugly
* casts with the following macro.
*/
#define tcp_time_stamp ((__u32)(jiffies))
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 5a737ed9dac..7430640f981 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1809,11 +1809,12 @@ int cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask)
if (gfp_mask & __GFP_HARDWALL) /* If hardwall request, stop here */
return 0;
+ if (current->flags & PF_EXITING) /* Let dying task have memory */
+ return 1;
+
/* Not hardwall and node outside mems_allowed: scan up cpusets */
down(&callback_sem);
- if (current->flags & PF_EXITING) /* Let dying task have memory */
- return 1;
task_lock(current);
cs = nearest_exclusive_ancestor(current->cpuset);
task_unlock(current);
diff --git a/kernel/exit.c b/kernel/exit.c
index 452a1d11617..ee515683b92 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -859,7 +859,7 @@ fastcall NORET_TYPE void do_exit(long code)
if (group_dead && tsk->signal->leader)
disassociate_ctty(1);
- module_put(tsk->thread_info->exec_domain->module);
+ module_put(task_thread_info(tsk)->exec_domain->module);
if (tsk->binfmt)
module_put(tsk->binfmt->module);
diff --git a/kernel/fork.c b/kernel/fork.c
index 158710d2256..e0d0b77343f 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -171,10 +171,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
return NULL;
}
- *ti = *orig->thread_info;
*tsk = *orig;
tsk->thread_info = ti;
- ti->task = tsk;
+ setup_thread_stack(tsk, orig);
/* One for us, one for whoever does the "release_task()" (usually parent) */
atomic_set(&tsk->usage,2);
@@ -324,7 +323,6 @@ static struct mm_struct * mm_init(struct mm_struct * mm)
spin_lock_init(&mm->page_table_lock);
rwlock_init(&mm->ioctx_list_lock);
mm->ioctx_list = NULL;
- mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm);
mm->free_area_cache = TASK_UNMAPPED_BASE;
mm->cached_hole_size = ~0UL;
@@ -919,7 +917,7 @@ static task_t *copy_process(unsigned long clone_flags,
if (nr_threads >= max_threads)
goto bad_fork_cleanup_count;
- if (!try_module_get(p->thread_info->exec_domain->module))
+ if (!try_module_get(task_thread_info(p)->exec_domain->module))
goto bad_fork_cleanup_count;
if (p->binfmt && !try_module_get(p->binfmt->module))
@@ -1180,7 +1178,7 @@ bad_fork_cleanup:
if (p->binfmt)
module_put(p->binfmt->module);
bad_fork_cleanup_put_domain:
- module_put(p->thread_info->exec_domain->module);
+ module_put(task_thread_info(p)->exec_domain->module);
bad_fork_cleanup_count:
put_group_info(p->group_info);
atomic_dec(&p->user->processes);
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index ea55c7a1cd7..5870efb3e20 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -270,7 +270,7 @@ static void tstojiffie(struct timespec *tp, int res, u64 *jiff)
long sec = tp->tv_sec;
long nsec = tp->tv_nsec + res - 1;
- if (nsec > NSEC_PER_SEC) {
+ if (nsec >= NSEC_PER_SEC) {
sec++;
nsec -= NSEC_PER_SEC;
}
@@ -1209,13 +1209,9 @@ static int do_posix_clock_monotonic_get(clockid_t clock, struct timespec *tp)
do_posix_clock_monotonic_gettime_parts(tp, &wall_to_mono);
- tp->tv_sec += wall_to_mono.tv_sec;
- tp->tv_nsec += wall_to_mono.tv_nsec;
+ set_normalized_timespec(tp, tp->tv_sec + wall_to_mono.tv_sec,
+ tp->tv_nsec + wall_to_mono.tv_nsec);
- if ((tp->tv_nsec - NSEC_PER_SEC) > 0) {
- tp->tv_nsec -= NSEC_PER_SEC;
- tp->tv_sec++;
- }
return 0;
}
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 46a5e5acff9..5ec248cb7f4 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -19,6 +19,15 @@ config PM
will issue the hlt instruction if nothing is to be done, thereby
sending the processor to sleep and saving power.
+config PM_LEGACY
+ bool "Legacy Power Management API"
+ depends on PM
+ default y
+ ---help---
+ Support for pm_register() and friends.
+
+ If unsure, say Y.
+
config PM_DEBUG
bool "Power Management Debug Support"
depends on PM
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index c71eb4579c0..04be7d0d96a 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -3,7 +3,8 @@ ifeq ($(CONFIG_PM_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
-obj-y := main.o process.o console.o pm.o
+obj-y := main.o process.o console.o
+obj-$(CONFIG_PM_LEGACY) += pm.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o snapshot.o
obj-$(CONFIG_SUSPEND_SMP) += smp.o
diff --git a/kernel/power/pm.c b/kernel/power/pm.c
index 159149321b3..33c508e857d 100644
--- a/kernel/power/pm.c
+++ b/kernel/power/pm.c
@@ -23,6 +23,7 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/interrupt.h>
int pm_active;
diff --git a/kernel/printk.c b/kernel/printk.c
index e9be027bc93..ac8a08f3620 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -491,7 +491,10 @@ __attribute__((weak)) unsigned long long printk_clock(void)
return sched_clock();
}
-/*
+/**
+ * printk - print a kernel message
+ * @fmt: format string
+ *
* This is printk. It can be called from any context. We want it to work.
*
* We try to grab the console_sem. If we succeed, it's easy - we log the output and
@@ -503,6 +506,9 @@ __attribute__((weak)) unsigned long long printk_clock(void)
* One effect of this deferred printing is that code which calls printk() and
* then changes console_loglevel may break. This is because console_loglevel
* is inspected when the actual printing occurs.
+ *
+ * See also:
+ * printf(3)
*/
asmlinkage int printk(const char *fmt, ...)
@@ -655,6 +661,9 @@ static void call_console_drivers(unsigned long start, unsigned long end)
/**
* add_preferred_console - add a device to the list of preferred consoles.
+ * @name: device name
+ * @idx: device index
+ * @options: options for this console
*
* The last preferred console added will be used for kernel messages
* and stdin/out/err for init. Normally this is used by console_setup
@@ -764,7 +773,8 @@ void release_console_sem(void)
}
EXPORT_SYMBOL(release_console_sem);
-/** console_conditional_schedule - yield the CPU if required
+/**
+ * console_conditional_schedule - yield the CPU if required
*
* If the console code is currently allowed to sleep, and
* if this CPU should yield the CPU to another task, do
@@ -976,6 +986,8 @@ EXPORT_SYMBOL(unregister_console);
/**
* tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
*
* This is used for messages that need to be redirected to a specific tty.
* We don't put it into the syslog queue right now maybe in the future if
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index b88d4186cd7..17ee7e5a345 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -470,7 +470,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
if (request == PTRACE_ATTACH) {
ret = ptrace_attach(child);
- goto out;
+ goto out_put_task_struct;
}
ret = ptrace_check_attach(child, request == PTRACE_KILL);
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 9b58f1eff3c..eb6719c50b4 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -195,6 +195,8 @@ rcu_torture_writer(void *arg)
static DEFINE_RCU_RANDOM(rand);
VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
+ set_user_nice(current, 19);
+
do {
schedule_timeout_uninterruptible(1);
if (rcu_batches_completed() == oldbatch)
@@ -238,6 +240,8 @@ rcu_torture_reader(void *arg)
int pipe_count;
VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
+ set_user_nice(current, 19);
+
do {
rcu_read_lock();
completed = rcu_batches_completed();
diff --git a/kernel/sched.c b/kernel/sched.c
index b6506671b2b..6f46c94cc29 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1437,7 +1437,7 @@ void fastcall sched_fork(task_t *p, int clone_flags)
#endif
#ifdef CONFIG_PREEMPT
/* Want to start with kernel preemption disabled. */
- p->thread_info->preempt_count = 1;
+ task_thread_info(p)->preempt_count = 1;
#endif
/*
* Share the timeslice between parent and child, thus the
@@ -4327,10 +4327,10 @@ static void show_task(task_t *p)
#endif
#ifdef CONFIG_DEBUG_STACK_USAGE
{
- unsigned long *n = (unsigned long *) (p->thread_info+1);
+ unsigned long *n = end_of_stack(p);
while (!*n)
n++;
- free = (unsigned long) n - (unsigned long)(p->thread_info+1);
+ free = (unsigned long)n - (unsigned long)end_of_stack(p);
}
#endif
printk("%5lu %5d %6d ", free, p->pid, p->parent->pid);
@@ -4410,9 +4410,9 @@ void __devinit init_idle(task_t *idle, int cpu)
/* Set the preempt count _outside_ the spinlocks! */
#if defined(CONFIG_PREEMPT) && !defined(CONFIG_PREEMPT_BKL)
- idle->thread_info->preempt_count = (idle->lock_depth >= 0);
+ task_thread_info(idle)->preempt_count = (idle->lock_depth >= 0);
#else
- idle->thread_info->preempt_count = 0;
+ task_thread_info(idle)->preempt_count = 0;
#endif
}
diff --git a/kernel/signal.c b/kernel/signal.c
index 80789a59b4d..d7611f189ef 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -513,16 +513,7 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
{
int sig = 0;
- /* SIGKILL must have priority, otherwise it is quite easy
- * to create an unkillable process, sending sig < SIGKILL
- * to self */
- if (unlikely(sigismember(&pending->signal, SIGKILL))) {
- if (!sigismember(mask, SIGKILL))
- sig = SIGKILL;
- }
-
- if (likely(!sig))
- sig = next_signal(pending, mask);
+ sig = next_signal(pending, mask);
if (sig) {
if (current->notifier) {
if (sigismember(current->notifier_mask, sig)) {
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 84a9d18aa8d..b3d4dc858e3 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -119,13 +119,12 @@ static int stop_machine(void)
return ret;
}
- /* Don't schedule us away at this point, please. */
- local_irq_disable();
-
/* Now they are all started, make them hold the CPUs, ready. */
+ preempt_disable();
stopmachine_set_state(STOPMACHINE_PREPARE);
/* Make them disable irqs. */
+ local_irq_disable();
stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);
return 0;
@@ -135,6 +134,7 @@ static void restart_machine(void)
{
stopmachine_set_state(STOPMACHINE_EXIT);
local_irq_enable();
+ preempt_enable_no_resched();
}
struct stop_machine_data
diff --git a/mm/filemap.c b/mm/filemap.c
index 5d6e4c2000d..33a28bfde15 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -134,7 +134,7 @@ static int sync_page(void *word)
struct address_space *mapping;
struct page *page;
- page = container_of((page_flags_t *)word, struct page, flags);
+ page = container_of((unsigned long *)word, struct page, flags);
/*
* page_mapping() is being called without PG_locked held.
diff --git a/mm/memory.c b/mm/memory.c
index 0f60baf6f69..2998cfc12f5 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -549,10 +549,10 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
return 0;
}
-static void zap_pte_range(struct mmu_gather *tlb,
+static unsigned long zap_pte_range(struct mmu_gather *tlb,
struct vm_area_struct *vma, pmd_t *pmd,
unsigned long addr, unsigned long end,
- struct zap_details *details)
+ long *zap_work, struct zap_details *details)
{
struct mm_struct *mm = tlb->mm;
pte_t *pte;
@@ -563,10 +563,15 @@ static void zap_pte_range(struct mmu_gather *tlb,
pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
do {
pte_t ptent = *pte;
- if (pte_none(ptent))
+ if (pte_none(ptent)) {
+ (*zap_work)--;
continue;
+ }
if (pte_present(ptent)) {
struct page *page = NULL;
+
+ (*zap_work) -= PAGE_SIZE;
+
if (!(vma->vm_flags & VM_RESERVED)) {
unsigned long pfn = pte_pfn(ptent);
if (unlikely(!pfn_valid(pfn)))
@@ -624,16 +629,18 @@ static void zap_pte_range(struct mmu_gather *tlb,
if (!pte_file(ptent))
free_swap_and_cache(pte_to_swp_entry(ptent));
pte_clear_full(mm, addr, pte, tlb->fullmm);
- } while (pte++, addr += PAGE_SIZE, addr != end);
+ } while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0));
add_mm_rss(mm, file_rss, anon_rss);
pte_unmap_unlock(pte - 1, ptl);
+
+ return addr;
}
-static inline void zap_pmd_range(struct mmu_gather *tlb,
+static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,
struct vm_area_struct *vma, pud_t *pud,
unsigned long addr, unsigned long end,
- struct zap_details *details)
+ long *zap_work, struct zap_details *details)
{
pmd_t *pmd;
unsigned long next;
@@ -641,16 +648,21 @@ static inline void zap_pmd_range(struct mmu_gather *tlb,
pmd = pmd_offset(pud, addr);
do {
next = pmd_addr_end(addr, end);
- if (pmd_none_or_clear_bad(pmd))
+ if (pmd_none_or_clear_bad(pmd)) {
+ (*zap_work)--;
continue;
- zap_pte_range(tlb, vma, pmd, addr, next, details);
- } while (pmd++, addr = next, addr != end);
+ }
+ next = zap_pte_range(tlb, vma, pmd, addr, next,
+ zap_work, details);
+ } while (pmd++, addr = next, (addr != end && *zap_work > 0));
+
+ return addr;
}
-static inline void zap_pud_range(struct mmu_gather *tlb,
+static inline unsigned long zap_pud_range(struct mmu_gather *tlb,
struct vm_area_struct *vma, pgd_t *pgd,
unsigned long addr, unsigned long end,
- struct zap_details *details)
+ long *zap_work, struct zap_details *details)
{
pud_t *pud;
unsigned long next;
@@ -658,15 +670,21 @@ static inline void zap_pud_range(struct mmu_gather *tlb,
pud = pud_offset(pgd, addr);
do {
next = pud_addr_end(addr, end);
- if (pud_none_or_clear_bad(pud))
+ if (pud_none_or_clear_bad(pud)) {
+ (*zap_work)--;
continue;
- zap_pmd_range(tlb, vma, pud, addr, next, details);
- } while (pud++, addr = next, addr != end);
+ }
+ next = zap_pmd_range(tlb, vma, pud, addr, next,
+ zap_work, details);
+ } while (pud++, addr = next, (addr != end && *zap_work > 0));
+
+ return addr;
}
-static void unmap_page_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
+static unsigned long unmap_page_range(struct mmu_gather *tlb,
+ struct vm_area_struct *vma,
unsigned long addr, unsigned long end,
- struct zap_details *details)
+ long *zap_work, struct zap_details *details)
{
pgd_t *pgd;
unsigned long next;
@@ -679,11 +697,16 @@ static void unmap_page_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
pgd = pgd_offset(vma->vm_mm, addr);
do {
next = pgd_addr_end(addr, end);
- if (pgd_none_or_clear_bad(pgd))
+ if (pgd_none_or_clear_bad(pgd)) {
+ (*zap_work)--;
continue;
- zap_pud_range(tlb, vma, pgd, addr, next, details);
- } while (pgd++, addr = next, addr != end);
+ }
+ next = zap_pud_range(tlb, vma, pgd, addr, next,
+ zap_work, details);
+ } while (pgd++, addr = next, (addr != end && *zap_work > 0));
tlb_end_vma(tlb, vma);
+
+ return addr;
}
#ifdef CONFIG_PREEMPT
@@ -724,7 +747,7 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp,
unsigned long end_addr, unsigned long *nr_accounted,
struct zap_details *details)
{
- unsigned long zap_bytes = ZAP_BLOCK_SIZE;
+ long zap_work = ZAP_BLOCK_SIZE;
unsigned long tlb_start = 0; /* For tlb_finish_mmu */
int tlb_start_valid = 0;
unsigned long start = start_addr;
@@ -745,27 +768,25 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp,
*nr_accounted += (end - start) >> PAGE_SHIFT;
while (start != end) {
- unsigned long block;
-
if (!tlb_start_valid) {
tlb_start = start;
tlb_start_valid = 1;
}
- if (is_vm_hugetlb_page(vma)) {
- block = end - start;
+ if (unlikely(is_vm_hugetlb_page(vma))) {
unmap_hugepage_range(vma, start, end);
- } else {
- block = min(zap_bytes, end - start);
- unmap_page_range(*tlbp, vma, start,
- start + block, details);
+ zap_work -= (end - start) /
+ (HPAGE_SIZE / PAGE_SIZE);
+ start = end;
+ } else
+ start = unmap_page_range(*tlbp, vma,
+ start, end, &zap_work, details);
+
+ if (zap_work > 0) {
+ BUG_ON(start != end);
+ break;
}
- start += block;
- zap_bytes -= block;
- if ((long)zap_bytes > 0)
- continue;
-
tlb_finish_mmu(*tlbp, tlb_start, start);
if (need_resched() ||
@@ -779,7 +800,7 @@ unsigned long unmap_vmas(struct mmu_gather **tlbp,
*tlbp = tlb_gather_mmu(vma->vm_mm, fullmm);
tlb_start_valid = 0;
- zap_bytes = ZAP_BLOCK_SIZE;
+ zap_work = ZAP_BLOCK_SIZE;
}
}
out:
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 987225bdd66..104e69ca55e 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -60,8 +60,11 @@ long nr_swap_pages;
* NORMAL allocation will leave 784M/256 of ram reserved in the ZONE_DMA
* HIGHMEM allocation will leave 224M/32 of ram reserved in ZONE_NORMAL
* HIGHMEM allocation will (224M+784M)/256 of ram reserved in ZONE_DMA
+ *
+ * TBD: should special case ZONE_DMA32 machines here - in those we normally
+ * don't need any ZONE_NORMAL reservation
*/
-int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = { 256, 32 };
+int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = { 256, 256, 32 };
EXPORT_SYMBOL(totalram_pages);
@@ -72,7 +75,7 @@ EXPORT_SYMBOL(totalram_pages);
struct zone *zone_table[1 << ZONETABLE_SHIFT] __read_mostly;
EXPORT_SYMBOL(zone_table);
-static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" };
+static char *zone_names[MAX_NR_ZONES] = { "DMA", "DMA32", "Normal", "HighMem" };
int min_free_kbytes = 1024;
unsigned long __initdata nr_kernel_pages;
@@ -124,7 +127,7 @@ static void bad_page(const char *function, struct page *page)
printk(KERN_EMERG "Bad page state at %s (in process '%s', page %p)\n",
function, current->comm, page);
printk(KERN_EMERG "flags:0x%0*lx mapping:%p mapcount:%d count:%d\n",
- (int)(2*sizeof(page_flags_t)), (unsigned long)page->flags,
+ (int)(2*sizeof(unsigned long)), (unsigned long)page->flags,
page->mapping, page_mapcount(page), page_count(page));
printk(KERN_EMERG "Backtrace:\n");
dump_stack();
@@ -732,9 +735,7 @@ buffered_rmqueue(struct zone *zone, int order, gfp_t gfp_flags)
}
local_irq_restore(flags);
put_cpu();
- }
-
- if (page == NULL) {
+ } else {
spin_lock_irqsave(&zone->lock, flags);
page = __rmqueue(zone, order);
spin_unlock_irqrestore(&zone->lock, flags);
@@ -754,20 +755,25 @@ buffered_rmqueue(struct zone *zone, int order, gfp_t gfp_flags)
return page;
}
+#define ALLOC_NO_WATERMARKS 0x01 /* don't check watermarks at all */
+#define ALLOC_HARDER 0x02 /* try to alloc harder */
+#define ALLOC_HIGH 0x04 /* __GFP_HIGH set */
+#define ALLOC_CPUSET 0x08 /* check for correct cpuset */
+
/*
* Return 1 if free pages are above 'mark'. This takes into account the order
* of the allocation.
*/
int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
- int classzone_idx, int can_try_harder, gfp_t gfp_high)
+ int classzone_idx, int alloc_flags)
{
/* free_pages my go negative - that's OK */
long min = mark, free_pages = z->free_pages - (1 << order) + 1;
int o;
- if (gfp_high)
+ if (alloc_flags & ALLOC_HIGH)
min -= min / 2;
- if (can_try_harder)
+ if (alloc_flags & ALLOC_HARDER)
min -= min / 4;
if (free_pages <= min + z->lowmem_reserve[classzone_idx])
@@ -785,14 +791,40 @@ int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
return 1;
}
-static inline int
-should_reclaim_zone(struct zone *z, gfp_t gfp_mask)
+/*
+ * get_page_from_freeliest goes through the zonelist trying to allocate
+ * a page.
+ */
+static struct page *
+get_page_from_freelist(gfp_t gfp_mask, unsigned int order,
+ struct zonelist *zonelist, int alloc_flags)
{
- if (!z->reclaim_pages)
- return 0;
- if (gfp_mask & __GFP_NORECLAIM)
- return 0;
- return 1;
+ struct zone **z = zonelist->zones;
+ struct page *page = NULL;
+ int classzone_idx = zone_idx(*z);
+
+ /*
+ * Go through the zonelist once, looking for a zone with enough free.
+ * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+ */
+ do {
+ if ((alloc_flags & ALLOC_CPUSET) &&
+ !cpuset_zone_allowed(*z, gfp_mask))
+ continue;
+
+ if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
+ if (!zone_watermark_ok(*z, order, (*z)->pages_low,
+ classzone_idx, alloc_flags))
+ continue;
+ }
+
+ page = buffered_rmqueue(*z, order, gfp_mask);
+ if (page) {
+ zone_statistics(zonelist, *z);
+ break;
+ }
+ } while (*(++z) != NULL);
+ return page;
}
/*
@@ -803,105 +835,75 @@ __alloc_pages(gfp_t gfp_mask, unsigned int order,
struct zonelist *zonelist)
{
const gfp_t wait = gfp_mask & __GFP_WAIT;
- struct zone **zones, *z;
+ struct zone **z;
struct page *page;
struct reclaim_state reclaim_state;
struct task_struct *p = current;
- int i;
- int classzone_idx;
int do_retry;
- int can_try_harder;
+ int alloc_flags;
int did_some_progress;
might_sleep_if(wait);
- /*
- * The caller may dip into page reserves a bit more if the caller
- * cannot run direct reclaim, or is the caller has realtime scheduling
- * policy
- */
- can_try_harder = (unlikely(rt_task(p)) && !in_interrupt()) || !wait;
-
- zones = zonelist->zones; /* the list of zones suitable for gfp_mask */
+ z = zonelist->zones; /* the list of zones suitable for gfp_mask */
- if (unlikely(zones[0] == NULL)) {
+ if (unlikely(*z == NULL)) {
/* Should this ever happen?? */
return NULL;
}
+restart:
+ page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order,
+ zonelist, ALLOC_CPUSET);
+ if (page)
+ goto got_pg;
- classzone_idx = zone_idx(zones[0]);
+ do
+ wakeup_kswapd(*z, order);
+ while (*(++z));
-restart:
/*
- * Go through the zonelist once, looking for a zone with enough free.
- * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+ * OK, we're below the kswapd watermark and have kicked background
+ * reclaim. Now things get more complex, so set up alloc_flags according
+ * to how we want to proceed.
+ *
+ * The caller may dip into page reserves a bit more if the caller
+ * cannot run direct reclaim, or if the caller has realtime scheduling
+ * policy.
*/
- for (i = 0; (z = zones[i]) != NULL; i++) {
- int do_reclaim = should_reclaim_zone(z, gfp_mask);
-
- if (!cpuset_zone_allowed(z, __GFP_HARDWALL))
- continue;
-
- /*
- * If the zone is to attempt early page reclaim then this loop
- * will try to reclaim pages and check the watermark a second
- * time before giving up and falling back to the next zone.
- */
-zone_reclaim_retry:
- if (!zone_watermark_ok(z, order, z->pages_low,
- classzone_idx, 0, 0)) {
- if (!do_reclaim)
- continue;
- else {
- zone_reclaim(z, gfp_mask, order);
- /* Only try reclaim once */
- do_reclaim = 0;
- goto zone_reclaim_retry;
- }
- }
-
- page = buffered_rmqueue(z, order, gfp_mask);
- if (page)
- goto got_pg;
- }
-
- for (i = 0; (z = zones[i]) != NULL; i++)
- wakeup_kswapd(z, order);
+ alloc_flags = 0;
+ if ((unlikely(rt_task(p)) && !in_interrupt()) || !wait)
+ alloc_flags |= ALLOC_HARDER;
+ if (gfp_mask & __GFP_HIGH)
+ alloc_flags |= ALLOC_HIGH;
+ if (wait)
+ alloc_flags |= ALLOC_CPUSET;
/*
* Go through the zonelist again. Let __GFP_HIGH and allocations
- * coming from realtime tasks to go deeper into reserves
+ * coming from realtime tasks go deeper into reserves.
*
* This is the last chance, in general, before the goto nopage.
* Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
* See also cpuset_zone_allowed() comment in kernel/cpuset.c.
*/
- for (i = 0; (z = zones[i]) != NULL; i++) {
- if (!zone_watermark_ok(z, order, z->pages_min,
- classzone_idx, can_try_harder,
- gfp_mask & __GFP_HIGH))
- continue;
-
- if (wait && !cpuset_zone_allowed(z, gfp_mask))
- continue;
-
- page = buffered_rmqueue(z, order, gfp_mask);
- if (page)
- goto got_pg;
- }
+ page = get_page_from_freelist(gfp_mask, order, zonelist, alloc_flags);
+ if (page)
+ goto got_pg;
/* This allocation should allow future memory freeing. */
if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE)))
&& !in_interrupt()) {
if (!(gfp_mask & __GFP_NOMEMALLOC)) {
+nofail_alloc:
/* go through the zonelist yet again, ignoring mins */
- for (i = 0; (z = zones[i]) != NULL; i++) {
- if (!cpuset_zone_allowed(z, gfp_mask))
- continue;
- page = buffered_rmqueue(z, order, gfp_mask);
- if (page)
- goto got_pg;
+ page = get_page_from_freelist(gfp_mask, order,
+ zonelist, ALLOC_NO_WATERMARKS|ALLOC_CPUSET);
+ if (page)
+ goto got_pg;
+ if (gfp_mask & __GFP_NOFAIL) {
+ blk_congestion_wait(WRITE, HZ/50);
+ goto nofail_alloc;
}
}
goto nopage;
@@ -919,7 +921,7 @@ rebalance:
reclaim_state.reclaimed_slab = 0;
p->reclaim_state = &reclaim_state;
- did_some_progress = try_to_free_pages(zones, gfp_mask);
+ did_some_progress = try_to_free_pages(zonelist->zones, gfp_mask);
p->reclaim_state = NULL;
p->flags &= ~PF_MEMALLOC;
@@ -927,19 +929,10 @@ rebalance:
cond_resched();
if (likely(did_some_progress)) {
- for (i = 0; (z = zones[i]) != NULL; i++) {
- if (!zone_watermark_ok(z, order, z->pages_min,
- classzone_idx, can_try_harder,
- gfp_mask & __GFP_HIGH))
- continue;
-
- if (!cpuset_zone_allowed(z, gfp_mask))
- continue;
-
- page = buffered_rmqueue(z, order, gfp_mask);
- if (page)
- goto got_pg;
- }
+ page = get_page_from_freelist(gfp_mask, order,
+ zonelist, alloc_flags);
+ if (page)
+ goto got_pg;
} else if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) {
/*
* Go through the zonelist yet one more time, keep
@@ -947,18 +940,10 @@ rebalance:
* a parallel oom killing, we must fail if we're still
* under heavy pressure.
*/
- for (i = 0; (z = zones[i]) != NULL; i++) {
- if (!zone_watermark_ok(z, order, z->pages_high,
- classzone_idx, 0, 0))
- continue;
-
- if (!cpuset_zone_allowed(z, __GFP_HARDWALL))
- continue;
-
- page = buffered_rmqueue(z, order, gfp_mask);
- if (page)
- goto got_pg;
- }
+ page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, order,
+ zonelist, ALLOC_CPUSET);
+ if (page)
+ goto got_pg;
out_of_memory(gfp_mask, order);
goto restart;
@@ -991,9 +976,7 @@ nopage:
dump_stack();
show_mem();
}
- return NULL;
got_pg:
- zone_statistics(zonelist, z);
return page;
}
@@ -1441,6 +1424,10 @@ static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zoneli
zone = pgdat->node_zones + ZONE_NORMAL;
if (zone->present_pages)
zonelist->zones[j++] = zone;
+ case ZONE_DMA32:
+ zone = pgdat->node_zones + ZONE_DMA32;
+ if (zone->present_pages)
+ zonelist->zones[j++] = zone;
case ZONE_DMA:
zone = pgdat->node_zones + ZONE_DMA;
if (zone->present_pages)
@@ -1455,6 +1442,8 @@ static inline int highest_zone(int zone_bits)
int res = ZONE_NORMAL;
if (zone_bits & (__force int)__GFP_HIGHMEM)
res = ZONE_HIGHMEM;
+ if (zone_bits & (__force int)__GFP_DMA32)
+ res = ZONE_DMA32;
if (zone_bits & (__force int)__GFP_DMA)
res = ZONE_DMA;
return res;
@@ -1866,11 +1855,10 @@ static int __devinit pageset_cpuup_callback(struct notifier_block *nfb,
if (process_zones(cpu))
ret = NOTIFY_BAD;
break;
-#ifdef CONFIG_HOTPLUG_CPU
+ case CPU_UP_CANCELED:
case CPU_DEAD:
free_zone_pagesets(cpu);
break;
-#endif
default:
break;
}
@@ -1975,7 +1963,7 @@ static void __init free_area_init_core(struct pglist_data *pgdat,
if (zholes_size)
realsize -= zholes_size[j];
- if (j == ZONE_DMA || j == ZONE_NORMAL)
+ if (j < ZONE_HIGHMEM)
nr_kernel_pages += realsize;
nr_all_pages += realsize;
@@ -2417,13 +2405,18 @@ void setup_per_zone_pages_min(void)
}
for_each_zone(zone) {
+ unsigned long tmp;
spin_lock_irqsave(&zone->lru_lock, flags);
+ tmp = (pages_min * zone->present_pages) / lowmem_pages;
if (is_highmem(zone)) {
/*
- * Often, highmem doesn't need to reserve any pages.
- * But the pages_min/low/high values are also used for
- * batching up page reclaim activity so we need a
- * decent value here.
+ * __GFP_HIGH and PF_MEMALLOC allocations usually don't
+ * need highmem pages, so cap pages_min to a small
+ * value here.
+ *
+ * The (pages_high-pages_low) and (pages_low-pages_min)
+ * deltas controls asynch page reclaim, and so should
+ * not be capped for highmem.
*/
int min_pages;
@@ -2434,19 +2427,15 @@ void setup_per_zone_pages_min(void)
min_pages = 128;
zone->pages_min = min_pages;
} else {
- /* if it's a lowmem zone, reserve a number of pages
+ /*
+ * If it's a lowmem zone, reserve a number of pages
* proportionate to the zone's size.
*/
- zone->pages_min = (pages_min * zone->present_pages) /
- lowmem_pages;
+ zone->pages_min = tmp;
}
- /*
- * When interpreting these watermarks, just keep in mind that:
- * zone->pages_min == (zone->pages_min * 4) / 4;
- */
- zone->pages_low = (zone->pages_min * 5) / 4;
- zone->pages_high = (zone->pages_min * 6) / 4;
+ zone->pages_low = zone->pages_min + tmp / 4;
+ zone->pages_high = zone->pages_min + tmp / 2;
spin_unlock_irqrestore(&zone->lru_lock, flags);
}
}
diff --git a/mm/slab.c b/mm/slab.c
index 8a73dcfc6a2..e5ec26e0c46 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -565,14 +565,29 @@ static void **dbg_userword(kmem_cache_t *cachep, void *objp)
#define BREAK_GFP_ORDER_LO 0
static int slab_break_gfp_order = BREAK_GFP_ORDER_LO;
-/* Macros for storing/retrieving the cachep and or slab from the
+/* Functions for storing/retrieving the cachep and or slab from the
* global 'mem_map'. These are used to find the slab an obj belongs to.
* With kfree(), these are used to find the cache which an obj belongs to.
*/
-#define SET_PAGE_CACHE(pg,x) ((pg)->lru.next = (struct list_head *)(x))
-#define GET_PAGE_CACHE(pg) ((kmem_cache_t *)(pg)->lru.next)
-#define SET_PAGE_SLAB(pg,x) ((pg)->lru.prev = (struct list_head *)(x))
-#define GET_PAGE_SLAB(pg) ((struct slab *)(pg)->lru.prev)
+static inline void page_set_cache(struct page *page, struct kmem_cache *cache)
+{
+ page->lru.next = (struct list_head *)cache;
+}
+
+static inline struct kmem_cache *page_get_cache(struct page *page)
+{
+ return (struct kmem_cache *)page->lru.next;
+}
+
+static inline void page_set_slab(struct page *page, struct slab *slab)
+{
+ page->lru.prev = (struct list_head *)slab;
+}
+
+static inline struct slab *page_get_slab(struct page *page)
+{
+ return (struct slab *)page->lru.prev;
+}
/* These are the default caches for kmalloc. Custom caches can have other sizes. */
struct cache_sizes malloc_sizes[] = {
@@ -1190,11 +1205,7 @@ static void *kmem_getpages(kmem_cache_t *cachep, gfp_t flags, int nodeid)
int i;
flags |= cachep->gfpflags;
- if (likely(nodeid == -1)) {
- page = alloc_pages(flags, cachep->gfporder);
- } else {
- page = alloc_pages_node(nodeid, flags, cachep->gfporder);
- }
+ page = alloc_pages_node(nodeid, flags, cachep->gfporder);
if (!page)
return NULL;
addr = page_address(page);
@@ -1368,7 +1379,7 @@ static void check_poison_obj(kmem_cache_t *cachep, void *objp)
/* Print some data about the neighboring objects, if they
* exist:
*/
- struct slab *slabp = GET_PAGE_SLAB(virt_to_page(objp));
+ struct slab *slabp = page_get_slab(virt_to_page(objp));
int objnr;
objnr = (objp-slabp->s_mem)/cachep->objsize;
@@ -2138,8 +2149,8 @@ static void set_slab_attr(kmem_cache_t *cachep, struct slab *slabp, void *objp)
i = 1 << cachep->gfporder;
page = virt_to_page(objp);
do {
- SET_PAGE_CACHE(page, cachep);
- SET_PAGE_SLAB(page, slabp);
+ page_set_cache(page, cachep);
+ page_set_slab(page, slabp);
page++;
} while (--i);
}
@@ -2269,14 +2280,14 @@ static void *cache_free_debugcheck(kmem_cache_t *cachep, void *objp,
kfree_debugcheck(objp);
page = virt_to_page(objp);
- if (GET_PAGE_CACHE(page) != cachep) {
+ if (page_get_cache(page) != cachep) {
printk(KERN_ERR "mismatch in kmem_cache_free: expected cache %p, got %p\n",
- GET_PAGE_CACHE(page),cachep);
+ page_get_cache(page),cachep);
printk(KERN_ERR "%p is %s.\n", cachep, cachep->name);
- printk(KERN_ERR "%p is %s.\n", GET_PAGE_CACHE(page), GET_PAGE_CACHE(page)->name);
+ printk(KERN_ERR "%p is %s.\n", page_get_cache(page), page_get_cache(page)->name);
WARN_ON(1);
}
- slabp = GET_PAGE_SLAB(page);
+ slabp = page_get_slab(page);
if (cachep->flags & SLAB_RED_ZONE) {
if (*dbg_redzone1(cachep, objp) != RED_ACTIVE || *dbg_redzone2(cachep, objp) != RED_ACTIVE) {
@@ -2628,7 +2639,7 @@ static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects, int n
struct slab *slabp;
unsigned int objnr;
- slabp = GET_PAGE_SLAB(virt_to_page(objp));
+ slabp = page_get_slab(virt_to_page(objp));
l3 = cachep->nodelists[node];
list_del(&slabp->list);
objnr = (objp - slabp->s_mem) / cachep->objsize;
@@ -2744,7 +2755,7 @@ static inline void __cache_free(kmem_cache_t *cachep, void *objp)
#ifdef CONFIG_NUMA
{
struct slab *slabp;
- slabp = GET_PAGE_SLAB(virt_to_page(objp));
+ slabp = page_get_slab(virt_to_page(objp));
if (unlikely(slabp->nodeid != numa_node_id())) {
struct array_cache *alien = NULL;
int nodeid = slabp->nodeid;
@@ -2830,7 +2841,7 @@ int fastcall kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)
page = virt_to_page(ptr);
if (unlikely(!PageSlab(page)))
goto out;
- if (unlikely(GET_PAGE_CACHE(page) != cachep))
+ if (unlikely(page_get_cache(page) != cachep))
goto out;
return 1;
out:
@@ -3026,7 +3037,7 @@ void kfree(const void *objp)
return;
local_irq_save(flags);
kfree_debugcheck(objp);
- c = GET_PAGE_CACHE(virt_to_page(objp));
+ c = page_get_cache(virt_to_page(objp));
__cache_free(c, (void*)objp);
local_irq_restore(flags);
}
@@ -3596,7 +3607,7 @@ unsigned int ksize(const void *objp)
if (unlikely(objp == NULL))
return 0;
- return obj_reallen(GET_PAGE_CACHE(virt_to_page(objp)));
+ return obj_reallen(page_get_cache(virt_to_page(objp)));
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 135bf8ca96e..28130541270 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1074,7 +1074,7 @@ loop_again:
continue;
if (!zone_watermark_ok(zone, order,
- zone->pages_high, 0, 0, 0)) {
+ zone->pages_high, 0, 0)) {
end_zone = i;
goto scan;
}
@@ -1111,7 +1111,7 @@ scan:
if (nr_pages == 0) { /* Not software suspend */
if (!zone_watermark_ok(zone, order,
- zone->pages_high, end_zone, 0, 0))
+ zone->pages_high, end_zone, 0))
all_zones_ok = 0;
}
zone->temp_priority = priority;
@@ -1259,7 +1259,7 @@ void wakeup_kswapd(struct zone *zone, int order)
return;
pgdat = zone->zone_pgdat;
- if (zone_watermark_ok(zone, order, zone->pages_low, 0, 0, 0))
+ if (zone_watermark_ok(zone, order, zone->pages_low, 0, 0))
return;
if (pgdat->kswapd_max_order < order)
pgdat->kswapd_max_order = order;
diff --git a/net/Makefile b/net/Makefile
index 4aa2f46d2a5..f5141b9d4f3 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -15,8 +15,8 @@ obj-$(CONFIG_NET) += $(tmp-y)
# LLC has to be linked before the files in net/802/
obj-$(CONFIG_LLC) += llc/
obj-$(CONFIG_NET) += ethernet/ 802/ sched/ netlink/
-obj-$(CONFIG_INET) += ipv4/
obj-$(CONFIG_NETFILTER) += netfilter/
+obj-$(CONFIG_INET) += ipv4/
obj-$(CONFIG_XFRM) += xfrm/
obj-$(CONFIG_UNIX) += unix/
ifneq ($(CONFIG_IPV6),)
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index d2a4fec2286..de9f4464438 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -467,7 +467,7 @@ out:
}
#endif
-static const int cta_min_ip[CTA_IP_MAX] = {
+static const size_t cta_min_ip[CTA_IP_MAX] = {
[CTA_IP_V4_SRC-1] = sizeof(u_int32_t),
[CTA_IP_V4_DST-1] = sizeof(u_int32_t),
};
@@ -497,7 +497,7 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
return 0;
}
-static const int cta_min_proto[CTA_PROTO_MAX] = {
+static const size_t cta_min_proto[CTA_PROTO_MAX] = {
[CTA_PROTO_NUM-1] = sizeof(u_int16_t),
[CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t),
[CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t),
@@ -576,7 +576,7 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
}
#ifdef CONFIG_IP_NF_NAT_NEEDED
-static const int cta_min_protonat[CTA_PROTONAT_MAX] = {
+static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = {
[CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t),
[CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t),
};
@@ -614,6 +614,11 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
return 0;
}
+static const size_t cta_min_nat[CTA_NAT_MAX] = {
+ [CTA_NAT_MINIP-1] = sizeof(u_int32_t),
+ [CTA_NAT_MAXIP-1] = sizeof(u_int32_t),
+};
+
static inline int
ctnetlink_parse_nat(struct nfattr *cda[],
const struct ip_conntrack *ct, struct ip_nat_range *range)
@@ -627,6 +632,9 @@ ctnetlink_parse_nat(struct nfattr *cda[],
nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
+ if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat))
+ return -EINVAL;
+
if (tb[CTA_NAT_MINIP-1])
range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
@@ -667,6 +675,14 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
return 0;
}
+static const size_t cta_min[CTA_MAX] = {
+ [CTA_STATUS-1] = sizeof(u_int32_t),
+ [CTA_TIMEOUT-1] = sizeof(u_int32_t),
+ [CTA_MARK-1] = sizeof(u_int32_t),
+ [CTA_USE-1] = sizeof(u_int32_t),
+ [CTA_ID-1] = sizeof(u_int32_t)
+};
+
static int
ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
@@ -678,6 +694,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
DEBUGP("entered %s\n", __FUNCTION__);
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
if (cda[CTA_TUPLE_ORIG-1])
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
else if (cda[CTA_TUPLE_REPLY-1])
@@ -760,6 +779,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
return 0;
}
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
if (cda[CTA_TUPLE_ORIG-1])
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG);
else if (cda[CTA_TUPLE_REPLY-1])
@@ -1047,6 +1069,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
DEBUGP("entered %s\n", __FUNCTION__);
+ if (nfattr_bad_size(cda, CTA_MAX, cta_min))
+ return -EINVAL;
+
if (cda[CTA_TUPLE_ORIG-1]) {
err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG);
if (err < 0)
@@ -1252,6 +1277,11 @@ out:
return skb->len;
}
+static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
+ [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t),
+ [CTA_EXPECT_ID-1] = sizeof(u_int32_t)
+};
+
static int
ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *cda[], int *errp)
@@ -1263,6 +1293,9 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
DEBUGP("entered %s\n", __FUNCTION__);
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct nfgenmsg *msg = NLMSG_DATA(nlh);
u32 rlen;
@@ -1333,6 +1366,9 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
struct ip_conntrack_helper *h;
int err;
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
if (cda[CTA_EXPECT_TUPLE-1]) {
/* delete a single expect by tuple */
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
@@ -1462,6 +1498,9 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
DEBUGP("entered %s\n", __FUNCTION__);
+ if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
+ return -EINVAL;
+
if (!cda[CTA_EXPECT_TUPLE-1]
|| !cda[CTA_EXPECT_MASK-1]
|| !cda[CTA_EXPECT_MASTER-1])
@@ -1504,29 +1543,22 @@ static struct notifier_block ctnl_notifier_exp = {
static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
[IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack,
- .attr_count = CTA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_MAX, },
[IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack,
- .attr_count = CTA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_MAX, },
[IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack,
- .attr_count = CTA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_MAX, },
[IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack,
- .attr_count = CTA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_MAX, },
};
static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
[IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect,
- .attr_count = CTA_EXPECT_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_EXPECT_MAX, },
[IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect,
- .attr_count = CTA_EXPECT_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_EXPECT_MAX, },
[IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect,
- .attr_count = CTA_EXPECT_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = CTA_EXPECT_MAX, },
};
static struct nfnetlink_subsystem ctnl_subsys = {
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index 5b3f5220f28..ee3b7d6c4d2 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -357,6 +357,10 @@ nfattr_failure:
return -1;
}
+static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = {
+ [CTA_PROTOINFO_TCP_STATE-1] = sizeof(u_int8_t),
+};
+
static int nfattr_to_tcp(struct nfattr *cda[], struct ip_conntrack *ct)
{
struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1];
@@ -369,6 +373,9 @@ static int nfattr_to_tcp(struct nfattr *cda[], struct ip_conntrack *ct)
nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr);
+ if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp))
+ return -EINVAL;
+
if (!tb[CTA_PROTOINFO_TCP_STATE-1])
return -EINVAL;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 40a26b7157b..bf2e23086bc 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -367,7 +367,7 @@ static void tcp_rcv_rtt_update(struct tcp_sock *tp, u32 sample, int win_dep)
* are stalled on filesystem I/O.
*
* Also, since we are only going for a minimum in the
- * non-timestamp case, we do not smoother things out
+ * non-timestamp case, we do not smooth things out
* else with timestamps disabled convergence takes too
* long.
*/
@@ -546,7 +546,7 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
*
* Funny. This algorithm seems to be very broken.
* These formulae increase RTO, when it should be decreased, increase
- * too slowly, when it should be increased fastly, decrease too fastly
+ * too slowly, when it should be increased quickly, decrease too quickly
* etc. I guess in BSD RTO takes ONE value, so that it is absolutely
* does not matter how to _calculate_ it. Seems, it was trap
* that VJ failed to avoid. 8)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index ddcf7754eec..56a09a4ac41 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1045,9 +1045,10 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
}
#endif
/* Rule 8: Use longest matching prefix */
- if (hiscore.rule < 8)
+ if (hiscore.rule < 8) {
hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr);
- score.rule++;
+ hiscore.rule++;
+ }
score.matchlen = ipv6_addr_diff(&ifa->addr, daddr);
if (score.matchlen > hiscore.matchlen) {
score.rule = 8;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 003fd99ff59..25757ade989 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -287,7 +287,7 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
{
struct ipv6_txoptions *opt;
if (optlen == 0)
- optval = 0;
+ optval = NULL;
/* hop-by-hop / destination options are privileged option */
retv = -EPERM;
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 971ba60bf6e..060d6120241 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -5,10 +5,20 @@
menu "IPv6: Netfilter Configuration (EXPERIMENTAL)"
depends on INET && IPV6 && NETFILTER && EXPERIMENTAL
-#tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP6_NF_CONNTRACK
-#if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
-# dep_tristate ' FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
-#fi
+config NF_CONNTRACK_IPV6
+ tristate "IPv6 support for new connection tracking (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && NF_CONNTRACK
+ ---help---
+ Connection tracking keeps a record of what packets have passed
+ through your machine, in order to figure out how they are related
+ into connections.
+
+ This is IPv6 support on Layer 3 independent connection tracking.
+ Layer 3 independent connection tracking is experimental scheme
+ which generalize ip_conntrack to support other layer 3 protocols.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP6_NF_QUEUE
tristate "IP6 Userspace queueing via NETLINK (OBSOLETE)"
---help---
@@ -114,7 +124,6 @@ config IP6_NF_MATCH_OWNER
To compile it as a module, choose M here. If unsure, say N.
-# dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
config IP6_NF_MATCH_MARK
tristate "netfilter MARK match support"
depends on IP6_NF_IPTABLES
@@ -170,15 +179,6 @@ config IP6_NF_MATCH_PHYSDEV
To compile it as a module, choose M here. If unsure, say N.
-# dep_tristate ' Multiple port match support' CONFIG_IP6_NF_MATCH_MULTIPORT $CONFIG_IP6_NF_IPTABLES
-# dep_tristate ' TOS match support' CONFIG_IP6_NF_MATCH_TOS $CONFIG_IP6_NF_IPTABLES
-# if [ "$CONFIG_IP6_NF_CONNTRACK" != "n" ]; then
-# dep_tristate ' Connection state match support' CONFIG_IP6_NF_MATCH_STATE $CONFIG_IP6_NF_CONNTRACK $CONFIG_IP6_NF_IPTABLES
-# fi
-# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-# dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_UNCLEAN $CONFIG_IP6_NF_IPTABLES
-# dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_OWNER $CONFIG_IP6_NF_IPTABLES
-# fi
# The targets
config IP6_NF_FILTER
tristate "Packet filtering"
@@ -220,12 +220,6 @@ config IP6_NF_TARGET_NFQUEUE
To compile it as a module, choose M here. If unsure, say N.
-# if [ "$CONFIG_IP6_NF_FILTER" != "n" ]; then
-# dep_tristate ' REJECT target support' CONFIG_IP6_NF_TARGET_REJECT $CONFIG_IP6_NF_FILTER
-# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-# dep_tristate ' MIRROR target support (EXPERIMENTAL)' CONFIG_IP6_NF_TARGET_MIRROR $CONFIG_IP6_NF_FILTER
-# fi
-# fi
config IP6_NF_MANGLE
tristate "Packet mangling"
depends on IP6_NF_IPTABLES
@@ -236,7 +230,6 @@ config IP6_NF_MANGLE
To compile it as a module, choose M here. If unsure, say N.
-# dep_tristate ' TOS target support' CONFIG_IP6_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE
config IP6_NF_TARGET_MARK
tristate "MARK target support"
depends on IP6_NF_MANGLE
@@ -266,7 +259,6 @@ config IP6_NF_TARGET_HL
To compile it as a module, choose M here. If unsure, say N.
-#dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
config IP6_NF_RAW
tristate 'raw table support (required for TRACE)'
depends on IP6_NF_IPTABLES
@@ -278,19 +270,5 @@ config IP6_NF_RAW
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
-config NF_CONNTRACK_IPV6
- tristate "IPv6 support for new connection tracking (EXPERIMENTAL)"
- depends on EXPERIMENTAL && NF_CONNTRACK
- ---help---
- Connection tracking keeps a record of what packets have passed
- through your machine, in order to figure out how they are related
- into connections.
-
- This is IPv6 support on Layer 3 independent connection tracking.
- Layer 3 independent connection tracking is experimental scheme
- which generalize ip_conntrack to support other layer 3 protocols.
-
- To compile it as a module, choose M here. If unsure, say N.
-
endmenu
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index e2c90b3a807..753a3ae8502 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -339,8 +339,8 @@ extern unsigned long nf_ct_icmpv6_timeout;
/* From nf_conntrack_frag6.c */
extern unsigned long nf_ct_frag6_timeout;
-extern unsigned long nf_ct_frag6_low_thresh;
-extern unsigned long nf_ct_frag6_high_thresh;
+extern unsigned int nf_ct_frag6_low_thresh;
+extern unsigned int nf_ct_frag6_high_thresh;
static struct ctl_table_header *nf_ct_ipv6_sysctl_header;
@@ -367,7 +367,7 @@ static ctl_table nf_ct_sysctl_table[] = {
.data = &nf_ct_frag6_low_thresh,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = &proc_dointvec_jiffies,
+ .proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_NF_CONNTRACK_FRAG6_HIGH_THRESH,
@@ -375,7 +375,7 @@ static ctl_table nf_ct_sysctl_table[] = {
.data = &nf_ct_frag6_high_thresh,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = &proc_dointvec_jiffies,
+ .proc_handler = &proc_dointvec,
},
{ .ctl_name = 0 }
};
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 7640b9bb769..c2c52af9e56 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -55,9 +55,9 @@
#define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */
#define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT
-int nf_ct_frag6_high_thresh = 256*1024;
-int nf_ct_frag6_low_thresh = 192*1024;
-int nf_ct_frag6_timeout = IPV6_FRAG_TIMEOUT;
+unsigned int nf_ct_frag6_high_thresh = 256*1024;
+unsigned int nf_ct_frag6_low_thresh = 192*1024;
+unsigned long nf_ct_frag6_timeout = IPV6_FRAG_TIMEOUT;
struct nf_ct_frag6_skb_cb
{
@@ -190,8 +190,10 @@ static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
atomic_t nf_ct_frag6_mem = ATOMIC_INIT(0);
/* Memory Tracking Functions. */
-static inline void frag_kfree_skb(struct sk_buff *skb)
+static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work)
{
+ if (work)
+ *work -= skb->truesize;
atomic_sub(skb->truesize, &nf_ct_frag6_mem);
if (NFCT_FRAG6_CB(skb)->orig)
kfree_skb(NFCT_FRAG6_CB(skb)->orig);
@@ -199,8 +201,11 @@ static inline void frag_kfree_skb(struct sk_buff *skb)
kfree_skb(skb);
}
-static inline void frag_free_queue(struct nf_ct_frag6_queue *fq)
+static inline void frag_free_queue(struct nf_ct_frag6_queue *fq,
+ unsigned int *work)
{
+ if (work)
+ *work -= sizeof(struct nf_ct_frag6_queue);
atomic_sub(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem);
kfree(fq);
}
@@ -218,7 +223,8 @@ static inline struct nf_ct_frag6_queue *frag_alloc_queue(void)
/* Destruction primitives. */
/* Complete destruction of fq. */
-static void nf_ct_frag6_destroy(struct nf_ct_frag6_queue *fq)
+static void nf_ct_frag6_destroy(struct nf_ct_frag6_queue *fq,
+ unsigned int *work)
{
struct sk_buff *fp;
@@ -230,17 +236,17 @@ static void nf_ct_frag6_destroy(struct nf_ct_frag6_queue *fq)
while (fp) {
struct sk_buff *xp = fp->next;
- frag_kfree_skb(fp);
+ frag_kfree_skb(fp, work);
fp = xp;
}
- frag_free_queue(fq);
+ frag_free_queue(fq, work);
}
-static __inline__ void fq_put(struct nf_ct_frag6_queue *fq)
+static __inline__ void fq_put(struct nf_ct_frag6_queue *fq, unsigned int *work)
{
if (atomic_dec_and_test(&fq->refcnt))
- nf_ct_frag6_destroy(fq);
+ nf_ct_frag6_destroy(fq, work);
}
/* Kill fq entry. It is not destroyed immediately,
@@ -262,16 +268,21 @@ static void nf_ct_frag6_evictor(void)
{
struct nf_ct_frag6_queue *fq;
struct list_head *tmp;
+ unsigned int work;
- for (;;) {
- if (atomic_read(&nf_ct_frag6_mem) <= nf_ct_frag6_low_thresh)
- return;
+ work = atomic_read(&nf_ct_frag6_mem);
+ if (work <= nf_ct_frag6_low_thresh)
+ return;
+
+ work -= nf_ct_frag6_low_thresh;
+ while (work > 0) {
read_lock(&nf_ct_frag6_lock);
if (list_empty(&nf_ct_frag6_lru_list)) {
read_unlock(&nf_ct_frag6_lock);
return;
}
tmp = nf_ct_frag6_lru_list.next;
+ BUG_ON(tmp == NULL);
fq = list_entry(tmp, struct nf_ct_frag6_queue, lru_list);
atomic_inc(&fq->refcnt);
read_unlock(&nf_ct_frag6_lock);
@@ -281,7 +292,7 @@ static void nf_ct_frag6_evictor(void)
fq_kill(fq);
spin_unlock(&fq->lock);
- fq_put(fq);
+ fq_put(fq, &work);
}
}
@@ -298,7 +309,7 @@ static void nf_ct_frag6_expire(unsigned long data)
out:
spin_unlock(&fq->lock);
- fq_put(fq);
+ fq_put(fq, NULL);
}
/* Creation primitives. */
@@ -318,7 +329,7 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
atomic_inc(&fq->refcnt);
write_unlock(&nf_ct_frag6_lock);
fq_in->last_in |= COMPLETE;
- fq_put(fq_in);
+ fq_put(fq_in, NULL);
return fq;
}
}
@@ -535,7 +546,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
fq->fragments = next;
fq->meat -= free_it->len;
- frag_kfree_skb(free_it);
+ frag_kfree_skb(free_it, NULL);
}
}
@@ -811,7 +822,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {
spin_unlock(&fq->lock);
DEBUGP("Can't insert skb to queue\n");
- fq_put(fq);
+ fq_put(fq, NULL);
goto ret_orig;
}
@@ -822,7 +833,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
}
spin_unlock(&fq->lock);
- fq_put(fq);
+ fq_put(fq, NULL);
return ret_skb;
ret_orig:
@@ -881,5 +892,6 @@ int nf_ct_frag6_init(void)
void nf_ct_frag6_cleanup(void)
{
del_timer(&nf_ct_frag6_secret_timer);
+ nf_ct_frag6_low_thresh = 0;
nf_ct_frag6_evictor();
}
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 59d02cbbeb9..c3f0b078345 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -116,7 +116,9 @@ static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, int noblock)
struct llc_sock* llc = llc_sk(sk);
int rc = 0;
- if (unlikely(llc_data_accept_state(llc->state) || llc->p_flag)) {
+ if (unlikely(llc_data_accept_state(llc->state) ||
+ llc->remote_busy_flag ||
+ llc->p_flag)) {
long timeout = sock_sndtimeo(sk, noblock);
rc = llc_ui_wait_for_busy_core(sk, timeout);
@@ -542,6 +544,7 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout)
if (sk_wait_event(sk, &timeout,
(sk->sk_shutdown & RCV_SHUTDOWN) ||
(!llc_data_accept_state(llc->state) &&
+ !llc->remote_busy_flag &&
!llc->p_flag)))
break;
rc = -ERESTARTSYS;
diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
index b0bcfb1f12d..91fb6bc1b11 100644
--- a/net/llc/llc_c_ac.c
+++ b/net/llc/llc_c_ac.c
@@ -866,7 +866,8 @@ int llc_conn_ac_send_ack_if_needed(struct sock *sk, struct sk_buff *skb)
llc->ack_must_be_send = 1;
llc->ack_pf = pf_bit & 1;
}
- if (((llc->vR - llc->first_pdu_Ns + 129) % 128) >= llc->npta) {
+ if (((llc->vR - llc->first_pdu_Ns + 1 + LLC_2_SEQ_NBR_MODULO)
+ % LLC_2_SEQ_NBR_MODULO) >= llc->npta) {
llc_conn_ac_send_rr_rsp_f_set_ackpf(sk, skb);
llc->ack_must_be_send = 0;
llc->ack_pf = 0;
@@ -994,8 +995,8 @@ static int llc_conn_ac_inc_npta_value(struct sock *sk, struct sk_buff *skb)
llc->dec_step = 0;
llc->dec_cntr = llc->inc_cntr = 2;
++llc->npta;
- if (llc->npta > 127)
- llc->npta = 127 ;
+ if (llc->npta > ~LLC_2_SEQ_NBR_MODULO)
+ llc->npta = ~LLC_2_SEQ_NBR_MODULO ;
} else
--llc->inc_cntr;
return 0;
@@ -1065,9 +1066,10 @@ int llc_conn_ac_dec_tx_win_size(struct sock *sk, struct sk_buff *skb)
struct llc_sock *llc = llc_sk(sk);
u8 unacked_pdu = skb_queue_len(&llc->pdu_unack_q);
- llc->k -= unacked_pdu;
- if (llc->k < 2)
- llc->k = 2;
+ if (llc->k - unacked_pdu < 1)
+ llc->k = 1;
+ else
+ llc->k -= unacked_pdu;
return 0;
}
@@ -1084,8 +1086,8 @@ int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct sk_buff *skb)
struct llc_sock *llc = llc_sk(sk);
llc->k += 1;
- if (llc->k > 128)
- llc->k = 128 ;
+ if (llc->k > ~LLC_2_SEQ_NBR_MODULO)
+ llc->k = ~LLC_2_SEQ_NBR_MODULO ;
return 0;
}
@@ -1309,7 +1311,7 @@ int llc_conn_ac_set_vs_nr(struct sock *sk, struct sk_buff *skb)
static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb)
{
- llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % 128;
+ llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % LLC_2_SEQ_NBR_MODULO;
return 0;
}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 9a67c796b38..ea094b231d6 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1395,6 +1395,13 @@ void nf_conntrack_cleanup(void)
kmem_cache_destroy(nf_conntrack_expect_cachep);
free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc,
nf_conntrack_htable_size);
+
+ /* free l3proto protocol tables */
+ for (i = 0; i < PF_MAX; i++)
+ if (nf_ct_protos[i]) {
+ kfree(nf_ct_protos[i]);
+ nf_ct_protos[i] = NULL;
+ }
}
static struct list_head *alloc_hashtable(int size, int *vmalloced)
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 156680ddb04..5a6fcf349bd 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -970,6 +970,12 @@ static int tcp_packet(struct nf_conn *conntrack,
conntrack->timeout.function((unsigned long)
conntrack);
return -NF_REPEAT;
+ } else {
+ write_unlock_bh(&tcp_lock);
+ if (LOG_INVALID(IPPROTO_TCP))
+ nf_log_packet(pf, 0, skb, NULL, NULL,
+ NULL, "nf_ct_tcp: invalid SYN");
+ return -NF_ACCEPT;
}
case TCP_CONNTRACK_CLOSE:
if (index == TCP_RST_SET
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 45224db4fe2..5af381f9fe3 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -694,7 +694,7 @@ static int init_or_cleanup(int init)
cleanup_proc_stat:
#endif
#ifdef CONFIG_PROC_FS
- proc_net_remove("nf_conntrack_stat");
+ remove_proc_entry("nf_conntrack", proc_net_stat);
cleanup_proc_exp:
proc_net_remove("nf_conntrack_expect");
cleanup_proc:
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 83f4c53030f..a60c59b9763 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -223,6 +223,12 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
NFNL_SUBSYS_ID(nlh->nlmsg_type),
NFNL_MSG_TYPE(nlh->nlmsg_type));
+ if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
+ DEBUGP("missing CAP_NET_ADMIN\n");
+ *errp = -EPERM;
+ return -1;
+ }
+
/* Only requests are handled by kernel now. */
if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
DEBUGP("received non-request message\n");
@@ -240,15 +246,12 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
ss = nfnetlink_get_subsys(type);
if (!ss) {
#ifdef CONFIG_KMOD
- if (cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
- /* don't call nfnl_shunlock, since it would reenter
- * with further packet processing */
- up(&nfnl_sem);
- request_module("nfnetlink-subsys-%d",
- NFNL_SUBSYS_ID(type));
- nfnl_shlock();
- ss = nfnetlink_get_subsys(type);
- }
+ /* don't call nfnl_shunlock, since it would reenter
+ * with further packet processing */
+ up(&nfnl_sem);
+ request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
+ nfnl_shlock();
+ ss = nfnetlink_get_subsys(type);
if (!ss)
#endif
goto err_inval;
@@ -260,13 +263,6 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
goto err_inval;
}
- if (nc->cap_required &&
- !cap_raised(NETLINK_CB(skb).eff_cap, nc->cap_required)) {
- DEBUGP("permission denied for type %d\n", type);
- *errp = -EPERM;
- return -1;
- }
-
{
u_int16_t attr_count =
ss->cb[NFNL_MSG_TYPE(nlh->nlmsg_type)].attr_count;
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index d194676f365..cba63729313 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -862,11 +862,9 @@ out_put:
static struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = {
[NFULNL_MSG_PACKET] = { .call = nfulnl_recv_unsupp,
- .attr_count = NFULA_MAX,
- .cap_required = CAP_NET_ADMIN, },
+ .attr_count = NFULA_MAX, },
[NFULNL_MSG_CONFIG] = { .call = nfulnl_recv_config,
- .attr_count = NFULA_CFG_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = NFULA_CFG_MAX, },
};
static struct nfnetlink_subsystem nfulnl_subsys = {
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index f065a6c9495..f28460b61e4 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -931,14 +931,11 @@ out_put:
static struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
[NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp,
- .attr_count = NFQA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = NFQA_MAX, },
[NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict,
- .attr_count = NFQA_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = NFQA_MAX, },
[NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config,
- .attr_count = NFQA_CFG_MAX,
- .cap_required = CAP_NET_ADMIN },
+ .attr_count = NFQA_CFG_MAX, },
};
static struct nfnetlink_subsystem nfqnl_subsys = {
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index e50e7cf4373..c6a51911e71 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1178,6 +1178,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
arg->tail[0].iov_len = 0;
try_to_freeze();
+ cond_resched();
if (signalled())
return -EINTR;
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 8aaf74e6418..2f45fd2969d 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -117,6 +117,8 @@ use strict;
# struct my_struct {
# int a;
# int b;
+# /* private: */
+# int c;
# };
#
# All descriptions can be multiline, except the short function description.
@@ -1304,6 +1306,12 @@ sub dump_struct($$) {
# ignore embedded structs or unions
$members =~ s/{.*?}//g;
+ # ignore members marked private:
+ $members =~ s/\/\*.*?private:.*?public:.*?\*\///gos;
+ $members =~ s/\/\*.*?private:.*//gos;
+ # strip comments:
+ $members =~ s/\/\*.*?\*\///gos;
+
create_parameterlist($members, ';', $file);
output_declaration($declaration_name,
@@ -1329,6 +1337,7 @@ sub dump_enum($$) {
my $x = shift;
my $file = shift;
+ $x =~ s@/\*.*?\*/@@gos; # strip comments.
if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
$declaration_name = $1;
my $members = $2;
@@ -1365,6 +1374,7 @@ sub dump_typedef($$) {
my $x = shift;
my $file = shift;
+ $x =~ s@/\*.*?\*/@@gos; # strip comments.
while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) {
$x =~ s/\(*.\)\s*;$/;/;
$x =~ s/\[*.\]\s*;$/;/;
@@ -1420,7 +1430,7 @@ sub create_parameterlist($$$) {
$type = $arg;
$type =~ s/([^\(]+\(\*)$param/$1/;
push_parameter($param, $type, $file);
- } else {
+ } elsif ($arg) {
$arg =~ s/\s*:\s*/:/g;
$arg =~ s/\s*\[/\[/g;
@@ -1628,7 +1638,6 @@ sub process_state3_type($$) {
my $x = shift;
my $file = shift;
- $x =~ s@/\*.*?\*/@@gos; # strip comments.
$x =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
$x =~ s@^\s+@@gos; # strip leading spaces
$x =~ s@\s+$@@gos; # strip trailing spaces
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index 7c835abd99b..3f30c57676c 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -47,6 +47,7 @@
#include <linux/module.h>
#include <linux/stddef.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/isapnp.h>
#include <linux/pnp.h>
#include <linux/spinlock.h>
diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
index d0d3963e1b8..adc689649fe 100644
--- a/sound/oss/cs4281/cs4281m.c
+++ b/sound/oss/cs4281/cs4281m.c
@@ -298,6 +298,7 @@ struct cs4281_state {
struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES];
};
+#include <linux/pm_legacy.h>
#include "cs4281pm-24.c"
#if CSDEBUG
diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c
index 3dce504e6d6..3abd3541cbc 100644
--- a/sound/oss/maestro.c
+++ b/sound/oss/maestro.c
@@ -231,6 +231,7 @@
#include <asm/uaccess.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
static int maestro_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *d);
#include "maestro.h"
diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c
index 66970062eb3..0ce2c404a73 100644
--- a/sound/oss/nm256_audio.c
+++ b/sound/oss/nm256_audio.c
@@ -25,6 +25,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include "sound_config.h"
diff --git a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c
index 2efbd865109..cd41d0e4706 100644
--- a/sound/oss/opl3sa2.c
+++ b/sound/oss/opl3sa2.c
@@ -70,6 +70,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/pm.h>
+#include <linux/pm_legacy.h>
#include "sound_config.h"
#include "ad1848.h"
@@ -138,7 +139,7 @@ typedef struct {
struct pnp_dev* pdev;
int activated; /* Whether said devices have been activated */
#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
unsigned int in_suspend;
struct pm_dev *pmdev;
#endif
@@ -341,7 +342,7 @@ static void opl3sa2_mixer_reset(opl3sa2_state_t* devc)
}
/* Currently only used for power management */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
static void opl3sa2_mixer_restore(opl3sa2_state_t* devc)
{
if (devc) {
@@ -354,7 +355,7 @@ static void opl3sa2_mixer_restore(opl3sa2_state_t* devc)
}
}
}
-#endif
+#endif /* CONFIG_PM_LEGACY */
static inline void arg_to_vol_mono(unsigned int vol, int* value)
{
@@ -831,7 +832,8 @@ static struct pnp_driver opl3sa2_driver = {
/* End of component functions */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
+
static DEFINE_SPINLOCK(opl3sa2_lock);
/* Power Management support functions */
@@ -906,7 +908,7 @@ static int opl3sa2_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *dat
}
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_LEGACY */
/*
* Install OPL3-SA2 based card(s).
@@ -1019,12 +1021,12 @@ static int __init init_opl3sa2(void)
/* ewww =) */
opl3sa2_state[card].card = card;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
/* register our power management capabilities */
opl3sa2_state[card].pmdev = pm_register(PM_ISA_DEV, card, opl3sa2_pm_callback);
if (opl3sa2_state[card].pmdev)
opl3sa2_state[card].pmdev->data = &opl3sa2_state[card];
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_LEGACY */
/*
* Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and
@@ -1081,7 +1083,7 @@ static void __exit cleanup_opl3sa2(void)
int card;
for(card = 0; card < opl3sa2_cards_num; card++) {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_LEGACY
if (opl3sa2_state[card].pmdev)
pm_unregister(opl3sa2_state[card].pmdev);
#endif